diff --git a/internal/fuse/dir.go b/internal/fuse/dir.go index f899a4313..bff1b2308 100644 --- a/internal/fuse/dir.go +++ b/internal/fuse/dir.go @@ -98,8 +98,6 @@ func newDirFromSnapshot(ctx context.Context, root *Root, inode uint64, snapshot return &dir{ root: root, node: &restic.Node{ - UID: uint32(os.Getuid()), - GID: uint32(os.Getgid()), AccessTime: snapshot.Time, ModTime: snapshot.Time, ChangeTime: snapshot.Time, @@ -114,11 +112,8 @@ func (d *dir) Attr(ctx context.Context, a *fuse.Attr) error { debug.Log("called") a.Inode = d.inode a.Mode = os.ModeDir | d.node.Mode - - if !d.root.cfg.OwnerIsRoot { - a.Uid = d.node.UID - a.Gid = d.node.GID - } + a.Uid = d.root.uid + a.Gid = d.root.gid a.Atime = d.node.AccessTime a.Ctime = d.node.ChangeTime a.Mtime = d.node.ModTime diff --git a/internal/fuse/file_test.go b/internal/fuse/fuse_test.go similarity index 76% rename from internal/fuse/file_test.go rename to internal/fuse/fuse_test.go index 2909d6636..5d4cbb268 100644 --- a/internal/fuse/file_test.go +++ b/internal/fuse/fuse_test.go @@ -8,6 +8,7 @@ package fuse import ( "bytes" "math/rand" + "os" "testing" "time" @@ -152,3 +153,44 @@ func TestFuseFile(t *testing.T) { rtest.OK(t, f.Release(ctx, nil)) } + +// Test top-level directories for their UID and GID. +func TestTopUidGid(t *testing.T) { + repo, cleanup := repository.TestRepository(t) + defer cleanup() + + restic.TestCreateSnapshot(t, repo, time.Unix(1460289341, 207401672), 0, 0) + + testTopUidGid(t, Config{}, repo, uint32(os.Getuid()), uint32(os.Getgid())) + testTopUidGid(t, Config{OwnerIsRoot: true}, repo, 0, 0) +} + +func testTopUidGid(t *testing.T, cfg Config, repo restic.Repository, uid, gid uint32) { + t.Helper() + + ctx := context.Background() + root, err := NewRoot(ctx, repo, cfg) + rtest.OK(t, err) + + var attr fuse.Attr + err = root.Attr(ctx, &attr) + rtest.OK(t, err) + rtest.Equals(t, uid, attr.Uid) + rtest.Equals(t, gid, attr.Gid) + + idsdir, err := root.Lookup(ctx, "ids") + rtest.OK(t, err) + + err = idsdir.Attr(ctx, &attr) + rtest.OK(t, err) + rtest.Equals(t, uid, attr.Uid) + rtest.Equals(t, gid, attr.Gid) + + snapID := loadFirstSnapshot(t, repo).ID().Str() + snapshotdir, err := idsdir.(fs.NodeStringLookuper).Lookup(ctx, snapID) + + err = snapshotdir.Attr(ctx, &attr) + rtest.OK(t, err) + rtest.Equals(t, uid, attr.Uid) + rtest.Equals(t, gid, attr.Gid) +} diff --git a/internal/fuse/meta_dir.go b/internal/fuse/meta_dir.go index 3271b3c29..b6b681065 100644 --- a/internal/fuse/meta_dir.go +++ b/internal/fuse/meta_dir.go @@ -42,11 +42,9 @@ func NewMetaDir(root *Root, inode uint64, entries map[string]fs.Node) *MetaDir { func (d *MetaDir) Attr(ctx context.Context, attr *fuse.Attr) error { attr.Inode = d.inode attr.Mode = os.ModeDir | 0555 + attr.Uid = d.root.uid + attr.Gid = d.root.gid - if !d.root.cfg.OwnerIsRoot { - attr.Uid = uint32(os.Getuid()) - attr.Gid = uint32(os.Getgid()) - } debug.Log("attr: %v", attr) return nil } diff --git a/internal/fuse/root.go b/internal/fuse/root.go index 871e66b2c..12418488f 100644 --- a/internal/fuse/root.go +++ b/internal/fuse/root.go @@ -6,6 +6,7 @@ package fuse import ( + "os" "time" "github.com/restic/restic/internal/debug" @@ -37,6 +38,8 @@ type Root struct { lastCheck time.Time *MetaDir + + uid, gid uint32 } // ensure that *Root implements these interfaces @@ -56,6 +59,11 @@ func NewRoot(ctx context.Context, repo restic.Repository, cfg Config) (*Root, er blobSizeCache: NewBlobSizeCache(ctx, repo.Index()), } + if !cfg.OwnerIsRoot { + root.uid = uint32(os.Getuid()) + root.gid = uint32(os.Getgid()) + } + entries := map[string]fs.Node{ "snapshots": NewSnapshotsDir(root, fs.GenerateDynamicInode(root.inode, "snapshots"), "", ""), "tags": NewTagsDir(root, fs.GenerateDynamicInode(root.inode, "tags")), diff --git a/internal/fuse/snapshots_dir.go b/internal/fuse/snapshots_dir.go index 22247093a..a579d6de4 100644 --- a/internal/fuse/snapshots_dir.go +++ b/internal/fuse/snapshots_dir.go @@ -168,11 +168,9 @@ func NewTagsDir(root *Root, inode uint64) *TagsDir { func (d *SnapshotsDir) Attr(ctx context.Context, attr *fuse.Attr) error { attr.Inode = d.inode attr.Mode = os.ModeDir | 0555 + attr.Uid = d.root.uid + attr.Gid = d.root.gid - if !d.root.cfg.OwnerIsRoot { - attr.Uid = uint32(os.Getuid()) - attr.Gid = uint32(os.Getgid()) - } debug.Log("attr: %v", attr) return nil } @@ -181,11 +179,9 @@ func (d *SnapshotsDir) Attr(ctx context.Context, attr *fuse.Attr) error { func (d *SnapshotsIDSDir) Attr(ctx context.Context, attr *fuse.Attr) error { attr.Inode = d.inode attr.Mode = os.ModeDir | 0555 + attr.Uid = d.root.uid + attr.Gid = d.root.gid - if !d.root.cfg.OwnerIsRoot { - attr.Uid = uint32(os.Getuid()) - attr.Gid = uint32(os.Getgid()) - } debug.Log("attr: %v", attr) return nil } @@ -194,11 +190,9 @@ func (d *SnapshotsIDSDir) Attr(ctx context.Context, attr *fuse.Attr) error { func (d *HostsDir) Attr(ctx context.Context, attr *fuse.Attr) error { attr.Inode = d.inode attr.Mode = os.ModeDir | 0555 + attr.Uid = d.root.uid + attr.Gid = d.root.gid - if !d.root.cfg.OwnerIsRoot { - attr.Uid = uint32(os.Getuid()) - attr.Gid = uint32(os.Getgid()) - } debug.Log("attr: %v", attr) return nil } @@ -207,11 +201,9 @@ func (d *HostsDir) Attr(ctx context.Context, attr *fuse.Attr) error { func (d *TagsDir) Attr(ctx context.Context, attr *fuse.Attr) error { attr.Inode = d.inode attr.Mode = os.ModeDir | 0555 + attr.Uid = d.root.uid + attr.Gid = d.root.gid - if !d.root.cfg.OwnerIsRoot { - attr.Uid = uint32(os.Getuid()) - attr.Gid = uint32(os.Getgid()) - } debug.Log("attr: %v", attr) return nil } @@ -437,11 +429,8 @@ func (l *snapshotLink) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) func (l *snapshotLink) Attr(ctx context.Context, a *fuse.Attr) error { a.Inode = l.inode a.Mode = os.ModeSymlink | 0777 - - if !l.root.cfg.OwnerIsRoot { - a.Uid = uint32(os.Getuid()) - a.Gid = uint32(os.Getgid()) - } + a.Uid = l.root.uid + a.Gid = l.root.gid a.Atime = l.snapshot.Time a.Ctime = l.snapshot.Time a.Mtime = l.snapshot.Time