2022-08-18 11:44:33 +03:00
|
|
|
package rclonefs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-08-20 11:18:41 +03:00
|
|
|
"fmt"
|
|
|
|
"io/fs"
|
2022-08-18 16:15:38 +03:00
|
|
|
"os"
|
2022-08-18 11:44:33 +03:00
|
|
|
"os/user"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
2022-08-18 16:15:38 +03:00
|
|
|
"time"
|
2022-08-18 11:44:33 +03:00
|
|
|
|
|
|
|
_ "github.com/rclone/rclone/backend/all"
|
2022-08-20 11:18:41 +03:00
|
|
|
rclfs "github.com/rclone/rclone/fs"
|
2022-08-18 11:44:33 +03:00
|
|
|
"github.com/rclone/rclone/fs/config"
|
|
|
|
"github.com/rclone/rclone/fs/config/configfile"
|
|
|
|
"github.com/rclone/rclone/vfs"
|
2022-08-18 16:15:38 +03:00
|
|
|
"github.com/spf13/afero"
|
2022-08-18 11:44:33 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
type RCFS struct {
|
2022-08-18 16:15:38 +03:00
|
|
|
Fs *vfs.VFS
|
|
|
|
Cwd string
|
2022-08-18 11:44:33 +03:00
|
|
|
}
|
|
|
|
|
2022-08-18 12:00:12 +03:00
|
|
|
func CreateRCFS(path string) (*RCFS, error) {
|
2022-08-18 11:44:33 +03:00
|
|
|
u, e := user.Current()
|
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
|
|
|
|
cfgpath := filepath.Join(u.HomeDir, ".config/rclone/rclone.conf")
|
|
|
|
|
|
|
|
e = config.SetConfigPath(cfgpath)
|
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
|
|
|
|
configfile.Install()
|
|
|
|
|
|
|
|
rootdir, cwd, _ := strings.Cut(path, ":")
|
|
|
|
rootdir += ":"
|
2022-08-20 11:18:41 +03:00
|
|
|
cwd = filepath.Join("/", cwd)
|
2022-08-18 11:44:33 +03:00
|
|
|
|
2022-08-20 11:18:41 +03:00
|
|
|
rfs, e := rclfs.NewFs(context.Background(), rootdir)
|
2022-08-18 11:44:33 +03:00
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
|
|
|
|
vfs := vfs.New(rfs, nil)
|
|
|
|
|
|
|
|
return &RCFS{Fs: vfs, Cwd: cwd}, nil
|
|
|
|
}
|
2022-08-18 16:15:38 +03:00
|
|
|
|
|
|
|
func (rcfs *RCFS) AbsPath(name string) string {
|
|
|
|
if !filepath.IsAbs(name) {
|
|
|
|
name = filepath.Join(rcfs.Cwd, name)
|
|
|
|
}
|
|
|
|
|
|
|
|
return name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rcfs *RCFS) Name() string { return "RClone virtual filesystem" }
|
|
|
|
|
|
|
|
func (rcfs *RCFS) Create(name string) (afero.File, error) {
|
|
|
|
name = rcfs.AbsPath(name)
|
|
|
|
|
|
|
|
return rcfs.Fs.Create(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rcfs *RCFS) Mkdir(name string, perm os.FileMode) error {
|
|
|
|
// TODO
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rcfs *RCFS) MkdirAll(name string, perm os.FileMode) error {
|
|
|
|
// TODO
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rcfs *RCFS) Open(name string) (afero.File, error) {
|
|
|
|
name = rcfs.AbsPath(name)
|
|
|
|
|
|
|
|
f, e := rcfs.Fs.Open(name)
|
|
|
|
if f == nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
return f, e
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rcfs *RCFS) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) {
|
|
|
|
name = rcfs.AbsPath(name)
|
|
|
|
|
|
|
|
return rcfs.Fs.OpenFile(name, flag, perm)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rcfs *RCFS) Stat(name string) (os.FileInfo, error) {
|
|
|
|
name = rcfs.AbsPath(name)
|
|
|
|
|
|
|
|
return rcfs.Fs.Stat(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rcfs *RCFS) Remove(name string) error {
|
|
|
|
name = rcfs.AbsPath(name)
|
|
|
|
|
|
|
|
return rcfs.Fs.Remove(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rcfs *RCFS) RemoveAll(path string) error {
|
2022-08-20 11:18:41 +03:00
|
|
|
path = rcfs.AbsPath(path)
|
2022-08-20 13:21:54 +03:00
|
|
|
|
2022-08-20 12:16:05 +03:00
|
|
|
afero.Walk(rcfs, path, func(path string, info fs.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if info.IsDir() {
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
rcfs.Remove(path)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
})
|
2022-08-20 11:18:41 +03:00
|
|
|
|
2022-08-20 13:21:54 +03:00
|
|
|
for {
|
|
|
|
if ok, err := afero.IsEmpty(rcfs, path); err == nil {
|
|
|
|
if ok {
|
|
|
|
rcfs.Remove(path)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
afero.Walk(rcfs, path, func(path string, info fs.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if ok, err := afero.IsEmpty(rcfs, path); ok {
|
|
|
|
rcfs.Remove(path)
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-08-18 16:15:38 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rcfs *RCFS) Rename(oldname, newname string) error {
|
|
|
|
oldname = rcfs.AbsPath(oldname)
|
|
|
|
newname = rcfs.AbsPath(newname)
|
|
|
|
|
|
|
|
return rcfs.Fs.Rename(oldname, newname)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rcfs *RCFS) Chmod(name string, mode os.FileMode) error {
|
|
|
|
// TODO
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rcfs *RCFS) Chown(name string, uid, gid int) error {
|
|
|
|
// TODO
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rcfs *RCFS) Chtimes(name string, atime time.Time, mtime time.Time) error {
|
|
|
|
name = rcfs.AbsPath(name)
|
|
|
|
|
|
|
|
return rcfs.Fs.Chtimes(name, atime, mtime)
|
|
|
|
}
|
|
|
|
|
2022-08-20 11:18:41 +03:00
|
|
|
func printNode(path string, info fs.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("prevent panic by handling failure accessing a path %q: %v\n", path, err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if info.IsDir() {
|
|
|
|
fmt.Printf("visited dir: %q\n", path)
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
fmt.Printf("visited file: %q\n", path)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
func rmNode(path string, info fs.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-08-18 16:15:38 +03:00
|
|
|
|
2022-08-20 11:18:41 +03:00
|
|
|
if info.IsDir() {
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
a
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
2022-08-18 16:15:38 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|