archive.go 36 KB

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