Browse code

archive: add ChownOpts support to TarWithOptions

Signed-off-by: Sébastien HOUZÉ <cto@verylastroom.com>

Sébastien HOUZÉ authored on 2017/08/22 09:17:46
Showing 3 changed files
... ...
@@ -382,6 +382,7 @@ type tarAppender struct {
382 382
 	// for hardlink mapping
383 383
 	SeenFiles  map[uint64]string
384 384
 	IDMappings *idtools.IDMappings
385
+	ChownOpts  *idtools.IDPair
385 386
 
386 387
 	// For packing and unpacking whiteout files in the
387 388
 	// non standard format. The whiteout files defined
... ...
@@ -390,12 +391,13 @@ type tarAppender struct {
390 390
 	WhiteoutConverter tarWhiteoutConverter
391 391
 }
392 392
 
393
-func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer) *tarAppender {
393
+func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *idtools.IDPair) *tarAppender {
394 394
 	return &tarAppender{
395 395
 		SeenFiles:  make(map[uint64]string),
396 396
 		TarWriter:  tar.NewWriter(writer),
397 397
 		Buffer:     pools.BufioWriter32KPool.Get(nil),
398 398
 		IDMappings: idMapping,
399
+		ChownOpts:  chownOpts,
399 400
 	}
400 401
 }
401 402
 
... ...
@@ -470,6 +472,12 @@ func (ta *tarAppender) addTarFile(path, name string) error {
470 470
 		}
471 471
 	}
472 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
+
473 479
 	if ta.WhiteoutConverter != nil {
474 480
 		wo, err := ta.WhiteoutConverter.ConvertWrite(hdr, path, fi)
475 481
 		if err != nil {
... ...
@@ -692,6 +700,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
692 692
 		ta := newTarAppender(
693 693
 			idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps),
694 694
 			compressWriter,
695
+			options.ChownOpts,
695 696
 		)
696 697
 		ta.WhiteoutConverter = getWhiteoutConverter(options.WhiteoutFormat)
697 698
 
... ...
@@ -14,6 +14,7 @@ import (
14 14
 	"testing"
15 15
 	"time"
16 16
 
17
+	"github.com/docker/docker/pkg/idtools"
17 18
 	"github.com/stretchr/testify/assert"
18 19
 	"github.com/stretchr/testify/require"
19 20
 )
... ...
@@ -724,6 +725,57 @@ func TestTarUntar(t *testing.T) {
724 724
 	}
725 725
 }
726 726
 
727
+func TestTarWithOptionsChownOptsAlwaysOverridesIdPair(t *testing.T) {
728
+	origin, err := ioutil.TempDir("", "docker-test-tar-chown-opt")
729
+	require.NoError(t, err)
730
+
731
+	defer os.RemoveAll(origin)
732
+	filePath := filepath.Join(origin, "1")
733
+	err = ioutil.WriteFile(filePath, []byte("hello world"), 0700)
734
+	require.NoError(t, err)
735
+
736
+	idMaps := []idtools.IDMap{
737
+		0: {
738
+			ContainerID: 0,
739
+			HostID:      0,
740
+			Size:        65536,
741
+		},
742
+		1: {
743
+			ContainerID: 0,
744
+			HostID:      100000,
745
+			Size:        65536,
746
+		},
747
+	}
748
+
749
+	cases := []struct {
750
+		opts        *TarOptions
751
+		expectedUID int
752
+		expectedGID int
753
+	}{
754
+		{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1337, GID: 42}}, 1337, 42},
755
+		{&TarOptions{ChownOpts: &idtools.IDPair{UID: 100001, GID: 100001}, UIDMaps: idMaps, GIDMaps: idMaps}, 100001, 100001},
756
+		{&TarOptions{ChownOpts: &idtools.IDPair{UID: 0, GID: 0}, NoLchown: false}, 0, 0},
757
+		{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1, GID: 1}, NoLchown: true}, 1, 1},
758
+		{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1000, GID: 1000}, NoLchown: true}, 1000, 1000},
759
+	}
760
+	for _, testCase := range cases {
761
+		reader, err := TarWithOptions(filePath, testCase.opts)
762
+		require.NoError(t, err)
763
+		tr := tar.NewReader(reader)
764
+		defer reader.Close()
765
+		for {
766
+			hdr, err := tr.Next()
767
+			if err == io.EOF {
768
+				// end of tar archive
769
+				break
770
+			}
771
+			require.NoError(t, err)
772
+			assert.Equal(t, hdr.Uid, testCase.expectedUID, "Uid equals expected value")
773
+			assert.Equal(t, hdr.Gid, testCase.expectedGID, "Gid equals expected value")
774
+		}
775
+	}
776
+}
777
+
727 778
 func TestTarWithOptions(t *testing.T) {
728 779
 	// TODO Windows: Figure out how to fix this test.
729 780
 	if runtime.GOOS == "windows" {
... ...
@@ -394,7 +394,7 @@ func ChangesSize(newDir string, changes []Change) int64 {
394 394
 func ExportChanges(dir string, changes []Change, uidMaps, gidMaps []idtools.IDMap) (io.ReadCloser, error) {
395 395
 	reader, writer := io.Pipe()
396 396
 	go func() {
397
-		ta := newTarAppender(idtools.NewIDMappingsFromMaps(uidMaps, gidMaps), writer)
397
+		ta := newTarAppender(idtools.NewIDMappingsFromMaps(uidMaps, gidMaps), writer, nil)
398 398
 
399 399
 		// this buffer is needed for the duration of this piped stream
400 400
 		defer pools.BufioWriter32KPool.Put(ta.Buffer)