package webdavclient import ( "errors" "io" "log" "os" "path/filepath" "regexp" "strings" "time" "github.com/studio-b12/gowebdav" ) /* WebDAV Client This script is design as a wrapper of the studio-b12/gowebdav module that allow access to webdav network drive in ArozOS and allow arozos cross-mounting each others */ type WebDAVFileSystem struct { UUID string Hierarchy string root string user string tmp string c *gowebdav.Client } func NewWebDAVMount(UUID string, Hierarchy string, root string, user string, password string, tmpBuff string) (*WebDAVFileSystem, error) { //Connect to webdav server c := gowebdav.NewClient(root, user, password) err := c.Connect() if err != nil { log.Println("[WebDAV FS] Unable to connect to remote: ", err.Error()) return nil, err } else { log.Println("[WebDAV FS] Connected to remote: " + root) } //Create tmp buff folder if not exists os.MkdirAll(tmpBuff, 0775) return &WebDAVFileSystem{ UUID: UUID, Hierarchy: Hierarchy, c: c, root: root, user: user, tmp: tmpBuff, }, nil } func (e WebDAVFileSystem) Chmod(filename string, mode os.FileMode) error { return errors.New("filesystem type not supported") } func (e WebDAVFileSystem) Chown(filename string, uid int, gid int) error { return errors.New("filesystem type not supported") } func (e WebDAVFileSystem) Chtimes(filename string, atime time.Time, mtime time.Time) error { return errors.New("filesystem type not supported") } func (e WebDAVFileSystem) Create(filename string) (*os.File, error) { return nil, errors.New("filesystem type not supported") } func (e WebDAVFileSystem) Mkdir(filename string, mode os.FileMode) error { filename = filepath.ToSlash(filename) return e.c.Mkdir(filename, mode) } func (e WebDAVFileSystem) MkdirAll(filename string, mode os.FileMode) error { filename = filepath.ToSlash(filename) return e.c.MkdirAll(filename, mode) } func (e WebDAVFileSystem) Name() string { return "" } func (e WebDAVFileSystem) Open(filename string) (*os.File, error) { return nil, errors.New("filesystem type not supported") } func (e WebDAVFileSystem) OpenFile(filename string, flag int, perm os.FileMode) (*os.File, error) { return nil, errors.New("filesystem type not supported") } func (e WebDAVFileSystem) Remove(filename string) error { filename = filepath.ToSlash(filename) return e.c.Remove(filename) } func (e WebDAVFileSystem) RemoveAll(filename string) error { filename = filepath.ToSlash(filename) return e.c.RemoveAll(filename) } func (e WebDAVFileSystem) Rename(oldname, newname string) error { oldname = filepath.ToSlash(oldname) newname = filepath.ToSlash(newname) return e.c.Rename(oldname, newname, false) } func (e WebDAVFileSystem) Stat(filename string) (os.FileInfo, error) { filename = filepath.ToSlash(filename) return e.c.Stat(filename) } func (e WebDAVFileSystem) VirtualPathToRealPath(subpath string, username string) (string, error) { if strings.HasPrefix(subpath, e.UUID+":/") { //This is full virtual path. Trim the uuid and correct the subpath subpath = subpath[len(e.UUID+":/"):] } if e.Hierarchy == "user" { return filepath.ToSlash(filepath.Join("users", username, subpath)), nil } else if e.Hierarchy == "public" { return filepath.ToSlash(subpath), nil } return "", errors.New("unsupported filesystem hierarchy") } func (e WebDAVFileSystem) RealPathToVirtualPath(rpath string, username string) (string, error) { return e.UUID + ":" + filepath.ToSlash(rpath), nil } func (e WebDAVFileSystem) FileExists(filename string) bool { filename = filepath.ToSlash(filename) _, err := e.c.Stat(filename) if os.IsNotExist(err) || err != nil { return false } return true } func (e WebDAVFileSystem) IsDir(filename string) bool { filename = filepath.ToSlash(filename) s, err := e.c.Stat(filename) if err != nil { return false } return s.IsDir() } //Notes: This is not actual Glob function. This just emulate Glob using ReadDir with max depth 1 layer func (e WebDAVFileSystem) Glob(wildcard string) ([]string, error) { fileInfos, err := e.c.ReadDir(filepath.ToSlash(filepath.Clean(filepath.Dir(wildcard)))) if err != nil { return []string{}, err } validFiles := []string{} for _, fileInfo := range fileInfos { thisFullPath := filepath.ToSlash(filepath.Join(filepath.Dir(wildcard), fileInfo.Name())) match, _ := regexp.MatchString(wildcard, thisFullPath) if match { validFiles = append(validFiles, thisFullPath) } } return validFiles, nil } func (e WebDAVFileSystem) GetFileSize(filename string) int64 { filename = filepath.ToSlash(filename) s, err := e.Stat(filename) if err != nil { return 0 } return s.Size() } func (e WebDAVFileSystem) GetModTime(filename string) (int64, error) { filename = filepath.ToSlash(filename) s, err := e.Stat(filename) if err != nil { return 0, err } return s.ModTime().Unix(), nil } func (e WebDAVFileSystem) WriteFile(filename string, content []byte, mode os.FileMode) error { filename = filepath.ToSlash(filename) return e.c.Write(filename, content, mode) } func (e WebDAVFileSystem) ReadFile(filename string) ([]byte, error) { filename = filepath.ToSlash(filename) bytes, err := e.c.Read(filename) if err != nil { return []byte(""), err } return bytes, nil } func (e WebDAVFileSystem) WriteStream(filename string, stream io.Reader, mode os.FileMode) error { filename = filepath.ToSlash(filename) return e.c.WriteStream(filename, stream, mode) } func (e WebDAVFileSystem) ReadStream(filename string) (io.ReadCloser, error) { filename = filepath.ToSlash(filename) return e.c.ReadStream(filename) } func (e WebDAVFileSystem) Walk(rootpath string, walkFn filepath.WalkFunc) error { rootpath = filepath.ToSlash(rootpath) return e.walk(rootpath, walkFn) } func (e WebDAVFileSystem) walk(thisPath string, walkFun filepath.WalkFunc) error { files, err := e.c.ReadDir(thisPath) if err != nil { return err } for _, file := range files { thisFileFullPath := filepath.ToSlash(filepath.Join(thisPath, file.Name())) if file.IsDir() { err = walkFun(thisFileFullPath, file, nil) if err != nil { return err } err = e.walk(thisFileFullPath, walkFun) if err != nil { return err } } else { err = walkFun(thisFileFullPath, file, nil) if err != nil { return err } } } return nil }