// +build !linux package archive import ( "fmt" "os" "path/filepath" "runtime" "strings" "github.com/docker/docker/pkg/system" ) func collectFileInfoForChanges(oldDir, newDir string) (*FileInfo, *FileInfo, error) { var ( oldRoot, newRoot *FileInfo err1, err2 error errs = make(chan error, 2) ) go func() { oldRoot, err1 = collectFileInfo(oldDir) errs <- err1 }() go func() { newRoot, err2 = collectFileInfo(newDir) errs <- err2 }() // block until both routines have returned for i := 0; i < 2; i++ { if err := <-errs; err != nil { return nil, nil, err } } return oldRoot, newRoot, nil } func collectFileInfo(sourceDir string) (*FileInfo, error) { root := newRootFileInfo() err := filepath.Walk(sourceDir, func(path string, f os.FileInfo, err error) error { if err != nil { return err } // Rebase path relPath, err := filepath.Rel(sourceDir, path) if err != nil { return err } // As this runs on the daemon side, file paths are OS specific. relPath = filepath.Join(string(os.PathSeparator), relPath) // See https://github.com/golang/go/issues/9168 - bug in filepath.Join. // Temporary workaround. If the returned path starts with two backslashes, // trim it down to a single backslash. Only relevant on Windows. if runtime.GOOS == "windows" { if strings.HasPrefix(relPath, `\\`) { relPath = relPath[1:] } } if relPath == string(os.PathSeparator) { return nil } parent := root.LookUp(filepath.Dir(relPath)) if parent == nil { return fmt.Errorf("collectFileInfo: Unexpectedly no parent for %s", relPath) } info := &FileInfo{ name: filepath.Base(relPath), children: make(map[string]*FileInfo), parent: parent, } s, err := system.Lstat(path) if err != nil { return err } info.stat = s info.capability, _ = system.Lgetxattr(path, "security.capability") parent.children[info.name] = info return nil }) if err != nil { return nil, err } return root, nil }