Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

archiver: Shortcut for handling empty files #4267

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions internal/archiver/archiver.go
Expand Up @@ -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
Expand Down
7 changes: 2 additions & 5 deletions internal/fs/fs_reader.go
Expand Up @@ -23,7 +23,6 @@ type Reader struct {
// for FileInfo
Mode os.FileMode
ModTime time.Time
Size int64

AllowEmptyFile bool

Expand Down Expand Up @@ -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,
}
Expand Down Expand Up @@ -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(),
}
Expand Down Expand Up @@ -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
}
Expand All @@ -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 {
Expand Down
8 changes: 0 additions & 8 deletions internal/fs/fs_reader_test.go
Expand Up @@ -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())
}
Expand Down Expand Up @@ -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})
},
Expand All @@ -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})
},
Expand Down Expand Up @@ -324,7 +318,6 @@ func TestFSReader(t *testing.T) {
ReadCloser: io.NopCloser(bytes.NewReader(data)),

Mode: 0644,
Size: int64(len(data)),
ModTime: now,
}

Expand Down Expand Up @@ -359,7 +352,6 @@ func TestFSReaderDir(t *testing.T) {
ReadCloser: io.NopCloser(bytes.NewReader(data)),

Mode: 0644,
Size: int64(len(data)),
ModTime: now,
}

Expand Down