forked from TrueCloudLab/restic
fuse: Fix inode handling
This commit is contained in:
parent
52752659c1
commit
a66760d86d
5 changed files with 42 additions and 72 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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])
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue