diff --git a/kernel/util/file.go b/kernel/util/file.go index 8f974f153..f6ef9b3ac 100644 --- a/kernel/util/file.go +++ b/kernel/util/file.go @@ -231,3 +231,55 @@ func CeilSize(size int64) int64 { func IsReservedFilename(baseName string) bool { return "assets" == baseName || "templates" == baseName || "widgets" == baseName || "emojis" == baseName || ".siyuan" == baseName || strings.HasPrefix(baseName, ".") } + +func WalkWithSymlinks(root string, fn filepath.WalkFunc) error { + // 感谢 https://github.com/edwardrf/symwalk/blob/main/symwalk.go + + rr, err := filepath.EvalSymlinks(root) // Find real base if there is any symlinks in the path + if err != nil { + return err + } + + visitedDirs := make(map[string]struct{}) + return filepath.Walk(rr, getWalkFn(visitedDirs, fn)) +} + +func getWalkFn(visitedDirs map[string]struct{}, fn filepath.WalkFunc) filepath.WalkFunc { + return func(path string, info os.FileInfo, err error) error { + if err != nil { + return fn(path, info, err) + } + + if info.IsDir() { + if _, ok := visitedDirs[path]; ok { + return filepath.SkipDir + } + visitedDirs[path] = struct{}{} + } + + if err := fn(path, info, err); err != nil { + return err + } + + if info.Mode()&os.ModeSymlink == 0 { + return nil + } + + // path is a symlink + rp, err := filepath.EvalSymlinks(path) + if err != nil { + return err + } + + ri, err := os.Stat(rp) + if err != nil { + return err + } + + if ri.IsDir() { + return filepath.Walk(rp, getWalkFn(visitedDirs, fn)) + } + + return nil + } +} diff --git a/kernel/util/runtime.go b/kernel/util/runtime.go index 66d8a8044..34e670936 100644 --- a/kernel/util/runtime.go +++ b/kernel/util/runtime.go @@ -262,31 +262,11 @@ func isICloudPath(absPath string) bool { // macOS 端对工作空间放置在 iCloud 路径下做检查 https://github.com/siyuan-note/siyuan/issues/7747 iCloudRoot := filepath.Join(HomeDir, "Library", "Mobile Documents") - err := filepath.Walk(iCloudRoot, func(path string, info os.FileInfo, err error) error { + err := WalkWithSymlinks(iCloudRoot, func(path string, info os.FileInfo, err error) error { if nil != err { return err } - if 0 != info.Mode()&os.ModeSymlink && 0 != info.Mode()&os.ModeDir { - resolved, symErr := filepath.EvalSymlinks(path) - if nil != symErr { - logging.LogErrorf("resolve symlink [%s] failed: %s", path, symErr) - return nil - } - filepath.Walk(resolved, func(path string, info os.FileInfo, err error) error { - if nil != err { - return err - } - - if absPath == strings.ToLower(path) { - logging.LogInfof("under symlink path: %s", path) - return fmt.Errorf("found") - } - - return nil - }) - } - logging.LogInfof("path: %s", path) return nil })