Pārlūkot izejas kodu

Optimized glob logic in webdavfs driver

Toby Chui 3 gadi atpakaļ
vecāks
revīzija
f0becfcf5e
1 mainītis faili ar 108 papildinājumiem un 53 dzēšanām
  1. 108 53
      mod/filesystem/abstractions/webdavfs/webdavfs.go

+ 108 - 53
mod/filesystem/abstractions/webdavfs/webdavfs.go

@@ -3,7 +3,6 @@ package webdavfs
 import (
 	"errors"
 	"io"
-	"io/fs"
 	"log"
 	"os"
 	"path/filepath"
@@ -164,61 +163,64 @@ func (e WebDAVFileSystem) Glob(wildcard string) ([]string, error) {
 		//Handle case for listing root, "*"
 		wildcard = "/" + wildcard
 	}
-
-	//Get the longest path without *
-	chunksWithoutStar := []string{}
-	chunks := strings.Split(wildcard, "/")
-	for _, chunk := range chunks {
-		if !strings.Contains(chunk, "*") {
-			chunksWithoutStar = append(chunksWithoutStar, chunk)
-		} else {
-			//Cut off
-			break
-		}
-	}
-
-	if strings.Count(wildcard, "*") <= 1 && strings.Contains(chunks[len(chunks)-1], "*") {
-		//Fast Glob
-		fileInfos, err := e.c.ReadDir(filterFilepath(filepath.ToSlash(filepath.Clean(filepath.Dir(wildcard)))))
-		if err != nil {
-			return []string{}, err
-		}
-
-		validFiles := []string{}
-		matchingRule := wildCardToRegexp(wildcard)
-		for _, thisFileInfo := range fileInfos {
-			thisFileFullpath := filepath.ToSlash(filepath.Join(filepath.Dir(wildcard), thisFileInfo.Name()))
-			match, _ := regexp.MatchString(matchingRule, thisFileFullpath)
-			if match {
-				validFiles = append(validFiles, thisFileFullpath)
+	chunks := strings.Split(strings.TrimPrefix(wildcard, "/"), "/")
+	results, err := e.globpath("/", chunks, 0)
+	return results, err
+	/*
+		//Get the longest path without *
+		chunksWithoutStar := []string{}
+		chunks := strings.Split(wildcard, "/")
+		for _, chunk := range chunks {
+			if !strings.Contains(chunk, "*") {
+				chunksWithoutStar = append(chunksWithoutStar, chunk)
+			} else {
+				//Cut off
+				break
 			}
 		}
-		return validFiles, nil
-	} else {
-		//Slow Glob
-		walkRoot := strings.Join(chunksWithoutStar, "/")
-		if !strings.HasPrefix(walkRoot, "/") {
-			walkRoot = "/" + walkRoot
-		}
 
-		allFiles := []string{}
-		e.Walk(walkRoot, func(path string, info fs.FileInfo, err error) error {
-			allFiles = append(allFiles, path)
-			return nil
-		})
+		if strings.Count(wildcard, "*") <= 1 && strings.Contains(chunks[len(chunks)-1], "*") {
+			//Fast Glob
+			fileInfos, err := e.c.ReadDir(filterFilepath(filepath.ToSlash(filepath.Clean(filepath.Dir(wildcard)))))
+			if err != nil {
+				return []string{}, err
+			}
 
-		validFiles := []string{}
-		matchingRule := wildCardToRegexp(wildcard) + "$"
-		for _, thisFilepath := range allFiles {
-			match, _ := regexp.MatchString(matchingRule, thisFilepath)
-			if match {
-				validFiles = append(validFiles, thisFilepath)
+			validFiles := []string{}
+			matchingRule := wildCardToRegexp(wildcard)
+			for _, thisFileInfo := range fileInfos {
+				thisFileFullpath := filepath.ToSlash(filepath.Join(filepath.Dir(wildcard), thisFileInfo.Name()))
+				match, _ := regexp.MatchString(matchingRule, thisFileFullpath)
+				if match {
+					validFiles = append(validFiles, thisFileFullpath)
+				}
+			}
+			return validFiles, nil
+		} else {
+			//Slow Glob
+			walkRoot := strings.Join(chunksWithoutStar, "/")
+			if !strings.HasPrefix(walkRoot, "/") {
+				walkRoot = "/" + walkRoot
 			}
-		}
 
-		return validFiles, nil
+			allFiles := []string{}
+			e.Walk(walkRoot, func(path string, info fs.FileInfo, err error) error {
+				allFiles = append(allFiles, path)
+				return nil
+			})
+
+			validFiles := []string{}
+			matchingRule := wildCardToRegexp(wildcard) + "$"
+			for _, thisFilepath := range allFiles {
+				match, _ := regexp.MatchString(matchingRule, thisFilepath)
+				if match {
+					validFiles = append(validFiles, thisFilepath)
+				}
+			}
 
-	}
+			return validFiles, nil
+		}
+	*/
 }
 func (e WebDAVFileSystem) GetFileSize(filename string) int64 {
 	filename = filterFilepath(filepath.ToSlash(filepath.Clean(filename)))
@@ -302,14 +304,67 @@ func (e WebDAVFileSystem) walk(thisPath string, walkFun filepath.WalkFunc) error
 	return nil
 }
 
-/*
-func (e WebDAVFileSystem) globscan(currentPath string, wildcardChunks []string, layer int) ([]string, error) {
-	if layer >= len(wildcardChunks) {
+func (e WebDAVFileSystem) globpath(currentPath string, pathSegments []string, depth int) ([]string, error) {
+	const pathSeparatorsLimit = 1000
+	if depth == pathSeparatorsLimit {
+		return nil, errors.New("bad pattern")
+	}
+
+	// Check pattern is well-formed.
+	if _, err := regexp.MatchString(wildCardToRegexp(strings.Join(pathSegments, "/")), ""); err != nil {
+		return nil, err
+	}
+
+	if len(pathSegments) == 0 {
+		//Reaching the bottom
 		return []string{}, nil
 	}
 
+	thisSegment := pathSegments[0]
+	if strings.Contains(thisSegment, "*") {
+		//Search for matching
+		matchPattern := currentPath + thisSegment
+		files, err := e.c.ReadDir(currentPath)
+		if err != nil {
+			return []string{}, nil
+		}
+
+		//Check which file in the currentPath matches the wildcard
+		matchedSubpaths := []string{}
+		for _, file := range files {
+			thisPath := currentPath + file.Name()
+			match, _ := regexp.MatchString(wildCardToRegexp(matchPattern), thisPath)
+			if match {
+				if file.IsDir() {
+					matchedSubpaths = append(matchedSubpaths, thisPath+"/")
+				} else {
+					matchedSubpaths = append(matchedSubpaths, thisPath)
+				}
+
+			}
+		}
+
+		if len(pathSegments[1:]) == 0 {
+			return matchedSubpaths, nil
+		}
+
+		//For each of the subpaths, do a globpath
+		matchingFilenames := []string{}
+		for _, subpath := range matchedSubpaths {
+			thisMatchedNames, _ := e.globpath(subpath, pathSegments[1:], depth+1)
+			matchingFilenames = append(matchingFilenames, thisMatchedNames...)
+		}
+		return matchingFilenames, nil
+	} else {
+		//Check folder exists
+		if e.FileExists(currentPath+thisSegment) && e.IsDir(currentPath+thisSegment) {
+			return e.globpath(currentPath+thisSegment+"/", pathSegments[1:], depth+1)
+		} else {
+			//Not matching
+			return []string{}, nil
+		}
+	}
 }
-*/
 
 func filterFilepath(rawpath string) string {
 	rawpath = strings.TrimSpace(rawpath)