diff --git a/pkg/archive/copy.go b/pkg/archive/copy.go index d0f13ca79b..57fddac078 100644 --- a/pkg/archive/copy.go +++ b/pkg/archive/copy.go @@ -336,6 +336,14 @@ func RebaseArchiveEntries(srcContent io.Reader, oldBase, newBase string) io.Read return } + // srcContent tar stream, as served by TarWithOptions(), is + // definitely in PAX format, but tar.Next() mistakenly guesses it + // as USTAR, which creates a problem: if the newBase is >100 + // characters long, WriteHeader() returns an error like + // "archive/tar: cannot encode header: Format specifies USTAR; and USTAR cannot encode Name=...". + // + // To fix, set the format to PAX here. See docker/for-linux issue #484. + hdr.Format = tar.FormatPAX hdr.Name = strings.Replace(hdr.Name, oldBase, newBase, 1) if hdr.Typeflag == tar.TypeLink { hdr.Linkname = strings.Replace(hdr.Linkname, oldBase, newBase, 1) diff --git a/pkg/archive/copy_unix_test.go b/pkg/archive/copy_unix_test.go index 739ad0e3ef..ca0f4653af 100644 --- a/pkg/archive/copy_unix_test.go +++ b/pkg/archive/copy_unix_test.go @@ -257,6 +257,30 @@ func TestCopyErrDstNotDir(t *testing.T) { } } +// Test to check if CopyTo works with a long (>100 characters) destination file name. +// This is a regression (see https://github.com/docker/for-linux/issues/484). +func TestCopyLongDstFilename(t *testing.T) { + const longName = "a_very_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_long_filename_that_is_101_characters" + tmpDirA, tmpDirB := getTestTempDirs(t) + defer removeAllPaths(tmpDirA, tmpDirB) + + // Load A with some sample files and directories. + createSampleDir(t, tmpDirA) + + srcInfo := CopyInfo{Path: filepath.Join(tmpDirA, "file1"), Exists: true, IsDir: false} + + content, err := TarResource(srcInfo) + if err != nil { + t.Fatalf("unexpected error %T: %s", err, err) + } + defer content.Close() + + err = CopyTo(content, srcInfo, filepath.Join(tmpDirB, longName)) + if err != nil { + t.Fatalf("unexpected error %T: %s", err, err) + } +} + // Possibilities are reduced to the remaining 10 cases: // // case | srcIsDir | onlyDirContents | dstExists | dstIsDir | dstTrSep | action