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