github.com/sams1990/dockerrepo@v17.12.1-ce-rc2+incompatible/builder/remotecontext/archive.go (about) 1 package remotecontext 2 3 import ( 4 "io" 5 "os" 6 "path/filepath" 7 8 "github.com/docker/docker/builder" 9 "github.com/docker/docker/pkg/archive" 10 "github.com/docker/docker/pkg/chrootarchive" 11 "github.com/docker/docker/pkg/containerfs" 12 "github.com/docker/docker/pkg/ioutils" 13 "github.com/docker/docker/pkg/tarsum" 14 "github.com/pkg/errors" 15 ) 16 17 type archiveContext struct { 18 root containerfs.ContainerFS 19 sums tarsum.FileInfoSums 20 } 21 22 func (c *archiveContext) Close() error { 23 return c.root.RemoveAll(c.root.Path()) 24 } 25 26 func convertPathError(err error, cleanpath string) error { 27 if err, ok := err.(*os.PathError); ok { 28 err.Path = cleanpath 29 return err 30 } 31 return err 32 } 33 34 type modifiableContext interface { 35 builder.Source 36 // Remove deletes the entry specified by `path`. 37 // It is usual for directory entries to delete all its subentries. 38 Remove(path string) error 39 } 40 41 // FromArchive returns a build source from a tar stream. 42 // 43 // It extracts the tar stream to a temporary folder that is deleted as soon as 44 // the Context is closed. 45 // As the extraction happens, a tarsum is calculated for every file, and the set of 46 // all those sums then becomes the source of truth for all operations on this Context. 47 // 48 // Closing tarStream has to be done by the caller. 49 func FromArchive(tarStream io.Reader) (builder.Source, error) { 50 root, err := ioutils.TempDir("", "docker-builder") 51 if err != nil { 52 return nil, err 53 } 54 55 // Assume local file system. Since it's coming from a tar file. 56 tsc := &archiveContext{root: containerfs.NewLocalContainerFS(root)} 57 58 // Make sure we clean-up upon error. In the happy case the caller 59 // is expected to manage the clean-up 60 defer func() { 61 if err != nil { 62 tsc.Close() 63 } 64 }() 65 66 decompressedStream, err := archive.DecompressStream(tarStream) 67 if err != nil { 68 return nil, err 69 } 70 71 sum, err := tarsum.NewTarSum(decompressedStream, true, tarsum.Version1) 72 if err != nil { 73 return nil, err 74 } 75 76 err = chrootarchive.Untar(sum, root, nil) 77 if err != nil { 78 return nil, err 79 } 80 81 tsc.sums = sum.GetSums() 82 return tsc, nil 83 } 84 85 func (c *archiveContext) Root() containerfs.ContainerFS { 86 return c.root 87 } 88 89 func (c *archiveContext) Remove(path string) error { 90 _, fullpath, err := normalize(path, c.root) 91 if err != nil { 92 return err 93 } 94 return c.root.RemoveAll(fullpath) 95 } 96 97 func (c *archiveContext) Hash(path string) (string, error) { 98 cleanpath, fullpath, err := normalize(path, c.root) 99 if err != nil { 100 return "", err 101 } 102 103 rel, err := c.root.Rel(c.root.Path(), fullpath) 104 if err != nil { 105 return "", convertPathError(err, cleanpath) 106 } 107 108 // Use the checksum of the followed path(not the possible symlink) because 109 // this is the file that is actually copied. 110 if tsInfo := c.sums.GetFile(filepath.ToSlash(rel)); tsInfo != nil { 111 return tsInfo.Sum(), nil 112 } 113 // We set sum to path by default for the case where GetFile returns nil. 114 // The usual case is if relative path is empty. 115 return path, nil // backwards compat TODO: see if really needed 116 } 117 118 func normalize(path string, root containerfs.ContainerFS) (cleanPath, fullPath string, err error) { 119 cleanPath = root.Clean(string(root.Separator()) + path)[1:] 120 fullPath, err = root.ResolveScopedPath(path, true) 121 if err != nil { 122 return "", "", errors.Wrapf(err, "forbidden path outside the build context: %s (%s)", path, cleanPath) 123 } 124 return 125 }