archive.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053
  1. package archive
  2. import (
  3. "archive/tar"
  4. "bufio"
  5. "bytes"
  6. "compress/bzip2"
  7. "compress/gzip"
  8. "errors"
  9. "fmt"
  10. "io"
  11. "io/ioutil"
  12. "os"
  13. "os/exec"
  14. "path/filepath"
  15. "runtime"
  16. "strings"
  17. "syscall"
  18. "github.com/Sirupsen/logrus"
  19. "github.com/docker/docker/pkg/fileutils"
  20. "github.com/docker/docker/pkg/idtools"
  21. "github.com/docker/docker/pkg/ioutils"
  22. "github.com/docker/docker/pkg/pools"
  23. "github.com/docker/docker/pkg/promise"
  24. "github.com/docker/docker/pkg/system"
  25. )
  26. type (
  27. // Archive is a type of io.ReadCloser which has two interfaces Read and Closer.
  28. Archive io.ReadCloser
  29. // Reader is a type of io.Reader.
  30. Reader io.Reader
  31. // Compression is the state represents if compressed or not.
  32. Compression int
  33. // TarChownOptions wraps the chown options UID and GID.
  34. TarChownOptions struct {
  35. UID, GID int
  36. }
  37. // TarOptions wraps the tar options.
  38. TarOptions struct {
  39. IncludeFiles []string
  40. ExcludePatterns []string
  41. Compression Compression
  42. NoLchown bool
  43. UIDMaps []idtools.IDMap
  44. GIDMaps []idtools.IDMap
  45. ChownOpts *TarChownOptions
  46. IncludeSourceDir bool
  47. // When unpacking, specifies whether overwriting a directory with a
  48. // non-directory is allowed and vice versa.
  49. NoOverwriteDirNonDir bool
  50. // For each include when creating an archive, the included name will be
  51. // replaced with the matching name from this map.
  52. RebaseNames map[string]string
  53. }
  54. // Archiver allows the reuse of most utility functions of this package
  55. // with a pluggable Untar function. Also, to facilitate the passing of
  56. // specific id mappings for untar, an archiver can be created with maps
  57. // which will then be passed to Untar operations
  58. Archiver struct {
  59. Untar func(io.Reader, string, *TarOptions) error
  60. UIDMaps []idtools.IDMap
  61. GIDMaps []idtools.IDMap
  62. }
  63. // breakoutError is used to differentiate errors related to breaking out
  64. // When testing archive breakout in the unit tests, this error is expected
  65. // in order for the test to pass.
  66. breakoutError error
  67. )
  68. var (
  69. // ErrNotImplemented is the error message of function not implemented.
  70. ErrNotImplemented = errors.New("Function not implemented")
  71. defaultArchiver = &Archiver{Untar: Untar, UIDMaps: nil, GIDMaps: nil}
  72. )
  73. const (
  74. // HeaderSize is the size in bytes of a tar header
  75. HeaderSize = 512
  76. )
  77. const (
  78. // Uncompressed represents the uncompressed.
  79. Uncompressed Compression = iota
  80. // Bzip2 is bzip2 compression algorithm.
  81. Bzip2
  82. // Gzip is gzip compression algorithm.
  83. Gzip
  84. // Xz is xz compression algorithm.
  85. Xz
  86. )
  87. // IsArchive checks for the magic bytes of a tar or any supported compression
  88. // algorithm.
  89. func IsArchive(header []byte) bool {
  90. compression := DetectCompression(header)
  91. if compression != Uncompressed {
  92. return true
  93. }
  94. r := tar.NewReader(bytes.NewBuffer(header))
  95. _, err := r.Next()
  96. return err == nil
  97. }
  98. // IsArchivePath checks if the (possibly compressed) file at the given path
  99. // starts with a tar file header.
  100. func IsArchivePath(path string) bool {
  101. file, err := os.Open(path)
  102. if err != nil {
  103. return false
  104. }
  105. defer file.Close()
  106. rdr, err := DecompressStream(file)
  107. if err != nil {
  108. return false
  109. }
  110. r := tar.NewReader(rdr)
  111. _, err = r.Next()
  112. return err == nil
  113. }
  114. // DetectCompression detects the compression algorithm of the source.
  115. func DetectCompression(source []byte) Compression {
  116. for compression, m := range map[Compression][]byte{
  117. Bzip2: {0x42, 0x5A, 0x68},
  118. Gzip: {0x1F, 0x8B, 0x08},
  119. Xz: {0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00},
  120. } {
  121. if len(source) < len(m) {
  122. logrus.Debugf("Len too short")
  123. continue
  124. }
  125. if bytes.Compare(m, source[:len(m)]) == 0 {
  126. return compression
  127. }
  128. }
  129. return Uncompressed
  130. }
  131. func xzDecompress(archive io.Reader) (io.ReadCloser, <-chan struct{}, error) {
  132. args := []string{"xz", "-d", "-c", "-q"}
  133. return cmdStream(exec.Command(args[0], args[1:]...), archive)
  134. }
  135. // DecompressStream decompress the archive and returns a ReaderCloser with the decompressed archive.
  136. func DecompressStream(archive io.Reader) (io.ReadCloser, error) {
  137. p := pools.BufioReader32KPool
  138. buf := p.Get(archive)
  139. bs, err := buf.Peek(10)
  140. if err != nil && err != io.EOF {
  141. // Note: we'll ignore any io.EOF error because there are some odd
  142. // cases where the layer.tar file will be empty (zero bytes) and
  143. // that results in an io.EOF from the Peek() call. So, in those
  144. // cases we'll just treat it as a non-compressed stream and
  145. // that means just create an empty layer.
  146. // See Issue 18170
  147. return nil, err
  148. }
  149. compression := DetectCompression(bs)
  150. switch compression {
  151. case Uncompressed:
  152. readBufWrapper := p.NewReadCloserWrapper(buf, buf)
  153. return readBufWrapper, nil
  154. case Gzip:
  155. gzReader, err := gzip.NewReader(buf)
  156. if err != nil {
  157. return nil, err
  158. }
  159. readBufWrapper := p.NewReadCloserWrapper(buf, gzReader)
  160. return readBufWrapper, nil
  161. case Bzip2:
  162. bz2Reader := bzip2.NewReader(buf)
  163. readBufWrapper := p.NewReadCloserWrapper(buf, bz2Reader)
  164. return readBufWrapper, nil
  165. case Xz:
  166. xzReader, chdone, err := xzDecompress(buf)
  167. if err != nil {
  168. return nil, err
  169. }
  170. readBufWrapper := p.NewReadCloserWrapper(buf, xzReader)
  171. return ioutils.NewReadCloserWrapper(readBufWrapper, func() error {
  172. <-chdone
  173. return readBufWrapper.Close()
  174. }), nil
  175. default:
  176. return nil, fmt.Errorf("Unsupported compression format %s", (&compression).Extension())
  177. }
  178. }
  179. // CompressStream compresses the dest with specified compression algorithm.
  180. func CompressStream(dest io.WriteCloser, compression Compression) (io.WriteCloser, error) {
  181. p := pools.BufioWriter32KPool
  182. buf := p.Get(dest)
  183. switch compression {
  184. case Uncompressed:
  185. writeBufWrapper := p.NewWriteCloserWrapper(buf, buf)
  186. return writeBufWrapper, nil
  187. case Gzip:
  188. gzWriter := gzip.NewWriter(dest)
  189. writeBufWrapper := p.NewWriteCloserWrapper(buf, gzWriter)
  190. return writeBufWrapper, nil
  191. case Bzip2, Xz:
  192. // archive/bzip2 does not support writing, and there is no xz support at all
  193. // However, this is not a problem as docker only currently generates gzipped tars
  194. return nil, fmt.Errorf("Unsupported compression format %s", (&compression).Extension())
  195. default:
  196. return nil, fmt.Errorf("Unsupported compression format %s", (&compression).Extension())
  197. }
  198. }
  199. // Extension returns the extension of a file that uses the specified compression algorithm.
  200. func (compression *Compression) Extension() string {
  201. switch *compression {
  202. case Uncompressed:
  203. return "tar"
  204. case Bzip2:
  205. return "tar.bz2"
  206. case Gzip:
  207. return "tar.gz"
  208. case Xz:
  209. return "tar.xz"
  210. }
  211. return ""
  212. }
  213. type tarAppender struct {
  214. TarWriter *tar.Writer
  215. Buffer *bufio.Writer
  216. // for hardlink mapping
  217. SeenFiles map[uint64]string
  218. UIDMaps []idtools.IDMap
  219. GIDMaps []idtools.IDMap
  220. }
  221. // canonicalTarName provides a platform-independent and consistent posix-style
  222. //path for files and directories to be archived regardless of the platform.
  223. func canonicalTarName(name string, isDir bool) (string, error) {
  224. name, err := CanonicalTarNameForPath(name)
  225. if err != nil {
  226. return "", err
  227. }
  228. // suffix with '/' for directories
  229. if isDir && !strings.HasSuffix(name, "/") {
  230. name += "/"
  231. }
  232. return name, nil
  233. }
  234. func (ta *tarAppender) addTarFile(path, name string) error {
  235. fi, err := os.Lstat(path)
  236. if err != nil {
  237. return err
  238. }
  239. link := ""
  240. if fi.Mode()&os.ModeSymlink != 0 {
  241. if link, err = os.Readlink(path); err != nil {
  242. return err
  243. }
  244. }
  245. hdr, err := tar.FileInfoHeader(fi, link)
  246. if err != nil {
  247. return err
  248. }
  249. hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
  250. name, err = canonicalTarName(name, fi.IsDir())
  251. if err != nil {
  252. return fmt.Errorf("tar: cannot canonicalize path: %v", err)
  253. }
  254. hdr.Name = name
  255. inode, err := setHeaderForSpecialDevice(hdr, ta, name, fi.Sys())
  256. if err != nil {
  257. return err
  258. }
  259. // if it's not a directory and has more than 1 link,
  260. // it's hardlinked, so set the type flag accordingly
  261. if !fi.IsDir() && hasHardlinks(fi) {
  262. // a link should have a name that it links too
  263. // and that linked name should be first in the tar archive
  264. if oldpath, ok := ta.SeenFiles[inode]; ok {
  265. hdr.Typeflag = tar.TypeLink
  266. hdr.Linkname = oldpath
  267. hdr.Size = 0 // This Must be here for the writer math to add up!
  268. } else {
  269. ta.SeenFiles[inode] = name
  270. }
  271. }
  272. capability, _ := system.Lgetxattr(path, "security.capability")
  273. if capability != nil {
  274. hdr.Xattrs = make(map[string]string)
  275. hdr.Xattrs["security.capability"] = string(capability)
  276. }
  277. //handle re-mapping container ID mappings back to host ID mappings before
  278. //writing tar headers/files. We skip whiteout files because they were written
  279. //by the kernel and already have proper ownership relative to the host
  280. if !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && (ta.UIDMaps != nil || ta.GIDMaps != nil) {
  281. uid, gid, err := getFileUIDGID(fi.Sys())
  282. if err != nil {
  283. return err
  284. }
  285. xUID, err := idtools.ToContainer(uid, ta.UIDMaps)
  286. if err != nil {
  287. return err
  288. }
  289. xGID, err := idtools.ToContainer(gid, ta.GIDMaps)
  290. if err != nil {
  291. return err
  292. }
  293. hdr.Uid = xUID
  294. hdr.Gid = xGID
  295. }
  296. if err := ta.TarWriter.WriteHeader(hdr); err != nil {
  297. return err
  298. }
  299. if hdr.Typeflag == tar.TypeReg {
  300. file, err := os.Open(path)
  301. if err != nil {
  302. return err
  303. }
  304. ta.Buffer.Reset(ta.TarWriter)
  305. defer ta.Buffer.Reset(nil)
  306. _, err = io.Copy(ta.Buffer, file)
  307. file.Close()
  308. if err != nil {
  309. return err
  310. }
  311. err = ta.Buffer.Flush()
  312. if err != nil {
  313. return err
  314. }
  315. }
  316. return nil
  317. }
  318. func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *TarChownOptions) error {
  319. // hdr.Mode is in linux format, which we can use for sycalls,
  320. // but for os.Foo() calls we need the mode converted to os.FileMode,
  321. // so use hdrInfo.Mode() (they differ for e.g. setuid bits)
  322. hdrInfo := hdr.FileInfo()
  323. switch hdr.Typeflag {
  324. case tar.TypeDir:
  325. // Create directory unless it exists as a directory already.
  326. // In that case we just want to merge the two
  327. if fi, err := os.Lstat(path); !(err == nil && fi.IsDir()) {
  328. if err := os.Mkdir(path, hdrInfo.Mode()); err != nil {
  329. return err
  330. }
  331. }
  332. case tar.TypeReg, tar.TypeRegA:
  333. // Source is regular file
  334. file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, hdrInfo.Mode())
  335. if err != nil {
  336. return err
  337. }
  338. if _, err := io.Copy(file, reader); err != nil {
  339. file.Close()
  340. return err
  341. }
  342. file.Close()
  343. case tar.TypeBlock, tar.TypeChar, tar.TypeFifo:
  344. // Handle this is an OS-specific way
  345. if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
  346. return err
  347. }
  348. case tar.TypeLink:
  349. targetPath := filepath.Join(extractDir, hdr.Linkname)
  350. // check for hardlink breakout
  351. if !strings.HasPrefix(targetPath, extractDir) {
  352. return breakoutError(fmt.Errorf("invalid hardlink %q -> %q", targetPath, hdr.Linkname))
  353. }
  354. if err := os.Link(targetPath, path); err != nil {
  355. return err
  356. }
  357. case tar.TypeSymlink:
  358. // path -> hdr.Linkname = targetPath
  359. // e.g. /extractDir/path/to/symlink -> ../2/file = /extractDir/path/2/file
  360. targetPath := filepath.Join(filepath.Dir(path), hdr.Linkname)
  361. // the reason we don't need to check symlinks in the path (with FollowSymlinkInScope) is because
  362. // that symlink would first have to be created, which would be caught earlier, at this very check:
  363. if !strings.HasPrefix(targetPath, extractDir) {
  364. return breakoutError(fmt.Errorf("invalid symlink %q -> %q", path, hdr.Linkname))
  365. }
  366. if err := os.Symlink(hdr.Linkname, path); err != nil {
  367. return err
  368. }
  369. case tar.TypeXGlobalHeader:
  370. logrus.Debugf("PAX Global Extended Headers found and ignored")
  371. return nil
  372. default:
  373. return fmt.Errorf("Unhandled tar header type %d\n", hdr.Typeflag)
  374. }
  375. // Lchown is not supported on Windows.
  376. if Lchown && runtime.GOOS != "windows" {
  377. if chownOpts == nil {
  378. chownOpts = &TarChownOptions{UID: hdr.Uid, GID: hdr.Gid}
  379. }
  380. if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil {
  381. return err
  382. }
  383. }
  384. for key, value := range hdr.Xattrs {
  385. if err := system.Lsetxattr(path, key, []byte(value), 0); err != nil {
  386. return err
  387. }
  388. }
  389. // There is no LChmod, so ignore mode for symlink. Also, this
  390. // must happen after chown, as that can modify the file mode
  391. if err := handleLChmod(hdr, path, hdrInfo); err != nil {
  392. return err
  393. }
  394. aTime := hdr.AccessTime
  395. if aTime.Before(hdr.ModTime) {
  396. // Last access time should never be before last modified time.
  397. aTime = hdr.ModTime
  398. }
  399. // system.Chtimes doesn't support a NOFOLLOW flag atm
  400. if hdr.Typeflag == tar.TypeLink {
  401. if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
  402. if err := system.Chtimes(path, aTime, hdr.ModTime); err != nil {
  403. return err
  404. }
  405. }
  406. } else if hdr.Typeflag != tar.TypeSymlink {
  407. if err := system.Chtimes(path, aTime, hdr.ModTime); err != nil {
  408. return err
  409. }
  410. } else {
  411. ts := []syscall.Timespec{timeToTimespec(aTime), timeToTimespec(hdr.ModTime)}
  412. if err := system.LUtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform {
  413. return err
  414. }
  415. }
  416. return nil
  417. }
  418. // Tar creates an archive from the directory at `path`, and returns it as a
  419. // stream of bytes.
  420. func Tar(path string, compression Compression) (io.ReadCloser, error) {
  421. return TarWithOptions(path, &TarOptions{Compression: compression})
  422. }
  423. // TarWithOptions creates an archive from the directory at `path`, only including files whose relative
  424. // paths are included in `options.IncludeFiles` (if non-nil) or not in `options.ExcludePatterns`.
  425. func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) {
  426. // Fix the source path to work with long path names. This is a no-op
  427. // on platforms other than Windows.
  428. srcPath = fixVolumePathPrefix(srcPath)
  429. patterns, patDirs, exceptions, err := fileutils.CleanPatterns(options.ExcludePatterns)
  430. if err != nil {
  431. return nil, err
  432. }
  433. pipeReader, pipeWriter := io.Pipe()
  434. compressWriter, err := CompressStream(pipeWriter, options.Compression)
  435. if err != nil {
  436. return nil, err
  437. }
  438. go func() {
  439. ta := &tarAppender{
  440. TarWriter: tar.NewWriter(compressWriter),
  441. Buffer: pools.BufioWriter32KPool.Get(nil),
  442. SeenFiles: make(map[uint64]string),
  443. UIDMaps: options.UIDMaps,
  444. GIDMaps: options.GIDMaps,
  445. }
  446. defer func() {
  447. // Make sure to check the error on Close.
  448. if err := ta.TarWriter.Close(); err != nil {
  449. logrus.Errorf("Can't close tar writer: %s", err)
  450. }
  451. if err := compressWriter.Close(); err != nil {
  452. logrus.Errorf("Can't close compress writer: %s", err)
  453. }
  454. if err := pipeWriter.Close(); err != nil {
  455. logrus.Errorf("Can't close pipe writer: %s", err)
  456. }
  457. }()
  458. // this buffer is needed for the duration of this piped stream
  459. defer pools.BufioWriter32KPool.Put(ta.Buffer)
  460. // In general we log errors here but ignore them because
  461. // during e.g. a diff operation the container can continue
  462. // mutating the filesystem and we can see transient errors
  463. // from this
  464. stat, err := os.Lstat(srcPath)
  465. if err != nil {
  466. return
  467. }
  468. if !stat.IsDir() {
  469. // We can't later join a non-dir with any includes because the
  470. // 'walk' will error if "file/." is stat-ed and "file" is not a
  471. // directory. So, we must split the source path and use the
  472. // basename as the include.
  473. if len(options.IncludeFiles) > 0 {
  474. logrus.Warn("Tar: Can't archive a file with includes")
  475. }
  476. dir, base := SplitPathDirEntry(srcPath)
  477. srcPath = dir
  478. options.IncludeFiles = []string{base}
  479. }
  480. if len(options.IncludeFiles) == 0 {
  481. options.IncludeFiles = []string{"."}
  482. }
  483. seen := make(map[string]bool)
  484. for _, include := range options.IncludeFiles {
  485. rebaseName := options.RebaseNames[include]
  486. walkRoot := getWalkRoot(srcPath, include)
  487. filepath.Walk(walkRoot, func(filePath string, f os.FileInfo, err error) error {
  488. if err != nil {
  489. logrus.Errorf("Tar: Can't stat file %s to tar: %s", srcPath, err)
  490. return nil
  491. }
  492. relFilePath, err := filepath.Rel(srcPath, filePath)
  493. if err != nil || (!options.IncludeSourceDir && relFilePath == "." && f.IsDir()) {
  494. // Error getting relative path OR we are looking
  495. // at the source directory path. Skip in both situations.
  496. return nil
  497. }
  498. if options.IncludeSourceDir && include == "." && relFilePath != "." {
  499. relFilePath = strings.Join([]string{".", relFilePath}, string(filepath.Separator))
  500. }
  501. skip := false
  502. // If "include" is an exact match for the current file
  503. // then even if there's an "excludePatterns" pattern that
  504. // matches it, don't skip it. IOW, assume an explicit 'include'
  505. // is asking for that file no matter what - which is true
  506. // for some files, like .dockerignore and Dockerfile (sometimes)
  507. if include != relFilePath {
  508. skip, err = fileutils.OptimizedMatches(relFilePath, patterns, patDirs)
  509. if err != nil {
  510. logrus.Errorf("Error matching %s: %v", relFilePath, err)
  511. return err
  512. }
  513. }
  514. if skip {
  515. if !exceptions && f.IsDir() {
  516. return filepath.SkipDir
  517. }
  518. return nil
  519. }
  520. if seen[relFilePath] {
  521. return nil
  522. }
  523. seen[relFilePath] = true
  524. // Rename the base resource.
  525. if rebaseName != "" {
  526. var replacement string
  527. if rebaseName != string(filepath.Separator) {
  528. // Special case the root directory to replace with an
  529. // empty string instead so that we don't end up with
  530. // double slashes in the paths.
  531. replacement = rebaseName
  532. }
  533. relFilePath = strings.Replace(relFilePath, include, replacement, 1)
  534. }
  535. if err := ta.addTarFile(filePath, relFilePath); err != nil {
  536. logrus.Errorf("Can't add file %s to tar: %s", filePath, err)
  537. // if pipe is broken, stop writting tar stream to it
  538. if err == io.ErrClosedPipe {
  539. return err
  540. }
  541. }
  542. return nil
  543. })
  544. }
  545. }()
  546. return pipeReader, nil
  547. }
  548. // Unpack unpacks the decompressedArchive to dest with options.
  549. func Unpack(decompressedArchive io.Reader, dest string, options *TarOptions) error {
  550. tr := tar.NewReader(decompressedArchive)
  551. trBuf := pools.BufioReader32KPool.Get(nil)
  552. defer pools.BufioReader32KPool.Put(trBuf)
  553. var dirs []*tar.Header
  554. remappedRootUID, remappedRootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps)
  555. if err != nil {
  556. return err
  557. }
  558. // Iterate through the files in the archive.
  559. loop:
  560. for {
  561. hdr, err := tr.Next()
  562. if err == io.EOF {
  563. // end of tar archive
  564. break
  565. }
  566. if err != nil {
  567. return err
  568. }
  569. // Normalize name, for safety and for a simple is-root check
  570. // This keeps "../" as-is, but normalizes "/../" to "/". Or Windows:
  571. // This keeps "..\" as-is, but normalizes "\..\" to "\".
  572. hdr.Name = filepath.Clean(hdr.Name)
  573. for _, exclude := range options.ExcludePatterns {
  574. if strings.HasPrefix(hdr.Name, exclude) {
  575. continue loop
  576. }
  577. }
  578. // After calling filepath.Clean(hdr.Name) above, hdr.Name will now be in
  579. // the filepath format for the OS on which the daemon is running. Hence
  580. // the check for a slash-suffix MUST be done in an OS-agnostic way.
  581. if !strings.HasSuffix(hdr.Name, string(os.PathSeparator)) {
  582. // Not the root directory, ensure that the parent directory exists
  583. parent := filepath.Dir(hdr.Name)
  584. parentPath := filepath.Join(dest, parent)
  585. if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
  586. err = idtools.MkdirAllNewAs(parentPath, 0777, remappedRootUID, remappedRootGID)
  587. if err != nil {
  588. return err
  589. }
  590. }
  591. }
  592. path := filepath.Join(dest, hdr.Name)
  593. rel, err := filepath.Rel(dest, path)
  594. if err != nil {
  595. return err
  596. }
  597. if strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
  598. return breakoutError(fmt.Errorf("%q is outside of %q", hdr.Name, dest))
  599. }
  600. // If path exits we almost always just want to remove and replace it
  601. // The only exception is when it is a directory *and* the file from
  602. // the layer is also a directory. Then we want to merge them (i.e.
  603. // just apply the metadata from the layer).
  604. if fi, err := os.Lstat(path); err == nil {
  605. if options.NoOverwriteDirNonDir && fi.IsDir() && hdr.Typeflag != tar.TypeDir {
  606. // If NoOverwriteDirNonDir is true then we cannot replace
  607. // an existing directory with a non-directory from the archive.
  608. return fmt.Errorf("cannot overwrite directory %q with non-directory %q", path, dest)
  609. }
  610. if options.NoOverwriteDirNonDir && !fi.IsDir() && hdr.Typeflag == tar.TypeDir {
  611. // If NoOverwriteDirNonDir is true then we cannot replace
  612. // an existing non-directory with a directory from the archive.
  613. return fmt.Errorf("cannot overwrite non-directory %q with directory %q", path, dest)
  614. }
  615. if fi.IsDir() && hdr.Name == "." {
  616. continue
  617. }
  618. if !(fi.IsDir() && hdr.Typeflag == tar.TypeDir) {
  619. if err := os.RemoveAll(path); err != nil {
  620. return err
  621. }
  622. }
  623. }
  624. trBuf.Reset(tr)
  625. // if the options contain a uid & gid maps, convert header uid/gid
  626. // entries using the maps such that lchown sets the proper mapped
  627. // uid/gid after writing the file. We only perform this mapping if
  628. // the file isn't already owned by the remapped root UID or GID, as
  629. // that specific uid/gid has no mapping from container -> host, and
  630. // those files already have the proper ownership for inside the
  631. // container.
  632. if hdr.Uid != remappedRootUID {
  633. xUID, err := idtools.ToHost(hdr.Uid, options.UIDMaps)
  634. if err != nil {
  635. return err
  636. }
  637. hdr.Uid = xUID
  638. }
  639. if hdr.Gid != remappedRootGID {
  640. xGID, err := idtools.ToHost(hdr.Gid, options.GIDMaps)
  641. if err != nil {
  642. return err
  643. }
  644. hdr.Gid = xGID
  645. }
  646. if err := createTarFile(path, dest, hdr, trBuf, !options.NoLchown, options.ChownOpts); err != nil {
  647. return err
  648. }
  649. // Directory mtimes must be handled at the end to avoid further
  650. // file creation in them to modify the directory mtime
  651. if hdr.Typeflag == tar.TypeDir {
  652. dirs = append(dirs, hdr)
  653. }
  654. }
  655. for _, hdr := range dirs {
  656. path := filepath.Join(dest, hdr.Name)
  657. if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
  658. return err
  659. }
  660. }
  661. return nil
  662. }
  663. // Untar reads a stream of bytes from `archive`, parses it as a tar archive,
  664. // and unpacks it into the directory at `dest`.
  665. // The archive may be compressed with one of the following algorithms:
  666. // identity (uncompressed), gzip, bzip2, xz.
  667. // FIXME: specify behavior when target path exists vs. doesn't exist.
  668. func Untar(tarArchive io.Reader, dest string, options *TarOptions) error {
  669. return untarHandler(tarArchive, dest, options, true)
  670. }
  671. // UntarUncompressed reads a stream of bytes from `archive`, parses it as a tar archive,
  672. // and unpacks it into the directory at `dest`.
  673. // The archive must be an uncompressed stream.
  674. func UntarUncompressed(tarArchive io.Reader, dest string, options *TarOptions) error {
  675. return untarHandler(tarArchive, dest, options, false)
  676. }
  677. // Handler for teasing out the automatic decompression
  678. func untarHandler(tarArchive io.Reader, dest string, options *TarOptions, decompress bool) error {
  679. if tarArchive == nil {
  680. return fmt.Errorf("Empty archive")
  681. }
  682. dest = filepath.Clean(dest)
  683. if options == nil {
  684. options = &TarOptions{}
  685. }
  686. if options.ExcludePatterns == nil {
  687. options.ExcludePatterns = []string{}
  688. }
  689. r := tarArchive
  690. if decompress {
  691. decompressedArchive, err := DecompressStream(tarArchive)
  692. if err != nil {
  693. return err
  694. }
  695. defer decompressedArchive.Close()
  696. r = decompressedArchive
  697. }
  698. return Unpack(r, dest, options)
  699. }
  700. // TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
  701. // If either Tar or Untar fails, TarUntar aborts and returns the error.
  702. func (archiver *Archiver) TarUntar(src, dst string) error {
  703. logrus.Debugf("TarUntar(%s %s)", src, dst)
  704. archive, err := TarWithOptions(src, &TarOptions{Compression: Uncompressed})
  705. if err != nil {
  706. return err
  707. }
  708. defer archive.Close()
  709. var options *TarOptions
  710. if archiver.UIDMaps != nil || archiver.GIDMaps != nil {
  711. options = &TarOptions{
  712. UIDMaps: archiver.UIDMaps,
  713. GIDMaps: archiver.GIDMaps,
  714. }
  715. }
  716. return archiver.Untar(archive, dst, options)
  717. }
  718. // TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
  719. // If either Tar or Untar fails, TarUntar aborts and returns the error.
  720. func TarUntar(src, dst string) error {
  721. return defaultArchiver.TarUntar(src, dst)
  722. }
  723. // UntarPath untar a file from path to a destination, src is the source tar file path.
  724. func (archiver *Archiver) UntarPath(src, dst string) error {
  725. archive, err := os.Open(src)
  726. if err != nil {
  727. return err
  728. }
  729. defer archive.Close()
  730. var options *TarOptions
  731. if archiver.UIDMaps != nil || archiver.GIDMaps != nil {
  732. options = &TarOptions{
  733. UIDMaps: archiver.UIDMaps,
  734. GIDMaps: archiver.GIDMaps,
  735. }
  736. }
  737. return archiver.Untar(archive, dst, options)
  738. }
  739. // UntarPath is a convenience function which looks for an archive
  740. // at filesystem path `src`, and unpacks it at `dst`.
  741. func UntarPath(src, dst string) error {
  742. return defaultArchiver.UntarPath(src, dst)
  743. }
  744. // CopyWithTar creates a tar archive of filesystem path `src`, and
  745. // unpacks it at filesystem path `dst`.
  746. // The archive is streamed directly with fixed buffering and no
  747. // intermediary disk IO.
  748. func (archiver *Archiver) CopyWithTar(src, dst string) error {
  749. srcSt, err := os.Stat(src)
  750. if err != nil {
  751. return err
  752. }
  753. if !srcSt.IsDir() {
  754. return archiver.CopyFileWithTar(src, dst)
  755. }
  756. // Create dst, copy src's content into it
  757. logrus.Debugf("Creating dest directory: %s", dst)
  758. if err := system.MkdirAll(dst, 0755); err != nil {
  759. return err
  760. }
  761. logrus.Debugf("Calling TarUntar(%s, %s)", src, dst)
  762. return archiver.TarUntar(src, dst)
  763. }
  764. // CopyWithTar creates a tar archive of filesystem path `src`, and
  765. // unpacks it at filesystem path `dst`.
  766. // The archive is streamed directly with fixed buffering and no
  767. // intermediary disk IO.
  768. func CopyWithTar(src, dst string) error {
  769. return defaultArchiver.CopyWithTar(src, dst)
  770. }
  771. // CopyFileWithTar emulates the behavior of the 'cp' command-line
  772. // for a single file. It copies a regular file from path `src` to
  773. // path `dst`, and preserves all its metadata.
  774. func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
  775. logrus.Debugf("CopyFileWithTar(%s, %s)", src, dst)
  776. srcSt, err := os.Stat(src)
  777. if err != nil {
  778. return err
  779. }
  780. if srcSt.IsDir() {
  781. return fmt.Errorf("Can't copy a directory")
  782. }
  783. // Clean up the trailing slash. This must be done in an operating
  784. // system specific manner.
  785. if dst[len(dst)-1] == os.PathSeparator {
  786. dst = filepath.Join(dst, filepath.Base(src))
  787. }
  788. // Create the holding directory if necessary
  789. if err := system.MkdirAll(filepath.Dir(dst), 0700); err != nil {
  790. return err
  791. }
  792. r, w := io.Pipe()
  793. errC := promise.Go(func() error {
  794. defer w.Close()
  795. srcF, err := os.Open(src)
  796. if err != nil {
  797. return err
  798. }
  799. defer srcF.Close()
  800. hdr, err := tar.FileInfoHeader(srcSt, "")
  801. if err != nil {
  802. return err
  803. }
  804. hdr.Name = filepath.Base(dst)
  805. hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
  806. remappedRootUID, remappedRootGID, err := idtools.GetRootUIDGID(archiver.UIDMaps, archiver.GIDMaps)
  807. if err != nil {
  808. return err
  809. }
  810. // only perform mapping if the file being copied isn't already owned by the
  811. // uid or gid of the remapped root in the container
  812. if remappedRootUID != hdr.Uid {
  813. xUID, err := idtools.ToHost(hdr.Uid, archiver.UIDMaps)
  814. if err != nil {
  815. return err
  816. }
  817. hdr.Uid = xUID
  818. }
  819. if remappedRootGID != hdr.Gid {
  820. xGID, err := idtools.ToHost(hdr.Gid, archiver.GIDMaps)
  821. if err != nil {
  822. return err
  823. }
  824. hdr.Gid = xGID
  825. }
  826. tw := tar.NewWriter(w)
  827. defer tw.Close()
  828. if err := tw.WriteHeader(hdr); err != nil {
  829. return err
  830. }
  831. if _, err := io.Copy(tw, srcF); err != nil {
  832. return err
  833. }
  834. return nil
  835. })
  836. defer func() {
  837. if er := <-errC; err != nil {
  838. err = er
  839. }
  840. }()
  841. err = archiver.Untar(r, filepath.Dir(dst), nil)
  842. if err != nil {
  843. r.CloseWithError(err)
  844. }
  845. return err
  846. }
  847. // CopyFileWithTar emulates the behavior of the 'cp' command-line
  848. // for a single file. It copies a regular file from path `src` to
  849. // path `dst`, and preserves all its metadata.
  850. //
  851. // Destination handling is in an operating specific manner depending
  852. // where the daemon is running. If `dst` ends with a trailing slash
  853. // the final destination path will be `dst/base(src)` (Linux) or
  854. // `dst\base(src)` (Windows).
  855. func CopyFileWithTar(src, dst string) (err error) {
  856. return defaultArchiver.CopyFileWithTar(src, dst)
  857. }
  858. // cmdStream executes a command, and returns its stdout as a stream.
  859. // If the command fails to run or doesn't complete successfully, an error
  860. // will be returned, including anything written on stderr.
  861. func cmdStream(cmd *exec.Cmd, input io.Reader) (io.ReadCloser, <-chan struct{}, error) {
  862. chdone := make(chan struct{})
  863. cmd.Stdin = input
  864. pipeR, pipeW := io.Pipe()
  865. cmd.Stdout = pipeW
  866. var errBuf bytes.Buffer
  867. cmd.Stderr = &errBuf
  868. // Run the command and return the pipe
  869. if err := cmd.Start(); err != nil {
  870. return nil, nil, err
  871. }
  872. // Copy stdout to the returned pipe
  873. go func() {
  874. if err := cmd.Wait(); err != nil {
  875. pipeW.CloseWithError(fmt.Errorf("%s: %s", err, errBuf.String()))
  876. } else {
  877. pipeW.Close()
  878. }
  879. close(chdone)
  880. }()
  881. return pipeR, chdone, nil
  882. }
  883. // NewTempArchive reads the content of src into a temporary file, and returns the contents
  884. // of that file as an archive. The archive can only be read once - as soon as reading completes,
  885. // the file will be deleted.
  886. func NewTempArchive(src Archive, dir string) (*TempArchive, error) {
  887. f, err := ioutil.TempFile(dir, "")
  888. if err != nil {
  889. return nil, err
  890. }
  891. if _, err := io.Copy(f, src); err != nil {
  892. return nil, err
  893. }
  894. if _, err := f.Seek(0, 0); err != nil {
  895. return nil, err
  896. }
  897. st, err := f.Stat()
  898. if err != nil {
  899. return nil, err
  900. }
  901. size := st.Size()
  902. return &TempArchive{File: f, Size: size}, nil
  903. }
  904. // TempArchive is a temporary archive. The archive can only be read once - as soon as reading completes,
  905. // the file will be deleted.
  906. type TempArchive struct {
  907. *os.File
  908. Size int64 // Pre-computed from Stat().Size() as a convenience
  909. read int64
  910. closed bool
  911. }
  912. // Close closes the underlying file if it's still open, or does a no-op
  913. // to allow callers to try to close the TempArchive multiple times safely.
  914. func (archive *TempArchive) Close() error {
  915. if archive.closed {
  916. return nil
  917. }
  918. archive.closed = true
  919. return archive.File.Close()
  920. }
  921. func (archive *TempArchive) Read(data []byte) (int, error) {
  922. n, err := archive.File.Read(data)
  923. archive.read += int64(n)
  924. if err != nil || archive.read == archive.Size {
  925. archive.Close()
  926. os.Remove(archive.File.Name())
  927. }
  928. return n, err
  929. }