archive.go 35 KB

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