Przeglądaj źródła

Fixed smbfs glob issue

Toby Chui 3 lat temu
rodzic
commit
78a83a3ae6

+ 92 - 26
file_system.go

@@ -2503,48 +2503,98 @@ func system_fs_handleList(w http.ResponseWriter, r *http.Request) {
 	}
 
 	//Check for really special exception in where the path contains [ or ] which cannot be handled via Golang Glob function
-	files, err := fshAbs.Glob(realpath + "/*")
+	/*
+		files, err := fshAbs.Glob(realpath + "/*")
+		if err != nil {
+			systemWideLogger.PrintAndLog("File System", "Unable to list dir: "+err.Error(), err)
+			return
+		}
+
+		var shortCutInfo *shortcut.ShortcutData = nil
+		for _, v := range files {
+			//Check if it is hidden file
+			isHidden, _ := hidden.IsHidden(v, false)
+			if showHidden != "true" && isHidden {
+				//Skipping hidden files
+				continue
+			}
+
+			//Check if this is an aodb file
+			if filepath.Base(v) == "aofs.db" || filepath.Base(v) == "aofs.db.lock" {
+				//Database file (reserved)
+				continue
+			}
+
+			//Check if it is shortcut file. If yes, render a shortcut data struct
+			if filepath.Ext(v) == ".shortcut" {
+				//This is a shortcut file
+				shorcutData, err := shortcut.ReadShortcut(v)
+				if err == nil {
+					shortCutInfo = shorcutData
+				}
+			}
+
+			fstat, _ := fshAbs.Stat(v)
+
+			rawsize := fstat.Size()
+			modtime := fstat.ModTime().Unix()
+			thisvPath, _ := fshAbs.RealPathToVirtualPath(v, userinfo.Username)
+			thisFile := filesystem.FileData{
+				Filename:    filepath.Base(v),
+				Filepath:    currentDir + filepath.Base(v),
+				Realpath:    v,
+				IsDir:       fstat.IsDir(),
+				Filesize:    rawsize,
+				Displaysize: filesystem.GetFileDisplaySize(rawsize, 2),
+				ModTime:     modtime,
+				IsShared:    shareManager.FileIsShared(userinfo, thisvPath),
+				Shortcut:    shortCutInfo,
+			}
+
+			parsedFilelist = append(parsedFilelist, thisFile)
+		}
+	*/
+
+	files, err := fshAbs.ReadDir(realpath)
 	if err != nil {
-		systemWideLogger.PrintAndLog("File System", "Unable to list dir: "+err.Error(), err)
+		systemWideLogger.PrintAndLog("File System", "Unable to read dir: "+err.Error(), err)
 		return
 	}
