From a66760d86d9331706944f35298a4be4086837349 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 18 Jun 2017 15:11:32 +0200 Subject: [PATCH] fuse: Fix inode handling --- src/restic/fuse/dir.go | 47 ++++++++++++++------------------ src/restic/fuse/dir_snapshots.go | 2 +- src/restic/fuse/file.go | 36 +++++++++--------------- src/restic/fuse/fuse.go | 16 ----------- src/restic/fuse/link.go | 13 +++++---- 5 files changed, 42 insertions(+), 72 deletions(-) delete mode 100644 src/restic/fuse/fuse.go diff --git a/src/restic/fuse/dir.go b/src/restic/fuse/dir.go index 78049fddc..9546d81f6 100644 --- a/src/restic/fuse/dir.go +++ b/src/restic/fuse/dir.go @@ -19,18 +19,17 @@ var _ = fs.HandleReadDirAller(&dir{}) var _ = fs.NodeStringLookuper(&dir{}) type dir struct { - repo restic.Repository - items map[string]*restic.Node - inode uint64 - node *restic.Node - ownerIsRoot bool + root *Root + items map[string]*restic.Node + inode uint64 + node *restic.Node blobsize *BlobSizeCache } -func newDir(ctx context.Context, repo restic.Repository, node *restic.Node, ownerIsRoot bool, blobsize *BlobSizeCache) (*dir, error) { +func newDir(ctx context.Context, root *Root, inode uint64, node *restic.Node) (*dir, error) { debug.Log("new dir for %v (%v)", node.Name, node.Subtree.Str()) - tree, err := repo.LoadTree(ctx, *node.Subtree) + tree, err := root.repo.LoadTree(ctx, *node.Subtree) if err != nil { debug.Log(" error loading tree %v: %v", node.Subtree.Str(), err) return nil, err @@ -41,12 +40,10 @@ func newDir(ctx context.Context, repo restic.Repository, node *restic.Node, owne } return &dir{ - repo: repo, - node: node, - items: items, - inode: node.Inode, - ownerIsRoot: ownerIsRoot, - blobsize: blobsize, + root: root, + node: node, + items: items, + inode: inode, }, nil } @@ -69,16 +66,16 @@ func replaceSpecialNodes(ctx context.Context, repo restic.Repository, node *rest return tree.Nodes, nil } -func newDirFromSnapshot(ctx context.Context, repo restic.Repository, snapshot *restic.Snapshot, ownerIsRoot bool, blobsize *BlobSizeCache) (*dir, error) { +func newDirFromSnapshot(ctx context.Context, root *Root, inode uint64, snapshot *restic.Snapshot) (*dir, error) { debug.Log("new dir for snapshot %v (%v)", snapshot.ID().Str(), snapshot.Tree.Str()) - tree, err := repo.LoadTree(ctx, *snapshot.Tree) + tree, err := root.repo.LoadTree(ctx, *snapshot.Tree) if err != nil { debug.Log(" loadTree(%v) failed: %v", snapshot.ID().Str(), err) return nil, err } items := make(map[string]*restic.Node) for _, n := range tree.Nodes { - nodes, err := replaceSpecialNodes(ctx, repo, n) + nodes, err := replaceSpecialNodes(ctx, root.repo, n) if err != nil { debug.Log(" replaceSpecialNodes(%v) failed: %v", n, err) return nil, err @@ -90,7 +87,7 @@ func newDirFromSnapshot(ctx context.Context, repo restic.Repository, snapshot *r } return &dir{ - repo: repo, + root: root, node: &restic.Node{ UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), @@ -99,10 +96,8 @@ func newDirFromSnapshot(ctx context.Context, repo restic.Repository, snapshot *r ChangeTime: snapshot.Time, Mode: os.ModeDir | 0555, }, - items: items, - inode: inodeFromBackendID(*snapshot.ID()), - ownerIsRoot: ownerIsRoot, - blobsize: blobsize, + items: items, + inode: inode, }, nil } @@ -111,7 +106,7 @@ func (d *dir) Attr(ctx context.Context, a *fuse.Attr) error { a.Inode = d.inode a.Mode = os.ModeDir | d.node.Mode - if !d.ownerIsRoot { + if !d.root.cfg.OwnerIsRoot { a.Uid = d.node.UID a.Gid = d.node.GID } @@ -153,7 +148,7 @@ func (d *dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { } ret = append(ret, fuse.Dirent{ - Inode: node.Inode, + Inode: fs.GenerateDynamicInode(d.inode, node.Name), Type: typ, Name: node.Name, }) @@ -171,11 +166,11 @@ func (d *dir) Lookup(ctx context.Context, name string) (fs.Node, error) { } switch node.Type { case "dir": - return newDir(ctx, d.repo, node, d.ownerIsRoot, d.blobsize) + return newDir(ctx, d.root, fs.GenerateDynamicInode(d.inode, name), node) case "file": - return newFile(d.repo, node, d.ownerIsRoot, d.blobsize) + return newFile(ctx, d.root, fs.GenerateDynamicInode(d.inode, name), node) case "symlink": - return newLink(d.repo, node, d.ownerIsRoot) + return newLink(ctx, d.root, fs.GenerateDynamicInode(d.inode, name), node) default: debug.Log(" node %v has unknown type %v", name, node.Type) return nil, fuse.ENOENT diff --git a/src/restic/fuse/dir_snapshots.go b/src/restic/fuse/dir_snapshots.go index f51cff888..2f96aceac 100644 --- a/src/restic/fuse/dir_snapshots.go +++ b/src/restic/fuse/dir_snapshots.go @@ -101,5 +101,5 @@ func (d *DirSnapshots) Lookup(ctx context.Context, name string) (fs.Node, error) return nil, fuse.ENOENT } - return newDirFromSnapshot(ctx, d.root.repo, sn, d.root.cfg.OwnerIsRoot, d.root.blobSizeCache) + return newDirFromSnapshot(ctx, d.root, fs.GenerateDynamicInode(d.inode, name), sn) } diff --git a/src/restic/fuse/file.go b/src/restic/fuse/file.go index 81ecfb76e..5aba969f4 100644 --- a/src/restic/fuse/file.go +++ b/src/restic/fuse/file.go @@ -9,8 +9,6 @@ import ( "restic" "restic/debug" - scontext "context" - "bazil.org/fuse" "bazil.org/fuse/fs" "golang.org/x/net/context" @@ -23,30 +21,23 @@ const blockSize = 512 var _ = fs.HandleReader(&file{}) var _ = fs.HandleReleaser(&file{}) -// BlobLoader is an abstracted repository with a reduced set of methods used -// for fuse operations. -type BlobLoader interface { - LookupBlobSize(restic.ID, restic.BlobType) (uint, error) - LoadBlob(scontext.Context, restic.BlobType, restic.ID, []byte) (int, error) -} - type file struct { - repo BlobLoader - node *restic.Node - ownerIsRoot bool + root *Root + node *restic.Node + inode uint64 sizes []int blobs [][]byte } -func newFile(repo BlobLoader, node *restic.Node, ownerIsRoot bool, blobsize *BlobSizeCache) (fusefile *file, err error) { +func newFile(ctx context.Context, root *Root, inode uint64, node *restic.Node) (fusefile *file, err error) { debug.Log("create new file for %v with %d blobs", node.Name, len(node.Content)) var bytes uint64 sizes := make([]int, len(node.Content)) for i, id := range node.Content { - size, ok := blobsize.Lookup(id) + size, ok := root.blobSizeCache.Lookup(id) if !ok { - size, err = repo.LookupBlobSize(id, restic.DataBlob) + size, err = root.repo.LookupBlobSize(id, restic.DataBlob) if err != nil { return nil, err } @@ -62,24 +53,23 @@ func newFile(repo BlobLoader, node *restic.Node, ownerIsRoot bool, blobsize *Blo } return &file{ - repo: repo, - node: node, - sizes: sizes, - blobs: make([][]byte, len(node.Content)), - ownerIsRoot: ownerIsRoot, + root: root, + node: node, + sizes: sizes, + blobs: make([][]byte, len(node.Content)), }, nil } func (f *file) Attr(ctx context.Context, a *fuse.Attr) error { debug.Log("Attr(%v)", f.node.Name) - a.Inode = f.node.Inode + a.Inode = f.inode a.Mode = f.node.Mode a.Size = f.node.Size a.Blocks = (f.node.Size / blockSize) + 1 a.BlockSize = blockSize a.Nlink = uint32(f.node.Links) - if !f.ownerIsRoot { + if !f.root.cfg.OwnerIsRoot { a.Uid = f.node.UID a.Gid = f.node.GID } @@ -103,7 +93,7 @@ func (f *file) getBlobAt(ctx context.Context, i int) (blob []byte, err error) { } buf := restic.NewBlobBuffer(f.sizes[i]) - n, err := f.repo.LoadBlob(ctx, restic.DataBlob, f.node.Content[i], buf) + n, err := f.root.repo.LoadBlob(ctx, restic.DataBlob, f.node.Content[i], buf) if err != nil { debug.Log("LoadBlob(%v, %v) failed: %v", f.node.Name, f.node.Content[i], err) return nil, err diff --git a/src/restic/fuse/fuse.go b/src/restic/fuse/fuse.go deleted file mode 100644 index e8e45c445..000000000 --- a/src/restic/fuse/fuse.go +++ /dev/null @@ -1,16 +0,0 @@ -// +build !openbsd -// +build !windows - -package fuse - -import ( - "encoding/binary" - "restic" -) - -// inodeFromBackendId returns a unique uint64 from a backend id. -// Endianness has no specific meaning, it is just the simplest way to -// transform a []byte to an uint64 -func inodeFromBackendID(id restic.ID) uint64 { - return binary.BigEndian.Uint64(id[:8]) -} diff --git a/src/restic/fuse/link.go b/src/restic/fuse/link.go index e230acb07..53cc934a6 100644 --- a/src/restic/fuse/link.go +++ b/src/restic/fuse/link.go @@ -15,12 +15,13 @@ import ( var _ = fs.NodeReadlinker(&link{}) type link struct { - node *restic.Node - ownerIsRoot bool + root *Root + node *restic.Node + inode uint64 } -func newLink(repo restic.Repository, node *restic.Node, ownerIsRoot bool) (*link, error) { - return &link{node: node, ownerIsRoot: ownerIsRoot}, nil +func newLink(ctx context.Context, root *Root, inode uint64, node *restic.Node) (*link, error) { + return &link{root: root, inode: inode, node: node}, nil } func (l *link) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error) { @@ -28,10 +29,10 @@ func (l *link) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, } func (l *link) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = l.node.Inode + a.Inode = l.inode a.Mode = l.node.Mode - if !l.ownerIsRoot { + if !l.root.cfg.OwnerIsRoot { a.Uid = l.node.UID a.Gid = l.node.GID }