From 4304e01ca21885f0fa5a31106075c6a11c27c5e3 Mon Sep 17 00:00:00 2001 From: greatroar <61184462+greatroar@users.noreply.github.com> Date: Tue, 7 Mar 2023 22:12:08 +0100 Subject: [PATCH] fuse: Report fuse.Attr.Blocks correctly Fixes #4239. --- changelog/unreleased/issue-4239 | 11 +++++++++++ internal/fuse/file.go | 2 +- internal/fuse/fuse_test.go | 32 ++++++++++++++++++++++++++++++++ internal/fuse/link.go | 2 +- internal/fuse/snapshots_dir.go | 2 +- 5 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 changelog/unreleased/issue-4239 diff --git a/changelog/unreleased/issue-4239 b/changelog/unreleased/issue-4239 new file mode 100644 index 000000000..247f3d9ed --- /dev/null +++ b/changelog/unreleased/issue-4239 @@ -0,0 +1,11 @@ +Bugfix: Correct number of blocks reported in mount point + +Restic mount points incorrectly reported the number of 512-byte (POSIX +standard) blocks for files and links, due to a rounding bug. In particular, +empty files were reported as taking one block instead of zero. + +The rounding is now fixed: the number of blocks reported is the file size +(or link target size), divided by 512 and rounded up to a whole number. + +https://github.com/restic/restic/issues/4239 +https://github.com/restic/restic/pull/4240 diff --git a/internal/fuse/file.go b/internal/fuse/file.go index 28ff5d450..35bc2a73e 100644 --- a/internal/fuse/file.go +++ b/internal/fuse/file.go @@ -50,7 +50,7 @@ func (f *file) Attr(ctx context.Context, a *fuse.Attr) error { a.Inode = f.inode a.Mode = f.node.Mode a.Size = f.node.Size - a.Blocks = (f.node.Size / blockSize) + 1 + a.Blocks = (f.node.Size + blockSize - 1) / blockSize a.BlockSize = blockSize a.Nlink = uint32(f.node.Links) diff --git a/internal/fuse/fuse_test.go b/internal/fuse/fuse_test.go index e71bf6fee..863c7672d 100644 --- a/internal/fuse/fuse_test.go +++ b/internal/fuse/fuse_test.go @@ -8,6 +8,7 @@ import ( "context" "math/rand" "os" + "strings" "testing" "time" @@ -216,6 +217,37 @@ func testTopUIDGID(t *testing.T, cfg Config, repo restic.Repository, uid, gid ui rtest.Equals(t, uint32(0), attr.Gid) } +// Test reporting of fuse.Attr.Blocks in multiples of 512. +func TestBlocks(t *testing.T) { + root := &Root{} + + for _, c := range []struct { + size, blocks uint64 + }{ + {0, 0}, + {1, 1}, + {511, 1}, + {512, 1}, + {513, 2}, + {1024, 2}, + {1025, 3}, + {41253, 81}, + } { + target := strings.Repeat("x", int(c.size)) + + for _, n := range []fs.Node{ + &file{root: root, node: &restic.Node{Size: uint64(c.size)}}, + &link{root: root, node: &restic.Node{LinkTarget: target}}, + &snapshotLink{root: root, snapshot: &restic.Snapshot{}, target: target}, + } { + var a fuse.Attr + err := n.Attr(context.TODO(), &a) + rtest.OK(t, err) + rtest.Equals(t, c.blocks, a.Blocks) + } + } +} + func TestInodeFromNode(t *testing.T) { node := &restic.Node{Name: "foo.txt", Type: "chardev", Links: 2} ino1 := inodeFromNode(1, node) diff --git a/internal/fuse/link.go b/internal/fuse/link.go index f910aadc4..47ee666a3 100644 --- a/internal/fuse/link.go +++ b/internal/fuse/link.go @@ -42,7 +42,7 @@ func (l *link) Attr(ctx context.Context, a *fuse.Attr) error { a.Nlink = uint32(l.node.Links) a.Size = uint64(len(l.node.LinkTarget)) - a.Blocks = 1 + a.Size/blockSize + a.Blocks = (a.Size + blockSize - 1) / blockSize return nil } diff --git a/internal/fuse/snapshots_dir.go b/internal/fuse/snapshots_dir.go index 977d0ab17..c19155741 100644 --- a/internal/fuse/snapshots_dir.go +++ b/internal/fuse/snapshots_dir.go @@ -142,7 +142,7 @@ func (l *snapshotLink) Attr(ctx context.Context, a *fuse.Attr) error { a.Inode = l.inode a.Mode = os.ModeSymlink | 0777 a.Size = uint64(len(l.target)) - a.Blocks = 1 + a.Size/blockSize + a.Blocks = (a.Size + blockSize - 1) / blockSize a.Uid = l.root.uid a.Gid = l.root.gid a.Atime = l.snapshot.Time