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  }