mirror of
https://github.com/restic/restic.git
synced 2025-03-09 00:00:02 +01:00
archiver: Shortcut for handling empty files
Regular files that are empty according to stat are now not opened for reading their contents. Such files are quite common (in my homedir, at least) and we can save multiple system calls this way. On a network filesystem, that can mean round trips. Also, we can back up empty files that we cannot open for reading. Finally, fixes #4257. Existing tests cover this case. fs.Reader now no longer has a meaningful Size. Nothing depended on that.
This commit is contained in:
parent
f646406822
commit
50d8377e31
3 changed files with 22 additions and 13 deletions
|
@ -363,6 +363,26 @@ func (arch *Archiver) Save(ctx context.Context, snPath, target string, previous
|
|||
|
||||
switch {
|
||||
case fs.IsRegularFile(fi):
|
||||
if fi.Size() == 0 {
|
||||
// Shortcut for empty files. Git uses lots of these, and
|
||||
// some virtual filesystems (notably juicefs; #4257) present
|
||||
// infinitely-sized special files as empty regular files.
|
||||
// We can also save empty files without being able to open them.
|
||||
debug.Log(" %v empty", target)
|
||||
|
||||
node, err := arch.nodeFromFileInfo(snPath, target, fi)
|
||||
if err != nil {
|
||||
return FutureNode{}, false, err
|
||||
}
|
||||
node.Content = restic.IDs{}
|
||||
fn = newFutureNodeWithResult(futureNodeResult{
|
||||
snPath: snPath,
|
||||
target: target,
|
||||
node: node,
|
||||
})
|
||||
return fn, false, nil
|
||||
}
|
||||
|
||||
debug.Log(" %v regular file", target)
|
||||
|
||||
// check if the file has not changed before performing a fopen operation (more expensive, specially
|
||||
|
|
|
@ -23,7 +23,6 @@ type Reader struct {
|
|||
// for FileInfo
|
||||
Mode os.FileMode
|
||||
ModTime time.Time
|
||||
Size int64
|
||||
|
||||
AllowEmptyFile bool
|
||||
|
||||
|
@ -65,7 +64,6 @@ func (fs *Reader) Open(name string) (f File, err error) {
|
|||
func (fs *Reader) fi() os.FileInfo {
|
||||
return fakeFileInfo{
|
||||
name: fs.Name,
|
||||
size: fs.Size,
|
||||
mode: fs.Mode,
|
||||
modtime: fs.ModTime,
|
||||
}
|
||||
|
@ -107,7 +105,6 @@ func (fs *Reader) Lstat(name string) (os.FileInfo, error) {
|
|||
getDirInfo := func(name string) os.FileInfo {
|
||||
fi := fakeFileInfo{
|
||||
name: fs.Base(name),
|
||||
size: 0,
|
||||
mode: os.ModeDir | 0755,
|
||||
modtime: time.Now(),
|
||||
}
|
||||
|
@ -292,7 +289,6 @@ func (d fakeDir) Readdir(n int) ([]os.FileInfo, error) {
|
|||
// fakeFileInfo implements the bare minimum of os.FileInfo.
|
||||
type fakeFileInfo struct {
|
||||
name string
|
||||
size int64
|
||||
mode os.FileMode
|
||||
modtime time.Time
|
||||
}
|
||||
|
@ -302,7 +298,8 @@ func (fi fakeFileInfo) Name() string {
|
|||
}
|
||||
|
||||
func (fi fakeFileInfo) Size() int64 {
|
||||
return fi.size
|
||||
// Fake size to fool the archiver's empty file check.
|
||||
return -1
|
||||
}
|
||||
|
||||
func (fi fakeFileInfo) Mode() os.FileMode {
|
||||
|
|
|
@ -142,10 +142,6 @@ func verifyDirectoryContentsFI(t testing.TB, fs FS, dir string, want []os.FileIn
|
|||
t.Errorf("entry %d: wrong value for ModTime: want %v, got %v", i, fi1.ModTime(), fi2.ModTime())
|
||||
}
|
||||
|
||||
if fi1.Size() != fi2.Size() {
|
||||
t.Errorf("entry %d: wrong value for Size: want %v, got %v", i, fi1.Size(), fi2.Size())
|
||||
}
|
||||
|
||||
if fi1.Sys() != fi2.Sys() {
|
||||
t.Errorf("entry %d: wrong value for Sys: want %v, got %v", i, fi1.Sys(), fi2.Sys())
|
||||
}
|
||||
|
@ -202,7 +198,6 @@ func TestFSReader(t *testing.T) {
|
|||
mode: 0644,
|
||||
modtime: now,
|
||||
name: filename,
|
||||
size: int64(len(data)),
|
||||
}
|
||||
verifyDirectoryContentsFI(t, fs, "/", []os.FileInfo{fi})
|
||||
},
|
||||
|
@ -214,7 +209,6 @@ func TestFSReader(t *testing.T) {
|
|||
mode: 0644,
|
||||
modtime: now,
|
||||
name: filename,
|
||||
size: int64(len(data)),
|
||||
}
|
||||
verifyDirectoryContentsFI(t, fs, ".", []os.FileInfo{fi})
|
||||
},
|
||||
|
@ -324,7 +318,6 @@ func TestFSReader(t *testing.T) {
|
|||
ReadCloser: io.NopCloser(bytes.NewReader(data)),
|
||||
|
||||
Mode: 0644,
|
||||
Size: int64(len(data)),
|
||||
ModTime: now,
|
||||
}
|
||||
|
||||
|
@ -359,7 +352,6 @@ func TestFSReaderDir(t *testing.T) {
|
|||
ReadCloser: io.NopCloser(bytes.NewReader(data)),
|
||||
|
||||
Mode: 0644,
|
||||
Size: int64(len(data)),
|
||||
ModTime: now,
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue