fuse: Reduce code duplication, add MetaDir
This commit is contained in:
parent
4b4a63ed44
commit
2c02efd1fe
4 changed files with 142 additions and 275 deletions
|
@ -1,99 +0,0 @@
|
|||
// +build !openbsd
|
||||
// +build !windows
|
||||
|
||||
package fuse
|
||||
|
||||
import (
|
||||
"os"
|
||||
"restic"
|
||||
"restic/debug"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"bazil.org/fuse"
|
||||
"bazil.org/fuse/fs"
|
||||
)
|
||||
|
||||
// HostsDir is a fuse directory which contains hostnames.
|
||||
type HostsDir struct {
|
||||
inode uint64
|
||||
root *Root
|
||||
snapshots restic.Snapshots
|
||||
hosts map[string]*SnapshotsDir
|
||||
}
|
||||
|
||||
// NewHostsDir returns a new directory containing hostnames, which in
|
||||
// turn contains snapshots of a single host each.
|
||||
func NewHostsDir(root *Root, inode uint64, snapshots restic.Snapshots) *HostsDir {
|
||||
hosts := make(map[string]restic.Snapshots)
|
||||
for _, sn := range snapshots {
|
||||
hosts[sn.Hostname] = append(hosts[sn.Hostname], sn)
|
||||
}
|
||||
|
||||
debug.Log("create hosts dir with %d snapshots, inode %d", len(hosts), inode)
|
||||
|
||||
d := &HostsDir{
|
||||
root: root,
|
||||
inode: inode,
|
||||
snapshots: snapshots,
|
||||
hosts: make(map[string]*SnapshotsDir),
|
||||
}
|
||||
|
||||
for hostname, snapshots := range hosts {
|
||||
debug.Log(" host %v has %v snapshots", hostname, len(snapshots))
|
||||
d.hosts[hostname] = NewSnapshotsDir(root, fs.GenerateDynamicInode(inode, hostname), snapshots)
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// Attr returns the attributes for the root node.
|
||||
func (d *HostsDir) Attr(ctx context.Context, attr *fuse.Attr) error {
|
||||
attr.Inode = d.inode
|
||||
attr.Mode = os.ModeDir | 0555
|
||||
|
||||
if !d.root.cfg.OwnerIsRoot {
|
||||
attr.Uid = uint32(os.Getuid())
|
||||
attr.Gid = uint32(os.Getgid())
|
||||
}
|
||||
debug.Log("attr: %v", attr)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadDirAll returns all entries of the root node.
|
||||
func (d *HostsDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||
debug.Log("ReadDirAll()")
|
||||
items := []fuse.Dirent{
|
||||
{
|
||||
Inode: d.inode,
|
||||
Name: ".",
|
||||
Type: fuse.DT_Dir,
|
||||
},
|
||||
{
|
||||
Inode: d.root.inode,
|
||||
Name: "..",
|
||||
Type: fuse.DT_Dir,
|
||||
},
|
||||
}
|
||||
|
||||
for name := range d.hosts {
|
||||
items = append(items, fuse.Dirent{
|
||||
Inode: fs.GenerateDynamicInode(d.inode, name),
|
||||
Name: name,
|
||||
Type: fuse.DT_Dir,
|
||||
})
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// Lookup returns a specific entry from the root node.
|
||||
func (d *HostsDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
debug.Log("Lookup(%s)", name)
|
||||
|
||||
if dir, ok := d.hosts[name]; ok {
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
return nil, fuse.ENOENT
|
||||
}
|
87
src/restic/fuse/meta_dir.go
Normal file
87
src/restic/fuse/meta_dir.go
Normal file
|
@ -0,0 +1,87 @@
|
|||
// +build !openbsd
|
||||
// +build !windows
|
||||
|
||||
package fuse
|
||||
|
||||
import (
|
||||
"os"
|
||||
"restic/debug"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"bazil.org/fuse"
|
||||
"bazil.org/fuse/fs"
|
||||
)
|
||||
|
||||
// ensure that *DirSnapshots implements these interfaces
|
||||
var _ = fs.HandleReadDirAller(&MetaDir{})
|
||||
var _ = fs.NodeStringLookuper(&MetaDir{})
|
||||
|
||||
// MetaDir is a fuse directory which contains other directories.
|
||||
type MetaDir struct {
|
||||
inode uint64
|
||||
root *Root
|
||||
entries map[string]fs.Node
|
||||
}
|
||||
|
||||
// NewMetaDir returns a new meta dir.
|
||||
func NewMetaDir(root *Root, inode uint64, entries map[string]fs.Node) *MetaDir {
|
||||
debug.Log("new meta dir with %d entries, inode %d", len(entries), inode)
|
||||
|
||||
return &MetaDir{
|
||||
root: root,
|
||||
inode: inode,
|
||||
entries: entries,
|
||||
}
|
||||
}
|
||||
|
||||
// Attr returns the attributes for the root node.
|
||||
func (d *MetaDir) Attr(ctx context.Context, attr *fuse.Attr) error {
|
||||
attr.Inode = d.inode
|
||||
attr.Mode = os.ModeDir | 0555
|
||||
|
||||
if !d.root.cfg.OwnerIsRoot {
|
||||
attr.Uid = uint32(os.Getuid())
|
||||
attr.Gid = uint32(os.Getgid())
|
||||
}
|
||||
debug.Log("attr: %v", attr)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadDirAll returns all entries of the root node.
|
||||
func (d *MetaDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||
debug.Log("ReadDirAll()")
|
||||
items := []fuse.Dirent{
|
||||
{
|
||||
Inode: d.inode,
|
||||
Name: ".",
|
||||
Type: fuse.DT_Dir,
|
||||
},
|
||||
{
|
||||
Inode: d.root.inode,
|
||||
Name: "..",
|
||||
Type: fuse.DT_Dir,
|
||||
},
|
||||
}
|
||||
|
||||
for name := range d.entries {
|
||||
items = append(items, fuse.Dirent{
|
||||
Inode: fs.GenerateDynamicInode(d.inode, name),
|
||||
Name: name,
|
||||
Type: fuse.DT_Dir,
|
||||
})
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// Lookup returns a specific entry from the root node.
|
||||
func (d *MetaDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
debug.Log("Lookup(%s)", name)
|
||||
|
||||
if dir, ok := d.entries[name]; ok {
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
return nil, fuse.ENOENT
|
||||
}
|
|
@ -4,13 +4,11 @@
|
|||
package fuse
|
||||
|
||||
import (
|
||||
"os"
|
||||
"restic"
|
||||
"restic/debug"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"bazil.org/fuse"
|
||||
"bazil.org/fuse/fs"
|
||||
)
|
||||
|
||||
|
@ -30,15 +28,15 @@ type Root struct {
|
|||
snapshots restic.Snapshots
|
||||
blobSizeCache *BlobSizeCache
|
||||
|
||||
dirSnapshots *SnapshotsDir
|
||||
dirHosts *HostsDir
|
||||
dirTags *TagsDir
|
||||
*MetaDir
|
||||
}
|
||||
|
||||
// ensure that *Root implements these interfaces
|
||||
var _ = fs.HandleReadDirAller(&Root{})
|
||||
var _ = fs.NodeStringLookuper(&Root{})
|
||||
|
||||
const rootInode = 1
|
||||
|
||||
// NewRoot initializes a new root node from a repository.
|
||||
func NewRoot(ctx context.Context, repo restic.Repository, cfg Config) (*Root, error) {
|
||||
debug.Log("NewRoot(), config %v", cfg)
|
||||
|
@ -47,84 +45,66 @@ func NewRoot(ctx context.Context, repo restic.Repository, cfg Config) (*Root, er
|
|||
debug.Log("found %d matching snapshots", len(snapshots))
|
||||
|
||||
root := &Root{
|
||||
repo: repo,
|
||||
cfg: cfg,
|
||||
inode: 1,
|
||||
snapshots: snapshots,
|
||||
repo: repo,
|
||||
inode: rootInode,
|
||||
cfg: cfg,
|
||||
snapshots: snapshots,
|
||||
blobSizeCache: NewBlobSizeCache(ctx, repo.Index()),
|
||||
}
|
||||
|
||||
root.dirSnapshots = NewSnapshotsDir(root, fs.GenerateDynamicInode(root.inode, "snapshots"), snapshots)
|
||||
root.dirHosts = NewHostsDir(root, fs.GenerateDynamicInode(root.inode, "hosts"), snapshots)
|
||||
root.dirTags = NewTagsDir(root, fs.GenerateDynamicInode(root.inode, "tags"), snapshots)
|
||||
root.blobSizeCache = NewBlobSizeCache(ctx, repo.Index())
|
||||
entries := map[string]fs.Node{
|
||||
"snapshots": NewSnapshotsDir(root, fs.GenerateDynamicInode(root.inode, "snapshots"), snapshots),
|
||||
"tags": NewTagsDir(root, fs.GenerateDynamicInode(root.inode, "tags"), snapshots),
|
||||
"hosts": NewHostsDir(root, fs.GenerateDynamicInode(root.inode, "hosts"), snapshots),
|
||||
}
|
||||
|
||||
root.MetaDir = NewMetaDir(root, rootInode, entries)
|
||||
|
||||
return root, nil
|
||||
}
|
||||
|
||||
// NewTagsDir returns a new directory containing entries, which in turn contains
|
||||
// snapshots with this tag set.
|
||||
func NewTagsDir(root *Root, inode uint64, snapshots restic.Snapshots) fs.Node {
|
||||
tags := make(map[string]restic.Snapshots)
|
||||
for _, sn := range snapshots {
|
||||
for _, tag := range sn.Tags {
|
||||
tags[tag] = append(tags[tag], sn)
|
||||
}
|
||||
}
|
||||
|
||||
debug.Log("create tags dir with %d tags, inode %d", len(tags), inode)
|
||||
|
||||
entries := make(map[string]fs.Node)
|
||||
for name, snapshots := range tags {
|
||||
debug.Log(" tag %v has %v snapshots", name, len(snapshots))
|
||||
entries[name] = NewSnapshotsDir(root, fs.GenerateDynamicInode(inode, name), snapshots)
|
||||
}
|
||||
|
||||
return NewMetaDir(root, inode, entries)
|
||||
}
|
||||
|
||||
// NewHostsDir returns a new directory containing hostnames, which in
|
||||
// turn contains snapshots of a single host each.
|
||||
func NewHostsDir(root *Root, inode uint64, snapshots restic.Snapshots) fs.Node {
|
||||
hosts := make(map[string]restic.Snapshots)
|
||||
for _, sn := range snapshots {
|
||||
hosts[sn.Hostname] = append(hosts[sn.Hostname], sn)
|
||||
}
|
||||
|
||||
debug.Log("create hosts dir with %d snapshots, inode %d", len(hosts), inode)
|
||||
|
||||
entries := make(map[string]fs.Node)
|
||||
for name, snapshots := range hosts {
|
||||
debug.Log(" host %v has %v snapshots", name, len(snapshots))
|
||||
entries[name] = NewSnapshotsDir(root, fs.GenerateDynamicInode(inode, name), snapshots)
|
||||
}
|
||||
|
||||
return NewMetaDir(root, inode, entries)
|
||||
}
|
||||
|
||||
// Root is just there to satisfy fs.Root, it returns itself.
|
||||
func (r *Root) Root() (fs.Node, error) {
|
||||
debug.Log("Root()")
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Attr returns the attributes for the root node.
|
||||
func (r *Root) Attr(ctx context.Context, attr *fuse.Attr) error {
|
||||
attr.Inode = r.inode
|
||||
attr.Mode = os.ModeDir | 0555
|
||||
|
||||
if !r.cfg.OwnerIsRoot {
|
||||
attr.Uid = uint32(os.Getuid())
|
||||
attr.Gid = uint32(os.Getgid())
|
||||
}
|
||||
debug.Log("attr: %v", attr)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadDirAll returns all entries of the root node.
|
||||
func (r *Root) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||
debug.Log("ReadDirAll()")
|
||||
items := []fuse.Dirent{
|
||||
{
|
||||
Inode: r.inode,
|
||||
Name: ".",
|
||||
Type: fuse.DT_Dir,
|
||||
},
|
||||
{
|
||||
Inode: r.inode,
|
||||
Name: "..",
|
||||
Type: fuse.DT_Dir,
|
||||
},
|
||||
{
|
||||
Inode: fs.GenerateDynamicInode(r.inode, "snapshots"),
|
||||
Name: "snapshots",
|
||||
Type: fuse.DT_Dir,
|
||||
},
|
||||
{
|
||||
Inode: fs.GenerateDynamicInode(r.inode, "hosts"),
|
||||
Name: "hosts",
|
||||
Type: fuse.DT_Dir,
|
||||
},
|
||||
{
|
||||
Inode: fs.GenerateDynamicInode(r.inode, "tags"),
|
||||
Name: "tags",
|
||||
Type: fuse.DT_Dir,
|
||||
},
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// Lookup returns a specific entry from the root node.
|
||||
func (r *Root) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
debug.Log("Lookup(%s)", name)
|
||||
switch name {
|
||||
case "snapshots":
|
||||
return r.dirSnapshots, nil
|
||||
case "hosts":
|
||||
return r.dirHosts, nil
|
||||
case "tags":
|
||||
return r.dirTags, nil
|
||||
}
|
||||
|
||||
return nil, fuse.ENOENT
|
||||
}
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
// +build !openbsd
|
||||
// +build !windows
|
||||
|
||||
package fuse
|
||||
|
||||
import (
|
||||
"os"
|
||||
"restic"
|
||||
"restic/debug"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"bazil.org/fuse"
|
||||
"bazil.org/fuse/fs"
|
||||
)
|
||||
|
||||
// TagsDir is a fuse directory which contains hostnames.
|
||||
type TagsDir struct {
|
||||
inode uint64
|
||||
root *Root
|
||||
snapshots restic.Snapshots
|
||||
tags map[string]*SnapshotsDir
|
||||
}
|
||||
|
||||
// NewTagsDir returns a new directory containing tags, which in turn contains
|
||||
// snapshots with this tag set.
|
||||
func NewTagsDir(root *Root, inode uint64, snapshots restic.Snapshots) *TagsDir {
|
||||
tags := make(map[string]restic.Snapshots)
|
||||
for _, sn := range snapshots {
|
||||
for _, tag := range sn.Tags {
|
||||
tags[tag] = append(tags[tag], sn)
|
||||
}
|
||||
}
|
||||
|
||||
debug.Log("create tags dir with %d snapshots, inode %d", len(tags), inode)
|
||||
|
||||
d := &TagsDir{
|
||||
root: root,
|
||||
inode: inode,
|
||||
snapshots: snapshots,
|
||||
tags: make(map[string]*SnapshotsDir),
|
||||
}
|
||||
|
||||
for name, snapshots := range tags {
|
||||
debug.Log(" tag %v has %v snapshots", name, len(snapshots))
|
||||
d.tags[name] = NewSnapshotsDir(root, fs.GenerateDynamicInode(inode, name), snapshots)
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// Attr returns the attributes for the root node.
|
||||
func (d *TagsDir) Attr(ctx context.Context, attr *fuse.Attr) error {
|
||||
attr.Inode = d.inode
|
||||
attr.Mode = os.ModeDir | 0555
|
||||
|
||||
if !d.root.cfg.OwnerIsRoot {
|
||||
attr.Uid = uint32(os.Getuid())
|
||||
attr.Gid = uint32(os.Getgid())
|
||||
}
|
||||
debug.Log("attr: %v", attr)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadDirAll returns all entries of the root node.
|
||||
func (d *TagsDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||
debug.Log("ReadDirAll()")
|
||||
items := []fuse.Dirent{
|
||||
{
|
||||
Inode: d.inode,
|
||||
Name: ".",
|
||||
Type: fuse.DT_Dir,
|
||||
},
|
||||
{
|
||||
Inode: d.root.inode,
|
||||
Name: "..",
|
||||
Type: fuse.DT_Dir,
|
||||
},
|
||||
}
|
||||
|
||||
for name := range d.tags {
|
||||
items = append(items, fuse.Dirent{
|
||||
Inode: fs.GenerateDynamicInode(d.inode, name),
|
||||
Name: name,
|
||||
Type: fuse.DT_Dir,
|
||||
})
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// Lookup returns a specific entry from the root node.
|
||||
func (d *TagsDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
debug.Log("Lookup(%s)", name)
|
||||
|
||||
if dir, ok := d.tags[name]; ok {
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
return nil, fuse.ENOENT
|
||||
}
|
Loading…
Reference in a new issue