github.com/cdoern/storage@v1.12.13/pkg/archive/changes_other.go (about)

     1  // +build !linux
     2  
     3  package archive
     4  
     5  import (
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  	"strings"
    11  
    12  	"github.com/containers/storage/pkg/idtools"
    13  	"github.com/containers/storage/pkg/system"
    14  )
    15  
    16  func collectFileInfoForChanges(oldDir, newDir string, oldIDMap, newIDMap *idtools.IDMappings) (*FileInfo, *FileInfo, error) {
    17  	var (
    18  		oldRoot, newRoot *FileInfo
    19  		err1, err2       error
    20  		errs             = make(chan error, 2)
    21  	)
    22  	go func() {
    23  		oldRoot, err1 = collectFileInfo(oldDir, oldIDMap)
    24  		errs <- err1
    25  	}()
    26  	go func() {
    27  		newRoot, err2 = collectFileInfo(newDir, newIDMap)
    28  		errs <- err2
    29  	}()
    30  
    31  	// block until both routines have returned
    32  	for i := 0; i < 2; i++ {
    33  		if err := <-errs; err != nil {
    34  			return nil, nil, err
    35  		}
    36  	}
    37  
    38  	return oldRoot, newRoot, nil
    39  }
    40  
    41  func collectFileInfo(sourceDir string, idMappings *idtools.IDMappings) (*FileInfo, error) {
    42  	root := newRootFileInfo(idMappings)
    43  
    44  	err := filepath.Walk(sourceDir, func(path string, f os.FileInfo, err error) error {
    45  		if err != nil {
    46  			return err
    47  		}
    48  
    49  		// Rebase path
    50  		relPath, err := filepath.Rel(sourceDir, path)
    51  		if err != nil {
    52  			return err
    53  		}
    54  
    55  		// As this runs on the daemon side, file paths are OS specific.
    56  		relPath = filepath.Join(string(os.PathSeparator), relPath)
    57  
    58  		// See https://github.com/golang/go/issues/9168 - bug in filepath.Join.
    59  		// Temporary workaround. If the returned path starts with two backslashes,
    60  		// trim it down to a single backslash. Only relevant on Windows.
    61  		if runtime.GOOS == "windows" {
    62  			if strings.HasPrefix(relPath, `\\`) {
    63  				relPath = relPath[1:]
    64  			}
    65  		}
    66  
    67  		if relPath == string(os.PathSeparator) {
    68  			return nil
    69  		}
    70  
    71  		parent := root.LookUp(filepath.Dir(relPath))
    72  		if parent == nil {
    73  			return fmt.Errorf("collectFileInfo: Unexpectedly no parent for %s", relPath)
    74  		}
    75  
    76  		info := &FileInfo{
    77  			name:       filepath.Base(relPath),
    78  			children:   make(map[string]*FileInfo),
    79  			parent:     parent,
    80  			idMappings: idMappings,
    81  		}
    82  
    83  		s, err := system.Lstat(path)
    84  		if err != nil {
    85  			return err
    86  		}
    87  		info.stat = s
    88  
    89  		info.capability, _ = system.Lgetxattr(path, "security.capability")
    90  
    91  		parent.children[info.name] = info
    92  
    93  		return nil
    94  	})
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	return root, nil
    99  }