Merge pull request #251 from restic/fuse-ownership

fuse/mount: Use original UID/GID as owner
This commit is contained in:
Alexander Neumann 2015-07-27 21:39:45 +02:00
commit 17ee6b1c4b
6 changed files with 79 additions and 32 deletions

View File

@ -13,6 +13,8 @@ import (
) )
type CmdMount struct { type CmdMount struct {
Root bool `long:"owner-root" description:"use 'root' as the owner of files and dirs" default:"false"`
global *GlobalOptions global *GlobalOptions
ready chan struct{} ready chan struct{}
done chan struct{} done chan struct{}
@ -69,7 +71,7 @@ func (cmd CmdMount) Execute(args []string) error {
} }
root := fs.Tree{} root := fs.Tree{}
root.Add("snapshots", fuse.NewSnapshotsDir(repo)) root.Add("snapshots", fuse.NewSnapshotsDir(repo, cmd.Root))
cmd.global.Printf("Now serving %s at %s\n", repo.Backend().Location(), mountpoint) cmd.global.Printf("Now serving %s at %s\n", repo.Backend().Location(), mountpoint)
cmd.global.Printf("Don't forget to umount after quitting!\n") cmd.global.Printf("Don't forget to umount after quitting!\n")

View File

@ -16,12 +16,14 @@ var _ = fs.HandleReadDirAller(&dir{})
var _ = fs.NodeStringLookuper(&dir{}) var _ = fs.NodeStringLookuper(&dir{})
type dir struct { type dir struct {
repo *repository.Repository repo *repository.Repository
items map[string]*restic.Node items map[string]*restic.Node
inode uint64 inode uint64
node *restic.Node
ownerIsRoot bool
} }
func newDir(repo *repository.Repository, node *restic.Node) (*dir, error) { func newDir(repo *repository.Repository, node *restic.Node, ownerIsRoot bool) (*dir, error) {
tree, err := restic.LoadTree(repo, *node.Subtree) tree, err := restic.LoadTree(repo, *node.Subtree)
if err != nil { if err != nil {
return nil, err return nil, err
@ -32,13 +34,15 @@ func newDir(repo *repository.Repository, node *restic.Node) (*dir, error) {
} }
return &dir{ return &dir{
repo: repo, repo: repo,
items: items, node: node,
inode: node.Inode, items: items,
inode: node.Inode,
ownerIsRoot: ownerIsRoot,
}, nil }, nil
} }
func newDirFromSnapshot(repo *repository.Repository, snapshot SnapshotWithId) (*dir, error) { func newDirFromSnapshot(repo *repository.Repository, snapshot SnapshotWithId, ownerIsRoot bool) (*dir, error) {
tree, err := restic.LoadTree(repo, *snapshot.Tree) tree, err := restic.LoadTree(repo, *snapshot.Tree)
if err != nil { if err != nil {
return nil, err return nil, err
@ -49,15 +53,32 @@ func newDirFromSnapshot(repo *repository.Repository, snapshot SnapshotWithId) (*
} }
return &dir{ return &dir{
repo: repo, repo: repo,
items: items, node: &restic.Node{
inode: inodeFromBackendId(snapshot.ID), UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
AccessTime: snapshot.Time,
ModTime: snapshot.Time,
ChangeTime: snapshot.Time,
Mode: os.ModeDir | 0555,
},
items: items,
inode: inodeFromBackendId(snapshot.ID),
ownerIsRoot: ownerIsRoot,
}, nil }, nil
} }
func (d *dir) Attr(ctx context.Context, a *fuse.Attr) error { func (d *dir) Attr(ctx context.Context, a *fuse.Attr) error {
a.Inode = d.inode a.Inode = d.inode
a.Mode = os.ModeDir | 0555 a.Mode = os.ModeDir | d.node.Mode
if !d.ownerIsRoot {
a.Uid = d.node.UID
a.Gid = d.node.GID
}
a.Atime = d.node.AccessTime
a.Ctime = d.node.ChangeTime
a.Mtime = d.node.ModTime
return nil return nil
} }
@ -92,11 +113,11 @@ func (d *dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
} }
switch node.Type { switch node.Type {
case "dir": case "dir":
return newDir(d.repo, node) return newDir(d.repo, node, d.ownerIsRoot)
case "file": case "file":
return newFile(d.repo, node) return newFile(d.repo, node, d.ownerIsRoot)
case "symlink": case "symlink":
return newLink(d.repo, node) return newLink(d.repo, node, d.ownerIsRoot)
default: default:
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }

View File

@ -24,8 +24,9 @@ type BlobLoader interface {
} }
type file struct { type file struct {
repo BlobLoader repo BlobLoader
node *restic.Node node *restic.Node
ownerIsRoot bool
sizes []uint sizes []uint
blobs [][]byte blobs [][]byte
@ -39,7 +40,7 @@ var blobPool = sync.Pool{
}, },
} }
func newFile(repo BlobLoader, node *restic.Node) (*file, error) { func newFile(repo BlobLoader, node *restic.Node, ownerIsRoot bool) (*file, error) {
sizes := make([]uint, len(node.Content)) sizes := make([]uint, len(node.Content))
for i, id := range node.Content { for i, id := range node.Content {
size, err := repo.LookupBlobSize(id) size, err := repo.LookupBlobSize(id)
@ -51,10 +52,11 @@ func newFile(repo BlobLoader, node *restic.Node) (*file, error) {
} }
return &file{ return &file{
repo: repo, repo: repo,
node: node, node: node,
sizes: sizes, sizes: sizes,
blobs: make([][]byte, len(node.Content)), blobs: make([][]byte, len(node.Content)),
ownerIsRoot: ownerIsRoot,
}, nil }, nil
} }
@ -62,6 +64,14 @@ func (f *file) Attr(ctx context.Context, a *fuse.Attr) error {
a.Inode = f.node.Inode a.Inode = f.node.Inode
a.Mode = f.node.Mode a.Mode = f.node.Mode
a.Size = f.node.Size a.Size = f.node.Size
if !f.ownerIsRoot {
a.Uid = f.node.UID
a.Gid = f.node.GID
}
a.Atime = f.node.AccessTime
a.Ctime = f.node.ChangeTime
a.Mtime = f.node.ModTime
return nil return nil
} }

View File

@ -3,7 +3,6 @@ package fuse
import ( import (
"bytes" "bytes"
"errors" "errors"
"fmt"
"math/rand" "math/rand"
"testing" "testing"
"time" "time"
@ -121,7 +120,7 @@ func TestFuseFile(t *testing.T) {
Size: 42, Size: 42,
Content: ids, Content: ids,
} }
f, err := newFile(repo, node) f, err := newFile(repo, node, false)
OK(t, err) OK(t, err)
attr := fuse.Attr{} attr := fuse.Attr{}
@ -148,7 +147,6 @@ func TestFuseFile(t *testing.T) {
} }
b := memfile[offset : offset+length] b := memfile[offset : offset+length]
fmt.Printf("test offset %d, length %d\n", offset, length)
res := testRead(t, f, offset, length, b) res := testRead(t, f, offset, length, b)
if !bytes.Equal(b, res) { if !bytes.Equal(b, res) {
t.Errorf("test %d failed (offset %d, length %d), wrong data returned", i, offset, length) t.Errorf("test %d failed (offset %d, length %d), wrong data returned", i, offset, length)

View File

@ -12,11 +12,12 @@ import (
var _ = fs.NodeReadlinker(&link{}) var _ = fs.NodeReadlinker(&link{})
type link struct { type link struct {
node *restic.Node node *restic.Node
ownerIsRoot bool
} }
func newLink(repo *repository.Repository, node *restic.Node) (*link, error) { func newLink(repo *repository.Repository, node *restic.Node, ownerIsRoot bool) (*link, error) {
return &link{node: node}, nil return &link{node: node, ownerIsRoot: ownerIsRoot}, nil
} }
func (l *link) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error) { func (l *link) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error) {
@ -26,5 +27,13 @@ func (l *link) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string,
func (l *link) Attr(ctx context.Context, a *fuse.Attr) error { func (l *link) Attr(ctx context.Context, a *fuse.Attr) error {
a.Inode = l.node.Inode a.Inode = l.node.Inode
a.Mode = l.node.Mode a.Mode = l.node.Mode
if !l.ownerIsRoot {
a.Uid = l.node.UID
a.Gid = l.node.GID
}
a.Atime = l.node.AccessTime
a.Ctime = l.node.ChangeTime
a.Mtime = l.node.ModTime
return nil return nil
} }

View File

@ -27,23 +27,30 @@ var _ = fs.HandleReadDirAller(&SnapshotsDir{})
var _ = fs.NodeStringLookuper(&SnapshotsDir{}) var _ = fs.NodeStringLookuper(&SnapshotsDir{})
type SnapshotsDir struct { type SnapshotsDir struct {
repo *repository.Repository repo *repository.Repository
ownerIsRoot bool
// knownSnapshots maps snapshot timestamp to the snapshot // knownSnapshots maps snapshot timestamp to the snapshot
sync.RWMutex sync.RWMutex
knownSnapshots map[string]SnapshotWithId knownSnapshots map[string]SnapshotWithId
} }
func NewSnapshotsDir(repo *repository.Repository) *SnapshotsDir { func NewSnapshotsDir(repo *repository.Repository, ownerIsRoot bool) *SnapshotsDir {
return &SnapshotsDir{ return &SnapshotsDir{
repo: repo, repo: repo,
knownSnapshots: make(map[string]SnapshotWithId), knownSnapshots: make(map[string]SnapshotWithId),
ownerIsRoot: ownerIsRoot,
} }
} }
func (sn *SnapshotsDir) Attr(ctx context.Context, attr *fuse.Attr) error { func (sn *SnapshotsDir) Attr(ctx context.Context, attr *fuse.Attr) error {
attr.Inode = 0 attr.Inode = 0
attr.Mode = os.ModeDir | 0555 attr.Mode = os.ModeDir | 0555
if !sn.ownerIsRoot {
attr.Uid = uint32(os.Getuid())
attr.Gid = uint32(os.Getgid())
}
return nil return nil
} }
@ -105,5 +112,5 @@ func (sn *SnapshotsDir) Lookup(ctx context.Context, name string) (fs.Node, error
} }
} }
return newDirFromSnapshot(sn.repo, snapshot) return newDirFromSnapshot(sn.repo, snapshot, sn.ownerIsRoot)
} }