-	var shortCutInfo *shortcut.ShortcutData = nil
-	for _, v := range files {
+
+	for _, f := range files {
 		//Check if it is hidden file
-		isHidden, _ := hidden.IsHidden(v, false)
+		isHidden, _ := hidden.IsHidden(f.Name(), false)
 		if showHidden != "true" && isHidden {
 			//Skipping hidden files
 			continue
 		}
 
 		//Check if this is an aodb file
-		if filepath.Base(v) == "aofs.db" || filepath.Base(v) == "aofs.db.lock" {
+		if f.Name() == "aofs.db" || f.Name() == "aofs.db.lock" {
 			//Database file (reserved)
 			continue
 		}
 
 		//Check if it is shortcut file. If yes, render a shortcut data struct
-		if filepath.Ext(v) == ".shortcut" {
+		var shortCutInfo *shortcut.ShortcutData = nil
+		if filepath.Ext(f.Name()) == ".shortcut" {
 			//This is a shortcut file
-			shorcutData, err := shortcut.ReadShortcut(v)
+			shorcutData, err := shortcut.ReadShortcut(f.Name())
 			if err == nil {
 				shortCutInfo = shorcutData
 			}
 		}
 
-		fstat, _ := fshAbs.Stat(v)
-
-		rawsize := fstat.Size()
-		modtime := fstat.ModTime().Unix()
-		thisvPath, _ := fshAbs.RealPathToVirtualPath(v, userinfo.Username)
+		statInfo, _ := f.Info()
+		thisvPath, _ := fshAbs.RealPathToVirtualPath(filepath.Join(realpath, f.Name()), userinfo.Username)
 		thisFile := filesystem.FileData{
-			Filename:    filepath.Base(v),
-			Filepath:    currentDir + filepath.Base(v),
-			Realpath:    v,
-			IsDir:       fstat.IsDir(),
-			Filesize:    rawsize,
-			Displaysize: filesystem.GetFileDisplaySize(rawsize, 2),
-			ModTime:     modtime,
+			Filename:    f.Name(),
+			Filepath:    currentDir + f.Name(),
+			Realpath:    filepath.ToSlash(filepath.Join(realpath, f.Name())),
+			IsDir:       f.IsDir(),
+			Filesize:    statInfo.Size(),
+			Displaysize: filesystem.GetFileDisplaySize(statInfo.Size(), 2),
+			ModTime:     statInfo.ModTime().Unix(),
 			IsShared:    shareManager.FileIsShared(userinfo, thisvPath),
 			Shortcut:    shortCutInfo,
 		}
@@ -2607,19 +2657,35 @@ func system_fs_handleDirHash(w http.ResponseWriter, r *http.Request) {
 
 	//Get a list of files in this directory
 	currentDir = filepath.ToSlash(filepath.Clean(rpath)) + "/"
-	filesInDir, err := fshAbs.Glob(currentDir + "*")
+	/*
+		filesInDir, err := fshAbs.Glob(currentDir + "*")
+		if err != nil {
+			common.SendErrorResponse(w, err.Error())
+			return
+		}
+
+
+		filenames := []string{}
+		for _, file := range filesInDir {
+			if len(filepath.Base(file)) > 0 && string([]rune(filepath.Base(file))[0]) != "." {
+				//Ignore hidden files
+				filenames = append(filenames, filepath.Base(file))
+			}
+
+		}
+	*/
+	finfos, err := fshAbs.ReadDir(rpath)
 	if err != nil {
 		common.SendErrorResponse(w, err.Error())
 		return
 	}
-
 	filenames := []string{}
-	for _, file := range filesInDir {
-		if len(filepath.Base(file)) > 0 && string([]rune(filepath.Base(file))[0]) != "." {
+	for _, fi := range finfos {
+		isHiddenFile, _ := hidden.IsHidden(fi.Name(), false)
+		if len(fi.Name()) > 0 && !isHiddenFile {
 			//Ignore hidden files
-			filenames = append(filenames, filepath.Base(file))
+			filenames = append(filenames, fi.Name())
 		}
-
 	}
 
 	sort.Strings(filenames)

+ 14 - 2
mediaServer.go

@@ -203,7 +203,7 @@ func serverMedia(w http.ResponseWriter, r *http.Request) {
 		}
 
 	} else {
-		if targetFsh.RequireBuffer || !filesystem.FileExists(realFilepath) {
+		if targetFsh.RequireBuffer {
 			w.Header().Set("Content-Length", strconv.Itoa(int(targetFshAbs.GetFileSize(realFilepath))))
 			//Check buffer exists
 			ps, _ := targetFsh.GetUniquePathHash(vpath, userinfo.Username)
@@ -230,8 +230,8 @@ func serverMedia(w http.ResponseWriter, r *http.Request) {
 				common.SendErrorResponse(w, err.Error())
 				return
 			}
+			defer remoteStream.Close()
 			io.Copy(w, remoteStream)
-			remoteStream.Close()
 
 			if *enable_buffering {
 				os.MkdirAll(buffpool, 0775)
@@ -239,6 +239,18 @@ func serverMedia(w http.ResponseWriter, r *http.Request) {
 					BufferRemoteFileToTmp(buffFile, targetFsh, realFilepath)
 				}()
 			}
+
+		} else if !filesystem.FileExists(realFilepath) {
+			//Streaming from remote file system that support fseek
+			f, err := targetFsh.FileSystemAbstraction.Open(realFilepath)
+			if err != nil {
+				w.WriteHeader(http.StatusInternalServerError)
+				w.Write([]byte("500 - Internal Server Error"))
+				return
+			}
+			fstat, _ := f.Stat()
+			defer f.Close()
+			http.ServeContent(w, r, filepath.Base(realFilepath), fstat.ModTime(), f)
 		} else {
 			http.ServeFile(w, r, realFilepath)
 		}

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

@@ -2,6 +2,7 @@ package emptyfs
 
 import (
 	"io"
+	"io/fs"
 	"os"
 	"path/filepath"
 	"time"
@@ -104,6 +105,9 @@ func (l EmptyFileSystemAbstraction) WriteFile(filename string, content []byte, m
 func (l EmptyFileSystemAbstraction) ReadFile(filename string) ([]byte, error) {
 	return []byte(""), arozfs.ErrOperationNotSupported
 }
+func (l EmptyFileSystemAbstraction) ReadDir(filename string) ([]fs.DirEntry, error) {
+	return []fs.DirEntry{}, arozfs.ErrOperationNotSupported
+}
 func (l EmptyFileSystemAbstraction) WriteStream(filename string, stream io.Reader, mode os.FileMode) error {
 	return arozfs.ErrNullOperation
 }

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

@@ -2,6 +2,7 @@ package localfs
 
 import (
 	"io"
+	"io/fs"
 	"os"
 	"path/filepath"
 	"strings"
@@ -220,6 +221,9 @@ func (l LocalFileSystemAbstraction) WriteFile(filename string, content []byte, m
 func (l LocalFileSystemAbstraction) ReadFile(filename string) ([]byte, error) {
 	return os.ReadFile(filename)
 }
+func (l LocalFileSystemAbstraction) ReadDir(filename string) ([]fs.DirEntry, error) {
+	return os.ReadDir(filename)
+}
 func (l LocalFileSystemAbstraction) WriteStream(filename string, stream io.Reader, mode os.FileMode) error {
 	f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, mode)
 	if err != nil {

+ 26 - 0
mod/filesystem/abstractions/smbfs/smbFileWrapper.go

@@ -81,3 +81,29 @@ func (f *smbfsFile) WriteAt(b []byte, off int64) (n int, err error) {
 func (f *smbfsFile) WriteString(s string) (n int, err error) {
 	return f.file.WriteString(s)
 }
+
+type smbDirEntry struct {
+	finfo fs.FileInfo
+}
+
+func newDirEntryFromFileInfo(targetFileInfo fs.FileInfo) *smbDirEntry {
+	return &smbDirEntry{
+		finfo: targetFileInfo,
+	}
+}
+
+func (de smbDirEntry) Name() string {
+	return de.finfo.Name()
+}
+
+func (de smbDirEntry) IsDir() bool {
+	return de.finfo.IsDir()
+}
+
+func (de smbDirEntry) Type() fs.FileMode {
+	return de.finfo.Mode()
+}
+
+func (de smbDirEntry) Info() (fs.FileInfo, error) {
+	return de.finfo, nil
+}

+ 33 - 9
mod/filesystem/abstractions/smbfs/smbfs.go

@@ -8,6 +8,7 @@ import (
 	"net"
 	"os"
 	"path/filepath"
+	"regexp"
 	"strings"
 	"time"
 
@@ -201,19 +202,13 @@ func (a ServerMessageBlockFileSystemAbstraction) IsDir(realpath string) bool {
 }
 
 func (a ServerMessageBlockFileSystemAbstraction) Glob(realpathWildcard string) ([]string, error) {
-	realpathWildcard = toWinPath(filterFilepath(realpathWildcard))
-	fmt.Println("GLOBING", realpathWildcard)
-	filteredMatches := []string{}
+	realpathWildcard = strings.ReplaceAll(realpathWildcard, "[", "?")
+	realpathWildcard = strings.ReplaceAll(realpathWildcard, "]", "?")
 	matches, err := a.share.Glob(realpathWildcard)
 	if err != nil {
 		return []string{}, err
 	}
-
-	for _, thisMatch := range matches {
-		filteredMatches = append(filteredMatches, strings.ReplaceAll(thisMatch, "\\", "/"))
-		fmt.Println(filepath.ToSlash(thisMatch), strings.ReplaceAll(thisMatch, "\\", "/"))
-	}
-	return filteredMatches, nil
+	return matches, nil
 }
 
 func (a ServerMessageBlockFileSystemAbstraction) GetFileSize(realpath string) int64 {
@@ -242,6 +237,20 @@ func (a ServerMessageBlockFileSystemAbstraction) ReadFile(filename string) ([]by
 	filename = toWinPath(filterFilepath(filename))
 	return a.share.ReadFile(filename)
 }
+
+func (a ServerMessageBlockFileSystemAbstraction) ReadDir(filename string) ([]fs.DirEntry, error) {
+	filename = toWinPath(filterFilepath(filename))
+	fis, err := a.share.ReadDir(filename)
+	if err != nil {
+		return []fs.DirEntry{}, err
+	}
+	dirEntires := []fs.DirEntry{}
+	for _, fi := range fis {
+		dirEntires = append(dirEntires, newDirEntryFromFileInfo(fi))
+	}
+	return dirEntires, nil
+}
+
 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)
@@ -331,3 +340,18 @@ func filterFilepath(rawpath string) string {
 
 	return rawpath
 }
+
+func wildCardToRegexp(pattern string) string {
+	var result strings.Builder
+	for i, literal := range strings.Split(pattern, "*") {
+		// Replace * with .*
+		if i > 0 {
+			result.WriteString(".*")
+		}
+
+		// Quote any regular expression meta characters in the
+		// literal text.
+		result.WriteString(regexp.QuoteMeta(literal))
+	}
+	return result.String()
+}

+ 0 - 188
mod/filesystem/abstractions/webdavfs/bufffs/bufffs.go

@@ -1,188 +0,0 @@
-package bufffs
-
-/*
-	bufffs.go
-
-	This module provide a mockup template for buffered type file system to create
-	a os.File compatible type of file for other purposes
-*/
-
-import (
-	"errors"
-	"io"
-	"os"
-	"syscall"
-	"time"
-)
-
-type file struct {
-	name string
-	buf  []byte
-	ptr  int64
-
-	IsDir        bool
-	CloseHandler func(interface{}) error
-	ClosePayload interface{}
-	FshRealPath  string
-}
-
-// New creates new mock file, which can be used as os.File.
-//func New(name string, isDir bool, content []byte, fshRealpath string, closeHandler func(interface{}) error, closePayload interface{}) *file {
-func New(name string) *file {
-	return &file{
-		name: name,
-		buf:  []byte{},
-		ptr:  0,
-
-		IsDir:        false,
-		CloseHandler: nil,
-		ClosePayload: nil,
-		FshRealPath:  "",
-	}
-}
-
-func (f *file) SetContent(content []byte) {
-	f.buf = content
-}
-
-func (f *file) Chdir() error {
-	return errors.New("operation not supported")
-}
-func (f *file) Chmod(mode os.FileMode) error {
-	return errors.New("operation not supported")
-}
-func (f *file) Chown(uid, gid int) error {
-	return errors.New("operation not supported")
-}
-
-func (f *file) Fd() uintptr {
-	return 0
-}
-
-func (f *file) Name() string {
-	return ""
-}
-
-func (f *file) ReadDir(n int) ([]os.DirEntry, error) {
-	return []os.DirEntry{}, errors.New("operation not supported")
-}
-func (f *file) ReadFrom(r io.Reader) (n int64, err error) {
-	return 0, errors.New("operation not supported")
-}
-func (f *file) Readdir(n int) ([]os.FileInfo, error) {
-	return []os.FileInfo{}, errors.New("operation not supported")
-}
-func (f *file) Readdirnames(n int) (names []string, err error) {
-	return []string{}, errors.New("operation not supported")
-}
-
-func (f *file) SetDeadline(t time.Time) error {
-	return errors.New("operation not supported")
-}
-func (f *file) SetReadDeadline(t time.Time) error {
-	return errors.New("operation not supported")
-}
-func (f *file) SetWriteDeadline(t time.Time) error {
-	return errors.New("operation not supported")
-}
-
-func (f *file) Sync() error {
-	return errors.New("operation not supported")
-}
-func (f *file) SyscallConn() (syscall.RawConn, error) {
-	return nil, errors.New("operation not supported")
-}
-
-func (f *file) WriteAt(b []byte, off int64) (n int, err error) {
-	return 0, errors.New("operation not supported")
-}
-func (f *file) WriteString(s string) (n int, err error) {
-	return 0, errors.New("operation not supported")
-}
-
-func (m *file) Close() error {
-	if m.CloseHandler != nil {
-		return m.CloseHandler(m.ClosePayload)
-	}
-	return nil
-}
-
-func (m *file) Read(p []byte) (n int, err error) {
-	n, err = m.ReadAt(p, m.ptr)
-	m.ptr += int64(n)
-
-	return n, err
-}
-
-func (m *file) Seek(offset int64, whence int) (int64, error) {
-	switch whence {
-	case io.SeekStart:
-		m.ptr = offset
-	case io.SeekEnd:
-		m.ptr = int64(len(m.buf)) + offset
-	case io.SeekCurrent:
-		m.ptr = m.ptr + offset
-	}
-
-	return m.ptr, nil
-}
-
-func (m *file) Stat() (os.FileInfo, error) {
-	return fileInfo{
-		size: int64(len(m.buf)),
-		dir:  m.IsDir,
-	}, nil
-}
-
-func (m *file) ReadAt(p []byte, off int64) (n int, err error) {
-	if n = copy(p, m.buf[off:]); n == 0 {
-		return n, io.EOF
-	} else {
-		return n, nil
-	}
-}
-
-func (m *file) Write(p []byte) (n int, err error) {
-	m.buf = append(m.buf, p...)
-
-	return len(p), nil
-}
-
-func (m *file) Truncate(size int64) error {
-	if size > int64(len(m.buf)) {
-		size = int64(len(m.buf))
-	}
-
-	m.buf = m.buf[:size-1]
-
-	return nil
-}
-
-type fileInfo struct {
-	size int64
-	dir  bool
-}
-
-func (m fileInfo) Name() string {
-	return ""
-}
-
-func (m fileInfo) Size() int64 {
-	return m.size
-}
-
-func (m fileInfo) Mode() os.FileMode {
-	return os.FileMode(0)
-}
-
-func (m fileInfo) ModTime() time.Time {
-	return time.Time{}
-}
-
-func (m fileInfo) IsDir() bool {
-	return m.dir
-}
-
-func (m fileInfo) Sys() interface{} {
-	return nil
-}

+ 29 - 0
mod/filesystem/abstractions/webdavfs/webdavDirEntry.go

@@ -0,0 +1,29 @@
+package webdavfs
+
+import "io/fs"
+
+type WebdavDirEntry struct {
+	finfo fs.FileInfo
+}
+
+func newDirEntryFromFileInfo(targetFileInfo fs.FileInfo) *WebdavDirEntry {
+	return &WebdavDirEntry{
+		finfo: targetFileInfo,
+	}
+}
+
+func (de WebdavDirEntry) Name() string {
+	return de.finfo.Name()
+}
+
+func (de WebdavDirEntry) IsDir() bool {
+	return de.finfo.IsDir()
+}
+
+func (de WebdavDirEntry) Type() fs.FileMode {
+	return de.finfo.Mode()
+}
+
+func (de WebdavDirEntry) Info() (fs.FileInfo, error) {
+	return de.finfo, nil
+}

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

@@ -3,6 +3,7 @@ package webdavfs
 import (
 	"errors"
 	"io"
+	"io/fs"
 	"log"
 	"os"
 	"path/filepath"
@@ -254,6 +255,18 @@ func (e WebDAVFileSystem) ReadFile(filename string) ([]byte, error) {
 	}
 	return bytes, nil
 }
+func (e WebDAVFileSystem) ReadDir(filename string) ([]fs.DirEntry, error) {
+	fis, err := e.c.ReadDir(filename)
+	if err != nil {
+		return []fs.DirEntry{}, err
+	}
+
+	dirEntires := []fs.DirEntry{}
+	for _, fi := range fis {
+		dirEntires = append(dirEntires, newDirEntryFromFileInfo(fi))
+	}
+	return dirEntires, nil
+}
 func (e WebDAVFileSystem) WriteStream(filename string, stream io.Reader, mode os.FileMode) error {
 	filename = filterFilepath(filepath.ToSlash(filepath.Clean(filename)))
 	return e.c.WriteStream(filename, stream, mode)

+ 2 - 0
mod/filesystem/filesystem.go

@@ -15,6 +15,7 @@ import (
 	"encoding/hex"
 	"errors"
 	"io"
+	"io/fs"
 	"log"
 	"os"
 	"path/filepath"
@@ -77,6 +78,7 @@ type FileSystemAbstraction interface {
 	GetModTime(string) (int64, error)
 	WriteFile(string, []byte, os.FileMode) error
 	ReadFile(string) ([]byte, error)
+	ReadDir(string) ([]fs.DirEntry, error)
 	WriteStream(string, io.Reader, os.FileMode) error
 	ReadStream(string) (io.ReadCloser, error)
 	Walk(string, filepath.WalkFunc) error