github.com/cobalt77/jfrog-client-go@v0.14.5/utils/io/fileutils/listfiles.go (about) 1 package fileutils 2 3 import ( 4 "errors" 5 "os" 6 "path/filepath" 7 "sort" 8 ) 9 10 var SkipDir = errors.New("skip this directory") 11 12 type WalkFunc func(path string, info os.FileInfo, err error) error 13 type Stat func(path string) (info os.FileInfo, err error) 14 15 var stat = os.Stat 16 var lStat = os.Lstat 17 18 func walk(path string, info os.FileInfo, walkFn WalkFunc, visited map[string]bool, walkIntoDirSymlink bool) error { 19 realPath, err := filepath.EvalSymlinks(path) 20 if err != nil { 21 realPath = path 22 } 23 isRealPathDir, err := IsDirExists(realPath, false) 24 if err != nil { 25 return err 26 } 27 if isRealPathDir { 28 visited[realPath] = true 29 } 30 err = walkFn(path, info, nil) 31 if err != nil { 32 if info.IsDir() && err == SkipDir { 33 return nil 34 } 35 return err 36 } 37 38 if !info.IsDir() { 39 return nil 40 } 41 42 names, err := readDirNames(path) 43 if err != nil { 44 return walkFn(path, info, err) 45 } 46 47 for _, name := range names { 48 filename := filepath.Join(path, name) 49 realPath, err = filepath.EvalSymlinks(filename) 50 if err != nil { 51 realPath = filename 52 } 53 54 if walkIntoDirSymlink && visited[realPath] { 55 continue 56 } 57 var fileHandler Stat 58 if walkIntoDirSymlink { 59 fileHandler = stat 60 } else { 61 fileHandler = lStat 62 } 63 fileInfo, err := fileHandler(filename) 64 if err != nil { 65 if err := walkFn(filename, fileInfo, err); err != nil && err != SkipDir { 66 return err 67 } 68 } else { 69 err = walk(filename, fileInfo, walkFn, visited, walkIntoDirSymlink) 70 if err != nil { 71 if !fileInfo.IsDir() || err != SkipDir { 72 return err 73 } 74 } 75 } 76 } 77 return nil 78 } 79 80 // The same as filepath.Walk the only difference is that we can walk into symlink. 81 // Avoiding infinite loops by saving the real paths we already visited. 82 func Walk(root string, walkFn WalkFunc, walkIntoDirSymlink bool) error { 83 info, err := stat(root) 84 visited := make(map[string]bool) 85 if err != nil { 86 return walkFn(root, nil, err) 87 } 88 return walk(root, info, walkFn, visited, walkIntoDirSymlink) 89 } 90 91 // readDirNames reads the directory named by dirname and returns 92 // a sorted list of directory entries. 93 // The same as path/filepath readDirNames function 94 func readDirNames(dirname string) ([]string, error) { 95 f, err := os.Open(dirname) 96 if err != nil { 97 return nil, err 98 } 99 names, err := f.Readdirnames(-1) 100 f.Close() 101 if err != nil { 102 return nil, err 103 } 104 sort.Strings(names) 105 return names, nil 106 }