Signed-off-by: Daniel Nephin <dnephin@docker.com>
| ... | ... |
@@ -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 |
} |
| ... | ... |
@@ -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 {
|