github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/lib/objectserver/filesystem/scan/scan.go (about) 1 package scan 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 8 "github.com/Cloud-Foundations/Dominator/lib/concurrent" 9 "github.com/Cloud-Foundations/Dominator/lib/hash" 10 "github.com/Cloud-Foundations/Dominator/lib/objectcache" 11 ) 12 13 func scanTree(baseDir string, registerFunc func(hash.Hash, uint64)) error { 14 if fi, err := os.Stat(baseDir); err != nil { 15 return fmt.Errorf("Cannot stat: %s: %s\n", baseDir, err) 16 } else { 17 if !fi.IsDir() { 18 return fmt.Errorf("%s is not a directory\n", baseDir) 19 } 20 } 21 state := concurrent.NewState(0) 22 if err := scanDirectory(baseDir, "", state, registerFunc); err != nil { 23 return err 24 } 25 if err := state.Reap(); err != nil { 26 return err 27 } 28 return nil 29 } 30 31 func scanDirectory(baseDir string, subpath string, state *concurrent.State, 32 registerFunc func(hash.Hash, uint64)) error { 33 myPathName := filepath.Join(baseDir, subpath) 34 file, err := os.Open(myPathName) 35 if err != nil { 36 return err 37 } 38 names, err := file.Readdirnames(-1) 39 file.Close() 40 if err != nil { 41 return err 42 } 43 for _, name := range names { 44 if len(name) > 0 && name[0] == '.' { 45 continue // Skip hidden paths. 46 } 47 fullPathName := filepath.Join(myPathName, name) 48 fi, err := os.Lstat(fullPathName) 49 if err != nil { 50 continue 51 } 52 filename := filepath.Join(subpath, name) 53 if fi.IsDir() { 54 if state == nil { 55 err := scanDirectory(baseDir, filename, nil, registerFunc) 56 if err != nil { 57 return err 58 } 59 } else { 60 // GoRun() cannot be used recursively, so limit concurrency to 61 // the top level. It's also more efficient this way. 62 if err := state.GoRun(func() error { 63 return scanDirectory(baseDir, filename, nil, registerFunc) 64 }); err != nil { 65 return err 66 } 67 } 68 } else { 69 if fi.Size() < 1 { 70 return fmt.Errorf("zero-length file: %s", fullPathName) 71 } 72 hashVal, err := objectcache.FilenameToHash(filename) 73 if err != nil { 74 return err 75 } 76 registerFunc(hashVal, uint64(fi.Size())) 77 } 78 } 79 return nil 80 }