1// +build darwin freebsd linux
2
3package fuse
4
5import (
6	"context"
7	"os"
8
9	"github.com/restic/restic/internal/debug"
10
11	"bazil.org/fuse"
12	"bazil.org/fuse/fs"
13)
14
15// ensure that *DirSnapshots implements these interfaces
16var _ = fs.HandleReadDirAller(&MetaDir{})
17var _ = fs.NodeStringLookuper(&MetaDir{})
18
19// MetaDir is a fuse directory which contains other directories.
20type MetaDir struct {
21	inode   uint64
22	root    *Root
23	entries map[string]fs.Node
24}
25
26// NewMetaDir returns a new meta dir.
27func NewMetaDir(root *Root, inode uint64, entries map[string]fs.Node) *MetaDir {
28	debug.Log("new meta dir with %d entries, inode %d", len(entries), inode)
29
30	return &MetaDir{
31		root:    root,
32		inode:   inode,
33		entries: entries,
34	}
35}
36
37// Attr returns the attributes for the root node.
38func (d *MetaDir) Attr(ctx context.Context, attr *fuse.Attr) error {
39	attr.Inode = d.inode
40	attr.Mode = os.ModeDir | 0555
41	attr.Uid = d.root.uid
42	attr.Gid = d.root.gid
43
44	debug.Log("attr: %v", attr)
45	return nil
46}
47
48// ReadDirAll returns all entries of the root node.
49func (d *MetaDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
50	debug.Log("ReadDirAll()")
51	items := []fuse.Dirent{
52		{
53			Inode: d.inode,
54			Name:  ".",
55			Type:  fuse.DT_Dir,
56		},
57		{
58			Inode: d.root.inode,
59			Name:  "..",
60			Type:  fuse.DT_Dir,
61		},
62	}
63
64	for name := range d.entries {
65		items = append(items, fuse.Dirent{
66			Inode: fs.GenerateDynamicInode(d.inode, name),
67			Name:  name,
68			Type:  fuse.DT_Dir,
69		})
70	}
71
72	return items, nil
73}
74
75// Lookup returns a specific entry from the root node.
76func (d *MetaDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
77	debug.Log("Lookup(%s)", name)
78
79	if dir, ok := d.entries[name]; ok {
80		return dir, nil
81	}
82
83	return nil, fuse.ENOENT
84}
85