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>
| ... | ... |
@@ -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 |