Browse code

Fixing Tar functions to support Windows long paths.

Signed-off-by: Stefan J. Wernli <swernli@microsoft.com>

Stefan J. Wernli authored on 2015/08/11 07:21:30
Showing 4 changed files
... ...
@@ -405,6 +405,10 @@ func Tar(path string, compression Compression) (io.ReadCloser, error) {
405 405
 // paths are included in `options.IncludeFiles` (if non-nil) or not in `options.ExcludePatterns`.
406 406
 func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) {
407 407
 
408
+	// Fix the source path to work with long path names. This is a no-op
409
+	// on platforms other than Windows.
410
+	srcPath = fixVolumePathPrefix(srcPath)
411
+
408 412
 	patterns, patDirs, exceptions, err := fileutils.CleanPatterns(options.ExcludePatterns)
409 413
 
410 414
 	if err != nil {
... ...
@@ -474,9 +478,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
474 474
 		for _, include := range options.IncludeFiles {
475 475
 			rebaseName := options.RebaseNames[include]
476 476
 
477
-			// We can't use filepath.Join(srcPath, include) because this will
478
-			// clean away a trailing "." or "/" which may be important.
479
-			walkRoot := strings.Join([]string{srcPath, include}, string(filepath.Separator))
477
+			walkRoot := getWalkRoot(srcPath, include)
480 478
 			filepath.Walk(walkRoot, func(filePath string, f os.FileInfo, err error) error {
481 479
 				if err != nil {
482 480
 					logrus.Debugf("Tar: Can't stat file %s to tar: %s", srcPath, err)
... ...
@@ -6,11 +6,26 @@ import (
6 6
 	"archive/tar"
7 7
 	"errors"
8 8
 	"os"
9
+	"path/filepath"
9 10
 	"syscall"
10 11
 
11 12
 	"github.com/docker/docker/pkg/system"
12 13
 )
13 14
 
15
+// fixVolumePathPrefix does platform specific processing to ensure that if
16
+// the path being passed in is not in a volume path format, convert it to one.
17
+func fixVolumePathPrefix(srcPath string) string {
18
+	return srcPath
19
+}
20
+
21
+// getWalkRoot calculates the root path when performing a TarWithOptions.
22
+// We use a seperate function as this is platform specific. On Linux, we
23
+// can't use filepath.Join(srcPath,include) because this will clean away
24
+// a trailing "." or "/" which may be important.
25
+func getWalkRoot(srcPath string, include string) string {
26
+	return srcPath + string(filepath.Separator) + include
27
+}
28
+
14 29
 // CanonicalTarNameForPath returns platform-specific filepath
15 30
 // to canonical posix-style path for tar archival. p is relative
16 31
 // path.
... ...
@@ -6,9 +6,25 @@ import (
6 6
 	"archive/tar"
7 7
 	"fmt"
8 8
 	"os"
9
+	"path/filepath"
9 10
 	"strings"
10 11
 )
11 12
 
13
+// fixVolumePathPrefix does platform specific processing to ensure that if
14
+// the path being passed in is not in a volume path format, convert it to one.
15
+func fixVolumePathPrefix(srcPath string) string {
16
+	if !strings.HasPrefix(srcPath, `\\?\`) {
17
+		srcPath = `\\?\` + srcPath
18
+	}
19
+	return srcPath
20
+}
21
+
22
+// getWalkRoot calculates the root path when performing a TarWithOptions.
23
+// We use a seperate function as this is platform specific.
24
+func getWalkRoot(srcPath string, include string) string {
25
+	return filepath.Join(srcPath, include)
26
+}
27
+
12 28
 // canonicalTarNameForPath returns platform-specific filepath
13 29
 // to canonical posix-style path for tar archival. p is relative
14 30
 // path.
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"io/ioutil"
6 6
 	"os"
7 7
 	"path/filepath"
8
+	"strings"
8 9
 
9 10
 	"github.com/docker/docker/pkg/archive"
10 11
 )
... ...
@@ -14,6 +15,12 @@ import (
14 14
 // contents of the layer.
15 15
 func applyLayerHandler(dest string, layer archive.Reader, decompress bool) (size int64, err error) {
16 16
 	dest = filepath.Clean(dest)
17
+
18
+	// Ensure it is a Windows-style volume path
19
+	if !strings.HasPrefix(dest, `\\?\`) {
20
+		dest = `\\?\` + dest
21
+	}
22
+
17 23
 	if decompress {
18 24
 		decompressed, err := archive.DecompressStream(layer)
19 25
 		if err != nil {