github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/cmd/fs2objectcache/walk.go (about)

     1  package main
     2  
     3  import (
     4  	"os"
     5  	"path"
     6  	"sync"
     7  	"syscall"
     8  
     9  	"github.com/Cloud-Foundations/Dominator/lib/concurrent"
    10  )
    11  
    12  type stateType struct {
    13  	sync.Mutex
    14  	processedInodes     map[uint64]struct{}
    15  	directoriesToRemove []string
    16  	concurrencyState    *concurrent.State
    17  }
    18  
    19  func walk(rootDirName, dirName, objectsDir string) error {
    20  	var state stateType
    21  	state.processedInodes = make(map[uint64]struct{})
    22  	state.directoriesToRemove = make([]string, 0)
    23  	state.concurrencyState = concurrent.NewState(0)
    24  	if err := state.walk(rootDirName, dirName, objectsDir); err != nil {
    25  		return err
    26  	}
    27  	if err := state.concurrencyState.Reap(); err != nil {
    28  		return err
    29  	}
    30  	for _, dirname := range state.directoriesToRemove {
    31  		if err := os.Remove(dirname); err != nil {
    32  			return err
    33  		}
    34  	}
    35  	return nil
    36  }
    37  
    38  func (state *stateType) walk(rootDirName, dirName, objectsDir string) error {
    39  	file, err := os.Open(path.Join(rootDirName, dirName))
    40  	if err != nil {
    41  		return err
    42  	}
    43  	names, err := file.Readdirnames(-1)
    44  	file.Close()
    45  	if err != nil {
    46  		return err
    47  	}
    48  	for _, name := range names {
    49  		if dirName == "/" && name == ".subd" {
    50  			continue
    51  		}
    52  		filename := path.Join(dirName, name)
    53  		pathname := path.Join(rootDirName, filename)
    54  		var stat syscall.Stat_t
    55  		err := syscall.Lstat(pathname, &stat)
    56  		if err != nil {
    57  			return err
    58  		}
    59  		if stat.Mode&syscall.S_IFMT == syscall.S_IFDIR {
    60  			err = state.walk(rootDirName, filename, objectsDir)
    61  			if err == nil {
    62  				state.directoriesToRemove = append(state.directoriesToRemove,
    63  					pathname)
    64  			}
    65  		} else if stat.Mode&syscall.S_IFMT == syscall.S_IFREG {
    66  			err = state.concurrencyState.GoRun(func() error {
    67  				return state.handleFile(pathname, stat.Ino, objectsDir)
    68  			})
    69  		} else {
    70  			err = os.RemoveAll(pathname)
    71  		}
    72  		if err != nil {
    73  			return err
    74  		}
    75  	}
    76  	return nil
    77  }
    78  
    79  func (state *stateType) handleFile(pathname string, inum uint64,
    80  	objectsDir string) error {
    81  	state.Lock()
    82  	if _, ok := state.processedInodes[inum]; ok {
    83  		state.Unlock()
    84  		return os.Remove(pathname)
    85  	}
    86  	state.processedInodes[inum] = struct{}{}
    87  	state.Unlock()
    88  	return convertToObject(pathname, objectsDir)
    89  }