浏览代码

Added wip smb driver

Toby Chui 3 年之前
父节点
当前提交
006991e7a2

+ 2 - 1
go.mod

@@ -23,6 +23,7 @@ require (
 	github.com/gorilla/sessions v1.2.1
 	github.com/gorilla/websocket v1.5.0
 	github.com/grandcat/zeroconf v1.0.0
+	github.com/hirochachacha/go-smb2 v1.1.0 // indirect
 	github.com/kevinburke/ssh_config v1.2.0 // indirect
 	github.com/klauspost/compress v1.15.4 // indirect
 	github.com/koron/go-ssdp v0.0.3
@@ -45,7 +46,7 @@ require (
 	github.com/valyala/fasttemplate v1.2.1
 	github.com/xanzy/ssh-agent v0.3.1 // indirect
 	gitlab.com/NebulousLabs/go-upnp v0.0.0-20211002182029-11da932010b6
-	golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 // indirect
+	golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
 	golang.org/x/image v0.0.0-20220617043117-41969df76e82 // indirect
 	golang.org/x/net v0.0.0-20220513224357-95641704303c // indirect
 	golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5

+ 7 - 0
go.sum

@@ -142,6 +142,8 @@ github.com/fogleman/simplify v0.0.0-20170216171241-d32f302d5046/go.mod h1:KDwyDq
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/gabriel-vasile/mimetype v1.4.0 h1:Cn9dkdYsMIu56tGho+fqzh7XmvY2YyGU0FnbhiOsEro=
 github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
+github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w=
+github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
 github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
@@ -280,6 +282,8 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
 github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
 github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
 github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI=
+github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
@@ -470,6 +474,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
@@ -478,6 +483,8 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y
 golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
 golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 h1:NUzdAbFtCJSXU20AOXgeqaUwg8Ypg4MPYmL+d+rsB5c=
 golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
+golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=

+ 1 - 2
mod/disk/diskcapacity/diskcapacity.go

@@ -7,7 +7,6 @@ import (
 
 	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/disk/diskcapacity/dftool"
-	"imuslab.com/arozos/mod/filesystem"
 	"imuslab.com/arozos/mod/user"
 )
 
@@ -93,7 +92,7 @@ func (cr *Resolver) ResolveCapacityInfo(username string, vpath string) (*Capacit
 
 	realpath = filepath.ToSlash(filepath.Clean(realpath))
 
-	if filesystem.FileExists(realpath) && !fsh.RequireBuffer {
+	if common.FileExists(realpath) && !fsh.RequireBuffer {
 		//This is a local disk
 		capinfo, err := dftool.GetCapacityInfoFromPath(realpath)
 		if err != nil {

+ 3 - 0
mod/filesystem/abstractions/emptyfs/emptyfs.go

@@ -62,6 +62,9 @@ func (l EmptyFileSystemAbstraction) Rename(oldname, newname string) error {
 func (l EmptyFileSystemAbstraction) Stat(filename string) (os.FileInfo, error) {
 	return nil, fsdef.ErrNullOperation
 }
+func (l EmptyFileSystemAbstraction) Close() error {
+	return nil
+}
 
 /*
 	Abstraction Utilities

+ 3 - 0
mod/filesystem/abstractions/localfs/localfs.go

@@ -73,6 +73,9 @@ func (l LocalFileSystemAbstraction) Rename(oldname, newname string) error {
 func (l LocalFileSystemAbstraction) Stat(filename string) (os.FileInfo, error) {
 	return os.Stat(filename)
 }
+func (l LocalFileSystemAbstraction) Close() error {
+	return nil
+}
 
 /*
 	Abstraction Utilities

+ 291 - 0
mod/filesystem/abstractions/smbfs/smbfs.go

@@ -0,0 +1,291 @@
+package smbfs
+
+import (
+	"fmt"
+	"io"
+	"io/fs"
+	"log"
+	"net"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+
+	"github.com/hirochachacha/go-smb2"
+	"imuslab.com/arozos/mod/filesystem/fsdef"
+)
+
+/*
+	Server Message Block.go
+
+	This is a file abstraction that mount SMB folders onto ArozOS as virtual drive
+
+*/
+
+type ServerMessageBlockFileSystemAbstraction struct {
+	UUID      string
+	Hierarchy string
+	ipaddr    string
+	user      string
+	conn      *net.Conn
+	session   *smb2.Session
+	share     *smb2.Share
+}
+
+func NewServerMessageBlockFileSystemAbstraction(uuid string, hierarchy string, ipaddr string, username string, password string) (ServerMessageBlockFileSystemAbstraction, error) {
+	conn, err := net.Dial("tcp", ipaddr+":445")
+	if err != nil {
+		log.Println("[SMB-FS] Unable to connect to remote: ", err.Error())
+		return ServerMessageBlockFileSystemAbstraction{}, err
+	}
+
+	d := &smb2.Dialer{
+		Initiator: &smb2.NTLMInitiator{
+			User:     username,
+			Password: password,
+		},
+	}
+
+	s, err := d.Dial(conn)
+	if err != nil {
+		log.Println("[SMB-FS] Unable to connect to remote: ", err.Error())
+		return ServerMessageBlockFileSystemAbstraction{}, err
+	}
+
+	//Mound remote storage
+	//SSDBuffer
+
+	fs, err := s.Mount("SSDBuffer")
+	if err != nil {
+		log.Println("[SMB-FS] Unable to connect to remote: ", err.Error())
+		return ServerMessageBlockFileSystemAbstraction{}, err
+	}
+
+	log.Println("[SMB-FS] Connected to remote: " + ipaddr)
+	return ServerMessageBlockFileSystemAbstraction{
+		UUID:      uuid,
+		Hierarchy: hierarchy,
+		ipaddr:    ipaddr,
+		user:      username,
+		conn:      &conn,
+		session:   s,
+		share:     fs,
+	}, nil
+}
+
+func (a ServerMessageBlockFileSystemAbstraction) Chmod(filename string, mode os.FileMode) error {
+	filename = filterFilepath(filename)
+	filename = toWinPath(filename)
+	return a.share.Chmod(filename, mode)
+}
+func (a ServerMessageBlockFileSystemAbstraction) Chown(filename string, uid int, gid int) error {
+	return fsdef.ErrOperationNotSupported
+}
+func (a ServerMessageBlockFileSystemAbstraction) Chtimes(filename string, atime time.Time, mtime time.Time) error {
+	filename = filterFilepath(filename)
+	filename = toWinPath(filename)
+	return a.share.Chtimes(filename, atime, mtime)
+}
+func (a ServerMessageBlockFileSystemAbstraction) Create(filename string) (*os.File, error) {
+	return nil, fsdef.ErrOperationNotSupported
+}
+func (a ServerMessageBlockFileSystemAbstraction) Mkdir(filename string, mode os.FileMode) error {
+	filename = filterFilepath(filename)
+	filename = toWinPath(filename)
+	return a.share.Mkdir(filename, mode)
+}
+func (a ServerMessageBlockFileSystemAbstraction) MkdirAll(filename string, mode os.FileMode) error {
+	filename = filterFilepath(filename)
+	filename = toWinPath(filename)
+	return a.share.MkdirAll(filename, mode)
+}
+func (a ServerMessageBlockFileSystemAbstraction) Name() string {
+	return ""
+}
+func (a ServerMessageBlockFileSystemAbstraction) Open(filename string) (*os.File, error) {
+	return nil, fsdef.ErrOperationNotSupported
+}
+func (a ServerMessageBlockFileSystemAbstraction) OpenFile(filename string, flag int, perm os.FileMode) (*os.File, error) {
+	return nil, fsdef.ErrOperationNotSupported
+}
+func (a ServerMessageBlockFileSystemAbstraction) Remove(filename string) error {
+	filename = filterFilepath(filename)
+	filename = toWinPath(filename)
+	return a.share.Remove(filename)
+}
+func (a ServerMessageBlockFileSystemAbstraction) RemoveAll(filename string) error {
+	filename = filterFilepath(filename)
+	filename = toWinPath(filename)
+	return a.share.RemoveAll(filename)
+}
+func (a ServerMessageBlockFileSystemAbstraction) Rename(oldname, newname string) error {
+	oldname = toWinPath(filterFilepath(oldname))
+	newname = toWinPath(filterFilepath(newname))
+	return a.share.Rename(oldname, newname)
+}
+func (a ServerMessageBlockFileSystemAbstraction) Stat(filename string) (os.FileInfo, error) {
+	filename = toWinPath(filterFilepath(filename))
+	return a.share.Stat(filename)
+}
+func (a ServerMessageBlockFileSystemAbstraction) Close() error {
+	a.share.Umount()
+	a.session.Logoff()
+	conn := *(a.conn)
+	conn.Close()
+	return nil
+}
+
+/*
+	Abstraction Utilities
+*/
+
+func (a ServerMessageBlockFileSystemAbstraction) VirtualPathToRealPath(subpath string, username string) (string, error) {
+	if strings.HasPrefix(subpath, a.UUID+":") {
+		//This is full virtual path. Trim the uuid and correct the subpath
+		subpath = strings.TrimPrefix(subpath, a.UUID+":")
+	}
+	subpath = filterFilepath(subpath)
+
+	if a.Hierarchy == "user" {
+		return toWinPath(filepath.ToSlash(filepath.Clean(filepath.Join("users", username, subpath)))), nil
+	} else if a.Hierarchy == "public" {
+		return toWinPath(filepath.ToSlash(filepath.Clean(subpath))), nil
+	}
+
+	return "", fsdef.ErrVpathResolveFailed
+}
+
+func (a ServerMessageBlockFileSystemAbstraction) RealPathToVirtualPath(fullpath string, username string) (string, error) {
+	fullpath = strings.TrimPrefix(fullpath, "\\")
+	vpath := a.UUID + ":/" + filterFilepath(fullpath)
+	return vpath, nil
+}
+
+func (a ServerMessageBlockFileSystemAbstraction) FileExists(realpath string) bool {
+	realpath = toWinPath(filterFilepath(realpath))
+	_, err := a.share.Open(realpath)
+	return err == nil
+}
+
+func (a ServerMessageBlockFileSystemAbstraction) IsDir(realpath string) bool {
+	realpath = filterFilepath(realpath)
+	realpath = toWinPath(realpath)
+	stx, err := a.share.Stat(realpath)
+	if err != nil {
+		return false
+	}
+	return stx.IsDir()
+}
+
+func (a ServerMessageBlockFileSystemAbstraction) Glob(realpathWildcard string) ([]string, error) {
+	realpathWildcard = toWinPath(filterFilepath(realpathWildcard))
+	return a.share.Glob(realpathWildcard)
+}
+
+func (a ServerMessageBlockFileSystemAbstraction) GetFileSize(realpath string) int64 {
+	realpath = toWinPath(filterFilepath(realpath))
+	stat, err := a.share.Stat(realpath)
+	if err != nil {
+		return 0
+	}
+	return stat.Size()
+}
+
+func (a ServerMessageBlockFileSystemAbstraction) GetModTime(realpath string) (int64, error) {
+	realpath = toWinPath(filterFilepath(realpath))
+	stat, err := a.share.Stat(realpath)
+	if err != nil {
+		return 0, nil
+	}
+	return stat.ModTime().Unix(), nil
+}
+
+func (a ServerMessageBlockFileSystemAbstraction) WriteFile(filename string, content []byte, mode os.FileMode) error {
+	filename = toWinPath(filterFilepath(filename))
+	return a.share.WriteFile(filename, content, mode)
+}
+func (a ServerMessageBlockFileSystemAbstraction) ReadFile(filename string) ([]byte, error) {
+	filename = toWinPath(filterFilepath(filename))
+	return a.share.ReadFile(filename)
+}
+func (a ServerMessageBlockFileSystemAbstraction) WriteStream(filename string, stream io.Reader, mode os.FileMode) error {
+	filename = toWinPath(filterFilepath(filename))
+	f, err := a.share.OpenFile(filename, os.O_CREATE|os.O_WRONLY, mode)
+	if err != nil {
+		return err
+	}
+
+	p := make([]byte, 1024)
+	for {
+		_, err := stream.Read(p)
+		if err != nil {
+			if err == io.EOF {
+				break
+			} else {
+				return err
+			}
+		}
+		_, err = f.Write(p)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+func (a ServerMessageBlockFileSystemAbstraction) ReadStream(filename string) (io.ReadCloser, error) {
+	filename = toWinPath(filterFilepath(filename))
+	f, err := a.share.OpenFile(filename, os.O_RDONLY, 0755)
+	if err != nil {
+		return nil, err
+	}
+	return f, nil
+}
+
+func (a ServerMessageBlockFileSystemAbstraction) Walk(root string, walkFn filepath.WalkFunc) error {
+	root = toWinPath(filterFilepath(root))
+	err := fs.WalkDir(a.share.DirFS(root), ".", func(path string, d fs.DirEntry, err error) error {
+		statInfo, _ := d.Info()
+		walkFn(path, statInfo, err)
+		return nil
+	})
+	return err
+}
+
+/*
+
+	Optional Functions
+
+*/
+
+func (a *ServerMessageBlockFileSystemAbstraction) CapacityInfo() {
+	fsinfo, err := a.share.Statfs(".")
+	if err != nil {
+		return
+	}
+
+	fmt.Println(fsinfo)
+}
+
+/*
+
+	Helper Functions
+
+*/
+
+func toWinPath(filename string) string {
+	backslashed := strings.ReplaceAll(filename, "/", "\\")
+	return strings.TrimPrefix(backslashed, "\\")
+
+}
+
+func filterFilepath(rawpath string) string {
+	rawpath = filepath.ToSlash(filepath.Clean(rawpath))
+	rawpath = strings.TrimSpace(rawpath)
+	if strings.HasPrefix(rawpath, "./") {
+		return rawpath[1:]
+	} else if rawpath == "." || rawpath == "" {
+		return "/"
+	}
+	return rawpath
+}

+ 4 - 0
mod/filesystem/abstractions/webdavfs/webdavfs.go

@@ -273,6 +273,10 @@ func (e WebDAVFileSystem) Walk(rootpath string, walkFn filepath.WalkFunc) error
 	return e.walk(rootpath, walkFn)
 }
 
+func (e WebDAVFileSystem) Close() error {
+	return nil
+}
+
 /*
 	Helper Functions
 */

+ 30 - 1
mod/filesystem/filesystem.go

@@ -22,8 +22,8 @@ import (
 	"time"
 
 	db "imuslab.com/arozos/mod/database"
-	//"imuslab.com/arozos/mod/disk/hybridBackup"
 	"imuslab.com/arozos/mod/filesystem/abstractions/localfs"
+	"imuslab.com/arozos/mod/filesystem/abstractions/smbfs"
 	"imuslab.com/arozos/mod/filesystem/abstractions/webdavfs"
 	"imuslab.com/arozos/mod/filesystem/fsdef"
 )
@@ -65,6 +65,7 @@ type FileSystemAbstraction interface {
 	RemoveAll(string) error
 	Rename(string, string) error
 	Stat(string) (os.FileInfo, error)
+	Close() error
 
 	//Utils Functions
 	VirtualPathToRealPath(string, string) (string, error)
@@ -194,7 +195,30 @@ func NewFileSystemHandler(option FileSystemOption) (*FileSystemHandler, error) {
 			Filesystem:            fstype,
 			Closed:                false,
 		}, nil
+	} else if fstype == "smb" {
+		//WebDAV. Create an object and mount it
+		ipAddr := option.Path
+		user := option.Username
+		password := option.Password
 
+		smbfs, err := smbfs.NewServerMessageBlockFileSystemAbstraction(option.Uuid, option.Hierarchy, ipAddr, user, password)
+		if err != nil {
+			return nil, err
+		}
+		return &FileSystemHandler{
+			Name:                  option.Name,
+			UUID:                  option.Uuid,
+			Path:                  option.Path,
+			ReadOnly:              option.Access == fsdef.FsReadOnly,
+			RequireBuffer:         true,
+			Hierarchy:             option.Hierarchy,
+			HierarchyConfig:       nil,
+			InitiationTime:        time.Now().Unix(),
+			FilesystemDatabase:    nil,
+			FileSystemAbstraction: smbfs,
+			Filesystem:            fstype,
+			Closed:                false,
+		}, nil
 	} else if option.Filesystem == "virtual" {
 		//Virtual filesystem, deprecated
 		log.Println("Deprecated file system type: Virtual")
@@ -332,6 +356,11 @@ func (fsh *FileSystemHandler) Close() {
 		fsh.FilesystemDatabase.Close()
 	}
 
+	//Close the file system object
+	err := fsh.FileSystemAbstraction.Close()
+	if err != nil {
+		log.Println("Unable to close File System Abstraction for Handler: " + fsh.UUID + ". Skipping.")
+	}
 }
 
 //Helper function