diff --git a/archive/archive.go b/archive/archive.go index 0fb8e9b..ef7e331 100644 --- a/archive/archive.go +++ b/archive/archive.go @@ -405,6 +405,10 @@ func Tar(path string, compression Compression) (io.ReadCloser, error) { // paths are included in `options.IncludeFiles` (if non-nil) or not in `options.ExcludePatterns`. func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) { + // Fix the source path to work with long path names. This is a no-op + // on platforms other than Windows. + srcPath = fixVolumePathPrefix(srcPath) + patterns, patDirs, exceptions, err := fileutils.CleanPatterns(options.ExcludePatterns) if err != nil { @@ -474,9 +478,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) for _, include := range options.IncludeFiles { rebaseName := options.RebaseNames[include] - // We can't use filepath.Join(srcPath, include) because this will - // clean away a trailing "." or "/" which may be important. - walkRoot := strings.Join([]string{srcPath, include}, string(filepath.Separator)) + walkRoot := getWalkRoot(srcPath, include) filepath.Walk(walkRoot, func(filePath string, f os.FileInfo, err error) error { if err != nil { logrus.Debugf("Tar: Can't stat file %s to tar: %s", srcPath, err) diff --git a/archive/archive_unix.go b/archive/archive_unix.go index 9e1dfad..823c556 100644 --- a/archive/archive_unix.go +++ b/archive/archive_unix.go @@ -6,11 +6,26 @@ import ( "archive/tar" "errors" "os" + "path/filepath" "syscall" "github.com/docker/docker/pkg/system" ) +// fixVolumePathPrefix does platform specific processing to ensure that if +// the path being passed in is not in a volume path format, convert it to one. +func fixVolumePathPrefix(srcPath string) string { + return srcPath +} + +// getWalkRoot calculates the root path when performing a TarWithOptions. +// We use a seperate function as this is platform specific. On Linux, we +// can't use filepath.Join(srcPath,include) because this will clean away +// a trailing "." or "/" which may be important. +func getWalkRoot(srcPath string, include string) string { + return srcPath + string(filepath.Separator) + include +} + // CanonicalTarNameForPath returns platform-specific filepath // to canonical posix-style path for tar archival. p is relative // path. diff --git a/archive/archive_windows.go b/archive/archive_windows.go index 10db4bd..2500785 100644 --- a/archive/archive_windows.go +++ b/archive/archive_windows.go @@ -6,9 +6,25 @@ import ( "archive/tar" "fmt" "os" + "path/filepath" "strings" ) +// fixVolumePathPrefix does platform specific processing to ensure that if +// the path being passed in is not in a volume path format, convert it to one. +func fixVolumePathPrefix(srcPath string) string { + if !strings.HasPrefix(srcPath, `\\?\`) { + srcPath = `\\?\` + srcPath + } + return srcPath +} + +// getWalkRoot calculates the root path when performing a TarWithOptions. +// We use a seperate function as this is platform specific. +func getWalkRoot(srcPath string, include string) string { + return filepath.Join(srcPath, include) +} + // canonicalTarNameForPath returns platform-specific filepath // to canonical posix-style path for tar archival. p is relative // path. diff --git a/chrootarchive/diff_windows.go b/chrootarchive/diff_windows.go index 40f9054..a21bfe2 100644 --- a/chrootarchive/diff_windows.go +++ b/chrootarchive/diff_windows.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" "github.com/docker/docker/pkg/archive" ) @@ -14,6 +15,12 @@ import ( // contents of the layer. func applyLayerHandler(dest string, layer archive.Reader, decompress bool) (size int64, err error) { dest = filepath.Clean(dest) + + // Ensure it is a Windows-style volume path + if !strings.HasPrefix(dest, `\\?\`) { + dest = `\\?\` + dest + } + if decompress { decompressed, err := archive.DecompressStream(layer) if err != nil {