restic/internal/fuse/snapshots_dir.go

177 lines
4.3 KiB
Go
Raw Permalink Normal View History

2022-03-28 20:23:47 +00:00
//go:build darwin || freebsd || linux
// +build darwin freebsd linux
2017-06-18 12:59:44 +00:00
package fuse
import (
"context"
2017-06-18 12:59:44 +00:00
"os"
"syscall"
2017-06-18 12:59:44 +00:00
2017-07-23 12:21:03 +00:00
"github.com/restic/restic/internal/debug"
2017-07-24 15:42:25 +00:00
"github.com/restic/restic/internal/restic"
2017-07-23 12:21:03 +00:00
"github.com/anacrolix/fuse"
"github.com/anacrolix/fuse/fs"
2017-06-18 12:59:44 +00:00
)
// SnapshotsDir is a actual fuse directory generated from SnapshotsDirStructure
// It uses the saved prefix to select the corresponding MetaDirData.
type SnapshotsDir struct {
root *Root
forget forgetFn
inode uint64
parentInode uint64
dirStruct *SnapshotsDirStructure
prefix string
cache treeCache
2017-06-18 12:59:44 +00:00
}
2017-09-17 15:34:19 +00:00
// ensure that *SnapshotsDir implements these interfaces
var _ = fs.HandleReadDirAller(&SnapshotsDir{})
var _ = fs.NodeForgetter(&SnapshotsDir{})
var _ = fs.NodeStringLookuper(&SnapshotsDir{})
2017-06-18 12:59:44 +00:00
// NewSnapshotsDir returns a new directory structure containing snapshots and "latest" links
func NewSnapshotsDir(root *Root, forget forgetFn, inode, parentInode uint64, dirStruct *SnapshotsDirStructure, prefix string) *SnapshotsDir {
debug.Log("create snapshots dir, inode %d", inode)
return &SnapshotsDir{
root: root,
forget: forget,
inode: inode,
parentInode: parentInode,
dirStruct: dirStruct,
prefix: prefix,
cache: *newTreeCache(),
}
}
// Attr returns the attributes for any dir in the snapshots directory structure
func (d *SnapshotsDir) Attr(_ context.Context, attr *fuse.Attr) error {
2017-06-18 12:59:44 +00:00
attr.Inode = d.inode
attr.Mode = os.ModeDir | 0555
attr.Uid = d.root.uid
attr.Gid = d.root.gid
2017-06-18 12:59:44 +00:00
debug.Log("attr: %v", attr)
return nil
}
// ReadDirAll returns all entries of the SnapshotsDir.
func (d *SnapshotsDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
2017-06-18 12:59:44 +00:00
debug.Log("ReadDirAll()")
2017-10-08 15:47:10 +00:00
// update snapshots
meta, err := d.dirStruct.UpdatePrefix(ctx, d.prefix)
if err != nil {
return nil, unwrapCtxCanceled(err)
} else if meta == nil {
return nil, syscall.ENOENT
}
2017-06-18 12:59:44 +00:00
items := []fuse.Dirent{
{
Inode: d.inode,
Name: ".",
Type: fuse.DT_Dir,
},
{
Inode: d.parentInode,
2017-06-18 12:59:44 +00:00
Name: "..",
Type: fuse.DT_Dir,
},
}
for name, entry := range meta.names {
2024-07-31 17:30:47 +00:00
if ctx.Err() != nil {
return nil, ctx.Err()
}
d := fuse.Dirent{
Inode: inodeFromName(d.inode, name),
Name: name,
Type: fuse.DT_Dir,
}
if entry.linkTarget != "" {
d.Type = fuse.DT_Link
}
items = append(items, d)
}
return items, nil
}
// Lookup returns a specific entry from the SnapshotsDir.
func (d *SnapshotsDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
debug.Log("Lookup(%s)", name)
meta, err := d.dirStruct.UpdatePrefix(ctx, d.prefix)
if err != nil {
return nil, unwrapCtxCanceled(err)
} else if meta == nil {
return nil, syscall.ENOENT
}
return d.cache.lookupOrCreate(name, func(forget forgetFn) (fs.Node, error) {
entry := meta.names[name]
if entry == nil {
return nil, syscall.ENOENT
}
2022-11-27 12:53:42 +00:00
inode := inodeFromName(d.inode, name)
if entry.linkTarget != "" {
return newSnapshotLink(d.root, forget, inode, entry.linkTarget, entry.snapshot)
} else if entry.snapshot != nil {
return newDirFromSnapshot(d.root, forget, inode, entry.snapshot)
}
return NewSnapshotsDir(d.root, forget, inode, d.inode, d.dirStruct, d.prefix+"/"+name), nil
})
}
func (d *SnapshotsDir) Forget() {
d.forget()
}
// SnapshotLink
type snapshotLink struct {
root *Root
forget forgetFn
inode uint64
target string
snapshot *restic.Snapshot
}
var _ = fs.NodeForgetter(&snapshotLink{})
var _ = fs.NodeReadlinker(&snapshotLink{})
// newSnapshotLink
func newSnapshotLink(root *Root, forget forgetFn, inode uint64, target string, snapshot *restic.Snapshot) (*snapshotLink, error) {
return &snapshotLink{root: root, forget: forget, inode: inode, target: target, snapshot: snapshot}, nil
}
// Readlink
func (l *snapshotLink) Readlink(_ context.Context, _ *fuse.ReadlinkRequest) (string, error) {
return l.target, nil
}
// Attr
func (l *snapshotLink) Attr(_ context.Context, a *fuse.Attr) error {
a.Inode = l.inode
a.Mode = os.ModeSymlink | 0777
a.Size = uint64(len(l.target))
a.Blocks = (a.Size + blockSize - 1) / blockSize
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
a.Nlink = 1
return nil
}
func (l *snapshotLink) Forget() {
l.forget()
}