|
@@ -12,6 +12,7 @@ package filesystem
|
|
|
|
|
|
import (
|
|
|
"errors"
|
|
|
+ "io"
|
|
|
"log"
|
|
|
"os"
|
|
|
"path/filepath"
|
|
@@ -20,6 +21,7 @@ import (
|
|
|
|
|
|
db "imuslab.com/arozos/mod/database"
|
|
|
"imuslab.com/arozos/mod/disk/hybridBackup"
|
|
|
+ webdavclient "imuslab.com/arozos/mod/filesystem/webdavClient"
|
|
|
)
|
|
|
|
|
|
//Options for creating new file system handler
|
|
@@ -44,19 +46,52 @@ type FileSystemOpeningOptions struct{
|
|
|
*/
|
|
|
type HierarchySpecificConfig interface{}
|
|
|
|
|
|
+type FileSystemAbstraction interface {
|
|
|
+ //Fundemental Functions
|
|
|
+ Chmod(string, os.FileMode) error
|
|
|
+ Chown(string, int, int) error
|
|
|
+ Chtimes(string, time.Time, time.Time) error
|
|
|
+ Create(string) (*os.File, error)
|
|
|
+ Mkdir(string, os.FileMode) error
|
|
|
+ MkdirAll(string, os.FileMode) error
|
|
|
+ Name() string
|
|
|
+ Open(string) (*os.File, error)
|
|
|
+ OpenFile(string, int, os.FileMode) (*os.File, error)
|
|
|
+ Remove(string) error
|
|
|
+ RemoveAll(string) error
|
|
|
+ Rename(string, string) error
|
|
|
+ Stat(string) (os.FileInfo, error)
|
|
|
+
|
|
|
+ //Utils Functions
|
|
|
+ VirtualPathToRealPath(string, string) (string, error)
|
|
|
+ RealPathToVirtualPath(string, string) (string, error)
|
|
|
+ FileExists(string) bool
|
|
|
+ IsDir(string) bool
|
|
|
+ Glob(string) ([]string, error)
|
|
|
+ GetFileSize(string) int64
|
|
|
+ GetModTime(string) (int64, error)
|
|
|
+ WriteFile(string, []byte, os.FileMode) error
|
|
|
+ ReadFile(string) ([]byte, error)
|
|
|
+ WriteStream(string, io.Reader, os.FileMode) error
|
|
|
+ ReadStream(string) (io.ReadCloser, error)
|
|
|
+ Walk(string, filepath.WalkFunc) error
|
|
|
+}
|
|
|
+
|
|
|
//System Handler for returing
|
|
|
type FileSystemHandler struct {
|
|
|
- Name string
|
|
|
- UUID string
|
|
|
- Path string
|
|
|
- Hierarchy string
|
|
|
- HierarchyConfig HierarchySpecificConfig
|
|
|
- ReadOnly bool
|
|
|
- Parentuid string
|
|
|
- InitiationTime int64
|
|
|
- FilesystemDatabase *db.Database
|
|
|
- Filesystem string
|
|
|
- Closed bool
|
|
|
+ Name string
|
|
|
+ UUID string
|
|
|
+ Path string
|
|
|
+ Hierarchy string
|
|
|
+ HierarchyConfig HierarchySpecificConfig
|
|
|
+ ReadOnly bool
|
|
|
+ RequireBuffer bool //Set this to true if the fsh do not provide file header functions like Open() or Create(), require WriteStream() and ReadStream()
|
|
|
+ Parentuid string
|
|
|
+ InitiationTime int64
|
|
|
+ FilesystemDatabase *db.Database
|
|
|
+ FileSystemAbstraction FileSystemAbstraction
|
|
|
+ Filesystem string
|
|
|
+ Closed bool
|
|
|
}
|
|
|
|
|
|
//Create a list of file system handler from the given json content
|
|
@@ -99,16 +134,26 @@ func NewFileSystemHandler(option FileSystemOption) (*FileSystemHandler, error) {
|
|
|
}
|
|
|
|
|
|
//Handle Hierarchy branching
|
|
|
- var hierarchySpecificConfig interface{} = nil
|
|
|
-
|
|
|
if option.Hierarchy == "user" {
|
|
|
//Create user hierarchy for this virtual device
|
|
|
os.MkdirAll(filepath.ToSlash(filepath.Clean(option.Path))+"/users", 0755)
|
|
|
}
|
|
|
|
|
|
+ //Create the fsdb for this handler
|
|
|
+ var fsdb *db.Database = nil
|
|
|
+ dbp, err := db.NewDatabase(filepath.ToSlash(filepath.Join(filepath.Clean(option.Path), "aofs.db")), false)
|
|
|
+ if err != nil {
|
|
|
+ if option.Access != "readonly" {
|
|
|
+ log.Println("[Filesystem] Invalid config: Trying to mount a read only path as read-write mount point. Changing " + option.Name + " mount point to READONLY.")
|
|
|
+ option.Access = "readonly"
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ fsdb = dbp
|
|
|
+ }
|
|
|
+ rootpath := filepath.ToSlash(filepath.Clean(option.Path)) + "/"
|
|
|
if option.Hierarchy == "backup" {
|
|
|
//Backup disk. Create an Hierarchy Config for this drive
|
|
|
- hierarchySpecificConfig = hybridBackup.BackupTask{
|
|
|
+ hsConfig := hybridBackup.BackupTask{
|
|
|
CycleCounter: 0,
|
|
|
LastCycleTime: 0,
|
|
|
DiskUID: option.Uuid,
|
|
@@ -118,51 +163,80 @@ func NewFileSystemHandler(option FileSystemOption) (*FileSystemHandler, error) {
|
|
|
DeleteFileMarkers: map[string]int64{},
|
|
|
PanicStopped: false,
|
|
|
}
|
|
|
-
|
|
|
+ return &FileSystemHandler{
|
|
|
+ Name: option.Name,
|
|
|
+ UUID: option.Uuid,
|
|
|
+ Path: rootpath,
|
|
|
+ ReadOnly: option.Access == "readonly",
|
|
|
+ RequireBuffer: false,
|
|
|
+ Parentuid: option.Parentuid,
|
|
|
+ Hierarchy: option.Hierarchy,
|
|
|
+ HierarchyConfig: hsConfig,
|
|
|
+ InitiationTime: time.Now().Unix(),
|
|
|
+ FilesystemDatabase: fsdb,
|
|
|
+ FileSystemAbstraction: NewLocalFileSystemAbstraction(option.Uuid, rootpath, option.Hierarchy, option.Access == "readonly"),
|
|
|
+ Filesystem: fstype,
|
|
|
+ Closed: false,
|
|
|
+ }, nil
|
|
|
+ } else {
|
|
|
+ return &FileSystemHandler{
|
|
|
+ Name: option.Name,
|
|
|
+ UUID: option.Uuid,
|
|
|
+ Path: filepath.ToSlash(filepath.Clean(option.Path)) + "/",
|
|
|
+ ReadOnly: option.Access == "readonly",
|
|
|
+ RequireBuffer: false,
|
|
|
+ Parentuid: option.Parentuid,
|
|
|
+ Hierarchy: option.Hierarchy,
|
|
|
+ HierarchyConfig: DefaultEmptyHierarchySpecificConfig,
|
|
|
+ InitiationTime: time.Now().Unix(),
|
|
|
+ FilesystemDatabase: fsdb,
|
|
|
+ FileSystemAbstraction: NewLocalFileSystemAbstraction(option.Uuid, rootpath, option.Hierarchy, option.Access == "readonly"),
|
|
|
+ Filesystem: fstype,
|
|
|
+ Closed: false,
|
|
|
+ }, nil
|
|
|
}
|
|
|
|
|
|
- //Create the fsdb for this handler
|
|
|
- var fsdb *db.Database = nil
|
|
|
+ } else if fstype == "webdav" {
|
|
|
+ //WebDAV. Create an object and mount it
|
|
|
+ root := option.Path
|
|
|
+ user := option.Username
|
|
|
+ password := option.Password
|
|
|
|
|
|
- dbp, err := db.NewDatabase(filepath.ToSlash(filepath.Join(filepath.Clean(option.Path), "aofs.db")), false)
|
|
|
- if err != nil {
|
|
|
- if option.Access != "readonly" {
|
|
|
- log.Println("[Filesystem] Invalid config: Trying to mount a read only path as read-write mount point. Changing " + option.Name + " mount point to READONLY.")
|
|
|
- option.Access = "readonly"
|
|
|
- }
|
|
|
- } else {
|
|
|
- fsdb = dbp
|
|
|
- }
|
|
|
+ webdavfs, _ := webdavclient.NewWebDAVMount(option.Uuid, option.Hierarchy, root, user, password, "./tmp/webdavBuff")
|
|
|
|
|
|
return &FileSystemHandler{
|
|
|
- Name: option.Name,
|
|
|
- UUID: option.Uuid,
|
|
|
- Path: filepath.ToSlash(filepath.Clean(option.Path)) + "/",
|
|
|
- ReadOnly: option.Access == "readonly",
|
|
|
- Parentuid: option.Parentuid,
|
|
|
- Hierarchy: option.Hierarchy,
|
|
|
- HierarchyConfig: hierarchySpecificConfig,
|
|
|
- InitiationTime: time.Now().Unix(),
|
|
|
- FilesystemDatabase: fsdb,
|
|
|
- Filesystem: fstype,
|
|
|
- Closed: false,
|
|
|
+ Name: option.Name,
|
|
|
+ UUID: option.Uuid,
|
|
|
+ Path: "",
|
|
|
+ ReadOnly: option.Access == "readonly",
|
|
|
+ RequireBuffer: true,
|
|
|
+ Parentuid: option.Parentuid,
|
|
|
+ Hierarchy: option.Hierarchy,
|
|
|
+ HierarchyConfig: nil,
|
|
|
+ InitiationTime: time.Now().Unix(),
|
|
|
+ FilesystemDatabase: nil,
|
|
|
+ FileSystemAbstraction: webdavfs,
|
|
|
+ Filesystem: fstype,
|
|
|
+ Closed: false,
|
|
|
}, nil
|
|
|
} else if option.Filesystem == "virtual" {
|
|
|
//Virtual filesystem, use custom mapping logic to handle file access
|
|
|
if option.Hierarchy == "share" {
|
|
|
//Emulated share virtual file system. Use Share Manager structure
|
|
|
return &FileSystemHandler{
|
|
|
- Name: option.Name,
|
|
|
- UUID: option.Uuid,
|
|
|
- Path: "",
|
|
|
- ReadOnly: option.Access == "readonly",
|
|
|
- Parentuid: option.Parentuid,
|
|
|
- Hierarchy: option.Hierarchy,
|
|
|
- HierarchyConfig: nil,
|
|
|
- InitiationTime: time.Now().Unix(),
|
|
|
- FilesystemDatabase: nil,
|
|
|
- Filesystem: fstype,
|
|
|
- Closed: false,
|
|
|
+ Name: option.Name,
|
|
|
+ UUID: option.Uuid,
|
|
|
+ Path: "",
|
|
|
+ ReadOnly: option.Access == "readonly",
|
|
|
+ RequireBuffer: false,
|
|
|
+ Parentuid: option.Parentuid,
|
|
|
+ Hierarchy: option.Hierarchy,
|
|
|
+ HierarchyConfig: nil,
|
|
|
+ InitiationTime: time.Now().Unix(),
|
|
|
+ FilesystemDatabase: nil,
|
|
|
+ FileSystemAbstraction: NewEmptyFileSystemAbstraction(),
|
|
|
+ Filesystem: fstype,
|
|
|
+ Closed: false,
|
|
|
}, nil
|
|
|
}
|
|
|
}
|
|
@@ -170,6 +244,27 @@ func NewFileSystemHandler(option FileSystemOption) (*FileSystemHandler, error) {
|
|
|
return nil, errors.New("Not supported file system: " + fstype)
|
|
|
}
|
|
|
|
|
|
+//Check if a fsh is virtual (e.g. Network or fs Abstractions that cannot be listed with normal fs API)
|
|
|
+func (fsh *FileSystemHandler) IsVirtual() bool {
|
|
|
+ if fsh.Hierarchy == "virtual" || fsh.Filesystem == "webdav" {
|
|
|
+ //Check if the config return placeholder
|
|
|
+ c, ok := fsh.HierarchyConfig.(EmptyHierarchySpecificConfig)
|
|
|
+ if ok && c.HierarchyType == "placeholder" {
|
|
|
+ //Real file system.
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ //Do more checking here if needed
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ File Record Related Functions
|
|
|
+ fsh database that keep track of which files is owned by whom
|
|
|
+*/
|
|
|
+
|
|
|
//Create a file ownership record
|
|
|
func (fsh *FileSystemHandler) CreateFileRecord(realpath string, owner string) error {
|
|
|
if fsh.FilesystemDatabase == nil {
|