Browse code

Windows: revendor Microsoft/hcsshim to v0.1.0

This (the first tagged hcsshim release) fixes long-path bugs on
Windows TP5 that affect commit and save. These bugs were blocking
commit of Windows containers that had node.js installed.

Signed-off-by: John Starks <jostarks@microsoft.com>

John Starks authored on 2016/03/18 06:08:07
Showing 3 changed files
... ...
@@ -7,7 +7,7 @@ source 'hack/.vendor-helpers.sh'
7 7
 
8 8
 # the following lines are in sorted order, FYI
9 9
 clone git github.com/Azure/go-ansiterm 70b2c90b260171e829f1ebd7c17f600c11858dbe
10
-clone git github.com/Microsoft/hcsshim 116e0e9f5ced0cec94ae46d0aa1b3002a325f532
10
+clone git github.com/Microsoft/hcsshim v0.1.0
11 11
 clone git github.com/Microsoft/go-winio v0.1.0
12 12
 clone git github.com/Sirupsen/logrus v0.9.0 # logrus is a common dependency among multiple deps
13 13
 clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
... ...
@@ -3,6 +3,7 @@ package hcsshim
3 3
 import (
4 4
 	"io/ioutil"
5 5
 	"os"
6
+	"path/filepath"
6 7
 	"runtime"
7 8
 
8 9
 	"github.com/Microsoft/go-winio"
... ...
@@ -110,13 +111,22 @@ type legacyLayerWriterWrapper struct {
110 110
 	*LegacyLayerWriter
111 111
 	info             DriverInfo
112 112
 	layerId          string
113
+	path             string
113 114
 	parentLayerPaths []string
114 115
 }
115 116
 
116 117
 func (r *legacyLayerWriterWrapper) Close() error {
117 118
 	err := r.LegacyLayerWriter.Close()
118 119
 	if err == nil {
119
-		err = ImportLayer(r.info, r.layerId, r.root, r.parentLayerPaths)
120
+		// Use the original path here because ImportLayer does not support long paths for the source in TP5.
121
+		// But do use a long path for the destination to work around another bug with directories
122
+		// with MAX_PATH - 12 < length < MAX_PATH.
123
+		info := r.info
124
+		fullPath, err := makeLongAbsPath(filepath.Join(info.HomeDir, r.layerId))
125
+		if err == nil {
126
+			info.HomeDir = ""
127
+			err = ImportLayer(info, fullPath, r.path, r.parentLayerPaths)
128
+		}
120 129
 	}
121 130
 	os.RemoveAll(r.root)
122 131
 	return err
... ...
@@ -131,7 +141,13 @@ func NewLayerWriter(info DriverInfo, layerId string, parentLayerPaths []string)
131 131
 		if err != nil {
132 132
 			return nil, err
133 133
 		}
134
-		return &legacyLayerWriterWrapper{NewLegacyLayerWriter(path), info, layerId, parentLayerPaths}, nil
134
+		return &legacyLayerWriterWrapper{
135
+			LegacyLayerWriter: NewLegacyLayerWriter(path),
136
+			info:              info,
137
+			layerId:           layerId,
138
+			path:              path,
139
+			parentLayerPaths:  parentLayerPaths,
140
+		}, nil
135 141
 	}
136 142
 	layers, err := layerPathsToDescriptors(parentLayerPaths)
137 143
 	if err != nil {
... ...
@@ -29,6 +29,23 @@ func openFileOrDir(path string, mode uint32, createDisposition uint32) (file *os
29 29
 	return
30 30
 }
31 31
 
32
+func makeLongAbsPath(path string) (string, error) {
33
+	if strings.HasPrefix(path, `\\?\`) || strings.HasPrefix(path, `\\.\`) {
34
+		return path, nil
35
+	}
36
+	if !filepath.IsAbs(path) {
37
+		absPath, err := filepath.Abs(path)
38
+		if err != nil {
39
+			return "", err
40
+		}
41
+		path = absPath
42
+	}
43
+	if strings.HasPrefix(path, `\\`) {
44
+		return `\\?\UNC\` + path[2:], nil
45
+	}
46
+	return `\\?\` + path, nil
47
+}
48
+
32 49
 type fileEntry struct {
33 50
 	path string
34 51
 	fi   os.FileInfo
... ...
@@ -81,15 +98,16 @@ func readTombstones(path string) (map[string]([]string), error) {
81 81
 	return ts, nil
82 82
 }
83 83
 
84
-func (r *LegacyLayerReader) walk() {
85
-	defer close(r.result)
86
-	if !<-r.proceed {
87
-		return
84
+func (r *LegacyLayerReader) walkUntilCancelled() error {
85
+	root, err := makeLongAbsPath(r.root)
86
+	if err != nil {
87
+		return err
88 88
 	}
89 89
 
90
+	r.root = root
90 91
 	ts, err := readTombstones(r.root)
91 92
 	if err != nil {
92
-		goto ErrorLoop
93
+		return err
93 94
 	}
94 95
 
95 96
 	err = filepath.Walk(r.root, func(path string, info os.FileInfo, err error) error {
... ...
@@ -122,17 +140,27 @@ func (r *LegacyLayerReader) walk() {
122 122
 		return nil
123 123
 	})
124 124
 	if err == errorIterationCanceled {
125
-		return
125
+		return nil
126 126
 	}
127 127
 	if err == nil {
128
-		err = io.EOF
128
+		return io.EOF
129 129
 	}
130
+	return err
131
+}
130 132
 
131
-ErrorLoop:
132
-	for {
133
-		r.result <- &fileEntry{err: err}
134
-		if !<-r.proceed {
135
-			break
133
+func (r *LegacyLayerReader) walk() {
134
+	defer close(r.result)
135
+	if !<-r.proceed {
136
+		return
137
+	}
138
+
139
+	err := r.walkUntilCancelled()
140
+	if err != nil {
141
+		for {
142
+			r.result <- &fileEntry{err: err}
143
+			if !<-r.proceed {
144
+				return
145
+			}
136 146
 		}
137 147
 	}
138 148
 }
... ...
@@ -287,6 +315,7 @@ type LegacyLayerWriter struct {
287 287
 	backupWriter *winio.BackupFileWriter
288 288
 	tombstones   []string
289 289
 	isTP4Format  bool
290
+	pathFixed    bool
290 291
 }
291 292
 
292 293
 // NewLegacyLayerWriter returns a LayerWriter that can write the TP4 transport format
... ...
@@ -298,6 +327,18 @@ func NewLegacyLayerWriter(root string) *LegacyLayerWriter {
298 298
 	}
299 299
 }
300 300
 
301
+func (w *LegacyLayerWriter) init() error {
302
+	if !w.pathFixed {
303
+		path, err := makeLongAbsPath(w.root)
304
+		if err != nil {
305
+			return err
306
+		}
307
+		w.root = path
308
+		w.pathFixed = true
309
+	}
310
+	return nil
311
+}
312
+
301 313
 func (w *LegacyLayerWriter) reset() {
302 314
 	if w.backupWriter != nil {
303 315
 		w.backupWriter.Close()
... ...
@@ -311,6 +352,10 @@ func (w *LegacyLayerWriter) reset() {
311 311
 
312 312
 func (w *LegacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error {
313 313
 	w.reset()
314
+	err := w.init()
315
+	if err != nil {
316
+		return err
317
+	}
314 318
 	path := filepath.Join(w.root, name)
315 319
 
316 320
 	createDisposition := uint32(syscall.CREATE_NEW)
... ...
@@ -374,6 +419,10 @@ func (w *LegacyLayerWriter) Write(b []byte) (int, error) {
374 374
 
375 375
 func (w *LegacyLayerWriter) Close() error {
376 376
 	w.reset()
377
+	err := w.init()
378
+	if err != nil {
379
+		return err
380
+	}
377 381
 	tf, err := os.Create(filepath.Join(w.root, "tombstones.txt"))
378 382
 	if err != nil {
379 383
 		return err