mirror of
https://github.com/kopia/kopia.git
synced 2026-03-15 04:38:56 -04:00
133 lines
2.6 KiB
Go
133 lines
2.6 KiB
Go
// +build !windows
|
|
|
|
// Package fusemount implements FUSE filesystem nodes for mounting contents of filesystem stored in repository.
|
|
//
|
|
// The FUSE implementation used is from bazil.org/fuse
|
|
package fusemount
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
|
|
"github.com/kopia/kopia/fs"
|
|
|
|
"bazil.org/fuse"
|
|
fusefs "bazil.org/fuse/fs"
|
|
|
|
"golang.org/x/net/context"
|
|
)
|
|
|
|
type fuseNode struct {
|
|
entry fs.Entry
|
|
}
|
|
|
|
func (n *fuseNode) Attr(ctx context.Context, a *fuse.Attr) error {
|
|
m := n.entry.Metadata()
|
|
a.Mode = m.FileMode()
|
|
a.Size = uint64(m.FileSize)
|
|
a.Mtime = m.ModTime
|
|
a.Uid = m.UserID
|
|
a.Gid = m.GroupID
|
|
return nil
|
|
}
|
|
|
|
type fuseFileNode struct {
|
|
fuseNode
|
|
}
|
|
|
|
func (f *fuseFileNode) ReadAll(ctx context.Context) ([]byte, error) {
|
|
reader, err := f.entry.(fs.File).Open()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer reader.Close()
|
|
|
|
return ioutil.ReadAll(reader)
|
|
}
|
|
|
|
type fuseDirectoryNode struct {
|
|
fuseNode
|
|
}
|
|
|
|
func (dir *fuseDirectoryNode) directory() fs.Directory {
|
|
return dir.entry.(fs.Directory)
|
|
}
|
|
|
|
func (dir *fuseDirectoryNode) Lookup(ctx context.Context, fileName string) (fusefs.Node, error) {
|
|
entries, err := dir.directory().Readdir()
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil, fuse.ENOENT
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
e := entries.FindByName(fileName)
|
|
if e == nil {
|
|
return nil, fuse.ENOENT
|
|
}
|
|
|
|
return newFuseNode(e)
|
|
}
|
|
|
|
func (dir *fuseDirectoryNode) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
|
entries, err := dir.directory().Readdir()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := []fuse.Dirent{}
|
|
|
|
for _, e := range entries {
|
|
m := e.Metadata()
|
|
dirent := fuse.Dirent{
|
|
Name: m.Name,
|
|
}
|
|
|
|
switch m.Type {
|
|
case fs.EntryTypeDirectory:
|
|
dirent.Type = fuse.DT_Dir
|
|
case fs.EntryTypeFile:
|
|
dirent.Type = fuse.DT_File
|
|
case fs.EntryTypeSymlink:
|
|
dirent.Type = fuse.DT_Link
|
|
}
|
|
|
|
result = append(result, dirent)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
type fuseSymlinkNode struct {
|
|
fuseNode
|
|
}
|
|
|
|
func (sl *fuseSymlinkNode) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error) {
|
|
return sl.entry.(fs.Symlink).Readlink()
|
|
}
|
|
|
|
func newFuseNode(e fs.Entry) (fusefs.Node, error) {
|
|
switch e := e.(type) {
|
|
case fs.Directory:
|
|
return newDirectoryNode(e), nil
|
|
case fs.File:
|
|
return &fuseFileNode{fuseNode{e}}, nil
|
|
case fs.Symlink:
|
|
return &fuseSymlinkNode{fuseNode{e}}, nil
|
|
default:
|
|
return nil, fmt.Errorf("entry type not supported: %v", e.Metadata().Type)
|
|
}
|
|
}
|
|
|
|
func newDirectoryNode(dir fs.Directory) fusefs.Node {
|
|
return &fuseDirectoryNode{fuseNode{dir}}
|
|
}
|
|
|
|
// NewDirectoryNode returns FUSE Node for a given fs.Directory
|
|
func NewDirectoryNode(dir fs.Directory) fusefs.Node {
|
|
return newDirectoryNode(dir)
|
|
}
|