Browse code

Remove unused functions from archive.

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2017/05/25 00:53:41
Showing 12 changed files
... ...
@@ -425,7 +425,7 @@ func copyExistingContents(source, destination string) error {
425 425
 		}
426 426
 		if len(srcList) == 0 {
427 427
 			// If the source volume is empty, copies files from the root into the volume
428
-			if err := chrootarchive.CopyWithTar(source, destination); err != nil {
428
+			if err := chrootarchive.NewArchiver(nil).CopyWithTar(source, destination); err != nil {
429 429
 				return err
430 430
 			}
431 431
 		}
... ...
@@ -413,12 +413,7 @@ func (daemon *Daemon) CopyOnBuild(cID, destPath, srcRoot, srcPath string, decomp
413 413
 		destExists = false
414 414
 	}
415 415
 
416
-	archiver := &archive.Archiver{
417
-		Untar:   chrootarchive.Untar,
418
-		UIDMaps: daemon.idMappings.UIDs(),
419
-		GIDMaps: daemon.idMappings.GIDs(),
420
-	}
421
-
416
+	archiver := chrootarchive.NewArchiver(daemon.idMappings)
422 417
 	src, err := os.Stat(fullSrcPath)
423 418
 	if err != nil {
424 419
 		return err
... ...
@@ -20,9 +20,6 @@ func (daemon *Daemon) tarCopyOptions(container *container.Container, noOverwrite
20 20
 
21 21
 	return &archive.TarOptions{
22 22
 		NoOverwriteDirNonDir: noOverwriteDirNonDir,
23
-		ChownOpts: &archive.TarChownOptions{
24
-			UID: user.Uid,
25
-			GID: user.Gid,
26
-		},
23
+		ChownOpts:            idtools.IDPair{UID: user.Uid, GID: user.Gid},
27 24
 	}, nil
28 25
 }
... ...
@@ -15,7 +15,7 @@ import (
15 15
 
16 16
 var (
17 17
 	// CopyWithTar defines the copy method to use.
18
-	CopyWithTar = chrootarchive.CopyWithTar
18
+	CopyWithTar = chrootarchive.NewArchiver(nil).CopyWithTar
19 19
 )
20 20
 
21 21
 func init() {
... ...
@@ -152,7 +152,7 @@ func testDirectory(templateDir string) (dir string, err error) {
152 152
 		return
153 153
 	}
154 154
 	if templateDir != "" {
155
-		if err = archive.CopyWithTar(templateDir, dir); err != nil {
155
+		if err = archive.NewDefaultArchiver().CopyWithTar(templateDir, dir); err != nil {
156 156
 			return
157 157
 		}
158 158
 	}
... ...
@@ -20,7 +20,8 @@ import (
20 20
 
21 21
 func init() {
22 22
 	graphdriver.ApplyUncompressedLayer = archive.UnpackLayer
23
-	vfs.CopyWithTar = archive.CopyWithTar
23
+	defaultArchiver := archive.NewDefaultArchiver()
24
+	vfs.CopyWithTar = defaultArchiver.CopyWithTar
24 25
 }
25 26
 
26 27
 func newVFSGraphDriver(td string) (graphdriver.Driver, error) {
... ...
@@ -6,7 +6,6 @@ import (
6 6
 	"bytes"
7 7
 	"compress/bzip2"
8 8
 	"compress/gzip"
9
-	"errors"
10 9
 	"fmt"
11 10
 	"io"
12 11
 	"io/ioutil"
... ...
@@ -31,10 +30,6 @@ type (
31 31
 	Compression int
32 32
 	// WhiteoutFormat is the format of whiteouts unpacked
33 33
 	WhiteoutFormat int
34
-	// TarChownOptions wraps the chown options UID and GID.
35
-	TarChownOptions struct {
36
-		UID, GID int
37
-	}
38 34
 
39 35
 	// TarOptions wraps the tar options.
40 36
 	TarOptions struct {
... ...
@@ -44,7 +39,7 @@ type (
44 44
 		NoLchown         bool
45 45
 		UIDMaps          []idtools.IDMap
46 46
 		GIDMaps          []idtools.IDMap
47
-		ChownOpts        *TarChownOptions
47
+		ChownOpts        idtools.IDPair
48 48
 		IncludeSourceDir bool
49 49
 		// WhiteoutFormat is the expected on disk format for whiteout files.
50 50
 		// This format will be converted to the standard format on pack
... ...
@@ -58,33 +53,26 @@ type (
58 58
 		RebaseNames map[string]string
59 59
 		InUserNS    bool
60 60
 	}
61
-
62
-	// Archiver allows the reuse of most utility functions of this package
63
-	// with a pluggable Untar function. Also, to facilitate the passing of
64
-	// specific id mappings for untar, an archiver can be created with maps
65
-	// which will then be passed to Untar operations
66
-	Archiver struct {
67
-		Untar   func(io.Reader, string, *TarOptions) error
68
-		UIDMaps []idtools.IDMap
69
-		GIDMaps []idtools.IDMap
70
-	}
71
-
72
-	// breakoutError is used to differentiate errors related to breaking out
73
-	// When testing archive breakout in the unit tests, this error is expected
74
-	// in order for the test to pass.
75
-	breakoutError error
76 61
 )
77 62
 
78
-var (
79
-	// ErrNotImplemented is the error message of function not implemented.
80
-	ErrNotImplemented = errors.New("Function not implemented")
81
-	defaultArchiver   = &Archiver{Untar: Untar, UIDMaps: nil, GIDMaps: nil}
82
-)
63
+// Archiver allows the reuse of most utility functions of this package
64
+// with a pluggable Untar function. Also, to facilitate the passing of
65
+// specific id mappings for untar, an archiver can be created with maps
66
+// which will then be passed to Untar operations
67
+type Archiver struct {
68
+	Untar      func(io.Reader, string, *TarOptions) error
69
+	IDMappings *idtools.IDMappings
70
+}
83 71
 
84
-const (
85
-	// HeaderSize is the size in bytes of a tar header
86
-	HeaderSize = 512
87
-)
72
+// NewDefaultArchiver returns a new Archiver without any IDMappings
73
+func NewDefaultArchiver() *Archiver {
74
+	return &Archiver{Untar: Untar, IDMappings: &idtools.IDMappings{}}
75
+}
76
+
77
+// breakoutError is used to differentiate errors related to breaking out
78
+// When testing archive breakout in the unit tests, this error is expected
79
+// in order for the test to pass.
80
+type breakoutError error
88 81
 
89 82
 const (
90 83
 	// Uncompressed represents the uncompressed.
... ...
@@ -105,18 +93,6 @@ const (
105 105
 	OverlayWhiteoutFormat
106 106
 )
107 107
 
108
-// IsArchive checks for the magic bytes of a tar or any supported compression
109
-// algorithm.
110
-func IsArchive(header []byte) bool {
111
-	compression := DetectCompression(header)
112
-	if compression != Uncompressed {
113
-		return true
114
-	}
115
-	r := tar.NewReader(bytes.NewBuffer(header))
116
-	_, err := r.Next()
117
-	return err == nil
118
-}
119
-
120 108
 // IsArchivePath checks if the (possibly compressed) file at the given path
121 109
 // starts with a tar file header.
122 110
 func IsArchivePath(path string) bool {
... ...
@@ -496,7 +472,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
496 496
 	return nil
497 497
 }
498 498
 
499
-func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *TarChownOptions, inUserns bool) error {
499
+func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.IDPair, inUserns bool) error {
500 500
 	// hdr.Mode is in linux format, which we can use for sycalls,
501 501
 	// but for os.Foo() calls we need the mode converted to os.FileMode,
502 502
 	// so use hdrInfo.Mode() (they differ for e.g. setuid bits)
... ...
@@ -576,7 +552,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
576 576
 	// Lchown is not supported on Windows.
577 577
 	if Lchown && runtime.GOOS != "windows" {
578 578
 		if chownOpts == nil {
579
-			chownOpts = &TarChownOptions{UID: hdr.Uid, GID: hdr.Gid}
579
+			chownOpts = &idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid}
580 580
 		}
581 581
 		if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil {
582 582
 			return err
... ...
@@ -941,7 +917,7 @@ loop:
941 941
 			}
942 942
 		}
943 943
 
944
-		if err := createTarFile(path, dest, hdr, trBuf, !options.NoLchown, options.ChownOpts, options.InUserNS); err != nil {
944
+		if err := createTarFile(path, dest, hdr, trBuf, !options.NoLchown, &options.ChownOpts, options.InUserNS); err != nil {
945 945
 			return err
946 946
 		}
947 947
 
... ...
@@ -1013,23 +989,13 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
1013 1013
 		return err
1014 1014
 	}
1015 1015
 	defer archive.Close()
1016
-
1017
-	var options *TarOptions
1018
-	if archiver.UIDMaps != nil || archiver.GIDMaps != nil {
1019
-		options = &TarOptions{
1020
-			UIDMaps: archiver.UIDMaps,
1021
-			GIDMaps: archiver.GIDMaps,
1022
-		}
1016
+	options := &TarOptions{
1017
+		UIDMaps: archiver.IDMappings.UIDs(),
1018
+		GIDMaps: archiver.IDMappings.GIDs(),
1023 1019
 	}
1024 1020
 	return archiver.Untar(archive, dst, options)
1025 1021
 }
1026 1022
 
1027
-// TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
1028
-// If either Tar or Untar fails, TarUntar aborts and returns the error.
1029
-func TarUntar(src, dst string) error {
1030
-	return defaultArchiver.TarUntar(src, dst)
1031
-}
1032
-
1033 1023
 // UntarPath untar a file from path to a destination, src is the source tar file path.
1034 1024
 func (archiver *Archiver) UntarPath(src, dst string) error {
1035 1025
 	archive, err := os.Open(src)
... ...
@@ -1037,22 +1003,13 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
1037 1037
 		return err
1038 1038
 	}
1039 1039
 	defer archive.Close()
1040
-	var options *TarOptions
1041
-	if archiver.UIDMaps != nil || archiver.GIDMaps != nil {
1042
-		options = &TarOptions{
1043
-			UIDMaps: archiver.UIDMaps,
1044
-			GIDMaps: archiver.GIDMaps,
1045
-		}
1040
+	options := &TarOptions{
1041
+		UIDMaps: archiver.IDMappings.UIDs(),
1042
+		GIDMaps: archiver.IDMappings.GIDs(),
1046 1043
 	}
1047 1044
 	return archiver.Untar(archive, dst, options)
1048 1045
 }
1049 1046
 
1050
-// UntarPath is a convenience function which looks for an archive
1051
-// at filesystem path `src`, and unpacks it at `dst`.
1052
-func UntarPath(src, dst string) error {
1053
-	return defaultArchiver.UntarPath(src, dst)
1054
-}
1055
-
1056 1047
 // CopyWithTar creates a tar archive of filesystem path `src`, and
1057 1048
 // unpacks it at filesystem path `dst`.
1058 1049
 // The archive is streamed directly with fixed buffering and no
... ...
@@ -1069,27 +1026,19 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
1069 1069
 	// if this archiver is set up with ID mapping we need to create
1070 1070
 	// the new destination directory with the remapped root UID/GID pair
1071 1071
 	// as owner
1072
-	rootUID, rootGID, err := idtools.GetRootUIDGID(archiver.UIDMaps, archiver.GIDMaps)
1072
+	rootIDs, err := archiver.IDMappings.RootPair()
1073 1073
 	if err != nil {
1074 1074
 		return err
1075 1075
 	}
1076 1076
 	// Create dst, copy src's content into it
1077 1077
 	logrus.Debugf("Creating dest directory: %s", dst)
1078
-	if err := idtools.MkdirAllNewAs(dst, 0755, rootUID, rootGID); err != nil {
1078
+	if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
1079 1079
 		return err
1080 1080
 	}
1081 1081
 	logrus.Debugf("Calling TarUntar(%s, %s)", src, dst)
1082 1082
 	return archiver.TarUntar(src, dst)
1083 1083
 }
1084 1084
 
1085
-// CopyWithTar creates a tar archive of filesystem path `src`, and
1086
-// unpacks it at filesystem path `dst`.
1087
-// The archive is streamed directly with fixed buffering and no
1088
-// intermediary disk IO.
1089
-func CopyWithTar(src, dst string) error {
1090
-	return defaultArchiver.CopyWithTar(src, dst)
1091
-}
1092
-
1093 1085
 // CopyFileWithTar emulates the behavior of the 'cp' command-line
1094 1086
 // for a single file. It copies a regular file from path `src` to
1095 1087
 // path `dst`, and preserves all its metadata.
... ...
@@ -1131,26 +1080,24 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
1131 1131
 		hdr.Name = filepath.Base(dst)
1132 1132
 		hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
1133 1133
 
1134
-		remappedRootUID, remappedRootGID, err := idtools.GetRootUIDGID(archiver.UIDMaps, archiver.GIDMaps)
1134
+		remappedRootIDs, err := archiver.IDMappings.RootPair()
1135 1135
 		if err != nil {
1136 1136
 			return err
1137 1137
 		}
1138 1138
 
1139 1139
 		// only perform mapping if the file being copied isn't already owned by the
1140 1140
 		// uid or gid of the remapped root in the container
1141
-		if remappedRootUID != hdr.Uid {
1142
-			xUID, err := idtools.ToHost(hdr.Uid, archiver.UIDMaps)
1141
+		if remappedRootIDs.UID != hdr.Uid {
1142
+			hdr.Uid, err = archiver.IDMappings.UIDToHost(hdr.Uid)
1143 1143
 			if err != nil {
1144 1144
 				return err
1145 1145
 			}
1146
-			hdr.Uid = xUID
1147 1146
 		}
1148
-		if remappedRootGID != hdr.Gid {
1149
-			xGID, err := idtools.ToHost(hdr.Gid, archiver.GIDMaps)
1147
+		if remappedRootIDs.GID != hdr.Gid {
1148
+			hdr.Gid, err = archiver.IDMappings.GIDToHost(hdr.Gid)
1150 1149
 			if err != nil {
1151 1150
 				return err
1152 1151
 			}
1153
-			hdr.Gid = xGID
1154 1152
 		}
1155 1153
 
1156 1154
 		tw := tar.NewWriter(w)
... ...
@@ -1176,18 +1123,6 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
1176 1176
 	return err
1177 1177
 }
1178 1178
 
1179
-// CopyFileWithTar emulates the behavior of the 'cp' command-line
1180
-// for a single file. It copies a regular file from path `src` to
1181
-// path `dst`, and preserves all its metadata.
1182
-//
1183
-// Destination handling is in an operating specific manner depending
1184
-// where the daemon is running. If `dst` ends with a trailing slash
1185
-// the final destination path will be `dst/base(src)`  (Linux) or
1186
-// `dst\base(src)` (Windows).
1187
-func CopyFileWithTar(src, dst string) (err error) {
1188
-	return defaultArchiver.CopyFileWithTar(src, dst)
1189
-}
1190
-
1191 1179
 // cmdStream executes a command, and returns its stdout as a stream.
1192 1180
 // If the command fails to run or doesn't complete successfully, an error
1193 1181
 // will be returned, including anything written on stderr.
... ...
@@ -27,35 +27,22 @@ func init() {
27 27
 	}
28 28
 }
29 29
 
30
-func TestIsArchiveNilHeader(t *testing.T) {
31
-	out := IsArchive(nil)
32
-	if out {
33
-		t.Fatalf("isArchive should return false as nil is not a valid archive header")
34
-	}
30
+var defaultArchiver = NewDefaultArchiver()
31
+
32
+func defaultTarUntar(src, dst string) error {
33
+	return defaultArchiver.TarUntar(src, dst)
35 34
 }
36 35
 
37
-func TestIsArchiveInvalidHeader(t *testing.T) {
38
-	header := []byte{0x00, 0x01, 0x02}
39
-	out := IsArchive(header)
40
-	if out {
41
-		t.Fatalf("isArchive should return false as %s is not a valid archive header", header)
42
-	}
36
+func defaultUntarPath(src, dst string) error {
37
+	return defaultArchiver.UntarPath(src, dst)
43 38
 }
44 39
 
45
-func TestIsArchiveBzip2(t *testing.T) {
46
-	header := []byte{0x42, 0x5A, 0x68}
47
-	out := IsArchive(header)
48
-	if !out {
49
-		t.Fatalf("isArchive should return true as %s is a bz2 header", header)
50
-	}
40
+func defaultCopyFileWithTar(src, dst string) (err error) {
41
+	return defaultArchiver.CopyFileWithTar(src, dst)
51 42
 }
52 43
 
53
-func TestIsArchive7zip(t *testing.T) {
54
-	header := []byte{0x50, 0x4b, 0x03, 0x04}
55
-	out := IsArchive(header)
56
-	if out {
57
-		t.Fatalf("isArchive should return false as %s is a 7z header and it is not supported", header)
58
-	}
44
+func defaultCopyWithTar(src, dst string) error {
45
+	return defaultArchiver.CopyWithTar(src, dst)
59 46
 }
60 47
 
61 48
 func TestIsArchivePathDir(t *testing.T) {
... ...
@@ -301,7 +288,7 @@ func TestUntarPathWithInvalidDest(t *testing.T) {
301 301
 		t.Fatal(err)
302 302
 	}
303 303
 
304
-	err = UntarPath(tarFile, invalidDestFolder)
304
+	err = defaultUntarPath(tarFile, invalidDestFolder)
305 305
 	if err == nil {
306 306
 		t.Fatalf("UntarPath with invalid destination path should throw an error.")
307 307
 	}
... ...
@@ -313,7 +300,7 @@ func TestUntarPathWithInvalidSrc(t *testing.T) {
313 313
 		t.Fatalf("Fail to create the destination file")
314 314
 	}
315 315
 	defer os.RemoveAll(dest)
316
-	err = UntarPath("/invalid/path", dest)
316
+	err = defaultUntarPath("/invalid/path", dest)
317 317
 	if err == nil {
318 318
 		t.Fatalf("UntarPath with invalid src path should throw an error.")
319 319
 	}
... ...
@@ -348,7 +335,7 @@ func TestUntarPath(t *testing.T) {
348 348
 		t.Fatal(err)
349 349
 	}
350 350
 
351
-	err = UntarPath(tarFile, destFolder)
351
+	err = defaultUntarPath(tarFile, destFolder)
352 352
 	if err != nil {
353 353
 		t.Fatalf("UntarPath shouldn't throw an error, %s.", err)
354 354
 	}
... ...
@@ -387,7 +374,7 @@ func TestUntarPathWithDestinationFile(t *testing.T) {
387 387
 	if err != nil {
388 388
 		t.Fatalf("Fail to create the destination file")
389 389
 	}
390
-	err = UntarPath(tarFile, destFile)
390
+	err = defaultUntarPath(tarFile, destFile)
391 391
 	if err == nil {
392 392
 		t.Fatalf("UntarPath should throw an error if the destination if a file")
393 393
 	}
... ...
@@ -430,7 +417,7 @@ func TestUntarPathWithDestinationSrcFileAsFolder(t *testing.T) {
430 430
 	if err != nil {
431 431
 		t.Fatal(err)
432 432
 	}
433
-	err = UntarPath(tarFile, destFolder)
433
+	err = defaultUntarPath(tarFile, destFolder)
434 434
 	if err != nil {
435 435
 		t.Fatalf("UntarPath should throw not throw an error if the extracted file already exists and is a folder")
436 436
 	}
... ...
@@ -447,7 +434,7 @@ func TestCopyWithTarInvalidSrc(t *testing.T) {
447 447
 	if err != nil {
448 448
 		t.Fatal(err)
449 449
 	}
450
-	err = CopyWithTar(invalidSrc, destFolder)
450
+	err = defaultCopyWithTar(invalidSrc, destFolder)
451 451
 	if err == nil {
452 452
 		t.Fatalf("archiver.CopyWithTar with invalid src path should throw an error.")
453 453
 	}
... ...
@@ -464,7 +451,7 @@ func TestCopyWithTarInexistentDestWillCreateIt(t *testing.T) {
464 464
 	if err != nil {
465 465
 		t.Fatal(err)
466 466
 	}
467
-	err = CopyWithTar(srcFolder, inexistentDestFolder)
467
+	err = defaultCopyWithTar(srcFolder, inexistentDestFolder)
468 468
 	if err != nil {
469 469
 		t.Fatalf("CopyWithTar with an inexistent folder shouldn't fail.")
470 470
 	}
... ...
@@ -493,7 +480,7 @@ func TestCopyWithTarSrcFile(t *testing.T) {
493 493
 		t.Fatal(err)
494 494
 	}
495 495
 	ioutil.WriteFile(src, []byte("content"), 0777)
496
-	err = CopyWithTar(src, dest)
496
+	err = defaultCopyWithTar(src, dest)
497 497
 	if err != nil {
498 498
 		t.Fatalf("archiver.CopyWithTar shouldn't throw an error, %s.", err)
499 499
 	}
... ...
@@ -522,7 +509,7 @@ func TestCopyWithTarSrcFolder(t *testing.T) {
522 522
 		t.Fatal(err)
523 523
 	}
524 524
 	ioutil.WriteFile(filepath.Join(src, "file"), []byte("content"), 0777)
525
-	err = CopyWithTar(src, dest)
525
+	err = defaultCopyWithTar(src, dest)
526 526
 	if err != nil {
527 527
 		t.Fatalf("archiver.CopyWithTar shouldn't throw an error, %s.", err)
528 528
 	}
... ...
@@ -545,7 +532,7 @@ func TestCopyFileWithTarInvalidSrc(t *testing.T) {
545 545
 		t.Fatal(err)
546 546
 	}
547 547
 	invalidFile := filepath.Join(tempFolder, "doesnotexists")
548
-	err = CopyFileWithTar(invalidFile, destFolder)
548
+	err = defaultCopyFileWithTar(invalidFile, destFolder)
549 549
 	if err == nil {
550 550
 		t.Fatalf("archiver.CopyWithTar with invalid src path should throw an error.")
551 551
 	}
... ...
@@ -563,7 +550,7 @@ func TestCopyFileWithTarInexistentDestWillCreateIt(t *testing.T) {
563 563
 	if err != nil {
564 564
 		t.Fatal(err)
565 565
 	}
566
-	err = CopyFileWithTar(srcFile, inexistentDestFolder)
566
+	err = defaultCopyFileWithTar(srcFile, inexistentDestFolder)
567 567
 	if err != nil {
568 568
 		t.Fatalf("CopyWithTar with an inexistent folder shouldn't fail.")
569 569
 	}
... ...
@@ -590,7 +577,7 @@ func TestCopyFileWithTarSrcFolder(t *testing.T) {
590 590
 	if err != nil {
591 591
 		t.Fatal(err)
592 592
 	}
593
-	err = CopyFileWithTar(src, dest)
593
+	err = defaultCopyFileWithTar(src, dest)
594 594
 	if err == nil {
595 595
 		t.Fatalf("CopyFileWithTar should throw an error with a folder.")
596 596
 	}
... ...
@@ -614,7 +601,7 @@ func TestCopyFileWithTarSrcFile(t *testing.T) {
614 614
 		t.Fatal(err)
615 615
 	}
616 616
 	ioutil.WriteFile(src, []byte("content"), 0777)
617
-	err = CopyWithTar(src, dest+"/")
617
+	err = defaultCopyWithTar(src, dest+"/")
618 618
 	if err != nil {
619 619
 		t.Fatalf("archiver.CopyFileWithTar shouldn't throw an error, %s.", err)
620 620
 	}
... ...
@@ -657,7 +644,7 @@ func checkNoChanges(fileNum int, hardlinks bool) error {
657 657
 		return err
658 658
 	}
659 659
 
660
-	err = TarUntar(srcDir, destDir)
660
+	err = defaultTarUntar(srcDir, destDir)
661 661
 	if err != nil {
662 662
 		return err
663 663
 	}
... ...
@@ -871,7 +858,7 @@ func BenchmarkTarUntar(b *testing.B) {
871 871
 	b.ResetTimer()
872 872
 	b.SetBytes(int64(n))
873 873
 	for n := 0; n < b.N; n++ {
874
-		err := TarUntar(origin, target)
874
+		err := defaultTarUntar(origin, target)
875 875
 		if err != nil {
876 876
 			b.Fatal(err)
877 877
 		}
... ...
@@ -899,7 +886,7 @@ func BenchmarkTarUntarWithLinks(b *testing.B) {
899 899
 	b.ResetTimer()
900 900
 	b.SetBytes(int64(n))
901 901
 	for n := 0; n < b.N; n++ {
902
-		err := TarUntar(origin, target)
902
+		err := defaultTarUntar(origin, target)
903 903
 		if err != nil {
904 904
 			b.Fatal(err)
905 905
 		}
... ...
@@ -27,7 +27,7 @@ func TestCopyFileWithInvalidDest(t *testing.T) {
27 27
 		t.Fatal(err)
28 28
 	}
29 29
 	ioutil.WriteFile(src, []byte("content"), 0777)
30
-	err = CopyWithTar(src, dest)
30
+	err = defaultCopyWithTar(src, dest)
31 31
 	if err == nil {
32 32
 		t.Fatalf("archiver.CopyWithTar should throw an error on invalid dest.")
33 33
 	}
... ...
@@ -11,7 +11,13 @@ import (
11 11
 	"github.com/docker/docker/pkg/idtools"
12 12
 )
13 13
 
14
-var chrootArchiver = &archive.Archiver{Untar: Untar}
14
+// NewArchiver returns a new Archiver which uses chrootarchive.Untar
15
+func NewArchiver(idMappings *idtools.IDMappings) *archive.Archiver {
16
+	if idMappings == nil {
17
+		idMappings = &idtools.IDMappings{}
18
+	}
19
+	return &archive.Archiver{Untar: Untar, IDMappings: idMappings}
20
+}
15 21
 
16 22
 // Untar reads a stream of bytes from `archive`, parses it as a tar archive,
17 23
 // and unpacks it into the directory at `dest`.
... ...
@@ -30,7 +36,6 @@ func UntarUncompressed(tarArchive io.Reader, dest string, options *archive.TarOp
30 30
 
31 31
 // Handler for teasing out the automatic decompression
32 32
 func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions, decompress bool) error {
33
-
34 33
 	if tarArchive == nil {
35 34
 		return fmt.Errorf("Empty archive")
36 35
 	}
... ...
@@ -65,33 +70,3 @@ func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions
65 65
 
66 66
 	return invokeUnpack(r, dest, options)
67 67
 }
68
-
69
-// TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
70
-// If either Tar or Untar fails, TarUntar aborts and returns the error.
71
-func TarUntar(src, dst string) error {
72
-	return chrootArchiver.TarUntar(src, dst)
73
-}
74
-
75
-// CopyWithTar creates a tar archive of filesystem path `src`, and
76
-// unpacks it at filesystem path `dst`.
77
-// The archive is streamed directly with fixed buffering and no
78
-// intermediary disk IO.
79
-func CopyWithTar(src, dst string) error {
80
-	return chrootArchiver.CopyWithTar(src, dst)
81
-}
82
-
83
-// CopyFileWithTar emulates the behavior of the 'cp' command-line
84
-// for a single file. It copies a regular file from path `src` to
85
-// path `dst`, and preserves all its metadata.
86
-//
87
-// If `dst` ends with a trailing slash '/' ('\' on Windows), the final
88
-// destination path will be `dst/base(src)` or `dst\base(src)`
89
-func CopyFileWithTar(src, dst string) (err error) {
90
-	return chrootArchiver.CopyFileWithTar(src, dst)
91
-}
92
-
93
-// UntarPath is a convenience function which looks for an archive
94
-// at filesystem path `src`, and unpacks it at `dst`.
95
-func UntarPath(src, dst string) error {
96
-	return chrootArchiver.UntarPath(src, dst)
97
-}
... ...
@@ -22,6 +22,24 @@ func init() {
22 22
 	reexec.Init()
23 23
 }
24 24
 
25
+var chrootArchiver = NewArchiver(nil)
26
+
27
+func TarUntar(src, dst string) error {
28
+	return chrootArchiver.TarUntar(src, dst)
29
+}
30
+
31
+func CopyFileWithTar(src, dst string) (err error) {
32
+	return chrootArchiver.CopyFileWithTar(src, dst)
33
+}
34
+
35
+func UntarPath(src, dst string) error {
36
+	return chrootArchiver.UntarPath(src, dst)
37
+}
38
+
39
+func CopyWithTar(src, dst string) error {
40
+	return chrootArchiver.CopyWithTar(src, dst)
41
+}
42
+
25 43
 func TestChrootTarUntar(t *testing.T) {
26 44
 	tmpdir, err := ioutil.TempDir("", "docker-TestChrootTarUntar")
27 45
 	if err != nil {
... ...
@@ -118,6 +118,7 @@ func ToContainer(hostID int, idMap []IDMap) (int, error) {
118 118
 // ToHost takes an id mapping and a remapped ID, and translates the
119 119
 // ID to the mapped host ID. If no map is provided, then the translation
120 120
 // assumes a 1-to-1 mapping and returns the passed in id #
121
+// Depercated: use IDMappings.UIDToHost and IDMappings.GIDToHost
121 122
 func ToHost(contID int, idMap []IDMap) (int, error) {
122 123
 	if idMap == nil {
123 124
 		return contID, nil
... ...
@@ -174,6 +175,16 @@ func (i *IDMappings) RootPair() (IDPair, error) {
174 174
 	return IDPair{UID: uid, GID: gid}, err
175 175
 }
176 176
 
177
+// UIDToHost returns the host UID for the container uid
178
+func (i *IDMappings) UIDToHost(uid int) (int, error) {
179
+	return ToHost(uid, i.uids)
180
+}
181
+
182
+// GIDToHost returns the host GID for the container gid
183
+func (i *IDMappings) GIDToHost(gid int) (int, error) {
184
+	return ToHost(gid, i.gids)
185
+}
186
+
177 187
 // UIDs return the UID mapping
178 188
 // TODO: remove this once everything has been refactored to use pairs
179 189
 func (i *IDMappings) UIDs() []IDMap {