github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/pkg/chrootarchive/archive_unix.go (about) 1 //go:build !windows 2 // +build !windows 3 4 package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive" 5 6 import ( 7 "io" 8 "path/filepath" 9 "strings" 10 11 "github.com/docker/docker/pkg/archive" 12 "github.com/pkg/errors" 13 ) 14 15 func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.TarOptions, root string) error { 16 relDest, err := resolvePathInChroot(root, dest) 17 if err != nil { 18 return err 19 } 20 21 done := make(chan error) 22 err = goInChroot(root, func() { done <- archive.Unpack(decompressedArchive, relDest, options) }) 23 if err != nil { 24 return err 25 } 26 return <-done 27 } 28 29 func invokePack(srcPath string, options *archive.TarOptions, root string) (io.ReadCloser, error) { 30 relSrc, err := resolvePathInChroot(root, srcPath) 31 if err != nil { 32 return nil, err 33 } 34 35 // make sure we didn't trim a trailing slash with the call to `resolvePathInChroot` 36 if strings.HasSuffix(srcPath, "/") && !strings.HasSuffix(relSrc, "/") { 37 relSrc += "/" 38 } 39 40 tb, err := archive.NewTarballer(relSrc, options) 41 if err != nil { 42 return nil, errors.Wrap(err, "error processing tar file") 43 } 44 err = goInChroot(root, tb.Do) 45 if err != nil { 46 return nil, errors.Wrap(err, "could not chroot") 47 } 48 return tb.Reader(), nil 49 } 50 51 // resolvePathInChroot returns the equivalent to path inside a chroot rooted at root. 52 // The returned path always begins with '/'. 53 // 54 // - resolvePathInChroot("/a/b", "/a/b/c/d") -> "/c/d" 55 // - resolvePathInChroot("/a/b", "/a/b") -> "/" 56 // 57 // The implementation is buggy, and some bugs may be load-bearing. 58 // Here be dragons. 59 func resolvePathInChroot(root, path string) (string, error) { 60 if root == "" { 61 return "", errors.New("root path must not be empty") 62 } 63 rel, err := filepath.Rel(root, path) 64 if err != nil { 65 return "", err 66 } 67 if rel == "." { 68 rel = "/" 69 } 70 if rel[0] != '/' { 71 rel = "/" + rel 72 } 73 return rel, nil 74 }