Add fuse mount without read

This commit is contained in:
Ben Sarmiento
2023-11-05 21:25:50 +01:00
parent a9c71a3e93
commit 4bd672f301
6 changed files with 198 additions and 43 deletions

View File

@@ -19,7 +19,7 @@ import (
func main() {
rlog := logutil.NewLogger()
log := rlog.Named("main")
log := rlog.Named("zurg")
config, configErr := config.LoadZurgConfig("./config.yml")
if configErr != nil {
@@ -66,7 +66,7 @@ func main() {
}
}()
log.Infof("Mounting on %s", mountPoint)
if err := zfs.Mount(mountPoint); err != nil {
if err := zfs.Mount(mountPoint, config, t); err != nil {
log.Panicf("Failed to mount: %v", err)
}
}()
@@ -83,5 +83,5 @@ func main() {
log.Errorf("Unmount error: %v\n", err)
}
log.Info("Zurg signing off")
log.Info("BYE")
}

11
go.mod
View File

@@ -3,14 +3,11 @@ module github.com/debridmediamanager.com/zurg
go 1.21.3
require (
bazil.org/fuse v0.0.0-20230120002735-62a210ff1fd5
github.com/hashicorp/golang-lru/v2 v2.0.7
go.uber.org/zap v1.26.0
golang.org/x/sys v0.4.0
gopkg.in/yaml.v3 v3.0.1
)
require (
bazil.org/fuse v0.0.0-20230120002735-62a210ff1fd5 // indirect
github.com/mdlayher/sdnotify v1.0.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/sys v0.4.0 // indirect
)
require go.uber.org/multierr v1.10.0 // indirect

16
go.sum
View File

@@ -1,11 +1,19 @@
bazil.org/fuse v0.0.0-20230120002735-62a210ff1fd5 h1:A0NsYy4lDBZAC6QiYeJ4N+XuHIKBpyhAVRMHRQZKTeQ=
bazil.org/fuse v0.0.0-20230120002735-62a210ff1fd5/go.mod h1:gG3RZAMXCa/OTes6rr9EwusmR1OH1tDDy+cg9c5YliY=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ3c=
github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ=
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=

View File

@@ -3,8 +3,12 @@ package zfs
import (
"os"
"sync"
"time"
"bazil.org/fuse/fs"
"github.com/debridmediamanager.com/zurg/internal/config"
"github.com/debridmediamanager.com/zurg/internal/torrent"
"go.uber.org/zap"
)
type FS struct {
@@ -13,9 +17,17 @@ type FS struct {
umask os.FileMode
directIO bool
lock sync.RWMutex
c config.ConfigInterface
t *torrent.TorrentManager
log *zap.SugaredLogger
initTime time.Time
}
// Root returns the root path
func (f *FS) Root() (fs.Node, error) {
return nil, nil
return Object{
fs: f,
objType: ROOT,
mtime: f.initTime,
}, nil
}

View File

@@ -2,14 +2,21 @@ package zfs
import (
"os"
"time"
"bazil.org/fuse"
"bazil.org/fuse/fs"
"github.com/debridmediamanager.com/zurg/internal/config"
"github.com/debridmediamanager.com/zurg/internal/torrent"
"github.com/debridmediamanager.com/zurg/pkg/logutil"
"golang.org/x/sys/unix"
)
func Mount(mountpoint string) error {
func Mount(mountpoint string, c config.ConfigInterface, t *torrent.TorrentManager) error {
rlog := logutil.NewLogger()
log := rlog.Named("zfs")
options := []fuse.MountOption{
fuse.AllowOther(),
fuse.AllowNonEmptyMount(),
@@ -17,21 +24,24 @@ func Mount(mountpoint string) error {
fuse.DefaultPermissions(),
fuse.FSName("zurgfs"),
}
c, err := fuse.Mount(mountpoint, options...)
conn, err := fuse.Mount(mountpoint, options...)
if err != nil {
return err
}
defer c.Close()
defer conn.Close()
srv := fs.New(c, nil)
srv := fs.New(conn, nil)
filesys := &FS{
uid: uint32(unix.Geteuid()),
gid: uint32(unix.Getegid()),
umask: os.FileMode(0),
uid: uint32(unix.Geteuid()),
gid: uint32(unix.Getegid()),
umask: os.FileMode(0),
c: c,
t: t,
log: log,
initTime: time.Now(),
}
// Serve our tree via FUSE.
if err := srv.Serve(filesys); err != nil {
return err
}

View File

@@ -2,49 +2,177 @@ package zfs
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"syscall"
"time"
"bazil.org/fuse"
"bazil.org/fuse/fs"
"github.com/debridmediamanager.com/zurg/internal/torrent"
)
// define variable as rootObject id
const (
ROOT = 0
DIRECTORY = 1
TORRENT = 2
FILE = 3
)
type Object struct {
fs *FS
objectID string
}
func (o Object) GetObject() (object *torrent.Torrent, err error) {
return nil, nil
fs *FS
objType int
parentName string
name string
size uint64
mtime time.Time
}
// Attr returns the attributes for a directory
func (o Object) Attr(ctx context.Context, attr *fuse.Attr) error {
if o.objType == FILE {
attr.Mode = 0644
} else {
attr.Mode = os.ModeDir | 0755
}
attr.Size = o.size
attr.Uid = o.fs.uid
attr.Gid = o.fs.gid
attr.Ctime = o.mtime
attr.Mtime = o.mtime
attr.Blocks = (attr.Size + 511) >> 9
return nil
}
// ReadDirAll shows all files in the current directory
func (o Object) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
return nil, nil
dirs := []fuse.Dirent{}
switch o.objType {
case ROOT:
for _, directory := range o.fs.c.GetDirectories() {
dirs = append(dirs, fuse.Dirent{
Name: directory,
Type: fuse.DT_Dir,
})
}
case DIRECTORY:
seen := make(map[string]bool)
for _, item := range o.fs.t.GetByDirectory(o.name) {
if item.Progress != 100 {
continue
}
if _, exists := seen[item.Name]; exists {
continue
}
seen[item.Name] = true
dirs = append(dirs, fuse.Dirent{
Name: item.Name,
Type: fuse.DT_Dir,
})
}
case TORRENT:
finalName := make(map[string]bool)
for _, item := range o.fs.t.FindAllTorrentsWithName(o.parentName, o.name) {
for _, file := range item.SelectedFiles {
if file.Link == "" {
// log.Println("File has no link, skipping", file.Path)
continue
}
filename := filepath.Base(file.Path)
if finalName[filename] {
// fragment := davextra.GetLinkFragment(file.Link)
// filename = davextra.InsertLinkFragment(filename, fragment)
continue
}
finalName[filename] = true
dirs = append(dirs, fuse.Dirent{
Name: filename,
Type: fuse.DT_File,
})
}
}
}
return dirs, nil
}
// Lookup tests if a file is existent in the current directory
func (o Object) Lookup(ctx context.Context, name string) (fs.Node, error) {
return nil, nil
}
func (o Object) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
return nil
switch o.objType {
case ROOT:
for _, directory := range o.fs.c.GetDirectories() {
if directory == name {
return Object{
fs: o.fs,
objType: DIRECTORY,
parentName: o.name,
name: name,
mtime: o.fs.initTime,
}, nil
}
}
case DIRECTORY:
for _, item := range o.fs.t.GetByDirectory(o.name) {
if item.Name == name && item.Progress == 100 {
return Object{
fs: o.fs,
objType: TORRENT,
parentName: o.name,
name: name,
mtime: convertRFC3339toTime(item.Added),
}, nil
}
}
case TORRENT:
for _, item := range o.fs.t.FindAllTorrentsWithName(o.parentName, o.name) {
for _, file := range item.SelectedFiles {
if strings.HasSuffix(file.Path, name) && file.Link != "" {
return Object{
fs: o.fs,
objType: FILE,
parentName: o.name,
name: name,
size: uint64(file.Bytes),
mtime: convertRFC3339toTime(item.Added),
}, nil
}
}
}
}
return nil, syscall.ENOENT
}
// Open a file
func (o Object) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
return nil, nil
resp.Flags |= fuse.OpenDirectIO
return o, nil
}
// Read reads some bytes or the whole file
func (o Object) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
return fmt.Errorf("Read not yet implemented")
}
// Remove deletes an element
func (o Object) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
return nil
}
func (o Object) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
return nil, nil
return fmt.Errorf("Remove not yet implemented")
}
// Rename renames an element
func (o Object) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error {
return nil
return fmt.Errorf("Rename not yet implemented")
}
func convertRFC3339toTime(input string) time.Time {
layout := "2006-01-02T15:04:05.000Z"
t, err := time.Parse(layout, input)
if err != nil {
return time.Now()
}
return t
}