archive.go 34 KB

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