Browse Source

Merge pull request #20882 from Microsoft/jstarks/new_windows_diff_format

Write Windows layer diffs to tar in standard format
Sebastiaan van Stijn 9 năm trước cách đây
mục cha
commit
b76a55308f
33 tập tin đã thay đổi với 4164 bổ sung1680 xóa
  1. 3 26
      daemon/execdriver/windows/windows.go
  2. 269 78
      daemon/graphdriver/windows/windows.go
  3. 2 2
      hack/vendor.sh
  4. 27 0
      vendor/src/github.com/Microsoft/go-winio/archive/tar/LICENSE
  5. 342 0
      vendor/src/github.com/Microsoft/go-winio/archive/tar/common.go
  6. 996 0
      vendor/src/github.com/Microsoft/go-winio/archive/tar/reader.go
  7. 20 0
      vendor/src/github.com/Microsoft/go-winio/archive/tar/stat_atim.go
  8. 20 0
      vendor/src/github.com/Microsoft/go-winio/archive/tar/stat_atimespec.go
  9. 32 0
      vendor/src/github.com/Microsoft/go-winio/archive/tar/stat_unix.go
  10. 419 0
      vendor/src/github.com/Microsoft/go-winio/archive/tar/writer.go
  11. 241 0
      vendor/src/github.com/Microsoft/go-winio/backup.go
  12. 362 0
      vendor/src/github.com/Microsoft/go-winio/backuptar/tar.go
  13. 30 0
      vendor/src/github.com/Microsoft/go-winio/fileinfo.go
  14. 0 797
      vendor/src/github.com/Microsoft/go-winio/mksyscall_windows.go
  15. 1 1
      vendor/src/github.com/Microsoft/go-winio/pipe.go
  16. 147 0
      vendor/src/github.com/Microsoft/go-winio/privilege.go
  17. 124 0
      vendor/src/github.com/Microsoft/go-winio/reparse.go
  18. 15 2
      vendor/src/github.com/Microsoft/go-winio/sd.go
  19. 1 1
      vendor/src/github.com/Microsoft/go-winio/syscall.go
  20. 239 0
      vendor/src/github.com/Microsoft/go-winio/zsyscall.go
  21. 0 34
      vendor/src/github.com/Microsoft/hcsshim/copylayer.go
  22. 3 3
      vendor/src/github.com/Microsoft/hcsshim/createprocess.go
  23. 121 1
      vendor/src/github.com/Microsoft/hcsshim/exportlayer.go
  24. 29 9
      vendor/src/github.com/Microsoft/hcsshim/hcsshim.go
  25. 119 1
      vendor/src/github.com/Microsoft/hcsshim/importlayer.go
  26. 397 0
      vendor/src/github.com/Microsoft/hcsshim/legacy.go
  27. 8 1
      vendor/src/github.com/Microsoft/hcsshim/mksyscall_windows.go
  28. 7 0
      vendor/src/github.com/Microsoft/hcsshim/version.go
  29. 190 47
      vendor/src/github.com/Microsoft/hcsshim/zhcsshim.go
  30. 0 178
      vendor/src/golang.org/x/sys/windows/registry/key.go
  31. 0 33
      vendor/src/golang.org/x/sys/windows/registry/syscall.go
  32. 0 384
      vendor/src/golang.org/x/sys/windows/registry/value.go
  33. 0 82
      vendor/src/golang.org/x/sys/windows/registry/zsyscall_windows.go

+ 3 - 26
daemon/execdriver/windows/windows.go

@@ -4,16 +4,15 @@ package windows
 
 import (
 	"fmt"
-	"strconv"
 	"strings"
 	"sync"
 
+	"github.com/Microsoft/hcsshim"
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/engine-api/types/container"
-	"golang.org/x/sys/windows/registry"
 )
 
 // TP4RetryHack is a hack to retry CreateComputeSystem if it fails with
@@ -98,33 +97,11 @@ func NewDriver(root string, options []string) (*Driver, error) {
 	// TODO Windows TP5 timeframe. Remove this next block of code once TP4
 	// is no longer supported. Also remove the workaround in run.go.
 	//
-	// Hack for TP4 - determine the version of Windows from the registry.
+	// Hack for TP4.
 	// This overcomes an issue on TP4 which causes CreateComputeSystem to
 	// intermittently fail. It's predominantly here to make Windows to Windows
 	// CI more reliable.
-	TP4RetryHack = false
-	k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
-	if err != nil {
-		return &Driver{}, err
-	}
-	defer k.Close()
-
-	s, _, err := k.GetStringValue("BuildLab")
-	if err != nil {
-		return &Driver{}, err
-	}
-	parts := strings.Split(s, ".")
-	if len(parts) < 1 {
-		return &Driver{}, err
-	}
-	var val int
-	if val, err = strconv.Atoi(parts[0]); err != nil {
-		return &Driver{}, err
-	}
-	if val < 14250 {
-		TP4RetryHack = true
-	}
-	// End of Windows TP4 hack
+	TP4RetryHack = hcsshim.IsTP4()
 
 	return &Driver{
 		root:             root,

+ 269 - 78
daemon/graphdriver/windows/windows.go

@@ -3,17 +3,23 @@
 package windows
 
 import (
+	"bufio"
 	"crypto/sha512"
 	"encoding/json"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"os"
+	"path"
 	"path/filepath"
-	"strconv"
 	"strings"
 	"sync"
+	"syscall"
 	"time"
 
+	"github.com/Microsoft/go-winio"
+	"github.com/Microsoft/go-winio/archive/tar"
+	"github.com/Microsoft/go-winio/backuptar"
 	"github.com/Microsoft/hcsshim"
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/graphdriver"
@@ -21,7 +27,6 @@ import (
 	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/idtools"
 	"github.com/docker/docker/pkg/ioutils"
-	"github.com/docker/docker/pkg/random"
 	"github.com/vbatts/tar-split/tar/storage"
 )
 
@@ -265,7 +270,7 @@ func (d *Driver) Cleanup() error {
 
 // Diff produces an archive of the changes between the specified
 // layer and its parent layer which may be "".
-func (d *Driver) Diff(id, parent string) (arch archive.Archive, err error) {
+func (d *Driver) Diff(id, parent string) (_ archive.Archive, err error) {
 	rID, err := d.resolveID(id)
 	if err != nil {
 		return
@@ -277,6 +282,8 @@ func (d *Driver) Diff(id, parent string) (arch archive.Archive, err error) {
 		return
 	}
 
+	var undo func()
+
 	d.Lock()
 
 	// To support export, a layer must be activated but not prepared.
@@ -286,33 +293,99 @@ func (d *Driver) Diff(id, parent string) (arch archive.Archive, err error) {
 				d.Unlock()
 				return
 			}
-			defer func() {
+			undo = func() {
 				if err := hcsshim.DeactivateLayer(d.info, rID); err != nil {
 					logrus.Warnf("Failed to Deactivate %s: %s", rID, err)
 				}
-			}()
+			}
 		} else {
 			if err = hcsshim.UnprepareLayer(d.info, rID); err != nil {
 				d.Unlock()
 				return
 			}
-			defer func() {
+			undo = func() {
 				if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
 					logrus.Warnf("Failed to re-PrepareLayer %s: %s", rID, err)
 				}
-			}()
+			}
 		}
 	}
 
 	d.Unlock()
 
-	return d.exportLayer(rID, layerChain)
+	arch, err := d.exportLayer(rID, layerChain)
+	if err != nil {
+		undo()
+		return
+	}
+	return ioutils.NewReadCloserWrapper(arch, func() error {
+		defer undo()
+		return arch.Close()
+	}), nil
 }
 
 // Changes produces a list of changes between the specified layer
 // and its parent layer. If parent is "", then all changes will be ADD changes.
 func (d *Driver) Changes(id, parent string) ([]archive.Change, error) {
-	return nil, fmt.Errorf("The Windows graphdriver does not support Changes()")
+	rID, err := d.resolveID(id)
+	if err != nil {
+		return nil, err
+	}
+	parentChain, err := d.getLayerChain(rID)
+	if err != nil {
+		return nil, err
+	}
+
+	d.Lock()
+	if d.info.Flavour == filterDriver {
+		if d.active[rID] == 0 {
+			if err = hcsshim.ActivateLayer(d.info, rID); err != nil {
+				d.Unlock()
+				return nil, err
+			}
+			defer func() {
+				if err := hcsshim.DeactivateLayer(d.info, rID); err != nil {
+					logrus.Warnf("Failed to Deactivate %s: %s", rID, err)
+				}
+			}()
+		} else {
+			if err = hcsshim.UnprepareLayer(d.info, rID); err != nil {
+				d.Unlock()
+				return nil, err
+			}
+			defer func() {
+				if err := hcsshim.PrepareLayer(d.info, rID, parentChain); err != nil {
+					logrus.Warnf("Failed to re-PrepareLayer %s: %s", rID, err)
+				}
+			}()
+		}
+	}
+	d.Unlock()
+
+	r, err := hcsshim.NewLayerReader(d.info, id, parentChain)
+	if err != nil {
+		return nil, err
+	}
+	defer r.Close()
+
+	var changes []archive.Change
+	for {
+		name, _, fileInfo, err := r.Next()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			return nil, err
+		}
+		name = filepath.ToSlash(name)
+		if fileInfo == nil {
+			changes = append(changes, archive.Change{name, archive.ChangeDelete})
+		} else {
+			// Currently there is no way to tell between an add and a modify.
+			changes = append(changes, archive.Change{name, archive.ChangeModify})
+		}
+	}
+	return changes, nil
 }
 
 // ApplyDiff extracts the changeset from the given diff into the
@@ -444,71 +517,162 @@ func (d *Driver) GetMetadata(id string) (map[string]string, error) {
 	return m, nil
 }
 
-// exportLayer generates an archive from a layer based on the given ID.
-func (d *Driver) exportLayer(id string, parentLayerPaths []string) (arch archive.Archive, err error) {
-	layerFolder := d.dir(id)
-
-	tempFolder := layerFolder + "-" + strconv.FormatUint(uint64(random.Rand.Uint32()), 10)
-	if err = os.MkdirAll(tempFolder, 0755); err != nil {
-		logrus.Errorf("Could not create %s %s", tempFolder, err)
-		return
-	}
-	defer func() {
+func writeTarFromLayer(r hcsshim.LayerReader, w io.Writer) error {
+	t := tar.NewWriter(w)
+	for {
+		name, size, fileInfo, err := r.Next()
+		if err == io.EOF {
+			break
+		}
 		if err != nil {
-			_, folderName := filepath.Split(tempFolder)
-			if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil {
-				logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2)
+			return err
+		}
+		if fileInfo == nil {
+			// Write a whiteout file.
+			hdr := &tar.Header{
+				Name: filepath.ToSlash(filepath.Join(filepath.Dir(name), archive.WhiteoutPrefix+filepath.Base(name))),
+			}
+			err := t.WriteHeader(hdr)
+			if err != nil {
+				return err
+			}
+		} else {
+			err = backuptar.WriteTarFileFromBackupStream(t, r, name, size, fileInfo)
+			if err != nil {
+				return err
 			}
 		}
-	}()
+	}
+	return t.Close()
+}
 
-	if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil {
-		return
+// exportLayer generates an archive from a layer based on the given ID.
+func (d *Driver) exportLayer(id string, parentLayerPaths []string) (archive.Archive, error) {
+	if hcsshim.IsTP4() {
+		// Export in TP4 format to maintain compatibility with existing images and
+		// because ExportLayer is somewhat broken on TP4 and can't work with the new
+		// scheme.
+		tempFolder, err := ioutil.TempDir("", "hcs")
+		if err != nil {
+			return nil, err
+		}
+		defer func() {
+			if err != nil {
+				os.RemoveAll(tempFolder)
+			}
+		}()
+
+		if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil {
+			return nil, err
+		}
+		archive, err := archive.Tar(tempFolder, archive.Uncompressed)
+		if err != nil {
+			return nil, err
+		}
+		return ioutils.NewReadCloserWrapper(archive, func() error {
+			err := archive.Close()
+			os.RemoveAll(tempFolder)
+			return err
+		}), nil
 	}
 
-	archive, err := archive.Tar(tempFolder, archive.Uncompressed)
+	var r hcsshim.LayerReader
+	r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths)
 	if err != nil {
-		return
+		return nil, err
 	}
-	return ioutils.NewReadCloserWrapper(archive, func() error {
-		err := archive.Close()
-		d.Put(id)
-		_, folderName := filepath.Split(tempFolder)
-		if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil {
-			logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2)
+
+	archive, w := io.Pipe()
+	go func() {
+		err := writeTarFromLayer(r, w)
+		cerr := r.Close()
+		if err == nil {
+			err = cerr
 		}
-		return err
-	}), nil
+		w.CloseWithError(err)
+	}()
 
+	return archive, nil
+}
+
+func writeLayerFromTar(r archive.Reader, w hcsshim.LayerWriter) (int64, error) {
+	t := tar.NewReader(r)
+	hdr, err := t.Next()
+	totalSize := int64(0)
+	buf := bufio.NewWriter(nil)
+	for err == nil {
+		base := path.Base(hdr.Name)
+		if strings.HasPrefix(base, archive.WhiteoutPrefix) {
+			name := path.Join(path.Dir(hdr.Name), base[len(archive.WhiteoutPrefix):])
+			err = w.Remove(filepath.FromSlash(name))
+			if err != nil {
+				return 0, err
+			}
+			hdr, err = t.Next()
+		} else {
+			var (
+				name     string
+				size     int64
+				fileInfo *winio.FileBasicInfo
+			)
+			name, size, fileInfo, err = backuptar.FileInfoFromHeader(hdr)
+			if err != nil {
+				return 0, err
+			}
+			err = w.Add(filepath.FromSlash(name), fileInfo)
+			if err != nil {
+				return 0, err
+			}
+			buf.Reset(w)
+			hdr, err = backuptar.WriteBackupStreamFromTarFile(buf, t, hdr)
+			ferr := buf.Flush()
+			if ferr != nil {
+				err = ferr
+			}
+			totalSize += size
+		}
+	}
+	if err != io.EOF {
+		return 0, err
+	}
+	return totalSize, nil
 }
 
 // importLayer adds a new layer to the tag and graph store based on the given data.
 func (d *Driver) importLayer(id string, layerData archive.Reader, parentLayerPaths []string) (size int64, err error) {
-	layerFolder := d.dir(id)
+	if hcsshim.IsTP4() {
+		// Import from TP4 format to maintain compatibility with existing images.
+		var tempFolder string
+		tempFolder, err = ioutil.TempDir("", "hcs")
+		if err != nil {
+			return
+		}
+		defer os.RemoveAll(tempFolder)
 
-	tempFolder := layerFolder + "-" + strconv.FormatUint(uint64(random.Rand.Uint32()), 10)
-	if err = os.MkdirAll(tempFolder, 0755); err != nil {
-		logrus.Errorf("Could not create %s %s", tempFolder, err)
+		if size, err = chrootarchive.ApplyLayer(tempFolder, layerData); err != nil {
+			return
+		}
+		if err = hcsshim.ImportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil {
+			return
+		}
 		return
 	}
-	defer func() {
-		_, folderName := filepath.Split(tempFolder)
-		if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil {
-			logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2)
-		}
-	}()
 
-	start := time.Now().UTC()
-	logrus.Debugf("Start untar layer")
-	if size, err = chrootarchive.ApplyLayer(tempFolder, layerData); err != nil {
+	var w hcsshim.LayerWriter
+	w, err = hcsshim.NewLayerWriter(d.info, id, parentLayerPaths)
+	if err != nil {
 		return
 	}
-	logrus.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
 
-	if err = hcsshim.ImportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil {
+	size, err = writeLayerFromTar(layerData, w)
+	if err != nil {
+		w.Close()
+		return
+	}
+	err = w.Close()
+	if err != nil {
 		return
 	}
-
 	return
 }
 
@@ -567,51 +731,78 @@ func (d *Driver) setLayerChain(id string, chain []string) error {
 	return nil
 }
 
+type fileGetCloserWithBackupPrivileges struct {
+	path string
+}
+
+func (fg *fileGetCloserWithBackupPrivileges) Get(filename string) (io.ReadCloser, error) {
+	var f *os.File
+	// Open the file while holding the Windows backup privilege. This ensures that the
+	// file can be opened even if the caller does not actually have access to it according
+	// to the security descriptor.
+	err := winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
+		path := filepath.Join(fg.path, filename)
+		p, err := syscall.UTF16FromString(path)
+		if err != nil {
+			return err
+		}
+		h, err := syscall.CreateFile(&p[0], syscall.GENERIC_READ, syscall.FILE_SHARE_READ, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
+		if err != nil {
+			return &os.PathError{Op: "open", Path: path, Err: err}
+		}
+		f = os.NewFile(uintptr(h), path)
+		return nil
+	})
+	return f, err
+}
+
+func (fg *fileGetCloserWithBackupPrivileges) Close() error {
+	return nil
+}
+
 type fileGetDestroyCloser struct {
 	storage.FileGetter
-	d          *Driver
-	folderName string
+	path string
 }
 
 func (f *fileGetDestroyCloser) Close() error {
 	// TODO: activate layers and release here?
-	return hcsshim.DestroyLayer(f.d.info, f.folderName)
+	return os.RemoveAll(f.path)
 }
 
 // DiffGetter returns a FileGetCloser that can read files from the directory that
 // contains files for the layer differences. Used for direct access for tar-split.
-func (d *Driver) DiffGetter(id string) (fg graphdriver.FileGetCloser, err error) {
-	id, err = d.resolveID(id)
+func (d *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) {
+	id, err := d.resolveID(id)
 	if err != nil {
-		return
-	}
-
-	// Getting the layer paths must be done outside of the lock.
-	layerChain, err := d.getLayerChain(id)
-	if err != nil {
-		return
+		return nil, err
 	}
 
-	layerFolder := d.dir(id)
-	tempFolder := layerFolder + "-" + strconv.FormatUint(uint64(random.Rand.Uint32()), 10)
-	if err = os.MkdirAll(tempFolder, 0755); err != nil {
-		logrus.Errorf("Could not create %s %s", tempFolder, err)
-		return
-	}
+	if hcsshim.IsTP4() {
+		// The export format for TP4 is different from the contents of the layer, so
+		// fall back to exporting the layer and getting file contents from there.
+		layerChain, err := d.getLayerChain(id)
+		if err != nil {
+			return nil, err
+		}
 
-	defer func() {
+		var tempFolder string
+		tempFolder, err = ioutil.TempDir("", "hcs")
 		if err != nil {
-			_, folderName := filepath.Split(tempFolder)
-			if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil {
-				logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2)
+			return nil, err
+		}
+		defer func() {
+			if err != nil {
+				os.RemoveAll(tempFolder)
 			}
+		}()
+
+		if err = hcsshim.ExportLayer(d.info, id, tempFolder, layerChain); err != nil {
+			return nil, err
 		}
-	}()
 
-	if err = hcsshim.ExportLayer(d.info, id, tempFolder, layerChain); err != nil {
-		return
+		return &fileGetDestroyCloser{storage.NewPathFileGetter(tempFolder), tempFolder}, nil
 	}
 
-	_, folderName := filepath.Split(tempFolder)
-	return &fileGetDestroyCloser{storage.NewPathFileGetter(tempFolder), d, folderName}, nil
+	return &fileGetCloserWithBackupPrivileges{d.dir(id)}, nil
 }

+ 2 - 2
hack/vendor.sh

@@ -7,7 +7,8 @@ source 'hack/.vendor-helpers.sh'
 
 # the following lines are in sorted order, FYI
 clone git github.com/Azure/go-ansiterm 70b2c90b260171e829f1ebd7c17f600c11858dbe
-clone git github.com/Microsoft/go-winio eb176a9831c54b88eaf9eb4fbc24b94080d910ad
+clone git github.com/Microsoft/hcsshim 9488dda5ab5d3c1af26e17d3d9fc2e9f29009a7b
+clone git github.com/Microsoft/go-winio c40bf24f405ab3cc8e1383542d474e813332de6d
 clone git github.com/Sirupsen/logrus v0.9.0 # logrus is a common dependency among multiple deps
 clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
 clone git github.com/go-check/check 11d3bc7aa68e238947792f30573146a3231fc0f1
@@ -16,7 +17,6 @@ clone git github.com/gorilla/mux e444e69cbd
 clone git github.com/kr/pty 5cf931ef8f
 clone git github.com/mattn/go-shellwords v1.0.0
 clone git github.com/mattn/go-sqlite3 v1.1.0
-clone git github.com/Microsoft/hcsshim 43858ef3c5c944dfaaabfbe8b6ea093da7f28dba
 clone git github.com/mistifyio/go-zfs v2.1.1
 clone git github.com/tchap/go-patricia v2.1.0
 clone git github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3

+ 27 - 0
vendor/src/github.com/Microsoft/go-winio/archive/tar/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2012 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 342 - 0
vendor/src/github.com/Microsoft/go-winio/archive/tar/common.go

@@ -0,0 +1,342 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tar implements access to tar archives.
+// It aims to cover most of the variations, including those produced
+// by GNU and BSD tars.
+//
+// References:
+//   http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
+//   http://www.gnu.org/software/tar/manual/html_node/Standard.html
+//   http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
+package tar
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"os"
+	"path"
+	"time"
+)
+
+const (
+	blockSize = 512
+
+	// Types
+	TypeReg           = '0'    // regular file
+	TypeRegA          = '\x00' // regular file
+	TypeLink          = '1'    // hard link
+	TypeSymlink       = '2'    // symbolic link
+	TypeChar          = '3'    // character device node
+	TypeBlock         = '4'    // block device node
+	TypeDir           = '5'    // directory
+	TypeFifo          = '6'    // fifo node
+	TypeCont          = '7'    // reserved
+	TypeXHeader       = 'x'    // extended header
+	TypeXGlobalHeader = 'g'    // global extended header
+	TypeGNULongName   = 'L'    // Next file has a long name
+	TypeGNULongLink   = 'K'    // Next file symlinks to a file w/ a long name
+	TypeGNUSparse     = 'S'    // sparse file
+)
+
+// A Header represents a single header in a tar archive.
+// Some fields may not be populated.
+type Header struct {
+	Name       string    // name of header file entry
+	Mode       int64     // permission and mode bits
+	Uid        int       // user id of owner
+	Gid        int       // group id of owner
+	Size       int64     // length in bytes
+	ModTime    time.Time // modified time
+	Typeflag   byte      // type of header entry
+	Linkname   string    // target name of link
+	Uname      string    // user name of owner
+	Gname      string    // group name of owner
+	Devmajor   int64     // major number of character or block device
+	Devminor   int64     // minor number of character or block device
+	AccessTime time.Time // access time
+	ChangeTime time.Time // status change time
+	Xattrs     map[string]string
+	Winheaders map[string]string
+}
+
+// File name constants from the tar spec.
+const (
+	fileNameSize       = 100 // Maximum number of bytes in a standard tar name.
+	fileNamePrefixSize = 155 // Maximum number of ustar extension bytes.
+)
+
+// FileInfo returns an os.FileInfo for the Header.
+func (h *Header) FileInfo() os.FileInfo {
+	return headerFileInfo{h}
+}
+
+// headerFileInfo implements os.FileInfo.
+type headerFileInfo struct {
+	h *Header
+}
+
+func (fi headerFileInfo) Size() int64        { return fi.h.Size }
+func (fi headerFileInfo) IsDir() bool        { return fi.Mode().IsDir() }
+func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
+func (fi headerFileInfo) Sys() interface{}   { return fi.h }
+
+// Name returns the base name of the file.
+func (fi headerFileInfo) Name() string {
+	if fi.IsDir() {
+		return path.Base(path.Clean(fi.h.Name))
+	}
+	return path.Base(fi.h.Name)
+}
+
+// Mode returns the permission and mode bits for the headerFileInfo.
+func (fi headerFileInfo) Mode() (mode os.FileMode) {
+	// Set file permission bits.
+	mode = os.FileMode(fi.h.Mode).Perm()
+
+	// Set setuid, setgid and sticky bits.
+	if fi.h.Mode&c_ISUID != 0 {
+		// setuid
+		mode |= os.ModeSetuid
+	}
+	if fi.h.Mode&c_ISGID != 0 {
+		// setgid
+		mode |= os.ModeSetgid
+	}
+	if fi.h.Mode&c_ISVTX != 0 {
+		// sticky
+		mode |= os.ModeSticky
+	}
+
+	// Set file mode bits.
+	// clear perm, setuid, setgid and sticky bits.
+	m := os.FileMode(fi.h.Mode) &^ 07777
+	if m == c_ISDIR {
+		// directory
+		mode |= os.ModeDir
+	}
+	if m == c_ISFIFO {
+		// named pipe (FIFO)
+		mode |= os.ModeNamedPipe
+	}
+	if m == c_ISLNK {
+		// symbolic link
+		mode |= os.ModeSymlink
+	}
+	if m == c_ISBLK {
+		// device file
+		mode |= os.ModeDevice
+	}
+	if m == c_ISCHR {
+		// Unix character device
+		mode |= os.ModeDevice
+		mode |= os.ModeCharDevice
+	}
+	if m == c_ISSOCK {
+		// Unix domain socket
+		mode |= os.ModeSocket
+	}
+
+	switch fi.h.Typeflag {
+	case TypeSymlink:
+		// symbolic link
+		mode |= os.ModeSymlink
+	case TypeChar:
+		// character device node
+		mode |= os.ModeDevice
+		mode |= os.ModeCharDevice
+	case TypeBlock:
+		// block device node
+		mode |= os.ModeDevice
+	case TypeDir:
+		// directory
+		mode |= os.ModeDir
+	case TypeFifo:
+		// fifo node
+		mode |= os.ModeNamedPipe
+	}
+
+	return mode
+}
+
+// sysStat, if non-nil, populates h from system-dependent fields of fi.
+var sysStat func(fi os.FileInfo, h *Header) error
+
+// Mode constants from the tar spec.
+const (
+	c_ISUID  = 04000   // Set uid
+	c_ISGID  = 02000   // Set gid
+	c_ISVTX  = 01000   // Save text (sticky bit)
+	c_ISDIR  = 040000  // Directory
+	c_ISFIFO = 010000  // FIFO
+	c_ISREG  = 0100000 // Regular file
+	c_ISLNK  = 0120000 // Symbolic link
+	c_ISBLK  = 060000  // Block special file
+	c_ISCHR  = 020000  // Character special file
+	c_ISSOCK = 0140000 // Socket
+)
+
+// Keywords for the PAX Extended Header
+const (
+	paxAtime    = "atime"
+	paxCharset  = "charset"
+	paxComment  = "comment"
+	paxCtime    = "ctime" // please note that ctime is not a valid pax header.
+	paxGid      = "gid"
+	paxGname    = "gname"
+	paxLinkpath = "linkpath"
+	paxMtime    = "mtime"
+	paxPath     = "path"
+	paxSize     = "size"
+	paxUid      = "uid"
+	paxUname    = "uname"
+	paxXattr    = "SCHILY.xattr."
+	paxWindows  = "MSWINDOWS."
+	paxNone     = ""
+)
+
+// FileInfoHeader creates a partially-populated Header from fi.
+// If fi describes a symlink, FileInfoHeader records link as the link target.
+// If fi describes a directory, a slash is appended to the name.
+// Because os.FileInfo's Name method returns only the base name of
+// the file it describes, it may be necessary to modify the Name field
+// of the returned header to provide the full path name of the file.
+func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
+	if fi == nil {
+		return nil, errors.New("tar: FileInfo is nil")
+	}
+	fm := fi.Mode()
+	h := &Header{
+		Name:    fi.Name(),
+		ModTime: fi.ModTime(),
+		Mode:    int64(fm.Perm()), // or'd with c_IS* constants later
+	}
+	switch {
+	case fm.IsRegular():
+		h.Mode |= c_ISREG
+		h.Typeflag = TypeReg
+		h.Size = fi.Size()
+	case fi.IsDir():
+		h.Typeflag = TypeDir
+		h.Mode |= c_ISDIR
+		h.Name += "/"
+	case fm&os.ModeSymlink != 0:
+		h.Typeflag = TypeSymlink
+		h.Mode |= c_ISLNK
+		h.Linkname = link
+	case fm&os.ModeDevice != 0:
+		if fm&os.ModeCharDevice != 0 {
+			h.Mode |= c_ISCHR
+			h.Typeflag = TypeChar
+		} else {
+			h.Mode |= c_ISBLK
+			h.Typeflag = TypeBlock
+		}
+	case fm&os.ModeNamedPipe != 0:
+		h.Typeflag = TypeFifo
+		h.Mode |= c_ISFIFO
+	case fm&os.ModeSocket != 0:
+		h.Mode |= c_ISSOCK
+	default:
+		return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
+	}
+	if fm&os.ModeSetuid != 0 {
+		h.Mode |= c_ISUID
+	}
+	if fm&os.ModeSetgid != 0 {
+		h.Mode |= c_ISGID
+	}
+	if fm&os.ModeSticky != 0 {
+		h.Mode |= c_ISVTX
+	}
+	// If possible, populate additional fields from OS-specific
+	// FileInfo fields.
+	if sys, ok := fi.Sys().(*Header); ok {
+		// This FileInfo came from a Header (not the OS). Use the
+		// original Header to populate all remaining fields.
+		h.Uid = sys.Uid
+		h.Gid = sys.Gid
+		h.Uname = sys.Uname
+		h.Gname = sys.Gname
+		h.AccessTime = sys.AccessTime
+		h.ChangeTime = sys.ChangeTime
+		if sys.Xattrs != nil {
+			h.Xattrs = make(map[string]string)
+			for k, v := range sys.Xattrs {
+				h.Xattrs[k] = v
+			}
+		}
+		if sys.Typeflag == TypeLink {
+			// hard link
+			h.Typeflag = TypeLink
+			h.Size = 0
+			h.Linkname = sys.Linkname
+		}
+	}
+	if sysStat != nil {
+		return h, sysStat(fi, h)
+	}
+	return h, nil
+}
+
+var zeroBlock = make([]byte, blockSize)
+
+// POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values.
+// We compute and return both.
+func checksum(header []byte) (unsigned int64, signed int64) {
+	for i := 0; i < len(header); i++ {
+		if i == 148 {
+			// The chksum field (header[148:156]) is special: it should be treated as space bytes.
+			unsigned += ' ' * 8
+			signed += ' ' * 8
+			i += 7
+			continue
+		}
+		unsigned += int64(header[i])
+		signed += int64(int8(header[i]))
+	}
+	return
+}
+
+type slicer []byte
+
+func (sp *slicer) next(n int) (b []byte) {
+	s := *sp
+	b, *sp = s[0:n], s[n:]
+	return
+}
+
+func isASCII(s string) bool {
+	for _, c := range s {
+		if c >= 0x80 {
+			return false
+		}
+	}
+	return true
+}
+
+func toASCII(s string) string {
+	if isASCII(s) {
+		return s
+	}
+	var buf bytes.Buffer
+	for _, c := range s {
+		if c < 0x80 {
+			buf.WriteByte(byte(c))
+		}
+	}
+	return buf.String()
+}
+
+// isHeaderOnlyType checks if the given type flag is of the type that has no
+// data section even if a size is specified.
+func isHeaderOnlyType(flag byte) bool {
+	switch flag {
+	case TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo:
+		return true
+	default:
+		return false
+	}
+}

+ 996 - 0
vendor/src/github.com/Microsoft/go-winio/archive/tar/reader.go

@@ -0,0 +1,996 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+// TODO(dsymonds):
+//   - pax extensions
+
+import (
+	"bytes"
+	"errors"
+	"io"
+	"io/ioutil"
+	"math"
+	"os"
+	"strconv"
+	"strings"
+	"time"
+)
+
+var (
+	ErrHeader = errors.New("archive/tar: invalid tar header")
+)
+
+const maxNanoSecondIntSize = 9
+
+// A Reader provides sequential access to the contents of a tar archive.
+// A tar archive consists of a sequence of files.
+// The Next method advances to the next file in the archive (including the first),
+// and then it can be treated as an io.Reader to access the file's data.
+type Reader struct {
+	r       io.Reader
+	err     error
+	pad     int64           // amount of padding (ignored) after current file entry
+	curr    numBytesReader  // reader for current file entry
+	hdrBuff [blockSize]byte // buffer to use in readHeader
+}
+
+type parser struct {
+	err error // Last error seen
+}
+
+// A numBytesReader is an io.Reader with a numBytes method, returning the number
+// of bytes remaining in the underlying encoded data.
+type numBytesReader interface {
+	io.Reader
+	numBytes() int64
+}
+
+// A regFileReader is a numBytesReader for reading file data from a tar archive.
+type regFileReader struct {
+	r  io.Reader // underlying reader
+	nb int64     // number of unread bytes for current file entry
+}
+
+// A sparseFileReader is a numBytesReader for reading sparse file data from a
+// tar archive.
+type sparseFileReader struct {
+	rfr   numBytesReader // Reads the sparse-encoded file data
+	sp    []sparseEntry  // The sparse map for the file
+	pos   int64          // Keeps track of file position
+	total int64          // Total size of the file
+}
+
+// A sparseEntry holds a single entry in a sparse file's sparse map.
+//
+// Sparse files are represented using a series of sparseEntrys.
+// Despite the name, a sparseEntry represents an actual data fragment that
+// references data found in the underlying archive stream. All regions not
+// covered by a sparseEntry are logically filled with zeros.
+//
+// For example, if the underlying raw file contains the 10-byte data:
+//	var compactData = "abcdefgh"
+//
+// And the sparse map has the following entries:
+//	var sp = []sparseEntry{
+//		{offset: 2,  numBytes: 5} // Data fragment for [2..7]
+//		{offset: 18, numBytes: 3} // Data fragment for [18..21]
+//	}
+//
+// Then the content of the resulting sparse file with a "real" size of 25 is:
+//	var sparseData = "\x00"*2 + "abcde" + "\x00"*11 + "fgh" + "\x00"*4
+type sparseEntry struct {
+	offset   int64 // Starting position of the fragment
+	numBytes int64 // Length of the fragment
+}
+
+// Keywords for GNU sparse files in a PAX extended header
+const (
+	paxGNUSparseNumBlocks = "GNU.sparse.numblocks"
+	paxGNUSparseOffset    = "GNU.sparse.offset"
+	paxGNUSparseNumBytes  = "GNU.sparse.numbytes"
+	paxGNUSparseMap       = "GNU.sparse.map"
+	paxGNUSparseName      = "GNU.sparse.name"
+	paxGNUSparseMajor     = "GNU.sparse.major"
+	paxGNUSparseMinor     = "GNU.sparse.minor"
+	paxGNUSparseSize      = "GNU.sparse.size"
+	paxGNUSparseRealSize  = "GNU.sparse.realsize"
+)
+
+// Keywords for old GNU sparse headers
+const (
+	oldGNUSparseMainHeaderOffset               = 386
+	oldGNUSparseMainHeaderIsExtendedOffset     = 482
+	oldGNUSparseMainHeaderNumEntries           = 4
+	oldGNUSparseExtendedHeaderIsExtendedOffset = 504
+	oldGNUSparseExtendedHeaderNumEntries       = 21
+	oldGNUSparseOffsetSize                     = 12
+	oldGNUSparseNumBytesSize                   = 12
+)
+
+// NewReader creates a new Reader reading from r.
+func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
+
+// Next advances to the next entry in the tar archive.
+//
+// io.EOF is returned at the end of the input.
+func (tr *Reader) Next() (*Header, error) {
+	if tr.err != nil {
+		return nil, tr.err
+	}
+
+	var hdr *Header
+	var extHdrs map[string]string
+
+	// Externally, Next iterates through the tar archive as if it is a series of
+	// files. Internally, the tar format often uses fake "files" to add meta
+	// data that describes the next file. These meta data "files" should not
+	// normally be visible to the outside. As such, this loop iterates through
+	// one or more "header files" until it finds a "normal file".
+loop:
+	for {
+		tr.err = tr.skipUnread()
+		if tr.err != nil {
+			return nil, tr.err
+		}
+
+		hdr = tr.readHeader()
+		if tr.err != nil {
+			return nil, tr.err
+		}
+
+		// Check for PAX/GNU special headers and files.
+		switch hdr.Typeflag {
+		case TypeXHeader:
+			extHdrs, tr.err = parsePAX(tr)
+			if tr.err != nil {
+				return nil, tr.err
+			}
+			continue loop // This is a meta header affecting the next header
+		case TypeGNULongName, TypeGNULongLink:
+			var realname []byte
+			realname, tr.err = ioutil.ReadAll(tr)
+			if tr.err != nil {
+				return nil, tr.err
+			}
+
+			// Convert GNU extensions to use PAX headers.
+			if extHdrs == nil {
+				extHdrs = make(map[string]string)
+			}
+			var p parser
+			switch hdr.Typeflag {
+			case TypeGNULongName:
+				extHdrs[paxPath] = p.parseString(realname)
+			case TypeGNULongLink:
+				extHdrs[paxLinkpath] = p.parseString(realname)
+			}
+			if p.err != nil {
+				tr.err = p.err
+				return nil, tr.err
+			}
+			continue loop // This is a meta header affecting the next header
+		default:
+			mergePAX(hdr, extHdrs)
+
+			// Check for a PAX format sparse file
+			sp, err := tr.checkForGNUSparsePAXHeaders(hdr, extHdrs)
+			if err != nil {
+				tr.err = err
+				return nil, err
+			}
+			if sp != nil {
+				// Current file is a PAX format GNU sparse file.
+				// Set the current file reader to a sparse file reader.
+				tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
+				if tr.err != nil {
+					return nil, tr.err
+				}
+			}
+			break loop // This is a file, so stop
+		}
+	}
+	return hdr, nil
+}
+
+// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then
+// this function reads the sparse map and returns it. Unknown sparse formats are ignored, causing the file to
+// be treated as a regular file.
+func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]string) ([]sparseEntry, error) {
+	var sparseFormat string
+
+	// Check for sparse format indicators
+	major, majorOk := headers[paxGNUSparseMajor]
+	minor, minorOk := headers[paxGNUSparseMinor]
+	sparseName, sparseNameOk := headers[paxGNUSparseName]
+	_, sparseMapOk := headers[paxGNUSparseMap]
+	sparseSize, sparseSizeOk := headers[paxGNUSparseSize]
+	sparseRealSize, sparseRealSizeOk := headers[paxGNUSparseRealSize]
+
+	// Identify which, if any, sparse format applies from which PAX headers are set
+	if majorOk && minorOk {
+		sparseFormat = major + "." + minor
+	} else if sparseNameOk && sparseMapOk {
+		sparseFormat = "0.1"
+	} else if sparseSizeOk {
+		sparseFormat = "0.0"
+	} else {
+		// Not a PAX format GNU sparse file.
+		return nil, nil
+	}
+
+	// Check for unknown sparse format
+	if sparseFormat != "0.0" && sparseFormat != "0.1" && sparseFormat != "1.0" {
+		return nil, nil
+	}
+
+	// Update hdr from GNU sparse PAX headers
+	if sparseNameOk {
+		hdr.Name = sparseName
+	}
+	if sparseSizeOk {
+		realSize, err := strconv.ParseInt(sparseSize, 10, 0)
+		if err != nil {
+			return nil, ErrHeader
+		}
+		hdr.Size = realSize
+	} else if sparseRealSizeOk {
+		realSize, err := strconv.ParseInt(sparseRealSize, 10, 0)
+		if err != nil {
+			return nil, ErrHeader
+		}
+		hdr.Size = realSize
+	}
+
+	// Set up the sparse map, according to the particular sparse format in use
+	var sp []sparseEntry
+	var err error
+	switch sparseFormat {
+	case "0.0", "0.1":
+		sp, err = readGNUSparseMap0x1(headers)
+	case "1.0":
+		sp, err = readGNUSparseMap1x0(tr.curr)
+	}
+	return sp, err
+}
+
+// mergePAX merges well known headers according to PAX standard.
+// In general headers with the same name as those found
+// in the header struct overwrite those found in the header
+// struct with higher precision or longer values. Esp. useful
+// for name and linkname fields.
+func mergePAX(hdr *Header, headers map[string]string) error {
+	for k, v := range headers {
+		switch k {
+		case paxPath:
+			hdr.Name = v
+		case paxLinkpath:
+			hdr.Linkname = v
+		case paxGname:
+			hdr.Gname = v
+		case paxUname:
+			hdr.Uname = v
+		case paxUid:
+			uid, err := strconv.ParseInt(v, 10, 0)
+			if err != nil {
+				return err
+			}
+			hdr.Uid = int(uid)
+		case paxGid:
+			gid, err := strconv.ParseInt(v, 10, 0)
+			if err != nil {
+				return err
+			}
+			hdr.Gid = int(gid)
+		case paxAtime:
+			t, err := parsePAXTime(v)
+			if err != nil {
+				return err
+			}
+			hdr.AccessTime = t
+		case paxMtime:
+			t, err := parsePAXTime(v)
+			if err != nil {
+				return err
+			}
+			hdr.ModTime = t
+		case paxCtime:
+			t, err := parsePAXTime(v)
+			if err != nil {
+				return err
+			}
+			hdr.ChangeTime = t
+		case paxSize:
+			size, err := strconv.ParseInt(v, 10, 0)
+			if err != nil {
+				return err
+			}
+			hdr.Size = int64(size)
+		default:
+			if strings.HasPrefix(k, paxXattr) {
+				if hdr.Xattrs == nil {
+					hdr.Xattrs = make(map[string]string)
+				}
+				hdr.Xattrs[k[len(paxXattr):]] = v
+			} else if strings.HasPrefix(k, paxWindows) {
+				if hdr.Winheaders == nil {
+					hdr.Winheaders = make(map[string]string)
+				}
+				hdr.Winheaders[k[len(paxWindows):]] = v
+			}
+		}
+	}
+	return nil
+}
+
+// parsePAXTime takes a string of the form %d.%d as described in
+// the PAX specification.
+func parsePAXTime(t string) (time.Time, error) {
+	buf := []byte(t)
+	pos := bytes.IndexByte(buf, '.')
+	var seconds, nanoseconds int64
+	var err error
+	if pos == -1 {
+		seconds, err = strconv.ParseInt(t, 10, 0)
+		if err != nil {
+			return time.Time{}, err
+		}
+	} else {
+		seconds, err = strconv.ParseInt(string(buf[:pos]), 10, 0)
+		if err != nil {
+			return time.Time{}, err
+		}
+		nano_buf := string(buf[pos+1:])
+		// Pad as needed before converting to a decimal.
+		// For example .030 -> .030000000 -> 30000000 nanoseconds
+		if len(nano_buf) < maxNanoSecondIntSize {
+			// Right pad
+			nano_buf += strings.Repeat("0", maxNanoSecondIntSize-len(nano_buf))
+		} else if len(nano_buf) > maxNanoSecondIntSize {
+			// Right truncate
+			nano_buf = nano_buf[:maxNanoSecondIntSize]
+		}
+		nanoseconds, err = strconv.ParseInt(string(nano_buf), 10, 0)
+		if err != nil {
+			return time.Time{}, err
+		}
+	}
+	ts := time.Unix(seconds, nanoseconds)
+	return ts, nil
+}
+
+// parsePAX parses PAX headers.
+// If an extended header (type 'x') is invalid, ErrHeader is returned
+func parsePAX(r io.Reader) (map[string]string, error) {
+	buf, err := ioutil.ReadAll(r)
+	if err != nil {
+		return nil, err
+	}
+	sbuf := string(buf)
+
+	// For GNU PAX sparse format 0.0 support.
+	// This function transforms the sparse format 0.0 headers into sparse format 0.1 headers.
+	var sparseMap bytes.Buffer
+
+	headers := make(map[string]string)
+	// Each record is constructed as
+	//     "%d %s=%s\n", length, keyword, value
+	for len(sbuf) > 0 {
+		key, value, residual, err := parsePAXRecord(sbuf)
+		if err != nil {
+			return nil, ErrHeader
+		}
+		sbuf = residual
+
+		keyStr := string(key)
+		if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes {
+			// GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map.
+			sparseMap.WriteString(value)
+			sparseMap.Write([]byte{','})
+		} else {
+			// Normal key. Set the value in the headers map.
+			headers[keyStr] = string(value)
+		}
+	}
+	if sparseMap.Len() != 0 {
+		// Add sparse info to headers, chopping off the extra comma
+		sparseMap.Truncate(sparseMap.Len() - 1)
+		headers[paxGNUSparseMap] = sparseMap.String()
+	}
+	return headers, nil
+}
+
+// parsePAXRecord parses the input PAX record string into a key-value pair.
+// If parsing is successful, it will slice off the currently read record and
+// return the remainder as r.
+//
+// A PAX record is of the following form:
+//	"%d %s=%s\n" % (size, key, value)
+func parsePAXRecord(s string) (k, v, r string, err error) {
+	// The size field ends at the first space.
+	sp := strings.IndexByte(s, ' ')
+	if sp == -1 {
+		return "", "", s, ErrHeader
+	}
+
+	// Parse the first token as a decimal integer.
+	n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
+	if perr != nil || n < 5 || int64(len(s)) < n {
+		return "", "", s, ErrHeader
+	}
+
+	// Extract everything between the space and the final newline.
+	rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
+	if nl != "\n" {
+		return "", "", s, ErrHeader
+	}
+
+	// The first equals separates the key from the value.
+	eq := strings.IndexByte(rec, '=')
+	if eq == -1 {
+		return "", "", s, ErrHeader
+	}
+	return rec[:eq], rec[eq+1:], rem, nil
+}
+
+// parseString parses bytes as a NUL-terminated C-style string.
+// If a NUL byte is not found then the whole slice is returned as a string.
+func (*parser) parseString(b []byte) string {
+	n := 0
+	for n < len(b) && b[n] != 0 {
+		n++
+	}
+	return string(b[0:n])
+}
+
+// parseNumeric parses the input as being encoded in either base-256 or octal.
+// This function may return negative numbers.
+// If parsing fails or an integer overflow occurs, err will be set.
+func (p *parser) parseNumeric(b []byte) int64 {
+	// Check for base-256 (binary) format first.
+	// If the first bit is set, then all following bits constitute a two's
+	// complement encoded number in big-endian byte order.
+	if len(b) > 0 && b[0]&0x80 != 0 {
+		// Handling negative numbers relies on the following identity:
+		//	-a-1 == ^a
+		//
+		// If the number is negative, we use an inversion mask to invert the
+		// data bytes and treat the value as an unsigned number.
+		var inv byte // 0x00 if positive or zero, 0xff if negative
+		if b[0]&0x40 != 0 {
+			inv = 0xff
+		}
+
+		var x uint64
+		for i, c := range b {
+			c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing
+			if i == 0 {
+				c &= 0x7f // Ignore signal bit in first byte
+			}
+			if (x >> 56) > 0 {
+				p.err = ErrHeader // Integer overflow
+				return 0
+			}
+			x = x<<8 | uint64(c)
+		}
+		if (x >> 63) > 0 {
+			p.err = ErrHeader // Integer overflow
+			return 0
+		}
+		if inv == 0xff {
+			return ^int64(x)
+		}
+		return int64(x)
+	}
+
+	// Normal case is base-8 (octal) format.
+	return p.parseOctal(b)
+}
+
+func (p *parser) parseOctal(b []byte) int64 {
+	// Because unused fields are filled with NULs, we need
+	// to skip leading NULs. Fields may also be padded with
+	// spaces or NULs.
+	// So we remove leading and trailing NULs and spaces to
+	// be sure.
+	b = bytes.Trim(b, " \x00")
+
+	if len(b) == 0 {
+		return 0
+	}
+	x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
+	if perr != nil {
+		p.err = ErrHeader
+	}
+	return int64(x)
+}
+
+// skipUnread skips any unread bytes in the existing file entry, as well as any
+// alignment padding. It returns io.ErrUnexpectedEOF if any io.EOF is
+// encountered in the data portion; it is okay to hit io.EOF in the padding.
+//
+// Note that this function still works properly even when sparse files are being
+// used since numBytes returns the bytes remaining in the underlying io.Reader.
+func (tr *Reader) skipUnread() error {
+	dataSkip := tr.numBytes()      // Number of data bytes to skip
+	totalSkip := dataSkip + tr.pad // Total number of bytes to skip
+	tr.curr, tr.pad = nil, 0
+
+	// If possible, Seek to the last byte before the end of the data section.
+	// Do this because Seek is often lazy about reporting errors; this will mask
+	// the fact that the tar stream may be truncated. We can rely on the
+	// io.CopyN done shortly afterwards to trigger any IO errors.
+	var seekSkipped int64 // Number of bytes skipped via Seek
+	if sr, ok := tr.r.(io.Seeker); ok && dataSkip > 1 {
+		// Not all io.Seeker can actually Seek. For example, os.Stdin implements
+		// io.Seeker, but calling Seek always returns an error and performs
+		// no action. Thus, we try an innocent seek to the current position
+		// to see if Seek is really supported.
+		pos1, err := sr.Seek(0, os.SEEK_CUR)
+		if err == nil {
+			// Seek seems supported, so perform the real Seek.
+			pos2, err := sr.Seek(dataSkip-1, os.SEEK_CUR)
+			if err != nil {
+				tr.err = err
+				return tr.err
+			}
+			seekSkipped = pos2 - pos1
+		}
+	}
+
+	var copySkipped int64 // Number of bytes skipped via CopyN
+	copySkipped, tr.err = io.CopyN(ioutil.Discard, tr.r, totalSkip-seekSkipped)
+	if tr.err == io.EOF && seekSkipped+copySkipped < dataSkip {
+		tr.err = io.ErrUnexpectedEOF
+	}
+	return tr.err
+}
+
+func (tr *Reader) verifyChecksum(header []byte) bool {
+	if tr.err != nil {
+		return false
+	}
+
+	var p parser
+	given := p.parseOctal(header[148:156])
+	unsigned, signed := checksum(header)
+	return p.err == nil && (given == unsigned || given == signed)
+}
+
+// readHeader reads the next block header and assumes that the underlying reader
+// is already aligned to a block boundary.
+//
+// The err will be set to io.EOF only when one of the following occurs:
+//	* Exactly 0 bytes are read and EOF is hit.
+//	* Exactly 1 block of zeros is read and EOF is hit.
+//	* At least 2 blocks of zeros are read.
+func (tr *Reader) readHeader() *Header {
+	header := tr.hdrBuff[:]
+	copy(header, zeroBlock)
+
+	if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
+		return nil // io.EOF is okay here
+	}
+
+	// Two blocks of zero bytes marks the end of the archive.
+	if bytes.Equal(header, zeroBlock[0:blockSize]) {
+		if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
+			return nil // io.EOF is okay here
+		}
+		if bytes.Equal(header, zeroBlock[0:blockSize]) {
+			tr.err = io.EOF
+		} else {
+			tr.err = ErrHeader // zero block and then non-zero block
+		}
+		return nil
+	}
+
+	if !tr.verifyChecksum(header) {
+		tr.err = ErrHeader
+		return nil
+	}
+
+	// Unpack
+	var p parser
+	hdr := new(Header)
+	s := slicer(header)
+
+	hdr.Name = p.parseString(s.next(100))
+	hdr.Mode = p.parseNumeric(s.next(8))
+	hdr.Uid = int(p.parseNumeric(s.next(8)))
+	hdr.Gid = int(p.parseNumeric(s.next(8)))
+	hdr.Size = p.parseNumeric(s.next(12))
+	hdr.ModTime = time.Unix(p.parseNumeric(s.next(12)), 0)
+	s.next(8) // chksum
+	hdr.Typeflag = s.next(1)[0]
+	hdr.Linkname = p.parseString(s.next(100))
+
+	// The remainder of the header depends on the value of magic.
+	// The original (v7) version of tar had no explicit magic field,
+	// so its magic bytes, like the rest of the block, are NULs.
+	magic := string(s.next(8)) // contains version field as well.
+	var format string
+	switch {
+	case magic[:6] == "ustar\x00": // POSIX tar (1003.1-1988)
+		if string(header[508:512]) == "tar\x00" {
+			format = "star"
+		} else {
+			format = "posix"
+		}
+	case magic == "ustar  \x00": // old GNU tar
+		format = "gnu"
+	}
+
+	switch format {
+	case "posix", "gnu", "star":
+		hdr.Uname = p.parseString(s.next(32))
+		hdr.Gname = p.parseString(s.next(32))
+		devmajor := s.next(8)
+		devminor := s.next(8)
+		if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
+			hdr.Devmajor = p.parseNumeric(devmajor)
+			hdr.Devminor = p.parseNumeric(devminor)
+		}
+		var prefix string
+		switch format {
+		case "posix", "gnu":
+			prefix = p.parseString(s.next(155))
+		case "star":
+			prefix = p.parseString(s.next(131))
+			hdr.AccessTime = time.Unix(p.parseNumeric(s.next(12)), 0)
+			hdr.ChangeTime = time.Unix(p.parseNumeric(s.next(12)), 0)
+		}
+		if len(prefix) > 0 {
+			hdr.Name = prefix + "/" + hdr.Name
+		}
+	}
+
+	if p.err != nil {
+		tr.err = p.err
+		return nil
+	}
+
+	nb := hdr.Size
+	if isHeaderOnlyType(hdr.Typeflag) {
+		nb = 0
+	}
+	if nb < 0 {
+		tr.err = ErrHeader
+		return nil
+	}
+
+	// Set the current file reader.
+	tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
+	tr.curr = &regFileReader{r: tr.r, nb: nb}
+
+	// Check for old GNU sparse format entry.
+	if hdr.Typeflag == TypeGNUSparse {
+		// Get the real size of the file.
+		hdr.Size = p.parseNumeric(header[483:495])
+		if p.err != nil {
+			tr.err = p.err
+			return nil
+		}
+
+		// Read the sparse map.
+		sp := tr.readOldGNUSparseMap(header)
+		if tr.err != nil {
+			return nil
+		}
+
+		// Current file is a GNU sparse file. Update the current file reader.
+		tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
+		if tr.err != nil {
+			return nil
+		}
+	}
+
+	return hdr
+}
+
+// readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format.
+// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
+// then one or more extension headers are used to store the rest of the sparse map.
+func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
+	var p parser
+	isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0
+	spCap := oldGNUSparseMainHeaderNumEntries
+	if isExtended {
+		spCap += oldGNUSparseExtendedHeaderNumEntries
+	}
+	sp := make([]sparseEntry, 0, spCap)
+	s := slicer(header[oldGNUSparseMainHeaderOffset:])
+
+	// Read the four entries from the main tar header
+	for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ {
+		offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
+		numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
+		if p.err != nil {
+			tr.err = p.err
+			return nil
+		}
+		if offset == 0 && numBytes == 0 {
+			break
+		}
+		sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+	}
+
+	for isExtended {
+		// There are more entries. Read an extension header and parse its entries.
+		sparseHeader := make([]byte, blockSize)
+		if _, tr.err = io.ReadFull(tr.r, sparseHeader); tr.err != nil {
+			return nil
+		}
+		isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0
+		s = slicer(sparseHeader)
+		for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ {
+			offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
+			numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
+			if p.err != nil {
+				tr.err = p.err
+				return nil
+			}
+			if offset == 0 && numBytes == 0 {
+				break
+			}
+			sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+		}
+	}
+	return sp
+}
+
+// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
+// version 1.0. The format of the sparse map consists of a series of
+// newline-terminated numeric fields. The first field is the number of entries
+// and is always present. Following this are the entries, consisting of two
+// fields (offset, numBytes). This function must stop reading at the end
+// boundary of the block containing the last newline.
+//
+// Note that the GNU manual says that numeric values should be encoded in octal
+// format. However, the GNU tar utility itself outputs these values in decimal.
+// As such, this library treats values as being encoded in decimal.
+func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) {
+	var cntNewline int64
+	var buf bytes.Buffer
+	var blk = make([]byte, blockSize)
+
+	// feedTokens copies data in numBlock chunks from r into buf until there are
+	// at least cnt newlines in buf. It will not read more blocks than needed.
+	var feedTokens = func(cnt int64) error {
+		for cntNewline < cnt {
+			if _, err := io.ReadFull(r, blk); err != nil {
+				if err == io.EOF {
+					err = io.ErrUnexpectedEOF
+				}
+				return err
+			}
+			buf.Write(blk)
+			for _, c := range blk {
+				if c == '\n' {
+					cntNewline++
+				}
+			}
+		}
+		return nil
+	}
+
+	// nextToken gets the next token delimited by a newline. This assumes that
+	// at least one newline exists in the buffer.
+	var nextToken = func() string {
+		cntNewline--
+		tok, _ := buf.ReadString('\n')
+		return tok[:len(tok)-1] // Cut off newline
+	}
+
+	// Parse for the number of entries.
+	// Use integer overflow resistant math to check this.
+	if err := feedTokens(1); err != nil {
+		return nil, err
+	}
+	numEntries, err := strconv.ParseInt(nextToken(), 10, 0) // Intentionally parse as native int
+	if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
+		return nil, ErrHeader
+	}
+
+	// Parse for all member entries.
+	// numEntries is trusted after this since a potential attacker must have
+	// committed resources proportional to what this library used.
+	if err := feedTokens(2 * numEntries); err != nil {
+		return nil, err
+	}
+	sp := make([]sparseEntry, 0, numEntries)
+	for i := int64(0); i < numEntries; i++ {
+		offset, err := strconv.ParseInt(nextToken(), 10, 64)
+		if err != nil {
+			return nil, ErrHeader
+		}
+		numBytes, err := strconv.ParseInt(nextToken(), 10, 64)
+		if err != nil {
+			return nil, ErrHeader
+		}
+		sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+	}
+	return sp, nil
+}
+
+// readGNUSparseMap0x1 reads the sparse map as stored in GNU's PAX sparse format
+// version 0.1. The sparse map is stored in the PAX headers.
+func readGNUSparseMap0x1(extHdrs map[string]string) ([]sparseEntry, error) {
+	// Get number of entries.
+	// Use integer overflow resistant math to check this.
+	numEntriesStr := extHdrs[paxGNUSparseNumBlocks]
+	numEntries, err := strconv.ParseInt(numEntriesStr, 10, 0) // Intentionally parse as native int
+	if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
+		return nil, ErrHeader
+	}
+
+	// There should be two numbers in sparseMap for each entry.
+	sparseMap := strings.Split(extHdrs[paxGNUSparseMap], ",")
+	if int64(len(sparseMap)) != 2*numEntries {
+		return nil, ErrHeader
+	}
+
+	// Loop through the entries in the sparse map.
+	// numEntries is trusted now.
+	sp := make([]sparseEntry, 0, numEntries)
+	for i := int64(0); i < numEntries; i++ {
+		offset, err := strconv.ParseInt(sparseMap[2*i], 10, 64)
+		if err != nil {
+			return nil, ErrHeader
+		}
+		numBytes, err := strconv.ParseInt(sparseMap[2*i+1], 10, 64)
+		if err != nil {
+			return nil, ErrHeader
+		}
+		sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+	}
+	return sp, nil
+}
+
+// numBytes returns the number of bytes left to read in the current file's entry
+// in the tar archive, or 0 if there is no current file.
+func (tr *Reader) numBytes() int64 {
+	if tr.curr == nil {
+		// No current file, so no bytes
+		return 0
+	}
+	return tr.curr.numBytes()
+}
+
+// Read reads from the current entry in the tar archive.
+// It returns 0, io.EOF when it reaches the end of that entry,
+// until Next is called to advance to the next entry.
+//
+// Calling Read on special types like TypeLink, TypeSymLink, TypeChar,
+// TypeBlock, TypeDir, and TypeFifo returns 0, io.EOF regardless of what
+// the Header.Size claims.
+func (tr *Reader) Read(b []byte) (n int, err error) {
+	if tr.err != nil {
+		return 0, tr.err
+	}
+	if tr.curr == nil {
+		return 0, io.EOF
+	}
+
+	n, err = tr.curr.Read(b)
+	if err != nil && err != io.EOF {
+		tr.err = err
+	}
+	return
+}
+
+func (rfr *regFileReader) Read(b []byte) (n int, err error) {
+	if rfr.nb == 0 {
+		// file consumed
+		return 0, io.EOF
+	}
+	if int64(len(b)) > rfr.nb {
+		b = b[0:rfr.nb]
+	}
+	n, err = rfr.r.Read(b)
+	rfr.nb -= int64(n)
+
+	if err == io.EOF && rfr.nb > 0 {
+		err = io.ErrUnexpectedEOF
+	}
+	return
+}
+
+// numBytes returns the number of bytes left to read in the file's data in the tar archive.
+func (rfr *regFileReader) numBytes() int64 {
+	return rfr.nb
+}
+
+// newSparseFileReader creates a new sparseFileReader, but validates all of the
+// sparse entries before doing so.
+func newSparseFileReader(rfr numBytesReader, sp []sparseEntry, total int64) (*sparseFileReader, error) {
+	if total < 0 {
+		return nil, ErrHeader // Total size cannot be negative
+	}
+
+	// Validate all sparse entries. These are the same checks as performed by
+	// the BSD tar utility.
+	for i, s := range sp {
+		switch {
+		case s.offset < 0 || s.numBytes < 0:
+			return nil, ErrHeader // Negative values are never okay
+		case s.offset > math.MaxInt64-s.numBytes:
+			return nil, ErrHeader // Integer overflow with large length
+		case s.offset+s.numBytes > total:
+			return nil, ErrHeader // Region extends beyond the "real" size
+		case i > 0 && sp[i-1].offset+sp[i-1].numBytes > s.offset:
+			return nil, ErrHeader // Regions can't overlap and must be in order
+		}
+	}
+	return &sparseFileReader{rfr: rfr, sp: sp, total: total}, nil
+}
+
+// readHole reads a sparse hole ending at endOffset.
+func (sfr *sparseFileReader) readHole(b []byte, endOffset int64) int {
+	n64 := endOffset - sfr.pos
+	if n64 > int64(len(b)) {
+		n64 = int64(len(b))
+	}
+	n := int(n64)
+	for i := 0; i < n; i++ {
+		b[i] = 0
+	}
+	sfr.pos += n64
+	return n
+}
+
+// Read reads the sparse file data in expanded form.
+func (sfr *sparseFileReader) Read(b []byte) (n int, err error) {
+	// Skip past all empty fragments.
+	for len(sfr.sp) > 0 && sfr.sp[0].numBytes == 0 {
+		sfr.sp = sfr.sp[1:]
+	}
+
+	// If there are no more fragments, then it is possible that there
+	// is one last sparse hole.
+	if len(sfr.sp) == 0 {
+		// This behavior matches the BSD tar utility.
+		// However, GNU tar stops returning data even if sfr.total is unmet.
+		if sfr.pos < sfr.total {
+			return sfr.readHole(b, sfr.total), nil
+		}
+		return 0, io.EOF
+	}
+
+	// In front of a data fragment, so read a hole.
+	if sfr.pos < sfr.sp[0].offset {
+		return sfr.readHole(b, sfr.sp[0].offset), nil
+	}
+
+	// In a data fragment, so read from it.
+	// This math is overflow free since we verify that offset and numBytes can
+	// be safely added when creating the sparseFileReader.
+	endPos := sfr.sp[0].offset + sfr.sp[0].numBytes // End offset of fragment
+	bytesLeft := endPos - sfr.pos                   // Bytes left in fragment
+	if int64(len(b)) > bytesLeft {
+		b = b[:bytesLeft]
+	}
+
+	n, err = sfr.rfr.Read(b)
+	sfr.pos += int64(n)
+	if err == io.EOF {
+		if sfr.pos < endPos {
+			err = io.ErrUnexpectedEOF // There was supposed to be more data
+		} else if sfr.pos < sfr.total {
+			err = nil // There is still an implicit sparse hole at the end
+		}
+	}
+
+	if sfr.pos == endPos {
+		sfr.sp = sfr.sp[1:] // We are done with this fragment, so pop it
+	}
+	return n, err
+}
+
+// numBytes returns the number of bytes left to read in the sparse file's
+// sparse-encoded data in the tar archive.
+func (sfr *sparseFileReader) numBytes() int64 {
+	return sfr.rfr.numBytes()
+}

+ 20 - 0
vendor/src/github.com/Microsoft/go-winio/archive/tar/stat_atim.go

@@ -0,0 +1,20 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux dragonfly openbsd solaris
+
+package tar
+
+import (
+	"syscall"
+	"time"
+)
+
+func statAtime(st *syscall.Stat_t) time.Time {
+	return time.Unix(st.Atim.Unix())
+}
+
+func statCtime(st *syscall.Stat_t) time.Time {
+	return time.Unix(st.Ctim.Unix())
+}

+ 20 - 0
vendor/src/github.com/Microsoft/go-winio/archive/tar/stat_atimespec.go

@@ -0,0 +1,20 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin freebsd netbsd
+
+package tar
+
+import (
+	"syscall"
+	"time"
+)
+
+func statAtime(st *syscall.Stat_t) time.Time {
+	return time.Unix(st.Atimespec.Unix())
+}
+
+func statCtime(st *syscall.Stat_t) time.Time {
+	return time.Unix(st.Ctimespec.Unix())
+}

+ 32 - 0
vendor/src/github.com/Microsoft/go-winio/archive/tar/stat_unix.go

@@ -0,0 +1,32 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux darwin dragonfly freebsd openbsd netbsd solaris
+
+package tar
+
+import (
+	"os"
+	"syscall"
+)
+
+func init() {
+	sysStat = statUnix
+}
+
+func statUnix(fi os.FileInfo, h *Header) error {
+	sys, ok := fi.Sys().(*syscall.Stat_t)
+	if !ok {
+		return nil
+	}
+	h.Uid = int(sys.Uid)
+	h.Gid = int(sys.Gid)
+	// TODO(bradfitz): populate username & group.  os/user
+	// doesn't cache LookupId lookups, and lacks group
+	// lookup functions.
+	h.AccessTime = statAtime(sys)
+	h.ChangeTime = statCtime(sys)
+	// TODO(bradfitz): major/minor device numbers?
+	return nil
+}

+ 419 - 0
vendor/src/github.com/Microsoft/go-winio/archive/tar/writer.go

@@ -0,0 +1,419 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+// TODO(dsymonds):
+// - catch more errors (no first header, etc.)
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"io"
+	"path"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+)
+
+var (
+	ErrWriteTooLong    = errors.New("archive/tar: write too long")
+	ErrFieldTooLong    = errors.New("archive/tar: header field too long")
+	ErrWriteAfterClose = errors.New("archive/tar: write after close")
+	errInvalidHeader   = errors.New("archive/tar: header field too long or contains invalid values")
+)
+
+// A Writer provides sequential writing of a tar archive in POSIX.1 format.
+// A tar archive consists of a sequence of files.
+// Call WriteHeader to begin a new file, and then call Write to supply that file's data,
+// writing at most hdr.Size bytes in total.
+type Writer struct {
+	w          io.Writer
+	err        error
+	nb         int64 // number of unwritten bytes for current file entry
+	pad        int64 // amount of padding to write after current file entry
+	closed     bool
+	usedBinary bool            // whether the binary numeric field extension was used
+	preferPax  bool            // use pax header instead of binary numeric header
+	hdrBuff    [blockSize]byte // buffer to use in writeHeader when writing a regular header
+	paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header
+}
+
+type formatter struct {
+	err error // Last error seen
+}
+
+// NewWriter creates a new Writer writing to w.
+func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
+
+// Flush finishes writing the current file (optional).
+func (tw *Writer) Flush() error {
+	if tw.nb > 0 {
+		tw.err = fmt.Errorf("archive/tar: missed writing %d bytes", tw.nb)
+		return tw.err
+	}
+
+	n := tw.nb + tw.pad
+	for n > 0 && tw.err == nil {
+		nr := n
+		if nr > blockSize {
+			nr = blockSize
+		}
+		var nw int
+		nw, tw.err = tw.w.Write(zeroBlock[0:nr])
+		n -= int64(nw)
+	}
+	tw.nb = 0
+	tw.pad = 0
+	return tw.err
+}
+
+// Write s into b, terminating it with a NUL if there is room.
+func (f *formatter) formatString(b []byte, s string) {
+	if len(s) > len(b) {
+		f.err = ErrFieldTooLong
+		return
+	}
+	ascii := toASCII(s)
+	copy(b, ascii)
+	if len(ascii) < len(b) {
+		b[len(ascii)] = 0
+	}
+}
+
+// Encode x as an octal ASCII string and write it into b with leading zeros.
+func (f *formatter) formatOctal(b []byte, x int64) {
+	s := strconv.FormatInt(x, 8)
+	// leading zeros, but leave room for a NUL.
+	for len(s)+1 < len(b) {
+		s = "0" + s
+	}
+	f.formatString(b, s)
+}
+
+// fitsInBase256 reports whether x can be encoded into n bytes using base-256
+// encoding. Unlike octal encoding, base-256 encoding does not require that the
+// string ends with a NUL character. Thus, all n bytes are available for output.
+//
+// If operating in binary mode, this assumes strict GNU binary mode; which means
+// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
+// equivalent to the sign bit in two's complement form.
+func fitsInBase256(n int, x int64) bool {
+	var binBits = uint(n-1) * 8
+	return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
+}
+
+// Write x into b, as binary (GNUtar/star extension).
+func (f *formatter) formatNumeric(b []byte, x int64) {
+	if fitsInBase256(len(b), x) {
+		for i := len(b) - 1; i >= 0; i-- {
+			b[i] = byte(x)
+			x >>= 8
+		}
+		b[0] |= 0x80 // Highest bit indicates binary format
+		return
+	}
+
+	f.formatOctal(b, 0) // Last resort, just write zero
+	f.err = ErrFieldTooLong
+}
+
+var (
+	minTime = time.Unix(0, 0)
+	// There is room for 11 octal digits (33 bits) of mtime.
+	maxTime = minTime.Add((1<<33 - 1) * time.Second)
+)
+
+// WriteHeader writes hdr and prepares to accept the file's contents.
+// WriteHeader calls Flush if it is not the first header.
+// Calling after a Close will return ErrWriteAfterClose.
+func (tw *Writer) WriteHeader(hdr *Header) error {
+	return tw.writeHeader(hdr, true)
+}
+
+// WriteHeader writes hdr and prepares to accept the file's contents.
+// WriteHeader calls Flush if it is not the first header.
+// Calling after a Close will return ErrWriteAfterClose.
+// As this method is called internally by writePax header to allow it to
+// suppress writing the pax header.
+func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
+	if tw.closed {
+		return ErrWriteAfterClose
+	}
+	if tw.err == nil {
+		tw.Flush()
+	}
+	if tw.err != nil {
+		return tw.err
+	}
+
+	// a map to hold pax header records, if any are needed
+	paxHeaders := make(map[string]string)
+
+	// TODO(shanemhansen): we might want to use PAX headers for
+	// subsecond time resolution, but for now let's just capture
+	// too long fields or non ascii characters
+
+	var f formatter
+	var header []byte
+
+	// We need to select which scratch buffer to use carefully,
+	// since this method is called recursively to write PAX headers.
+	// If allowPax is true, this is the non-recursive call, and we will use hdrBuff.
+	// If allowPax is false, we are being called by writePAXHeader, and hdrBuff is
+	// already being used by the non-recursive call, so we must use paxHdrBuff.
+	header = tw.hdrBuff[:]
+	if !allowPax {
+		header = tw.paxHdrBuff[:]
+	}
+	copy(header, zeroBlock)
+	s := slicer(header)
+
+	// Wrappers around formatter that automatically sets paxHeaders if the
+	// argument extends beyond the capacity of the input byte slice.
+	var formatString = func(b []byte, s string, paxKeyword string) {
+		needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s)
+		if needsPaxHeader {
+			paxHeaders[paxKeyword] = s
+			return
+		}
+		f.formatString(b, s)
+	}
+	var formatNumeric = func(b []byte, x int64, paxKeyword string) {
+		// Try octal first.
+		s := strconv.FormatInt(x, 8)
+		if len(s) < len(b) {
+			f.formatOctal(b, x)
+			return
+		}
+
+		// If it is too long for octal, and PAX is preferred, use a PAX header.
+		if paxKeyword != paxNone && tw.preferPax {
+			f.formatOctal(b, 0)
+			s := strconv.FormatInt(x, 10)
+			paxHeaders[paxKeyword] = s
+			return
+		}
+
+		tw.usedBinary = true
+		f.formatNumeric(b, x)
+	}
+
+	// keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
+	pathHeaderBytes := s.next(fileNameSize)
+
+	formatString(pathHeaderBytes, hdr.Name, paxPath)
+
+	// Handle out of range ModTime carefully.
+	var modTime int64
+	if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) {
+		modTime = hdr.ModTime.Unix()
+	}
+
+	f.formatOctal(s.next(8), hdr.Mode)               // 100:108
+	formatNumeric(s.next(8), int64(hdr.Uid), paxUid) // 108:116
+	formatNumeric(s.next(8), int64(hdr.Gid), paxGid) // 116:124
+	formatNumeric(s.next(12), hdr.Size, paxSize)     // 124:136
+	formatNumeric(s.next(12), modTime, paxNone)      // 136:148 --- consider using pax for finer granularity
+	s.next(8)                                        // chksum (148:156)
+	s.next(1)[0] = hdr.Typeflag                      // 156:157
+
+	formatString(s.next(100), hdr.Linkname, paxLinkpath)
+
+	copy(s.next(8), []byte("ustar\x0000"))          // 257:265
+	formatString(s.next(32), hdr.Uname, paxUname)   // 265:297
+	formatString(s.next(32), hdr.Gname, paxGname)   // 297:329
+	formatNumeric(s.next(8), hdr.Devmajor, paxNone) // 329:337
+	formatNumeric(s.next(8), hdr.Devminor, paxNone) // 337:345
+
+	// keep a reference to the prefix to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
+	prefixHeaderBytes := s.next(155)
+	formatString(prefixHeaderBytes, "", paxNone) // 345:500  prefix
+
+	// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
+	if tw.usedBinary {
+		copy(header[257:265], []byte("ustar  \x00"))
+	}
+
+	_, paxPathUsed := paxHeaders[paxPath]
+	// try to use a ustar header when only the name is too long
+	if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
+		prefix, suffix, ok := splitUSTARPath(hdr.Name)
+		if ok {
+			// Since we can encode in USTAR format, disable PAX header.
+			delete(paxHeaders, paxPath)
+
+			// Update the path fields
+			formatString(pathHeaderBytes, suffix, paxNone)
+			formatString(prefixHeaderBytes, prefix, paxNone)
+		}
+	}
+
+	// The chksum field is terminated by a NUL and a space.
+	// This is different from the other octal fields.
+	chksum, _ := checksum(header)
+	f.formatOctal(header[148:155], chksum) // Never fails
+	header[155] = ' '
+
+	// Check if there were any formatting errors.
+	if f.err != nil {
+		tw.err = f.err
+		return tw.err
+	}
+
+	if allowPax {
+		for k, v := range hdr.Xattrs {
+			paxHeaders[paxXattr+k] = v
+		}
+		for k, v := range hdr.Winheaders {
+			paxHeaders[paxWindows+k] = v
+		}
+	}
+
+	if len(paxHeaders) > 0 {
+		if !allowPax {
+			return errInvalidHeader
+		}
+		if err := tw.writePAXHeader(hdr, paxHeaders); err != nil {
+			return err
+		}
+	}
+	tw.nb = int64(hdr.Size)
+	tw.pad = (blockSize - (tw.nb % blockSize)) % blockSize
+
+	_, tw.err = tw.w.Write(header)
+	return tw.err
+}
+
+// splitUSTARPath splits a path according to USTAR prefix and suffix rules.
+// If the path is not splittable, then it will return ("", "", false).
+func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
+	length := len(name)
+	if length <= fileNameSize || !isASCII(name) {
+		return "", "", false
+	} else if length > fileNamePrefixSize+1 {
+		length = fileNamePrefixSize + 1
+	} else if name[length-1] == '/' {
+		length--
+	}
+
+	i := strings.LastIndex(name[:length], "/")
+	nlen := len(name) - i - 1 // nlen is length of suffix
+	plen := i                 // plen is length of prefix
+	if i <= 0 || nlen > fileNameSize || nlen == 0 || plen > fileNamePrefixSize {
+		return "", "", false
+	}
+	return name[:i], name[i+1:], true
+}
+
+// writePaxHeader writes an extended pax header to the
+// archive.
+func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) error {
+	// Prepare extended header
+	ext := new(Header)
+	ext.Typeflag = TypeXHeader
+	// Setting ModTime is required for reader parsing to
+	// succeed, and seems harmless enough.
+	ext.ModTime = hdr.ModTime
+	// The spec asks that we namespace our pseudo files
+	// with the current pid.  However, this results in differing outputs
+	// for identical inputs.  As such, the constant 0 is now used instead.
+	// golang.org/issue/12358
+	dir, file := path.Split(hdr.Name)
+	fullName := path.Join(dir, "PaxHeaders.0", file)
+
+	ascii := toASCII(fullName)
+	if len(ascii) > 100 {
+		ascii = ascii[:100]
+	}
+	ext.Name = ascii
+	// Construct the body
+	var buf bytes.Buffer
+
+	// Keys are sorted before writing to body to allow deterministic output.
+	var keys []string
+	for k := range paxHeaders {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+
+	for _, k := range keys {
+		fmt.Fprint(&buf, formatPAXRecord(k, paxHeaders[k]))
+	}
+
+	ext.Size = int64(len(buf.Bytes()))
+	if err := tw.writeHeader(ext, false); err != nil {
+		return err
+	}
+	if _, err := tw.Write(buf.Bytes()); err != nil {
+		return err
+	}
+	if err := tw.Flush(); err != nil {
+		return err
+	}
+	return nil
+}
+
+// formatPAXRecord formats a single PAX record, prefixing it with the
+// appropriate length.
+func formatPAXRecord(k, v string) string {
+	const padding = 3 // Extra padding for ' ', '=', and '\n'
+	size := len(k) + len(v) + padding
+	size += len(strconv.Itoa(size))
+	record := fmt.Sprintf("%d %s=%s\n", size, k, v)
+
+	// Final adjustment if adding size field increased the record size.
+	if len(record) != size {
+		size = len(record)
+		record = fmt.Sprintf("%d %s=%s\n", size, k, v)
+	}
+	return record
+}
+
+// Write writes to the current entry in the tar archive.
+// Write returns the error ErrWriteTooLong if more than
+// hdr.Size bytes are written after WriteHeader.
+func (tw *Writer) Write(b []byte) (n int, err error) {
+	if tw.closed {
+		err = ErrWriteAfterClose
+		return
+	}
+	overwrite := false
+	if int64(len(b)) > tw.nb {
+		b = b[0:tw.nb]
+		overwrite = true
+	}
+	n, err = tw.w.Write(b)
+	tw.nb -= int64(n)
+	if err == nil && overwrite {
+		err = ErrWriteTooLong
+		return
+	}
+	tw.err = err
+	return
+}
+
+// Close closes the tar archive, flushing any unwritten
+// data to the underlying writer.
+func (tw *Writer) Close() error {
+	if tw.err != nil || tw.closed {
+		return tw.err
+	}
+	tw.Flush()
+	tw.closed = true
+	if tw.err != nil {
+		return tw.err
+	}
+
+	// trailer: two zero blocks
+	for i := 0; i < 2; i++ {
+		_, tw.err = tw.w.Write(zeroBlock)
+		if tw.err != nil {
+			break
+		}
+	}
+	return tw.err
+}

+ 241 - 0
vendor/src/github.com/Microsoft/go-winio/backup.go

@@ -0,0 +1,241 @@
+package winio
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"runtime"
+	"syscall"
+	"unicode/utf16"
+)
+
+//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
+//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
+
+const (
+	BackupData = uint32(iota + 1)
+	BackupEaData
+	BackupSecurity
+	BackupAlternateData
+	BackupLink
+	BackupPropertyData
+	BackupObjectId
+	BackupReparseData
+	BackupSparseBlock
+	BackupTxfsData
+
+	StreamSparseAttributes = uint32(8)
+)
+
+// BackupHeader represents a backup stream of a file.
+type BackupHeader struct {
+	Id         uint32 // The backup stream ID
+	Attributes uint32 // Stream attributes
+	Size       int64  // The size of the stream in bytes
+	Name       string // The name of the stream (for BackupAlternateData only).
+	Offset     int64  // The offset of the stream in the file (for BackupSparseBlock only).
+}
+
+type win32StreamId struct {
+	StreamId   uint32
+	Attributes uint32
+	Size       uint64
+	NameSize   uint32
+}
+
+// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series
+// of BackupHeader values.
+type BackupStreamReader struct {
+	r         io.Reader
+	bytesLeft int64
+}
+
+// NewBackupStreamReader produces a BackupStreamReader from any io.Reader.
+func NewBackupStreamReader(r io.Reader) *BackupStreamReader {
+	return &BackupStreamReader{r, 0}
+}
+
+// Next returns the next backup stream and prepares for calls to Write(). It skips the remainder of the current stream if
+// it was not completely read.
+func (r *BackupStreamReader) Next() (*BackupHeader, error) {
+	if r.bytesLeft > 0 {
+		if _, err := io.Copy(ioutil.Discard, r); err != nil {
+			return nil, err
+		}
+	}
+	var wsi win32StreamId
+	if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
+		return nil, err
+	}
+	hdr := &BackupHeader{
+		Id:         wsi.StreamId,
+		Attributes: wsi.Attributes,
+		Size:       int64(wsi.Size),
+	}
+	if wsi.NameSize != 0 {
+		name := make([]uint16, int(wsi.NameSize/2))
+		if err := binary.Read(r.r, binary.LittleEndian, name); err != nil {
+			return nil, err
+		}
+		hdr.Name = syscall.UTF16ToString(name)
+	}
+	if wsi.StreamId == BackupSparseBlock {
+		if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
+			return nil, err
+		}
+		hdr.Size -= 8
+	}
+	r.bytesLeft = hdr.Size
+	return hdr, nil
+}
+
+// Read reads from the current backup stream.
+func (r *BackupStreamReader) Read(b []byte) (int, error) {
+	if r.bytesLeft == 0 {
+		return 0, io.EOF
+	}
+	if int64(len(b)) > r.bytesLeft {
+		b = b[:r.bytesLeft]
+	}
+	n, err := r.r.Read(b)
+	r.bytesLeft -= int64(n)
+	if err == io.EOF {
+		err = io.ErrUnexpectedEOF
+	} else if r.bytesLeft == 0 && err == nil {
+		err = io.EOF
+	}
+	return n, err
+}
+
+// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API.
+type BackupStreamWriter struct {
+	w         io.Writer
+	bytesLeft int64
+}
+
+// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer.
+func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter {
+	return &BackupStreamWriter{w, 0}
+}
+
+// WriteHeader writes the next backup stream header and prepares for calls to Write().
+func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
+	if w.bytesLeft != 0 {
+		return fmt.Errorf("missing %d bytes", w.bytesLeft)
+	}
+	name := utf16.Encode([]rune(hdr.Name))
+	wsi := win32StreamId{
+		StreamId:   hdr.Id,
+		Attributes: hdr.Attributes,
+		Size:       uint64(hdr.Size),
+		NameSize:   uint32(len(name) * 2),
+	}
+	if hdr.Id == BackupSparseBlock {
+		// Include space for the int64 block offset
+		wsi.Size += 8
+	}
+	if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil {
+		return err
+	}
+	if len(name) != 0 {
+		if err := binary.Write(w.w, binary.LittleEndian, name); err != nil {
+			return err
+		}
+	}
+	if hdr.Id == BackupSparseBlock {
+		if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil {
+			return err
+		}
+	}
+	w.bytesLeft = hdr.Size
+	return nil
+}
+
+// Write writes to the current backup stream.
+func (w *BackupStreamWriter) Write(b []byte) (int, error) {
+	if w.bytesLeft < int64(len(b)) {
+		return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft)
+	}
+	n, err := w.w.Write(b)
+	w.bytesLeft -= int64(n)
+	return n, err
+}
+
+// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API.
+type BackupFileReader struct {
+	f               *os.File
+	includeSecurity bool
+	ctx             uintptr
+}
+
+// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true,
+// Read will attempt to read the security descriptor of the file.
+func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader {
+	r := &BackupFileReader{f, includeSecurity, 0}
+	runtime.SetFinalizer(r, func(r *BackupFileReader) { r.Close() })
+	return r
+}
+
+// Read reads a backup stream from the file by calling the Win32 API BackupRead().
+func (r *BackupFileReader) Read(b []byte) (int, error) {
+	var bytesRead uint32
+	err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
+	if err != nil {
+		return 0, &os.PathError{"BackupRead", r.f.Name(), err}
+	}
+	if bytesRead == 0 {
+		return 0, io.EOF
+	}
+	return int(bytesRead), nil
+}
+
+// Close frees Win32 resources associated with the BackupFileReader. It does not close
+// the underlying file.
+func (r *BackupFileReader) Close() error {
+	if r.ctx != 0 {
+		backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
+		r.ctx = 0
+	}
+	return nil
+}
+
+// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API.
+type BackupFileWriter struct {
+	f               *os.File
+	includeSecurity bool
+	ctx             uintptr
+}
+
+// NewBackupFileWrtier returns a new BackupFileWriter from a file handle. If includeSecurity is true,
+// Write() will attempt to restore the security descriptor from the stream.
+func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter {
+	w := &BackupFileWriter{f, includeSecurity, 0}
+	runtime.SetFinalizer(w, func(w *BackupFileWriter) { w.Close() })
+	return w
+}
+
+// Write restores a portion of the file using the provided backup stream.
+func (w *BackupFileWriter) Write(b []byte) (int, error) {
+	var bytesWritten uint32
+	err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
+	if err != nil {
+		return 0, &os.PathError{"BackupWrite", w.f.Name(), err}
+	}
+	if int(bytesWritten) != len(b) {
+		return int(bytesWritten), errors.New("not all bytes could be written")
+	}
+	return len(b), nil
+}
+
+// Close frees Win32 resources associated with the BackupFileWriter. It does not
+// close the underlying file.
+func (w *BackupFileWriter) Close() error {
+	if w.ctx != 0 {
+		backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
+		w.ctx = 0
+	}
+	return nil
+}

+ 362 - 0
vendor/src/github.com/Microsoft/go-winio/backuptar/tar.go

@@ -0,0 +1,362 @@
+package backuptar
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"syscall"
+	"time"
+
+	"github.com/Microsoft/go-winio"
+	"github.com/Microsoft/go-winio/archive/tar" // until archive/tar supports pax extensions in its interface
+)
+
+const (
+	c_ISUID  = 04000   // Set uid
+	c_ISGID  = 02000   // Set gid
+	c_ISVTX  = 01000   // Save text (sticky bit)
+	c_ISDIR  = 040000  // Directory
+	c_ISFIFO = 010000  // FIFO
+	c_ISREG  = 0100000 // Regular file
+	c_ISLNK  = 0120000 // Symbolic link
+	c_ISBLK  = 060000  // Block special file
+	c_ISCHR  = 020000  // Character special file
+	c_ISSOCK = 0140000 // Socket
+)
+
+const (
+	hdrFileAttributes     = "fileattr"
+	hdrAccessTime         = "accesstime"
+	hdrChangeTime         = "changetime"
+	hdrCreateTime         = "createtime"
+	hdrWriteTime          = "writetime"
+	hdrSecurityDescriptor = "sd"
+	hdrMountPoint         = "mountpoint"
+)
+
+func writeZeroes(w io.Writer, count int64) error {
+	buf := make([]byte, 8192)
+	c := len(buf)
+	for i := int64(0); i < count; i += int64(c) {
+		if int64(c) > count-i {
+			c = int(count - i)
+		}
+		_, err := w.Write(buf[:c])
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func copySparse(t *tar.Writer, br *winio.BackupStreamReader) error {
+	curOffset := int64(0)
+	for {
+		bhdr, err := br.Next()
+		if err == io.EOF {
+			err = io.ErrUnexpectedEOF
+		}
+		if err != nil {
+			return err
+		}
+		if bhdr.Id != winio.BackupSparseBlock {
+			return fmt.Errorf("unexpected stream %d", bhdr.Id)
+		}
+
+		// archive/tar does not support writing sparse files
+		// so just write zeroes to catch up to the current offset.
+		err = writeZeroes(t, bhdr.Offset-curOffset)
+		if bhdr.Size == 0 {
+			break
+		}
+		n, err := io.Copy(t, br)
+		if err != nil {
+			return err
+		}
+		curOffset = bhdr.Offset + n
+	}
+	return nil
+}
+
+func win32TimeFromTar(key string, hdrs map[string]string, unixTime time.Time) syscall.Filetime {
+	if s, ok := hdrs[key]; ok {
+		n, err := strconv.ParseUint(s, 10, 64)
+		if err == nil {
+			return syscall.Filetime{uint32(n & 0xffffffff), uint32(n >> 32)}
+		}
+	}
+	return syscall.NsecToFiletime(unixTime.UnixNano())
+}
+
+func win32TimeToTar(ft syscall.Filetime) (string, time.Time) {
+	return fmt.Sprintf("%d", uint64(ft.LowDateTime)+(uint64(ft.HighDateTime)<<32)), time.Unix(0, ft.Nanoseconds())
+}
+
+// Writes a file to a tar writer using data from a Win32 backup stream.
+//
+// This encodes Win32 metadata as tar pax vendor extensions starting with MSWINDOWS.
+//
+// The additional Win32 metadata is:
+//
+// MSWINDOWS.fileattr: The Win32 file attributes, as a decimal value
+//
+// MSWINDOWS.accesstime: The last access time, as a Filetime expressed as a 64-bit decimal value.
+//
+// MSWINDOWS.createtime: The creation time, as a Filetime expressed as a 64-bit decimal value.
+//
+// MSWINDOWS.changetime: The creation time, as a Filetime expressed as a 64-bit decimal value.
+//
+// MSWINDOWS.writetime: The creation time, as a Filetime expressed as a 64-bit decimal value.
+//
+// MSWINDOWS.sd: The Win32 security descriptor, in SDDL (string) format
+//
+// MSWINDOWS.mountpoint: If present, this is a mount point and not a symlink, even though the type is '2' (symlink)
+func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size int64, fileInfo *winio.FileBasicInfo) error {
+	name = filepath.ToSlash(name)
+	hdr := &tar.Header{
+		Name:       name,
+		Size:       size,
+		Typeflag:   tar.TypeReg,
+		Winheaders: make(map[string]string),
+	}
+	hdr.Winheaders[hdrFileAttributes] = fmt.Sprintf("%d", fileInfo.FileAttributes)
+	hdr.Winheaders[hdrAccessTime], hdr.AccessTime = win32TimeToTar(fileInfo.LastAccessTime)
+	hdr.Winheaders[hdrChangeTime], hdr.ChangeTime = win32TimeToTar(fileInfo.ChangeTime)
+	hdr.Winheaders[hdrCreateTime], _ = win32TimeToTar(fileInfo.CreationTime)
+	hdr.Winheaders[hdrWriteTime], hdr.ModTime = win32TimeToTar(fileInfo.LastWriteTime)
+
+	if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
+		hdr.Mode |= c_ISDIR
+		hdr.Size = 0
+		hdr.Typeflag = tar.TypeDir
+	}
+
+	br := winio.NewBackupStreamReader(r)
+	var dataHdr *winio.BackupHeader
+	for dataHdr == nil {
+		bhdr, err := br.Next()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			return err
+		}
+		switch bhdr.Id {
+		case winio.BackupData:
+			hdr.Mode |= c_ISREG
+			dataHdr = bhdr
+		case winio.BackupSecurity:
+			sd, err := ioutil.ReadAll(br)
+			if err != nil {
+				return err
+			}
+			sddl, err := winio.SecurityDescriptorToSddl(sd)
+			if err != nil {
+				return err
+			}
+			hdr.Winheaders[hdrSecurityDescriptor] = sddl
+
+		case winio.BackupReparseData:
+			hdr.Mode |= c_ISLNK
+			hdr.Typeflag = tar.TypeSymlink
+			reparseBuffer, err := ioutil.ReadAll(br)
+			rp, err := winio.DecodeReparsePoint(reparseBuffer)
+			if err != nil {
+				return err
+			}
+			if rp.IsMountPoint {
+				hdr.Winheaders[hdrMountPoint] = "1"
+			}
+			hdr.Linkname = rp.Target
+		case winio.BackupEaData, winio.BackupLink, winio.BackupPropertyData, winio.BackupObjectId, winio.BackupTxfsData:
+			// ignore these streams
+		default:
+			return fmt.Errorf("%s: unknown stream ID %d", name, bhdr.Id)
+		}
+	}
+
+	err := t.WriteHeader(hdr)
+	if err != nil {
+		return err
+	}
+
+	if dataHdr != nil {
+		// A data stream was found. Copy the data.
+		if (dataHdr.Attributes & winio.StreamSparseAttributes) == 0 {
+			if size != dataHdr.Size {
+				return fmt.Errorf("%s: mismatch between file size %d and header size %d", name, size, dataHdr.Size)
+			}
+			_, err = io.Copy(t, br)
+			if err != nil {
+				return err
+			}
+		} else {
+			err = copySparse(t, br)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	// Look for streams after the data stream. The only ones we handle are alternate data streams.
+	// Other streams may have metadata that could be serialized, but the tar header has already
+	// been written. In practice, this means that we don't get EA or TXF metadata.
+	for {
+		bhdr, err := br.Next()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			return err
+		}
+		switch bhdr.Id {
+		case winio.BackupAlternateData:
+			altName := bhdr.Name
+			if strings.HasSuffix(altName, ":$DATA") {
+				altName = altName[:len(altName)-len(":$DATA")]
+			}
+			if (bhdr.Attributes & winio.StreamSparseAttributes) == 0 {
+				hdr = &tar.Header{
+					Name:       name + altName,
+					Mode:       hdr.Mode,
+					Typeflag:   tar.TypeReg,
+					Size:       bhdr.Size,
+					ModTime:    hdr.ModTime,
+					AccessTime: hdr.AccessTime,
+					ChangeTime: hdr.ChangeTime,
+				}
+				err = t.WriteHeader(hdr)
+				if err != nil {
+					return err
+				}
+				_, err = io.Copy(t, br)
+				if err != nil {
+					return err
+				}
+
+			} else {
+				// Unsupported for now, since the size of the alternate stream is not present
+				// in the backup stream until after the data has been read.
+				return errors.New("tar of sparse alternate data streams is unsupported")
+			}
+		case winio.BackupEaData, winio.BackupLink, winio.BackupPropertyData, winio.BackupObjectId, winio.BackupTxfsData:
+			// ignore these streams
+		default:
+			return fmt.Errorf("%s: unknown stream ID %d after data", name, bhdr.Id)
+		}
+	}
+	return nil
+}
+
+// Retrieves basic Win32 file information from a tar header, using the additional metadata written by
+// WriteTarFileFromBackupStream.
+func FileInfoFromHeader(hdr *tar.Header) (name string, size int64, fileInfo *winio.FileBasicInfo, err error) {
+	name = hdr.Name
+	if hdr.Typeflag == tar.TypeReg || hdr.Typeflag == tar.TypeRegA {
+		size = hdr.Size
+	}
+	fileInfo = &winio.FileBasicInfo{
+		LastAccessTime: win32TimeFromTar(hdrAccessTime, hdr.Winheaders, hdr.AccessTime),
+		LastWriteTime:  win32TimeFromTar(hdrWriteTime, hdr.Winheaders, hdr.ModTime),
+		ChangeTime:     win32TimeFromTar(hdrChangeTime, hdr.Winheaders, hdr.ChangeTime),
+		CreationTime:   win32TimeFromTar(hdrCreateTime, hdr.Winheaders, hdr.ModTime),
+	}
+	if attrStr, ok := hdr.Winheaders[hdrFileAttributes]; ok {
+		attr, err := strconv.ParseUint(attrStr, 10, 32)
+		if err != nil {
+			return "", 0, nil, err
+		}
+		fileInfo.FileAttributes = uintptr(attr)
+	} else {
+		if hdr.Typeflag == tar.TypeDir {
+			fileInfo.FileAttributes |= syscall.FILE_ATTRIBUTE_DIRECTORY
+		}
+	}
+	return
+}
+
+// Writes a Win32 backup stream from the current tar file. Since this function may process multiple
+// tar file entries in order to collect all the alternate data streams for the file, it returns the next
+// tar file that was not processed, or io.EOF is there are no more.
+func WriteBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (*tar.Header, error) {
+	bw := winio.NewBackupStreamWriter(w)
+	if sddl, ok := hdr.Winheaders[hdrSecurityDescriptor]; ok {
+		sd, err := winio.SddlToSecurityDescriptor(sddl)
+		if err != nil {
+			return nil, err
+		}
+		bhdr := winio.BackupHeader{
+			Id:   winio.BackupSecurity,
+			Size: int64(len(sd)),
+		}
+		err = bw.WriteHeader(&bhdr)
+		if err != nil {
+			return nil, err
+		}
+		_, err = bw.Write(sd)
+		if err != nil {
+			return nil, err
+		}
+	}
+	if hdr.Typeflag == tar.TypeSymlink {
+		_, isMountPoint := hdr.Winheaders[hdrMountPoint]
+		rp := winio.ReparsePoint{
+			Target:       hdr.Linkname,
+			IsMountPoint: isMountPoint,
+		}
+		reparse := winio.EncodeReparsePoint(&rp)
+		bhdr := winio.BackupHeader{
+			Id:   winio.BackupReparseData,
+			Size: int64(len(reparse)),
+		}
+		err := bw.WriteHeader(&bhdr)
+		if err != nil {
+			return nil, err
+		}
+		_, err = bw.Write(reparse)
+		if err != nil {
+			return nil, err
+		}
+	}
+	if hdr.Typeflag == tar.TypeReg || hdr.Typeflag == tar.TypeRegA {
+		bhdr := winio.BackupHeader{
+			Id:   winio.BackupData,
+			Size: hdr.Size,
+		}
+		err := bw.WriteHeader(&bhdr)
+		if err != nil {
+			return nil, err
+		}
+		_, err = io.Copy(bw, t)
+		if err != nil {
+			return nil, err
+		}
+	}
+	// Copy all the alternate data streams and return the next non-ADS header.
+	for {
+		ahdr, err := t.Next()
+		if err != nil {
+			return nil, err
+		}
+		if ahdr.Typeflag != tar.TypeReg || !strings.HasPrefix(ahdr.Name, hdr.Name+":") {
+			return ahdr, nil
+		}
+		bhdr := winio.BackupHeader{
+			Id:   winio.BackupAlternateData,
+			Size: ahdr.Size,
+			Name: ahdr.Name[len(hdr.Name)+1:] + ":$DATA",
+		}
+		err = bw.WriteHeader(&bhdr)
+		if err != nil {
+			return nil, err
+		}
+		_, err = io.Copy(bw, t)
+		if err != nil {
+			return nil, err
+		}
+	}
+}

+ 30 - 0
vendor/src/github.com/Microsoft/go-winio/fileinfo.go

@@ -0,0 +1,30 @@
+package winio
+
+import (
+	"os"
+	"syscall"
+	"unsafe"
+)
+
+//sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx
+//sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle
+
+type FileBasicInfo struct {
+	CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime
+	FileAttributes                                          uintptr // includes padding
+}
+
+func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
+	bi := &FileBasicInfo{}
+	if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), 0, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
+		return nil, &os.PathError{"GetFileInformationByHandleEx", f.Name(), err}
+	}
+	return bi, nil
+}
+
+func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
+	if err := setFileInformationByHandle(syscall.Handle(f.Fd()), 0, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
+		return &os.PathError{"SetFileInformationByHandle", f.Name(), err}
+	}
+	return nil
+}

+ 0 - 797
vendor/src/github.com/Microsoft/go-winio/mksyscall_windows.go

@@ -1,797 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-mksyscall_windows generates windows system call bodies
-
-It parses all files specified on command line containing function
-prototypes (like syscall_windows.go) and prints system call bodies
-to standard output.
-
-The prototypes are marked by lines beginning with "//sys" and read
-like func declarations if //sys is replaced by func, but:
-
-* The parameter lists must give a name for each argument. This
-  includes return parameters.
-
-* The parameter lists must give a type for each argument:
-  the (x, y, z int) shorthand is not allowed.
-
-* If the return parameter is an error number, it must be named err.
-
-* If go func name needs to be different from it's winapi dll name,
-  the winapi name could be specified at the end, after "=" sign, like
-  //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
-
-* Each function that returns err needs to supply a condition, that
-  return value of winapi will be tested against to detect failure.
-  This would set err to windows "last-error", otherwise it will be nil.
-  The value can be provided at end of //sys declaration, like
-  //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
-  and is [failretval==0] by default.
-
-Usage:
-	mksyscall_windows [flags] [path ...]
-
-The flags are:
-	-output
-		Specify output file name (outputs to console if blank).
-	-trace
-		Generate print statement after every syscall.
-*/
-package main
-
-import (
-	"bufio"
-	"bytes"
-	"errors"
-	"flag"
-	"fmt"
-	"go/format"
-	"go/parser"
-	"go/token"
-	"io"
-	"io/ioutil"
-	"log"
-	"os"
-	"strconv"
-	"strings"
-	"text/template"
-)
-
-var (
-	filename       = flag.String("output", "", "output file name (standard output if omitted)")
-	printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
-)
-
-func trim(s string) string {
-	return strings.Trim(s, " \t")
-}
-
-var packageName string
-
-func packagename() string {
-	return packageName
-}
-
-func syscalldot() string {
-	if packageName == "syscall" {
-		return ""
-	}
-	return "syscall."
-}
-
-// Param is function parameter
-type Param struct {
-	Name      string
-	Type      string
-	fn        *Fn
-	tmpVarIdx int
-}
-
-// tmpVar returns temp variable name that will be used to represent p during syscall.
-func (p *Param) tmpVar() string {
-	if p.tmpVarIdx < 0 {
-		p.tmpVarIdx = p.fn.curTmpVarIdx
-		p.fn.curTmpVarIdx++
-	}
-	return fmt.Sprintf("_p%d", p.tmpVarIdx)
-}
-
-// BoolTmpVarCode returns source code for bool temp variable.
-func (p *Param) BoolTmpVarCode() string {
-	const code = `var %s uint32
-	if %s {
-		%s = 1
-	} else {
-		%s = 0
-	}`
-	tmp := p.tmpVar()
-	return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
-}
-
-// SliceTmpVarCode returns source code for slice temp variable.
-func (p *Param) SliceTmpVarCode() string {
-	const code = `var %s *%s
-	if len(%s) > 0 {
-		%s = &%s[0]
-	}`
-	tmp := p.tmpVar()
-	return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
-}
-
-// StringTmpVarCode returns source code for string temp variable.
-func (p *Param) StringTmpVarCode() string {
-	errvar := p.fn.Rets.ErrorVarName()
-	if errvar == "" {
-		errvar = "_"
-	}
-	tmp := p.tmpVar()
-	const code = `var %s %s
-	%s, %s = %s(%s)`
-	s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
-	if errvar == "-" {
-		return s
-	}
-	const morecode = `
-	if %s != nil {
-		return
-	}`
-	return s + fmt.Sprintf(morecode, errvar)
-}
-
-// TmpVarCode returns source code for temp variable.
-func (p *Param) TmpVarCode() string {
-	switch {
-	case p.Type == "bool":
-		return p.BoolTmpVarCode()
-	case strings.HasPrefix(p.Type, "[]"):
-		return p.SliceTmpVarCode()
-	default:
-		return ""
-	}
-}
-
-// TmpVarHelperCode returns source code for helper's temp variable.
-func (p *Param) TmpVarHelperCode() string {
-	if p.Type != "string" {
-		return ""
-	}
-	return p.StringTmpVarCode()
-}
-
-// SyscallArgList returns source code fragments representing p parameter
-// in syscall. Slices are translated into 2 syscall parameters: pointer to
-// the first element and length.
-func (p *Param) SyscallArgList() []string {
-	t := p.HelperType()
-	var s string
-	switch {
-	case t[0] == '*':
-		s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
-	case t == "bool":
-		s = p.tmpVar()
-	case strings.HasPrefix(t, "[]"):
-		return []string{
-			fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
-			fmt.Sprintf("uintptr(len(%s))", p.Name),
-		}
-	default:
-		s = p.Name
-	}
-	return []string{fmt.Sprintf("uintptr(%s)", s)}
-}
-
-// IsError determines if p parameter is used to return error.
-func (p *Param) IsError() bool {
-	return p.Name == "err" && p.Type == "error"
-}
-
-// HelperType returns type of parameter p used in helper function.
-func (p *Param) HelperType() string {
-	if p.Type == "string" {
-		return p.fn.StrconvType()
-	}
-	return p.Type
-}
-
-// join concatenates parameters ps into a string with sep separator.
-// Each parameter is converted into string by applying fn to it
-// before conversion.
-func join(ps []*Param, fn func(*Param) string, sep string) string {
-	if len(ps) == 0 {
-		return ""
-	}
-	a := make([]string, 0)
-	for _, p := range ps {
-		a = append(a, fn(p))
-	}
-	return strings.Join(a, sep)
-}
-
-// Rets describes function return parameters.
-type Rets struct {
-	Name         string
-	Type         string
-	ReturnsError bool
-	FailCond     string
-}
-
-// ErrorVarName returns error variable name for r.
-func (r *Rets) ErrorVarName() string {
-	if r.ReturnsError {
-		return "err"
-	}
-	if r.Type == "error" {
-		return r.Name
-	}
-	return ""
-}
-
-// ToParams converts r into slice of *Param.
-func (r *Rets) ToParams() []*Param {
-	ps := make([]*Param, 0)
-	if len(r.Name) > 0 {
-		ps = append(ps, &Param{Name: r.Name, Type: r.Type})
-	}
-	if r.ReturnsError {
-		ps = append(ps, &Param{Name: "err", Type: "error"})
-	}
-	return ps
-}
-
-// List returns source code of syscall return parameters.
-func (r *Rets) List() string {
-	s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
-	if len(s) > 0 {
-		s = "(" + s + ")"
-	}
-	return s
-}
-
-// PrintList returns source code of trace printing part correspondent
-// to syscall return values.
-func (r *Rets) PrintList() string {
-	return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
-}
-
-// SetReturnValuesCode returns source code that accepts syscall return values.
-func (r *Rets) SetReturnValuesCode() string {
-	if r.Name == "" && !r.ReturnsError {
-		return ""
-	}
-	retvar := "r0"
-	if r.Name == "" {
-		retvar = "r1"
-	}
-	errvar := "_"
-	if r.ReturnsError {
-		errvar = "e1"
-	}
-	return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
-}
-
-func (r *Rets) useLongHandleErrorCode(retvar string) string {
-	const code = `if %s {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = %sEINVAL
-		}
-	}`
-	cond := retvar + " == 0"
-	if r.FailCond != "" {
-		cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
-	}
-	return fmt.Sprintf(code, cond, syscalldot())
-}
-
-// SetErrorCode returns source code that sets return parameters.
-func (r *Rets) SetErrorCode() string {
-	const code = `if r0 != 0 {
-		%s = %sErrno(r0)
-	}`
-	if r.Name == "" && !r.ReturnsError {
-		return ""
-	}
-	if r.Name == "" {
-		return r.useLongHandleErrorCode("r1")
-	}
-	if r.Type == "error" {
-		return fmt.Sprintf(code, r.Name, syscalldot())
-	}
-	s := ""
-	switch {
-	case r.Type[0] == '*':
-		s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
-	case r.Type == "bool":
-		s = fmt.Sprintf("%s = r0 != 0", r.Name)
-	default:
-		s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
-	}
-	if !r.ReturnsError {
-		return s
-	}
-	return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
-}
-
-// Fn describes syscall function.
-type Fn struct {
-	Name        string
-	Params      []*Param
-	Rets        *Rets
-	PrintTrace  bool
-	confirmproc bool
-	dllname     string
-	dllfuncname string
-	src         string
-	// TODO: get rid of this field and just use parameter index instead
-	curTmpVarIdx int // insure tmp variables have uniq names
-}
-
-// extractParams parses s to extract function parameters.
-func extractParams(s string, f *Fn) ([]*Param, error) {
-	s = trim(s)
-	if s == "" {
-		return nil, nil
-	}
-	a := strings.Split(s, ",")
-	ps := make([]*Param, len(a))
-	for i := range ps {
-		s2 := trim(a[i])
-		b := strings.Split(s2, " ")
-		if len(b) != 2 {
-			b = strings.Split(s2, "\t")
-			if len(b) != 2 {
-				return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
-			}
-		}
-		ps[i] = &Param{
-			Name:      trim(b[0]),
-			Type:      trim(b[1]),
-			fn:        f,
-			tmpVarIdx: -1,
-		}
-	}
-	return ps, nil
-}
-
-// extractSection extracts text out of string s starting after start
-// and ending just before end. found return value will indicate success,
-// and prefix, body and suffix will contain correspondent parts of string s.
-func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
-	s = trim(s)
-	if strings.HasPrefix(s, string(start)) {
-		// no prefix
-		body = s[1:]
-	} else {
-		a := strings.SplitN(s, string(start), 2)
-		if len(a) != 2 {
-			return "", "", s, false
-		}
-		prefix = a[0]
-		body = a[1]
-	}
-	a := strings.SplitN(body, string(end), 2)
-	if len(a) != 2 {
-		return "", "", "", false
-	}
-	return prefix, a[0], a[1], true
-}
-
-// newFn parses string s and return created function Fn.
-func newFn(s string) (*Fn, error) {
-	s = trim(s)
-	f := &Fn{
-		Rets:       &Rets{},
-		src:        s,
-		PrintTrace: *printTraceFlag,
-	}
-	// function name and args
-	prefix, body, s, found := extractSection(s, '(', ')')
-	if !found || prefix == "" {
-		return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
-	}
-	f.Name = prefix
-	var err error
-	f.Params, err = extractParams(body, f)
-	if err != nil {
-		return nil, err
-	}
-	// return values
-	_, body, s, found = extractSection(s, '(', ')')
-	if found {
-		r, err := extractParams(body, f)
-		if err != nil {
-			return nil, err
-		}
-		switch len(r) {
-		case 0:
-		case 1:
-			if r[0].IsError() {
-				f.Rets.ReturnsError = true
-			} else {
-				f.Rets.Name = r[0].Name
-				f.Rets.Type = r[0].Type
-			}
-		case 2:
-			if !r[1].IsError() {
-				return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
-			}
-			f.Rets.ReturnsError = true
-			f.Rets.Name = r[0].Name
-			f.Rets.Type = r[0].Type
-		default:
-			return nil, errors.New("Too many return values in \"" + f.src + "\"")
-		}
-	}
-	// fail condition
-	_, body, s, found = extractSection(s, '[', ']')
-	if found {
-		f.Rets.FailCond = body
-	}
-	// dll and dll function names
-	s = trim(s)
-	if s == "" {
-		return f, nil
-	}
-	if !strings.HasPrefix(s, "=") {
-		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
-	}
-	s = trim(s[1:])
-	a := strings.Split(s, ".")
-	switch len(a) {
-	case 1:
-		f.dllfuncname = a[0]
-	case 2:
-		f.dllname = a[0]
-		f.dllfuncname = a[1]
-	default:
-		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
-	}
-	if f.dllfuncname[len(f.dllfuncname)-1] == '?' {
-		f.confirmproc = true
-		f.dllfuncname = f.dllfuncname[0 : len(f.dllfuncname)-1]
-	}
-	return f, nil
-}
-
-// DLLName returns DLL name for function f.
-func (f *Fn) DLLName() string {
-	if f.dllname == "" {
-		return "kernel32"
-	}
-	return f.dllname
-}
-
-// DLLName returns DLL function name for function f.
-func (f *Fn) DLLFuncName() string {
-	if f.dllfuncname == "" {
-		return f.Name
-	}
-	return f.dllfuncname
-}
-
-func (f *Fn) ConfirmProc() bool {
-	return f.confirmproc
-}
-
-// ParamList returns source code for function f parameters.
-func (f *Fn) ParamList() string {
-	return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
-}
-
-// HelperParamList returns source code for helper function f parameters.
-func (f *Fn) HelperParamList() string {
-	return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ")
-}
-
-// ParamPrintList returns source code of trace printing part correspondent
-// to syscall input parameters.
-func (f *Fn) ParamPrintList() string {
-	return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
-}
-
-// ParamCount return number of syscall parameters for function f.
-func (f *Fn) ParamCount() int {
-	n := 0
-	for _, p := range f.Params {
-		n += len(p.SyscallArgList())
-	}
-	return n
-}
-
-// SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
-// to use. It returns parameter count for correspondent SyscallX function.
-func (f *Fn) SyscallParamCount() int {
-	n := f.ParamCount()
-	switch {
-	case n <= 3:
-		return 3
-	case n <= 6:
-		return 6
-	case n <= 9:
-		return 9
-	case n <= 12:
-		return 12
-	case n <= 15:
-		return 15
-	default:
-		panic("too many arguments to system call")
-	}
-}
-
-// Syscall determines which SyscallX function to use for function f.
-func (f *Fn) Syscall() string {
-	c := f.SyscallParamCount()
-	if c == 3 {
-		return syscalldot() + "Syscall"
-	}
-	return syscalldot() + "Syscall" + strconv.Itoa(c)
-}
-
-// SyscallParamList returns source code for SyscallX parameters for function f.
-func (f *Fn) SyscallParamList() string {
-	a := make([]string, 0)
-	for _, p := range f.Params {
-		a = append(a, p.SyscallArgList()...)
-	}
-	for len(a) < f.SyscallParamCount() {
-		a = append(a, "0")
-	}
-	return strings.Join(a, ", ")
-}
-
-// HelperCallParamList returns source code of call into function f helper.
-func (f *Fn) HelperCallParamList() string {
-	a := make([]string, 0, len(f.Params))
-	for _, p := range f.Params {
-		s := p.Name
-		if p.Type == "string" {
-			s = p.tmpVar()
-		}
-		a = append(a, s)
-	}
-	return strings.Join(a, ", ")
-}
-
-// IsUTF16 is true, if f is W (utf16) function. It is false
-// for all A (ascii) functions.
-func (_ *Fn) IsUTF16() bool {
-	return true
-}
-
-// StrconvFunc returns name of Go string to OS string function for f.
-func (f *Fn) StrconvFunc() string {
-	if f.IsUTF16() {
-		return syscalldot() + "UTF16PtrFromString"
-	}
-	return syscalldot() + "BytePtrFromString"
-}
-
-// StrconvType returns Go type name used for OS string for f.
-func (f *Fn) StrconvType() string {
-	if f.IsUTF16() {
-		return "*uint16"
-	}
-	return "*byte"
-}
-
-// HasStringParam is true, if f has at least one string parameter.
-// Otherwise it is false.
-func (f *Fn) HasStringParam() bool {
-	for _, p := range f.Params {
-		if p.Type == "string" {
-			return true
-		}
-	}
-	return false
-}
-
-// HelperName returns name of function f helper.
-func (f *Fn) HelperName() string {
-	if !f.HasStringParam() {
-		return f.Name
-	}
-	return "_" + f.Name
-}
-
-// Source files and functions.
-type Source struct {
-	Funcs []*Fn
-	Files []string
-}
-
-// ParseFiles parses files listed in fs and extracts all syscall
-// functions listed in  sys comments. It returns source files
-// and functions collection *Source if successful.
-func ParseFiles(fs []string) (*Source, error) {
-	src := &Source{
-		Funcs: make([]*Fn, 0),
-		Files: make([]string, 0),
-	}
-	for _, file := range fs {
-		if err := src.ParseFile(file); err != nil {
-			return nil, err
-		}
-	}
-	return src, nil
-}
-
-// DLLs return dll names for a source set src.
-func (src *Source) DLLs() []string {
-	uniq := make(map[string]bool)
-	r := make([]string, 0)
-	for _, f := range src.Funcs {
-		name := f.DLLName()
-		if _, found := uniq[name]; !found {
-			uniq[name] = true
-			r = append(r, name)
-		}
-	}
-	return r
-}
-
-// ParseFile adds additional file path to a source set src.
-func (src *Source) ParseFile(path string) error {
-	file, err := os.Open(path)
-	if err != nil {
-		return err
-	}
-	defer file.Close()
-
-	s := bufio.NewScanner(file)
-	for s.Scan() {
-		t := trim(s.Text())
-		if len(t) < 7 {
-			continue
-		}
-		if !strings.HasPrefix(t, "//sys") {
-			continue
-		}
-		t = t[5:]
-		if !(t[0] == ' ' || t[0] == '\t') {
-			continue
-		}
-		f, err := newFn(t[1:])
-		if err != nil {
-			return err
-		}
-		src.Funcs = append(src.Funcs, f)
-	}
-	if err := s.Err(); err != nil {
-		return err
-	}
-	src.Files = append(src.Files, path)
-
-	// get package name
-	fset := token.NewFileSet()
-	_, err = file.Seek(0, 0)
-	if err != nil {
-		return err
-	}
-	pkg, err := parser.ParseFile(fset, "", file, parser.PackageClauseOnly)
-	if err != nil {
-		return err
-	}
-	packageName = pkg.Name.Name
-
-	return nil
-}
-
-// Generate output source file from a source set src.
-func (src *Source) Generate(w io.Writer) error {
-	funcMap := template.FuncMap{
-		"packagename": packagename,
-		"syscalldot":  syscalldot,
-	}
-	t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
-	err := t.Execute(w, src)
-	if err != nil {
-		return errors.New("Failed to execute template: " + err.Error())
-	}
-	return nil
-}
-
-func usage() {
-	fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n")
-	flag.PrintDefaults()
-	os.Exit(1)
-}
-
-func main() {
-	flag.Usage = usage
-	flag.Parse()
-	if len(flag.Args()) <= 0 {
-		fmt.Fprintf(os.Stderr, "no files to parse provided\n")
-		usage()
-	}
-
-	src, err := ParseFiles(flag.Args())
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	var buf bytes.Buffer
-	if err := src.Generate(&buf); err != nil {
-		log.Fatal(err)
-	}
-
-	data, err := format.Source(buf.Bytes())
-	if err != nil {
-		log.Fatal(err)
-	}
-	if *filename == "" {
-		_, err = os.Stdout.Write(data)
-	} else {
-		err = ioutil.WriteFile(*filename, data, 0644)
-	}
-	if err != nil {
-		log.Fatal(err)
-	}
-}
-
-// TODO: use println instead to print in the following template
-const srcTemplate = `
-
-{{define "main"}}// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
-
-package {{packagename}}
-
-import "unsafe"{{if syscalldot}}
-import "syscall"{{end}}
-
-var _ unsafe.Pointer
-
-var (
-{{template "dlls" .}}
-{{template "funcnames" .}})
-{{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}}
-{{end}}
-
-{{/* help functions */}}
-
-{{define "dlls"}}{{range .DLLs}}	mod{{.}} = {{syscalldot}}NewLazyDLL("{{.}}.dll")
-{{end}}{{end}}
-
-{{define "funcnames"}}{{range .Funcs}}	proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
-{{end}}{{end}}
-
-{{define "helperbody"}}
-func {{.Name}}({{.ParamList}}) {{template "results" .}}{
-{{template "helpertmpvars" .}}	return {{.HelperName}}({{.HelperCallParamList}})
-}
-{{end}}
-
-{{define "funcbody"}}
-func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{
-{{template "tmpvars" .}}	{{template "syscallcheck" .}}{{template "syscall" .}}
-{{template "seterror" .}}{{template "printtrace" .}}	return
-}
-{{end}}
-
-{{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}}	{{.TmpVarHelperCode}}
-{{end}}{{end}}{{end}}
-
-{{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}}	{{.TmpVarCode}}
-{{end}}{{end}}{{end}}
-
-{{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}}
-
-{{define "syscallcheck"}}{{if .ConfirmProc}}if {{.Rets.ErrorVarName}} = proc{{.DLLFuncName}}.Find(); {{.Rets.ErrorVarName}} != nil {
-    return
-}
-{{end}}{{end}}
-
-{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
-
-{{define "seterror"}}{{if .Rets.SetErrorCode}}	{{.Rets.SetErrorCode}}
-{{end}}{{end}}
-
-{{define "printtrace"}}{{if .PrintTrace}}	print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
-{{end}}{{end}}
-
-`

+ 1 - 1
vendor/src/github.com/Microsoft/go-winio/pipe.go

@@ -213,7 +213,7 @@ func ListenPipe(path, sddl string) (net.Listener, error) {
 		err error
 	)
 	if sddl != "" {
-		sd, err = sddlToSecurityDescriptor(sddl)
+		sd, err = SddlToSecurityDescriptor(sddl)
 		if err != nil {
 			return nil, err
 		}

+ 147 - 0
vendor/src/github.com/Microsoft/go-winio/privilege.go

@@ -0,0 +1,147 @@
+package winio
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"runtime"
+	"syscall"
+	"unicode/utf16"
+)
+
+//sys adjustTokenPrivileges(token syscall.Handle, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (err error) = advapi32.AdjustTokenPrivileges
+//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
+//sys revertToSelf() (err error) = advapi32.RevertToSelf
+//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *syscall.Handle) (err error) = advapi32.OpenThreadToken
+//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread
+//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
+//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
+//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
+
+const (
+	SE_PRIVILEGE_ENABLED = 2
+
+	SeBackupPrivilege  = "SeBackupPrivilege"
+	SeRestorePrivilege = "SeRestorePrivilege"
+)
+
+const (
+	securityAnonymous = iota
+	securityIdentification
+	securityImpersonation
+	securityDelegation
+)
+
+type PrivilegeError struct {
+	privileges []uint64
+}
+
+func (e *PrivilegeError) Error() string {
+	s := ""
+	if len(e.privileges) > 1 {
+		s = "Could not enable privileges "
+	} else {
+		s = "Could not enable privilege "
+	}
+	for i, p := range e.privileges {
+		if i != 0 {
+			s += ", "
+		}
+		s += `"`
+		s += getPrivilegeName(p)
+		s += `"`
+	}
+	return s
+}
+
+func RunWithPrivilege(name string, fn func() error) error {
+	return RunWithPrivileges([]string{name}, fn)
+}
+
+func RunWithPrivileges(names []string, fn func() error) error {
+	var privileges []uint64
+	for _, name := range names {
+		p := uint64(0)
+		err := lookupPrivilegeValue("", name, &p)
+		if err != nil {
+			return err
+		}
+		privileges = append(privileges, p)
+	}
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+	token, err := newThreadToken()
+	if err != nil {
+		return err
+	}
+	defer releaseThreadToken(token)
+	err = adjustPrivileges(token, privileges)
+	if err != nil {
+		return err
+	}
+	return fn()
+}
+
+func adjustPrivileges(token syscall.Handle, privileges []uint64) error {
+	var b bytes.Buffer
+	binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
+	for _, p := range privileges {
+		binary.Write(&b, binary.LittleEndian, p)
+		binary.Write(&b, binary.LittleEndian, uint32(SE_PRIVILEGE_ENABLED))
+	}
+	prevState := make([]byte, b.Len())
+	reqSize := uint32(0)
+	if err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize); err != nil {
+		return err
+	}
+	if int(binary.LittleEndian.Uint32(prevState[0:4])) < len(privileges) {
+		return &PrivilegeError{privileges}
+	}
+	return nil
+}
+
+func getPrivilegeName(luid uint64) string {
+	var nameBuffer [256]uint16
+	bufSize := uint32(len(nameBuffer))
+	err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize)
+	if err != nil {
+		return fmt.Sprintf("<unknown privilege %d>", luid)
+	}
+
+	var displayNameBuffer [256]uint16
+	displayBufSize := uint32(len(displayNameBuffer))
+	var langId uint32
+	err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langId)
+	if err != nil {
+		return fmt.Sprintf("<unknown privilege %s>", utf16.Decode(nameBuffer[:bufSize]))
+	}
+
+	return string(utf16.Decode(displayNameBuffer[:displayBufSize]))
+}
+
+func newThreadToken() (syscall.Handle, error) {
+	err := impersonateSelf(securityImpersonation)
+	if err != nil {
+		panic(err)
+		return 0, err
+	}
+
+	var token syscall.Handle
+	err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token)
+	if err != nil {
+		rerr := revertToSelf()
+		if rerr != nil {
+			panic(rerr)
+		}
+		return 0, err
+	}
+	return token, nil
+}
+
+func releaseThreadToken(h syscall.Handle) {
+	err := revertToSelf()
+	if err != nil {
+		panic(err)
+	}
+	syscall.Close(h)
+}

+ 124 - 0
vendor/src/github.com/Microsoft/go-winio/reparse.go

@@ -0,0 +1,124 @@
+package winio
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"strings"
+	"unicode/utf16"
+	"unsafe"
+)
+
+const (
+	reparseTagMountPoint = 0xA0000003
+	reparseTagSymlink    = 0xA000000C
+)
+
+type reparseDataBuffer struct {
+	ReparseTag           uint32
+	ReparseDataLength    uint16
+	Reserved             uint16
+	SubstituteNameOffset uint16
+	SubstituteNameLength uint16
+	PrintNameOffset      uint16
+	PrintNameLength      uint16
+}
+
+// ReparsePoint describes a Win32 symlink or mount point.
+type ReparsePoint struct {
+	Target       string
+	IsMountPoint bool
+}
+
+// UnsupportedReparsePointError is returned when trying to decode a non-symlink or
+// mount point reparse point.
+type UnsupportedReparsePointError struct {
+	Tag uint32
+}
+
+func (e *UnsupportedReparsePointError) Error() string {
+	return fmt.Sprintf("unsupported reparse point %x", e.Tag)
+}
+
+// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink
+// or a mount point.
+func DecodeReparsePoint(b []byte) (*ReparsePoint, error) {
+	isMountPoint := false
+	tag := binary.LittleEndian.Uint32(b[0:4])
+	switch tag {
+	case reparseTagMountPoint:
+		isMountPoint = true
+	case reparseTagSymlink:
+	default:
+		return nil, &UnsupportedReparsePointError{tag}
+	}
+	nameOffset := 16 + binary.LittleEndian.Uint16(b[12:14])
+	if !isMountPoint {
+		nameOffset += 4
+	}
+	nameLength := binary.LittleEndian.Uint16(b[14:16])
+	name := make([]uint16, nameLength/2)
+	err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name)
+	if err != nil {
+		return nil, err
+	}
+	return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil
+}
+
+func isDriveLetter(c byte) bool {
+	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+}
+
+// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or
+// mount point.
+func EncodeReparsePoint(rp *ReparsePoint) []byte {
+	// Generate an NT path and determine if this is a relative path.
+	var ntTarget string
+	relative := false
+	if strings.HasPrefix(rp.Target, `\\?\`) {
+		ntTarget = rp.Target
+	} else if strings.HasPrefix(rp.Target, `\\`) {
+		ntTarget = `\??\UNC\` + rp.Target[2:]
+	} else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' {
+		ntTarget = `\??\` + rp.Target
+	} else {
+		ntTarget = rp.Target
+		relative = true
+	}
+
+	// The paths must be NUL-terminated even though they are counted strings.
+	target16 := utf16.Encode([]rune(rp.Target + "\x00"))
+	ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00"))
+
+	size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8
+	size += len(ntTarget16)*2 + len(target16)*2
+
+	tag := uint32(reparseTagMountPoint)
+	if !rp.IsMountPoint {
+		tag = reparseTagSymlink
+		size += 4 // Add room for symlink flags
+	}
+
+	data := reparseDataBuffer{
+		ReparseTag:           tag,
+		ReparseDataLength:    uint16(size),
+		SubstituteNameOffset: 0,
+		SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2),
+		PrintNameOffset:      uint16(len(ntTarget16) * 2),
+		PrintNameLength:      uint16((len(target16) - 1) * 2),
+	}
+
+	var b bytes.Buffer
+	binary.Write(&b, binary.LittleEndian, &data)
+	if !rp.IsMountPoint {
+		flags := uint32(0)
+		if relative {
+			flags |= 1
+		}
+		binary.Write(&b, binary.LittleEndian, flags)
+	}
+
+	binary.Write(&b, binary.LittleEndian, ntTarget16)
+	binary.Write(&b, binary.LittleEndian, target16)
+	return b.Bytes()
+}

+ 15 - 2
vendor/src/github.com/Microsoft/go-winio/sd.go

@@ -8,6 +8,7 @@ import (
 //sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
 //sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
 //sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
+//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
 //sys localFree(mem uintptr) = LocalFree
 //sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
 
@@ -70,7 +71,7 @@ func LookupSidByName(name string) (sid string, err error) {
 	return sid, nil
 }
 
-func sddlToSecurityDescriptor(sddl string) ([]byte, error) {
+func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
 	var sdBuffer uintptr
 	err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
 	if err != nil {
@@ -78,6 +79,18 @@ func sddlToSecurityDescriptor(sddl string) ([]byte, error) {
 	}
 	defer localFree(sdBuffer)
 	sd := make([]byte, getSecurityDescriptorLength(sdBuffer))
-	copy(sd, (*[1 << 30]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
+	copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
 	return sd, nil
 }
+
+func SecurityDescriptorToSddl(sd []byte) (string, error) {
+	var sddl *uint16
+	// The returned string length seems to including an aribtrary number of terminating NULs.
+	// Don't use it.
+	err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
+	if err != nil {
+		return "", err
+	}
+	defer localFree(uintptr(unsafe.Pointer(sddl)))
+	return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil
+}

+ 1 - 1
vendor/src/github.com/Microsoft/go-winio/syscall.go

@@ -1,3 +1,3 @@
 package winio
 
-//go:generate go run mksyscall_windows.go -output zsyscall.go file.go pipe.go sd.go
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go

+ 239 - 0
vendor/src/github.com/Microsoft/go-winio/zsyscall.go

@@ -22,8 +22,21 @@ var (
 	procLookupAccountNameW                                   = modadvapi32.NewProc("LookupAccountNameW")
 	procConvertSidToStringSidW                               = modadvapi32.NewProc("ConvertSidToStringSidW")
 	procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
+	procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
 	procLocalFree                                            = modkernel32.NewProc("LocalFree")
 	procGetSecurityDescriptorLength                          = modadvapi32.NewProc("GetSecurityDescriptorLength")
+	procGetFileInformationByHandleEx                         = modkernel32.NewProc("GetFileInformationByHandleEx")
+	procSetFileInformationByHandle                           = modkernel32.NewProc("SetFileInformationByHandle")
+	procAdjustTokenPrivileges                                = modadvapi32.NewProc("AdjustTokenPrivileges")
+	procImpersonateSelf                                      = modadvapi32.NewProc("ImpersonateSelf")
+	procRevertToSelf                                         = modadvapi32.NewProc("RevertToSelf")
+	procOpenThreadToken                                      = modadvapi32.NewProc("OpenThreadToken")
+	procGetCurrentThread                                     = modkernel32.NewProc("GetCurrentThread")
+	procLookupPrivilegeValueW                                = modadvapi32.NewProc("LookupPrivilegeValueW")
+	procLookupPrivilegeNameW                                 = modadvapi32.NewProc("LookupPrivilegeNameW")
+	procLookupPrivilegeDisplayNameW                          = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
+	procBackupRead                                           = modkernel32.NewProc("BackupRead")
+	procBackupWrite                                          = modkernel32.NewProc("BackupWrite")
 )
 
 func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
@@ -206,6 +219,18 @@ func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision
 	return
 }
 
+func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) {
+	r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
 func localFree(mem uintptr) {
 	syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
 	return
@@ -216,3 +241,217 @@ func getSecurityDescriptorLength(sd uintptr) (len uint32) {
 	len = uint32(r0)
 	return
 }
+
+func getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
+	r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
+	r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func adjustTokenPrivileges(token syscall.Handle, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (err error) {
+	var _p0 uint32
+	if releaseAll {
+		_p0 = 1
+	} else {
+		_p0 = 0
+	}
+	r1, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func impersonateSelf(level uint32) (err error) {
+	r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func revertToSelf() (err error) {
+	r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *syscall.Handle) (err error) {
+	var _p0 uint32
+	if openAsSelf {
+		_p0 = 1
+	} else {
+		_p0 = 0
+	}
+	r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func getCurrentThread() (h syscall.Handle) {
+	r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
+	h = syscall.Handle(r0)
+	return
+}
+
+func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(systemName)
+	if err != nil {
+		return
+	}
+	var _p1 *uint16
+	_p1, err = syscall.UTF16PtrFromString(name)
+	if err != nil {
+		return
+	}
+	return _lookupPrivilegeValue(_p0, _p1, luid)
+}
+
+func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) {
+	r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(systemName)
+	if err != nil {
+		return
+	}
+	return _lookupPrivilegeName(_p0, luid, buffer, size)
+}
+
+func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
+	r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(systemName)
+	if err != nil {
+		return
+	}
+	return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId)
+}
+
+func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
+	r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
+	var _p0 *byte
+	if len(b) > 0 {
+		_p0 = &b[0]
+	}
+	var _p1 uint32
+	if abort {
+		_p1 = 1
+	} else {
+		_p1 = 0
+	}
+	var _p2 uint32
+	if processSecurity {
+		_p2 = 1
+	} else {
+		_p2 = 0
+	}
+	r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
+	var _p0 *byte
+	if len(b) > 0 {
+		_p0 = &b[0]
+	}
+	var _p1 uint32
+	if abort {
+		_p1 = 1
+	} else {
+		_p1 = 0
+	}
+	var _p2 uint32
+	if processSecurity {
+		_p2 = 1
+	} else {
+		_p2 = 0
+	}
+	r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}

+ 0 - 34
vendor/src/github.com/Microsoft/hcsshim/copylayer.go

@@ -1,34 +0,0 @@
-package hcsshim
-
-import "github.com/Sirupsen/logrus"
-
-// CopyLayer performs a commit of the srcId (which is expected to be a read-write
-// layer) into a new read-only layer at dstId.  This requires the full list of
-// on-disk paths to parent layers, provided in parentLayerPaths, in order to
-// complete the commit.
-func CopyLayer(info DriverInfo, srcId, dstId string, parentLayerPaths []string) error {
-	title := "hcsshim::CopyLayer "
-	logrus.Debugf(title+"srcId %s dstId", srcId, dstId)
-
-	// Generate layer descriptors
-	layers, err := layerPathsToDescriptors(parentLayerPaths)
-	if err != nil {
-		return err
-	}
-
-	// Convert info to API calling convention
-	infop, err := convertDriverInfo(info)
-	if err != nil {
-		return err
-	}
-
-	err = copyLayer(&infop, srcId, dstId, layers)
-	if err != nil {
-		err = makeErrorf(err, title, "srcId=%s dstId=%d", srcId, dstId)
-		logrus.Error(err)
-		return err
-	}
-
-	logrus.Debugf(title+" - succeeded srcId=%s dstId=%s", srcId, dstId)
-	return nil
-}

+ 3 - 3
vendor/src/github.com/Microsoft/hcsshim/createprocess.go

@@ -82,12 +82,12 @@ func CreateProcessInComputeSystem(id string, useStdin bool, useStdout bool, useS
 	err = createProcessWithStdHandlesInComputeSystem(id, string(paramsJson), &pid, stdinParam, stdoutParam, stderrParam)
 	if err != nil {
 		herr := makeErrorf(err, title, "id=%s params=%v", id, params)
-		err = herr
 		// Windows TP4: Hyper-V Containers may return this error with more than one
 		// concurrent exec. Do not log it as an error
-		if herr.Err != WSAEINVAL {
-			logrus.Error(err)
+		if err != WSAEINVAL {
+			logrus.Error(herr)
 		}
+		err = herr
 		return
 	}
 

+ 121 - 1
vendor/src/github.com/Microsoft/hcsshim/exportlayer.go

@@ -1,6 +1,15 @@
 package hcsshim
 
-import "github.com/Sirupsen/logrus"
+import (
+	"io"
+	"io/ioutil"
+	"os"
+	"runtime"
+	"syscall"
+
+	"github.com/Microsoft/go-winio"
+	"github.com/Sirupsen/logrus"
+)
 
 // ExportLayer will create a folder at exportFolderPath and fill that folder with
 // the transport format version of the layer identified by layerId. This transport
@@ -34,3 +43,114 @@ func ExportLayer(info DriverInfo, layerId string, exportFolderPath string, paren
 	logrus.Debugf(title+"succeeded flavour=%d layerId=%s folder=%s", info.Flavour, layerId, exportFolderPath)
 	return nil
 }
+
+type LayerReader interface {
+	Next() (string, int64, *winio.FileBasicInfo, error)
+	Read(b []byte) (int, error)
+	Close() error
+}
+
+// FilterLayerReader provides an interface for extracting the contents of an on-disk layer.
+type FilterLayerReader struct {
+	context uintptr
+}
+
+// Next reads the next available file from a layer, ensuring that parent directories are always read
+// before child files and directories.
+//
+// Next returns the file's relative path, size, and basic file metadata. Read() should be used to
+// extract a Win32 backup stream with the remainder of the metadata and the data.
+func (r *FilterLayerReader) Next() (string, int64, *winio.FileBasicInfo, error) {
+	var fileNamep *uint16
+	fileInfo := &winio.FileBasicInfo{}
+	var deleted uint32
+	var fileSize int64
+	err := exportLayerNext(r.context, &fileNamep, fileInfo, &fileSize, &deleted)
+	if err != nil {
+		if err == syscall.ERROR_NO_MORE_FILES {
+			err = io.EOF
+		} else {
+			err = makeError(err, "ExportLayerNext", "")
+		}
+		return "", 0, nil, err
+	}
+	fileName := convertAndFreeCoTaskMemString(fileNamep)
+	if deleted != 0 {
+		fileInfo = nil
+	}
+	if fileName[0] == '\\' {
+		fileName = fileName[1:]
+	}
+	return fileName, fileSize, fileInfo, nil
+}
+
+// Read reads from the current file's Win32 backup stream.
+func (r *FilterLayerReader) Read(b []byte) (int, error) {
+	var bytesRead uint32
+	err := exportLayerRead(r.context, b, &bytesRead)
+	if err != nil {
+		return 0, makeError(err, "ExportLayerRead", "")
+	}
+	if bytesRead == 0 {
+		return 0, io.EOF
+	}
+	return int(bytesRead), nil
+}
+
+// Close frees resources associated with the layer reader. It will return an
+// error if there was an error while reading the layer or of the layer was not
+// completely read.
+func (r *FilterLayerReader) Close() (err error) {
+	if r.context != 0 {
+		err = exportLayerEnd(r.context)
+		if err != nil {
+			err = makeError(err, "ExportLayerEnd", "")
+		}
+		r.context = 0
+	}
+	return
+}
+
+// NewLayerReader returns a new layer reader for reading the contents of an on-disk layer.
+func NewLayerReader(info DriverInfo, layerId string, parentLayerPaths []string) (LayerReader, error) {
+	if procExportLayerBegin.Find() != nil {
+		// The new layer reader is not available on this Windows build. Fall back to the
+		// legacy export code path.
+		path, err := ioutil.TempDir("", "hcs")
+		if err != nil {
+			return nil, err
+		}
+		err = ExportLayer(info, layerId, path, parentLayerPaths)
+		if err != nil {
+			os.RemoveAll(path)
+			return nil, err
+		}
+		return &legacyLayerReaderWrapper{NewLegacyLayerReader(path)}, nil
+	}
+
+	layers, err := layerPathsToDescriptors(parentLayerPaths)
+	if err != nil {
+		return nil, err
+	}
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		return nil, err
+	}
+	r := &FilterLayerReader{}
+	err = exportLayerBegin(&infop, layerId, layers, &r.context)
+	if err != nil {
+		return nil, makeError(err, "ExportLayerBegin", "")
+	}
+	runtime.SetFinalizer(r, func(r *FilterLayerReader) { r.Close() })
+	return r, err
+}
+
+type legacyLayerReaderWrapper struct {
+	*LegacyLayerReader
+}
+
+func (r *legacyLayerReaderWrapper) Close() error {
+	err := r.LegacyLayerReader.Close()
+	os.RemoveAll(r.root)
+	return err
+}

+ 29 - 9
vendor/src/github.com/Microsoft/hcsshim/hcsshim.go

@@ -28,6 +28,16 @@ import (
 //sys prepareLayer(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.PrepareLayer?
 //sys unprepareLayer(info *driverInfo, id string) (hr error) = vmcompute.UnprepareLayer?
 
+//sys importLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) = vmcompute.ImportLayerBegin?
+//sys importLayerNext(context uintptr, fileName string, fileInfo *winio.FileBasicInfo) (hr error) = vmcompute.ImportLayerNext?
+//sys importLayerWrite(context uintptr, buffer []byte) (hr error) = vmcompute.ImportLayerWrite?
+//sys importLayerEnd(context uintptr) (hr error) = vmcompute.ImportLayerEnd?
+
+//sys exportLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) = vmcompute.ExportLayerBegin?
+//sys exportLayerNext(context uintptr, fileName **uint16, fileInfo *winio.FileBasicInfo, fileSize *int64, deleted *uint32) (hr error) = vmcompute.ExportLayerNext?
+//sys exportLayerRead(context uintptr, buffer []byte, bytesRead *uint32) (hr error) = vmcompute.ExportLayerRead?
+//sys exportLayerEnd(context uintptr) (hr error) = vmcompute.ExportLayerEnd?
+
 //sys createComputeSystem(id string, configuration string) (hr error) = vmcompute.CreateComputeSystem?
 //sys createProcessWithStdHandlesInComputeSystem(id string, paramsJson string, pid *uint32, stdin *syscall.Handle, stdout *syscall.Handle, stderr *syscall.Handle) (hr error) = vmcompute.CreateProcessWithStdHandlesInComputeSystem?
 //sys resizeConsoleInComputeSystem(id string, pid uint32, height uint16, width uint16, flags uint32) (hr error) = vmcompute.ResizeConsoleInComputeSystem?
@@ -57,16 +67,15 @@ type HcsError struct {
 	Err   error
 }
 
-func makeError(err error, title, rest string) *HcsError {
-	if hr, ok := err.(syscall.Errno); ok {
-		// Convert the HRESULT to a Win32 error code so that it better matches
-		// error codes returned from go and other packages.
-		err = syscall.Errno(win32FromHresult(uint32(hr)))
+func makeError(err error, title, rest string) error {
+	// Pass through DLL errors directly since they do not originate from HCS.
+	if _, ok := err.(*syscall.DLLError); ok {
+		return err
 	}
 	return &HcsError{title, rest, err}
 }
 
-func makeErrorf(err error, title, format string, a ...interface{}) *HcsError {
+func makeErrorf(err error, title, format string, a ...interface{}) error {
 	return makeError(err, title, fmt.Sprintf(format, a...))
 }
 
@@ -75,12 +84,12 @@ func win32FromError(err error) uint32 {
 		return win32FromError(herr.Err)
 	}
 	if code, ok := err.(syscall.Errno); ok {
-		return win32FromHresult(uint32(code))
+		return uint32(code)
 	}
 	return uint32(ERROR_GEN_FAILURE)
 }
 
-func win32FromHresult(hr uint32) uint32 {
+func win32FromHresult(hr uintptr) uintptr {
 	if hr&0x1fff0000 == 0x00070000 {
 		return hr & 0xffff
 	}
@@ -88,7 +97,18 @@ func win32FromHresult(hr uint32) uint32 {
 }
 
 func (e *HcsError) Error() string {
-	return fmt.Sprintf("%s- Win32 API call returned error r1=0x%x err=%s%s", e.title, win32FromError(e.Err), e.Err, e.rest)
+	s := e.title
+	if len(s) > 0 && s[len(s)-1] != ' ' {
+		s += " "
+	}
+	s += fmt.Sprintf("failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err))
+	if e.rest != "" {
+		if e.rest[0] != ' ' {
+			s += " "
+		}
+		s += e.rest
+	}
+	return s
 }
 
 func convertAndFreeCoTaskMemString(buffer *uint16) string {

+ 119 - 1
vendor/src/github.com/Microsoft/hcsshim/importlayer.go

@@ -1,6 +1,13 @@
 package hcsshim
 
-import "github.com/Sirupsen/logrus"
+import (
+	"io/ioutil"
+	"os"
+	"runtime"
+
+	"github.com/Microsoft/go-winio"
+	"github.com/Sirupsen/logrus"
+)
 
 // ImportLayer will take the contents of the folder at importFolderPath and import
 // that into a layer with the id layerId.  Note that in order to correctly populate
@@ -33,3 +40,114 @@ func ImportLayer(info DriverInfo, layerId string, importFolderPath string, paren
 	logrus.Debugf(title+"succeeded flavour=%d layerId=%s folder=%s", info.Flavour, layerId, importFolderPath)
 	return nil
 }
+
+type LayerWriter interface {
+	Add(name string, fileInfo *winio.FileBasicInfo) error
+	Remove(name string) error
+	Write(b []byte) (int, error)
+	Close() error
+}
+
+// FilterLayerWriter provides an interface to write the contents of a layer to the file system.
+type FilterLayerWriter struct {
+	context uintptr
+}
+
+// Add adds a file or directory to the layer. The file's parent directory must have already been added.
+//
+// name contains the file's relative path. fileInfo contains file times and file attributes; the rest
+// of the file metadata and the file data must be written as a Win32 backup stream to the Write() method.
+// winio.BackupStreamWriter can be used to facilitate this.
+func (w *FilterLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error {
+	if name[0] != '\\' {
+		name = `\` + name
+	}
+	err := importLayerNext(w.context, name, fileInfo)
+	if err != nil {
+		return makeError(err, "ImportLayerNext", "")
+	}
+	return nil
+}
+
+// Remove removes a file from the layer. The file must have been present in the parent layer.
+//
+// name contains the file's relative path.
+func (w *FilterLayerWriter) Remove(name string) error {
+	if name[0] != '\\' {
+		name = `\` + name
+	}
+	err := importLayerNext(w.context, name, nil)
+	if err != nil {
+		return makeError(err, "ImportLayerNext", "")
+	}
+	return nil
+}
+
+// Write writes more backup stream data to the current file.
+func (w *FilterLayerWriter) Write(b []byte) (int, error) {
+	err := importLayerWrite(w.context, b)
+	if err != nil {
+		err = makeError(err, "ImportLayerWrite", "")
+		return 0, err
+	}
+	return len(b), err
+}
+
+// Close completes the layer write operation. The error must be checked to ensure that the
+// operation was successful.
+func (w *FilterLayerWriter) Close() (err error) {
+	if w.context != 0 {
+		err = importLayerEnd(w.context)
+		if err != nil {
+			err = makeError(err, "ImportLayerEnd", "")
+		}
+		w.context = 0
+	}
+	return
+}
+
+type legacyLayerWriterWrapper struct {
+	*LegacyLayerWriter
+	info             DriverInfo
+	layerId          string
+	parentLayerPaths []string
+}
+
+func (r *legacyLayerWriterWrapper) Close() error {
+	err := r.LegacyLayerWriter.Close()
+	if err == nil {
+		err = ImportLayer(r.info, r.layerId, r.root, r.parentLayerPaths)
+	}
+	os.RemoveAll(r.root)
+	return err
+}
+
+// NewLayerWriter returns a new layer writer for creating a layer on disk.
+func NewLayerWriter(info DriverInfo, layerId string, parentLayerPaths []string) (LayerWriter, error) {
+	if procImportLayerBegin.Find() != nil {
+		// The new layer reader is not available on this Windows build. Fall back to the
+		// legacy export code path.
+		path, err := ioutil.TempDir("", "hcs")
+		if err != nil {
+			return nil, err
+		}
+		return &legacyLayerWriterWrapper{NewLegacyLayerWriter(path), info, layerId, parentLayerPaths}, nil
+	}
+	layers, err := layerPathsToDescriptors(parentLayerPaths)
+	if err != nil {
+		return nil, err
+	}
+
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		return nil, err
+	}
+
+	w := &FilterLayerWriter{}
+	err = importLayerBegin(&infop, layerId, layers, &w.context)
+	if err != nil {
+		return nil, makeError(err, "ImportLayerStart", "")
+	}
+	runtime.SetFinalizer(w, func(w *FilterLayerWriter) { w.Close() })
+	return w, nil
+}

+ 397 - 0
vendor/src/github.com/Microsoft/hcsshim/legacy.go

@@ -0,0 +1,397 @@
+package hcsshim
+
+import (
+	"bufio"
+	"encoding/binary"
+	"errors"
+	"io"
+	"os"
+	"path/filepath"
+	"strings"
+	"syscall"
+
+	"github.com/Microsoft/go-winio"
+)
+
+var errorIterationCanceled = errors.New("")
+
+func openFileOrDir(path string, mode uint32, createDisposition uint32) (file *os.File, err error) {
+	winPath, err := syscall.UTF16FromString(path)
+	if err != nil {
+		return
+	}
+	h, err := syscall.CreateFile(&winPath[0], mode, syscall.FILE_SHARE_READ, nil, createDisposition, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
+	if err != nil {
+		err = &os.PathError{"open", path, err}
+		return
+	}
+	file = os.NewFile(uintptr(h), path)
+	return
+}
+
+type fileEntry struct {
+	path string
+	fi   os.FileInfo
+	err  error
+}
+
+type LegacyLayerReader struct {
+	root         string
+	result       chan *fileEntry
+	proceed      chan bool
+	currentFile  *os.File
+	backupReader *winio.BackupFileReader
+	isTP4Format  bool
+}
+
+// NewLegacyLayerReader returns a new LayerReader that can read the Windows
+// TP4 transport format from disk.
+func NewLegacyLayerReader(root string) *LegacyLayerReader {
+	r := &LegacyLayerReader{
+		root:        root,
+		result:      make(chan *fileEntry),
+		proceed:     make(chan bool),
+		isTP4Format: IsTP4(),
+	}
+	go r.walk()
+	return r
+}
+
+func readTombstones(path string) (map[string]([]string), error) {
+	tf, err := os.Open(filepath.Join(path, "tombstones.txt"))
+	if err != nil {
+		return nil, err
+	}
+	defer tf.Close()
+	s := bufio.NewScanner(tf)
+	if !s.Scan() || s.Text() != "\xef\xbb\xbfVersion 1.0" {
+		return nil, errors.New("Invalid tombstones file")
+	}
+
+	ts := make(map[string]([]string))
+	for s.Scan() {
+		t := s.Text()[1:] // skip leading `\`
+		dir := filepath.Dir(t)
+		ts[dir] = append(ts[dir], t)
+	}
+	if err = s.Err(); err != nil {
+		return nil, err
+	}
+
+	return ts, nil
+}
+
+func (r *LegacyLayerReader) walk() {
+	defer close(r.result)
+	if !<-r.proceed {
+		return
+	}
+
+	ts, err := readTombstones(r.root)
+	if err != nil {
+		goto ErrorLoop
+	}
+
+	err = filepath.Walk(r.root, func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+		if path == r.root || path == filepath.Join(r.root, "tombstones.txt") || strings.HasSuffix(path, ".$wcidirs$") {
+			return nil
+		}
+		r.result <- &fileEntry{path, info, nil}
+		if !<-r.proceed {
+			return errorIterationCanceled
+		}
+
+		// List all the tombstones.
+		if info.IsDir() {
+			relPath, err := filepath.Rel(r.root, path)
+			if err != nil {
+				return err
+			}
+			if dts, ok := ts[relPath]; ok {
+				for _, t := range dts {
+					r.result <- &fileEntry{t, nil, nil}
+					if !<-r.proceed {
+						return errorIterationCanceled
+					}
+				}
+			}
+		}
+		return nil
+	})
+	if err == errorIterationCanceled {
+		return
+	}
+	if err == nil {
+		err = io.EOF
+	}
+
+ErrorLoop:
+	for {
+		r.result <- &fileEntry{err: err}
+		if !<-r.proceed {
+			break
+		}
+	}
+}
+
+func (r *LegacyLayerReader) reset() {
+	if r.backupReader != nil {
+		r.backupReader.Close()
+		r.backupReader = nil
+	}
+	if r.currentFile != nil {
+		r.currentFile.Close()
+		r.currentFile = nil
+	}
+}
+
+func findBackupStreamSize(r io.Reader) (int64, error) {
+	br := winio.NewBackupStreamReader(r)
+	for {
+		hdr, err := br.Next()
+		if err != nil {
+			if err == io.EOF {
+				err = nil
+			}
+			return 0, err
+		}
+		if hdr.Id == winio.BackupData {
+			return hdr.Size, nil
+		}
+	}
+}
+
+func (r *LegacyLayerReader) Next() (path string, size int64, fileInfo *winio.FileBasicInfo, err error) {
+	r.reset()
+	r.proceed <- true
+	fe := <-r.result
+	if fe == nil {
+		err = errors.New("LegacyLayerReader closed")
+		return
+	}
+	if fe.err != nil {
+		err = fe.err
+		return
+	}
+
+	path, err = filepath.Rel(r.root, fe.path)
+	if err != nil {
+		return
+	}
+
+	if fe.fi == nil {
+		// This is a tombstone. Return a nil fileInfo.
+		return
+	}
+
+	if fe.fi.IsDir() && strings.HasPrefix(path, `Files\`) {
+		fe.path += ".$wcidirs$"
+	}
+
+	f, err := openFileOrDir(fe.path, syscall.GENERIC_READ, syscall.OPEN_EXISTING)
+	if err != nil {
+		return
+	}
+	defer func() {
+		if f != nil {
+			f.Close()
+		}
+	}()
+
+	fileInfo, err = winio.GetFileBasicInfo(f)
+	if err != nil {
+		return
+	}
+
+	if !strings.HasPrefix(path, `Files\`) {
+		size = fe.fi.Size()
+		r.backupReader = winio.NewBackupFileReader(f, false)
+		if path == "Hives" || path == "Files" {
+			// The Hives directory has a non-deterministic file time because of the
+			// nature of the import process. Use the times from System_Delta.
+			var g *os.File
+			g, err = os.Open(filepath.Join(r.root, `Hives\System_Delta`))
+			if err != nil {
+				return
+			}
+			attr := fileInfo.FileAttributes
+			fileInfo, err = winio.GetFileBasicInfo(g)
+			g.Close()
+			if err != nil {
+				return
+			}
+			fileInfo.FileAttributes = attr
+		}
+
+		// The creation time and access time get reset for files outside of the Files path.
+		fileInfo.CreationTime = fileInfo.LastWriteTime
+		fileInfo.LastAccessTime = fileInfo.LastWriteTime
+
+	} else {
+		beginning := int64(0)
+		if !r.isTP4Format {
+			// In TP5, the file attributes were added before the backup stream
+			var attr uint32
+			err = binary.Read(f, binary.LittleEndian, &attr)
+			if err != nil {
+				return
+			}
+			fileInfo.FileAttributes = uintptr(attr)
+			beginning = 4
+		}
+
+		// Find the accurate file size.
+		if !fe.fi.IsDir() {
+			size, err = findBackupStreamSize(f)
+			if err != nil {
+				err = &os.PathError{"findBackupStreamSize", fe.path, err}
+				return
+			}
+		}
+
+		// Return back to the beginning of the backup stream.
+		_, err = f.Seek(beginning, 0)
+		if err != nil {
+			return
+		}
+	}
+
+	r.currentFile = f
+	f = nil
+	return
+}
+
+func (r *LegacyLayerReader) Read(b []byte) (int, error) {
+	if r.backupReader == nil {
+		if r.currentFile == nil {
+			return 0, io.EOF
+		}
+		return r.currentFile.Read(b)
+	}
+	return r.backupReader.Read(b)
+}
+
+func (r *LegacyLayerReader) Close() error {
+	r.proceed <- false
+	<-r.result
+	r.reset()
+	return nil
+}
+
+type LegacyLayerWriter struct {
+	root         string
+	currentFile  *os.File
+	backupWriter *winio.BackupFileWriter
+	tombstones   []string
+	isTP4Format  bool
+}
+
+// NewLegacyLayerWriter returns a LayerWriter that can write the TP4 transport format
+// to disk.
+func NewLegacyLayerWriter(root string) *LegacyLayerWriter {
+	return &LegacyLayerWriter{
+		root:        root,
+		isTP4Format: IsTP4(),
+	}
+}
+
+func (w *LegacyLayerWriter) reset() {
+	if w.backupWriter != nil {
+		w.backupWriter.Close()
+		w.backupWriter = nil
+	}
+	if w.currentFile != nil {
+		w.currentFile.Close()
+		w.currentFile = nil
+	}
+}
+
+func (w *LegacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error {
+	w.reset()
+	path := filepath.Join(w.root, name)
+
+	createDisposition := uint32(syscall.CREATE_NEW)
+	if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
+		err := os.Mkdir(path, 0)
+		if err != nil {
+			return err
+		}
+		if strings.HasPrefix(name, `Files\`) {
+			path += ".$wcidirs$"
+		} else {
+			createDisposition = syscall.OPEN_EXISTING
+		}
+	}
+
+	f, err := openFileOrDir(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, createDisposition)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		if f != nil {
+			f.Close()
+			os.Remove(path)
+		}
+	}()
+
+	strippedFi := *fileInfo
+	strippedFi.FileAttributes = 0
+	err = winio.SetFileBasicInfo(f, &strippedFi)
+	if err != nil {
+		return err
+	}
+
+	if !strings.HasPrefix(name, `Files\`) {
+		w.backupWriter = winio.NewBackupFileWriter(f, false)
+	} else {
+		if !w.isTP4Format {
+			// In TP5, the file attributes were added to the header
+			err = binary.Write(f, binary.LittleEndian, uint32(fileInfo.FileAttributes))
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	w.currentFile = f
+	f = nil
+	return nil
+}
+
+func (w *LegacyLayerWriter) Remove(name string) error {
+	w.tombstones = append(w.tombstones, name)
+	return nil
+}
+
+func (w *LegacyLayerWriter) Write(b []byte) (int, error) {
+	if w.backupWriter == nil {
+		if w.currentFile == nil {
+			return 0, errors.New("closed")
+		}
+		return w.currentFile.Write(b)
+	}
+	return w.backupWriter.Write(b)
+}
+
+func (w *LegacyLayerWriter) Close() error {
+	w.reset()
+	tf, err := os.Create(filepath.Join(w.root, "tombstones.txt"))
+	if err != nil {
+		return err
+	}
+	defer tf.Close()
+	_, err = tf.Write([]byte("\xef\xbb\xbfVersion 1.0\n"))
+	if err != nil {
+		return err
+	}
+	for _, t := range w.tombstones {
+		_, err = tf.Write([]byte(filepath.Join(`\`, t) + "\n"))
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}

+ 8 - 1
vendor/src/github.com/Microsoft/hcsshim/mksyscall_windows.go

@@ -294,6 +294,9 @@ func (r *Rets) SetErrorCode() string {
 	const code = `if r0 != 0 {
 		%s = %sErrno(r0)
 	}`
+	const hrCode = `if int32(r0) < 0 {
+		%s = %sErrno(win32FromHresult(r0))
+	}`
 	if r.Name == "" && !r.ReturnsError {
 		return ""
 	}
@@ -301,7 +304,11 @@ func (r *Rets) SetErrorCode() string {
 		return r.useLongHandleErrorCode("r1")
 	}
 	if r.Type == "error" {
-		return fmt.Sprintf(code, r.Name, syscalldot())
+		if r.Name == "hr" {
+			return fmt.Sprintf(hrCode, r.Name, syscalldot())
+		} else {
+			return fmt.Sprintf(code, r.Name, syscalldot())
+		}
 	}
 	s := ""
 	switch {

+ 7 - 0
vendor/src/github.com/Microsoft/hcsshim/version.go

@@ -0,0 +1,7 @@
+package hcsshim
+
+// IsTP4 returns whether the currently running Windows build is at least TP4.
+func IsTP4() bool {
+	// HNSCall was not present in TP4
+	return procHNSCall.Find() != nil
+}

+ 190 - 47
vendor/src/github.com/Microsoft/hcsshim/zhcsshim.go

@@ -2,7 +2,11 @@
 
 package hcsshim
 
-import "unsafe"
+import (
+	"unsafe"
+
+	"github.com/Microsoft/go-winio"
+)
 import "syscall"
 
 var _ unsafe.Pointer
@@ -26,6 +30,14 @@ var (
 	procNameToGuid                                 = modvmcompute.NewProc("NameToGuid")
 	procPrepareLayer                               = modvmcompute.NewProc("PrepareLayer")
 	procUnprepareLayer                             = modvmcompute.NewProc("UnprepareLayer")
+	procImportLayerBegin                           = modvmcompute.NewProc("ImportLayerBegin")
+	procImportLayerNext                            = modvmcompute.NewProc("ImportLayerNext")
+	procImportLayerWrite                           = modvmcompute.NewProc("ImportLayerWrite")
+	procImportLayerEnd                             = modvmcompute.NewProc("ImportLayerEnd")
+	procExportLayerBegin                           = modvmcompute.NewProc("ExportLayerBegin")
+	procExportLayerNext                            = modvmcompute.NewProc("ExportLayerNext")
+	procExportLayerRead                            = modvmcompute.NewProc("ExportLayerRead")
+	procExportLayerEnd                             = modvmcompute.NewProc("ExportLayerEnd")
 	procCreateComputeSystem                        = modvmcompute.NewProc("CreateComputeSystem")
 	procCreateProcessWithStdHandlesInComputeSystem = modvmcompute.NewProc("CreateProcessWithStdHandlesInComputeSystem")
 	procResizeConsoleInComputeSystem               = modvmcompute.NewProc("ResizeConsoleInComputeSystem")
@@ -56,8 +68,8 @@ func _activateLayer(info *driverInfo, id *uint16) (hr error) {
 		return
 	}
 	r0, _, _ := syscall.Syscall(procActivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -85,8 +97,8 @@ func _copyLayer(info *driverInfo, srcId *uint16, dstId *uint16, descriptors []WC
 		return
 	}
 	r0, _, _ := syscall.Syscall6(procCopyLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(srcId)), uintptr(unsafe.Pointer(dstId)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -110,8 +122,8 @@ func _createLayer(info *driverInfo, id *uint16, parent *uint16) (hr error) {
 		return
 	}
 	r0, _, _ := syscall.Syscall(procCreateLayer.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(parent)))
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -139,8 +151,8 @@ func _createSandboxLayer(info *driverInfo, id *uint16, parent *uint16, descripto
 		return
 	}
 	r0, _, _ := syscall.Syscall6(procCreateSandboxLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(parent)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -159,8 +171,8 @@ func _deactivateLayer(info *driverInfo, id *uint16) (hr error) {
 		return
 	}
 	r0, _, _ := syscall.Syscall(procDeactivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -179,8 +191,8 @@ func _destroyLayer(info *driverInfo, id *uint16) (hr error) {
 		return
 	}
 	r0, _, _ := syscall.Syscall(procDestroyLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -208,8 +220,8 @@ func _exportLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_L
 		return
 	}
 	r0, _, _ := syscall.Syscall6(procExportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -228,8 +240,8 @@ func _getLayerMountPath(info *driverInfo, id *uint16, length *uintptr, buffer *u
 		return
 	}
 	r0, _, _ := syscall.Syscall6(procGetLayerMountPath.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(length)), uintptr(unsafe.Pointer(buffer)), 0, 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -239,8 +251,8 @@ func getBaseImages(buffer **uint16) (hr error) {
 		return
 	}
 	r0, _, _ := syscall.Syscall(procGetBaseImages.Addr(), 1, uintptr(unsafe.Pointer(buffer)), 0, 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -268,8 +280,8 @@ func _importLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_L
 		return
 	}
 	r0, _, _ := syscall.Syscall6(procImportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -288,8 +300,8 @@ func _layerExists(info *driverInfo, id *uint16, exists *uint32) (hr error) {
 		return
 	}
 	r0, _, _ := syscall.Syscall(procLayerExists.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(exists)))
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -308,8 +320,8 @@ func _nameToGuid(name *uint16, guid *GUID) (hr error) {
 		return
 	}
 	r0, _, _ := syscall.Syscall(procNameToGuid.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(guid)), 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -332,8 +344,8 @@ func _prepareLayer(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPT
 		return
 	}
 	r0, _, _ := syscall.Syscall6(procPrepareLayer.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0, 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -352,8 +364,139 @@ func _unprepareLayer(info *driverInfo, id *uint16) (hr error) {
 		return
 	}
 	r0, _, _ := syscall.Syscall(procUnprepareLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
+	}
+	return
+}
+
+func importLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _importLayerBegin(info, _p0, descriptors, context)
+}
+
+func _importLayerBegin(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
+	var _p1 *WC_LAYER_DESCRIPTOR
+	if len(descriptors) > 0 {
+		_p1 = &descriptors[0]
+	}
+	if hr = procImportLayerBegin.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procImportLayerBegin.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), uintptr(unsafe.Pointer(context)), 0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
+	}
+	return
+}
+
+func importLayerNext(context uintptr, fileName string, fileInfo *winio.FileBasicInfo) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(fileName)
+	if hr != nil {
+		return
+	}
+	return _importLayerNext(context, _p0, fileInfo)
+}
+
+func _importLayerNext(context uintptr, fileName *uint16, fileInfo *winio.FileBasicInfo) (hr error) {
+	if hr = procImportLayerNext.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procImportLayerNext.Addr(), 3, uintptr(context), uintptr(unsafe.Pointer(fileName)), uintptr(unsafe.Pointer(fileInfo)))
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
+	}
+	return
+}
+
+func importLayerWrite(context uintptr, buffer []byte) (hr error) {
+	var _p0 *byte
+	if len(buffer) > 0 {
+		_p0 = &buffer[0]
+	}
+	if hr = procImportLayerWrite.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procImportLayerWrite.Addr(), 3, uintptr(context), uintptr(unsafe.Pointer(_p0)), uintptr(len(buffer)))
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
+	}
+	return
+}
+
+func importLayerEnd(context uintptr) (hr error) {
+	if hr = procImportLayerEnd.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procImportLayerEnd.Addr(), 1, uintptr(context), 0, 0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
+	}
+	return
+}
+
+func exportLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _exportLayerBegin(info, _p0, descriptors, context)
+}
+
+func _exportLayerBegin(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
+	var _p1 *WC_LAYER_DESCRIPTOR
+	if len(descriptors) > 0 {
+		_p1 = &descriptors[0]
+	}
+	if hr = procExportLayerBegin.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procExportLayerBegin.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), uintptr(unsafe.Pointer(context)), 0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
+	}
+	return
+}
+
+func exportLayerNext(context uintptr, fileName **uint16, fileInfo *winio.FileBasicInfo, fileSize *int64, deleted *uint32) (hr error) {
+	if hr = procExportLayerNext.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procExportLayerNext.Addr(), 5, uintptr(context), uintptr(unsafe.Pointer(fileName)), uintptr(unsafe.Pointer(fileInfo)), uintptr(unsafe.Pointer(fileSize)), uintptr(unsafe.Pointer(deleted)), 0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
+	}
+	return
+}
+
+func exportLayerRead(context uintptr, buffer []byte, bytesRead *uint32) (hr error) {
+	var _p0 *byte
+	if len(buffer) > 0 {
+		_p0 = &buffer[0]
+	}
+	if hr = procExportLayerRead.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procExportLayerRead.Addr(), 4, uintptr(context), uintptr(unsafe.Pointer(_p0)), uintptr(len(buffer)), uintptr(unsafe.Pointer(bytesRead)), 0, 0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
+	}
+	return
+}
+
+func exportLayerEnd(context uintptr) (hr error) {
+	if hr = procExportLayerEnd.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procExportLayerEnd.Addr(), 1, uintptr(context), 0, 0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -377,8 +520,8 @@ func _createComputeSystem(id *uint16, configuration *uint16) (hr error) {
 		return
 	}
 	r0, _, _ := syscall.Syscall(procCreateComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -402,8 +545,8 @@ func _createProcessWithStdHandlesInComputeSystem(id *uint16, paramsJson *uint16,
 		return
 	}
 	r0, _, _ := syscall.Syscall6(procCreateProcessWithStdHandlesInComputeSystem.Addr(), 6, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(paramsJson)), uintptr(unsafe.Pointer(pid)), uintptr(unsafe.Pointer(stdin)), uintptr(unsafe.Pointer(stdout)), uintptr(unsafe.Pointer(stderr)))
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -422,8 +565,8 @@ func _resizeConsoleInComputeSystem(id *uint16, pid uint32, height uint16, width
 		return
 	}
 	r0, _, _ := syscall.Syscall6(procResizeConsoleInComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(pid), uintptr(height), uintptr(width), uintptr(flags), 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -442,8 +585,8 @@ func _shutdownComputeSystem(id *uint16, timeout uint32) (hr error) {
 		return
 	}
 	r0, _, _ := syscall.Syscall(procShutdownComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(timeout), 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -462,8 +605,8 @@ func _startComputeSystem(id *uint16) (hr error) {
 		return
 	}
 	r0, _, _ := syscall.Syscall(procStartComputeSystem.Addr(), 1, uintptr(unsafe.Pointer(id)), 0, 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -482,8 +625,8 @@ func _terminateComputeSystem(id *uint16) (hr error) {
 		return
 	}
 	r0, _, _ := syscall.Syscall(procTerminateComputeSystem.Addr(), 1, uintptr(unsafe.Pointer(id)), 0, 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -502,8 +645,8 @@ func _terminateProcessInComputeSystem(id *uint16, pid uint32) (hr error) {
 		return
 	}
 	r0, _, _ := syscall.Syscall(procTerminateProcessInComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(pid), 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -522,8 +665,8 @@ func _waitForProcessInComputeSystem(id *uint16, pid uint32, timeout uint32, exit
 		return
 	}
 	r0, _, _ := syscall.Syscall6(procWaitForProcessInComputeSystem.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(pid), uintptr(timeout), uintptr(unsafe.Pointer(exitCode)), 0, 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }
@@ -552,8 +695,8 @@ func __hnsCall(method *uint16, path *uint16, object *uint16, response **uint16)
 		return
 	}
 	r0, _, _ := syscall.Syscall6(procHNSCall.Addr(), 4, uintptr(unsafe.Pointer(method)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(object)), uintptr(unsafe.Pointer(response)), 0, 0)
-	if r0 != 0 {
-		hr = syscall.Errno(r0)
+	if int32(r0) < 0 {
+		hr = syscall.Errno(win32FromHresult(r0))
 	}
 	return
 }

+ 0 - 178
vendor/src/golang.org/x/sys/windows/registry/key.go

@@ -1,178 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build windows
-
-// Package registry provides access to the Windows registry.
-//
-// Here is a simple example, opening a registry key and reading a string value from it.
-//
-//	k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
-//	if err != nil {
-//		log.Fatal(err)
-//	}
-//	defer k.Close()
-//
-//	s, _, err := k.GetStringValue("SystemRoot")
-//	if err != nil {
-//		log.Fatal(err)
-//	}
-//	fmt.Printf("Windows system root is %q\n", s)
-//
-package registry
-
-import (
-	"io"
-	"syscall"
-	"time"
-)
-
-const (
-	// Registry key security and access rights.
-	// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878.aspx
-	// for details.
-	ALL_ACCESS         = 0xf003f
-	CREATE_LINK        = 0x00020
-	CREATE_SUB_KEY     = 0x00004
-	ENUMERATE_SUB_KEYS = 0x00008
-	EXECUTE            = 0x20019
-	NOTIFY             = 0x00010
-	QUERY_VALUE        = 0x00001
-	READ               = 0x20019
-	SET_VALUE          = 0x00002
-	WOW64_32KEY        = 0x00200
-	WOW64_64KEY        = 0x00100
-	WRITE              = 0x20006
-)
-
-// Key is a handle to an open Windows registry key.
-// Keys can be obtained by calling OpenKey; there are
-// also some predefined root keys such as CURRENT_USER.
-// Keys can be used directly in the Windows API.
-type Key syscall.Handle
-
-const (
-	// Windows defines some predefined root keys that are always open.
-	// An application can use these keys as entry points to the registry.
-	// Normally these keys are used in OpenKey to open new keys,
-	// but they can also be used anywhere a Key is required.
-	CLASSES_ROOT   = Key(syscall.HKEY_CLASSES_ROOT)
-	CURRENT_USER   = Key(syscall.HKEY_CURRENT_USER)
-	LOCAL_MACHINE  = Key(syscall.HKEY_LOCAL_MACHINE)
-	USERS          = Key(syscall.HKEY_USERS)
-	CURRENT_CONFIG = Key(syscall.HKEY_CURRENT_CONFIG)
-)
-
-// Close closes open key k.
-func (k Key) Close() error {
-	return syscall.RegCloseKey(syscall.Handle(k))
-}
-
-// OpenKey opens a new key with path name relative to key k.
-// It accepts any open key, including CURRENT_USER and others,
-// and returns the new key and an error.
-// The access parameter specifies desired access rights to the
-// key to be opened.
-func OpenKey(k Key, path string, access uint32) (Key, error) {
-	p, err := syscall.UTF16PtrFromString(path)
-	if err != nil {
-		return 0, err
-	}
-	var subkey syscall.Handle
-	err = syscall.RegOpenKeyEx(syscall.Handle(k), p, 0, access, &subkey)
-	if err != nil {
-		return 0, err
-	}
-	return Key(subkey), nil
-}
-
-// ReadSubKeyNames returns the names of subkeys of key k.
-// The parameter n controls the number of returned names,
-// analogous to the way os.File.Readdirnames works.
-func (k Key) ReadSubKeyNames(n int) ([]string, error) {
-	ki, err := k.Stat()
-	if err != nil {
-		return nil, err
-	}
-	names := make([]string, 0, ki.SubKeyCount)
-	buf := make([]uint16, ki.MaxSubKeyLen+1) // extra room for terminating zero byte
-loopItems:
-	for i := uint32(0); ; i++ {
-		if n > 0 {
-			if len(names) == n {
-				return names, nil
-			}
-		}
-		l := uint32(len(buf))
-		for {
-			err := syscall.RegEnumKeyEx(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
-			if err == nil {
-				break
-			}
-			if err == syscall.ERROR_MORE_DATA {
-				// Double buffer size and try again.
-				l = uint32(2 * len(buf))
-				buf = make([]uint16, l)
-				continue
-			}
-			if err == _ERROR_NO_MORE_ITEMS {
-				break loopItems
-			}
-			return names, err
-		}
-		names = append(names, syscall.UTF16ToString(buf[:l]))
-	}
-	if n > len(names) {
-		return names, io.EOF
-	}
-	return names, nil
-}
-
-// CreateKey creates a key named path under open key k.
-// CreateKey returns the new key and a boolean flag that reports
-// whether the key already existed.
-// The access parameter specifies the access rights for the key
-// to be created.
-func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) {
-	var h syscall.Handle
-	var d uint32
-	err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path),
-		0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d)
-	if err != nil {
-		return 0, false, err
-	}
-	return Key(h), d == _REG_OPENED_EXISTING_KEY, nil
-}
-
-// DeleteKey deletes the subkey path of key k and its values.
-func DeleteKey(k Key, path string) error {
-	return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path))
-}
-
-// A KeyInfo describes the statistics of a key. It is returned by Stat.
-type KeyInfo struct {
-	SubKeyCount     uint32
-	MaxSubKeyLen    uint32 // size of the key's subkey with the longest name, in Unicode characters, not including the terminating zero byte
-	ValueCount      uint32
-	MaxValueNameLen uint32 // size of the key's longest value name, in Unicode characters, not including the terminating zero byte
-	MaxValueLen     uint32 // longest data component among the key's values, in bytes
-	lastWriteTime   syscall.Filetime
-}
-
-// ModTime returns the key's last write time.
-func (ki *KeyInfo) ModTime() time.Time {
-	return time.Unix(0, ki.lastWriteTime.Nanoseconds())
-}
-
-// Stat retrieves information about the open key k.
-func (k Key) Stat() (*KeyInfo, error) {
-	var ki KeyInfo
-	err := syscall.RegQueryInfoKey(syscall.Handle(k), nil, nil, nil,
-		&ki.SubKeyCount, &ki.MaxSubKeyLen, nil, &ki.ValueCount,
-		&ki.MaxValueNameLen, &ki.MaxValueLen, nil, &ki.lastWriteTime)
-	if err != nil {
-		return nil, err
-	}
-	return &ki, nil
-}

+ 0 - 33
vendor/src/golang.org/x/sys/windows/registry/syscall.go

@@ -1,33 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build windows
-
-package registry
-
-import "syscall"
-
-//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
-
-const (
-	_REG_OPTION_NON_VOLATILE = 0
-
-	_REG_CREATED_NEW_KEY     = 1
-	_REG_OPENED_EXISTING_KEY = 2
-
-	_ERROR_NO_MORE_ITEMS syscall.Errno = 259
-)
-
-func LoadRegLoadMUIString() error {
-	return procRegLoadMUIStringW.Find()
-}
-
-//sys	regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) = advapi32.RegCreateKeyExW
-//sys	regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) = advapi32.RegDeleteKeyW
-//sys	regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) = advapi32.RegSetValueExW
-//sys	regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegEnumValueW
-//sys	regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) = advapi32.RegDeleteValueW
-//sys   regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) = advapi32.RegLoadMUIStringW
-
-//sys	expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW

+ 0 - 384
vendor/src/golang.org/x/sys/windows/registry/value.go

@@ -1,384 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build windows
-
-package registry
-
-import (
-	"errors"
-	"io"
-	"syscall"
-	"unicode/utf16"
-	"unsafe"
-)
-
-const (
-	// Registry value types.
-	NONE                       = 0
-	SZ                         = 1
-	EXPAND_SZ                  = 2
-	BINARY                     = 3
-	DWORD                      = 4
-	DWORD_BIG_ENDIAN           = 5
-	LINK                       = 6
-	MULTI_SZ                   = 7
-	RESOURCE_LIST              = 8
-	FULL_RESOURCE_DESCRIPTOR   = 9
-	RESOURCE_REQUIREMENTS_LIST = 10
-	QWORD                      = 11
-)
-
-var (
-	// ErrShortBuffer is returned when the buffer was too short for the operation.
-	ErrShortBuffer = syscall.ERROR_MORE_DATA
-
-	// ErrNotExist is returned when a registry key or value does not exist.
-	ErrNotExist = syscall.ERROR_FILE_NOT_FOUND
-
-	// ErrUnexpectedType is returned by Get*Value when the value's type was unexpected.
-	ErrUnexpectedType = errors.New("unexpected key value type")
-)
-
-// GetValue retrieves the type and data for the specified value associated
-// with an open key k. It fills up buffer buf and returns the retrieved
-// byte count n. If buf is too small to fit the stored value it returns
-// ErrShortBuffer error along with the required buffer size n.
-// If no buffer is provided, it returns true and actual buffer size n.
-// If no buffer is provided, GetValue returns the value's type only.
-// If the value does not exist, the error returned is ErrNotExist.
-//
-// GetValue is a low level function. If value's type is known, use the appropriate
-// Get*Value function instead.
-func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) {
-	pname, err := syscall.UTF16PtrFromString(name)
-	if err != nil {
-		return 0, 0, err
-	}
-	var pbuf *byte
-	if len(buf) > 0 {
-		pbuf = (*byte)(unsafe.Pointer(&buf[0]))
-	}
-	l := uint32(len(buf))
-	err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l)
-	if err != nil {
-		return int(l), valtype, err
-	}
-	return int(l), valtype, nil
-}
-
-func (k Key) getValue(name string, buf []byte) (date []byte, valtype uint32, err error) {
-	p, err := syscall.UTF16PtrFromString(name)
-	if err != nil {
-		return nil, 0, err
-	}
-	var t uint32
-	n := uint32(len(buf))
-	for {
-		err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n)
-		if err == nil {
-			return buf[:n], t, nil
-		}
-		if err != syscall.ERROR_MORE_DATA {
-			return nil, 0, err
-		}
-		if n <= uint32(len(buf)) {
-			return nil, 0, err
-		}
-		buf = make([]byte, n)
-	}
-}
-
-// GetStringValue retrieves the string value for the specified
-// value name associated with an open key k. It also returns the value's type.
-// If value does not exist, GetStringValue returns ErrNotExist.
-// If value is not SZ or EXPAND_SZ, it will return the correct value
-// type and ErrUnexpectedType.
-func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) {
-	data, typ, err2 := k.getValue(name, make([]byte, 64))
-	if err2 != nil {
-		return "", typ, err2
-	}
-	switch typ {
-	case SZ, EXPAND_SZ:
-	default:
-		return "", typ, ErrUnexpectedType
-	}
-	if len(data) == 0 {
-		return "", typ, nil
-	}
-	u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:]
-	return syscall.UTF16ToString(u), typ, nil
-}
-
-// GetMUIStringValue retrieves the localized string value for
-// the specified value name associated with an open key k.
-// If the value name doesn't exist or the localized string value
-// can't be resolved, GetMUIStringValue returns ErrNotExist.
-// GetMUIStringValue panics if the system doesn't support
-// regLoadMUIString; use LoadRegLoadMUIString to check if
-// regLoadMUIString is supported before calling this function.
-func (k Key) GetMUIStringValue(name string) (string, error) {
-	pname, err := syscall.UTF16PtrFromString(name)
-	if err != nil {
-		return "", err
-	}
-
-	buf := make([]uint16, 1024)
-	var buflen uint32
-	var pdir *uint16
-
-	err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
-	if err == syscall.ERROR_FILE_NOT_FOUND { // Try fallback path
-
-		// Try to resolve the string value using the system directory as
-		// a DLL search path; this assumes the string value is of the form
-		// @[path]\dllname,-strID but with no path given, e.g. @tzres.dll,-320.
-
-		// This approach works with tzres.dll but may have to be revised
-		// in the future to allow callers to provide custom search paths.
-
-		var s string
-		s, err = ExpandString("%SystemRoot%\\system32\\")
-		if err != nil {
-			return "", err
-		}
-		pdir, err = syscall.UTF16PtrFromString(s)
-		if err != nil {
-			return "", err
-		}
-
-		err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
-	}
-
-	for err == syscall.ERROR_MORE_DATA { // Grow buffer if needed
-		if buflen <= uint32(len(buf)) {
-			break // Buffer not growing, assume race; break
-		}
-		buf = make([]uint16, buflen)
-		err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
-	}
-
-	if err != nil {
-		return "", err
-	}
-
-	return syscall.UTF16ToString(buf), nil
-}
-
-// ExpandString expands environment-variable strings and replaces
-// them with the values defined for the current user.
-// Use ExpandString to expand EXPAND_SZ strings.
-func ExpandString(value string) (string, error) {
-	if value == "" {
-		return "", nil
-	}
-	p, err := syscall.UTF16PtrFromString(value)
-	if err != nil {
-		return "", err
-	}
-	r := make([]uint16, 100)
-	for {
-		n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r)))
-		if err != nil {
-			return "", err
-		}
-		if n <= uint32(len(r)) {
-			u := (*[1 << 29]uint16)(unsafe.Pointer(&r[0]))[:]
-			return syscall.UTF16ToString(u), nil
-		}
-		r = make([]uint16, n)
-	}
-}
-
-// GetStringsValue retrieves the []string value for the specified
-// value name associated with an open key k. It also returns the value's type.
-// If value does not exist, GetStringsValue returns ErrNotExist.
-// If value is not MULTI_SZ, it will return the correct value
-// type and ErrUnexpectedType.
-func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) {
-	data, typ, err2 := k.getValue(name, make([]byte, 64))
-	if err2 != nil {
-		return nil, typ, err2
-	}
-	if typ != MULTI_SZ {
-		return nil, typ, ErrUnexpectedType
-	}
-	if len(data) == 0 {
-		return nil, typ, nil
-	}
-	p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
-	if len(p) == 0 {
-		return nil, typ, nil
-	}
-	if p[len(p)-1] == 0 {
-		p = p[:len(p)-1] // remove terminating null
-	}
-	val = make([]string, 0, 5)
-	from := 0
-	for i, c := range p {
-		if c == 0 {
-			val = append(val, string(utf16.Decode(p[from:i])))
-			from = i + 1
-		}
-	}
-	return val, typ, nil
-}
-
-// GetIntegerValue retrieves the integer value for the specified
-// value name associated with an open key k. It also returns the value's type.
-// If value does not exist, GetIntegerValue returns ErrNotExist.
-// If value is not DWORD or QWORD, it will return the correct value
-// type and ErrUnexpectedType.
-func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) {
-	data, typ, err2 := k.getValue(name, make([]byte, 8))
-	if err2 != nil {
-		return 0, typ, err2
-	}
-	switch typ {
-	case DWORD:
-		if len(data) != 4 {
-			return 0, typ, errors.New("DWORD value is not 4 bytes long")
-		}
-		return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil
-	case QWORD:
-		if len(data) != 8 {
-			return 0, typ, errors.New("QWORD value is not 8 bytes long")
-		}
-		return uint64(*(*uint64)(unsafe.Pointer(&data[0]))), QWORD, nil
-	default:
-		return 0, typ, ErrUnexpectedType
-	}
-}
-
-// GetBinaryValue retrieves the binary value for the specified
-// value name associated with an open key k. It also returns the value's type.
-// If value does not exist, GetBinaryValue returns ErrNotExist.
-// If value is not BINARY, it will return the correct value
-// type and ErrUnexpectedType.
-func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) {
-	data, typ, err2 := k.getValue(name, make([]byte, 64))
-	if err2 != nil {
-		return nil, typ, err2
-	}
-	if typ != BINARY {
-		return nil, typ, ErrUnexpectedType
-	}
-	return data, typ, nil
-}
-
-func (k Key) setValue(name string, valtype uint32, data []byte) error {
-	p, err := syscall.UTF16PtrFromString(name)
-	if err != nil {
-		return err
-	}
-	if len(data) == 0 {
-		return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0)
-	}
-	return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data)))
-}
-
-// SetDWordValue sets the data and type of a name value
-// under key k to value and DWORD.
-func (k Key) SetDWordValue(name string, value uint32) error {
-	return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:])
-}
-
-// SetQWordValue sets the data and type of a name value
-// under key k to value and QWORD.
-func (k Key) SetQWordValue(name string, value uint64) error {
-	return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:])
-}
-
-func (k Key) setStringValue(name string, valtype uint32, value string) error {
-	v, err := syscall.UTF16FromString(value)
-	if err != nil {
-		return err
-	}
-	buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
-	return k.setValue(name, valtype, buf)
-}
-
-// SetStringValue sets the data and type of a name value
-// under key k to value and SZ. The value must not contain a zero byte.
-func (k Key) SetStringValue(name, value string) error {
-	return k.setStringValue(name, SZ, value)
-}
-
-// SetExpandStringValue sets the data and type of a name value
-// under key k to value and EXPAND_SZ. The value must not contain a zero byte.
-func (k Key) SetExpandStringValue(name, value string) error {
-	return k.setStringValue(name, EXPAND_SZ, value)
-}
-
-// SetStringsValue sets the data and type of a name value
-// under key k to value and MULTI_SZ. The value strings
-// must not contain a zero byte.
-func (k Key) SetStringsValue(name string, value []string) error {
-	ss := ""
-	for _, s := range value {
-		for i := 0; i < len(s); i++ {
-			if s[i] == 0 {
-				return errors.New("string cannot have 0 inside")
-			}
-		}
-		ss += s + "\x00"
-	}
-	v := utf16.Encode([]rune(ss + "\x00"))
-	buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
-	return k.setValue(name, MULTI_SZ, buf)
-}
-
-// SetBinaryValue sets the data and type of a name value
-// under key k to value and BINARY.
-func (k Key) SetBinaryValue(name string, value []byte) error {
-	return k.setValue(name, BINARY, value)
-}
-
-// DeleteValue removes a named value from the key k.
-func (k Key) DeleteValue(name string) error {
-	return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name))
-}
-
-// ReadValueNames returns the value names of key k.
-// The parameter n controls the number of returned names,
-// analogous to the way os.File.Readdirnames works.
-func (k Key) ReadValueNames(n int) ([]string, error) {
-	ki, err := k.Stat()
-	if err != nil {
-		return nil, err
-	}
-	names := make([]string, 0, ki.ValueCount)
-	buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character
-loopItems:
-	for i := uint32(0); ; i++ {
-		if n > 0 {
-			if len(names) == n {
-				return names, nil
-			}
-		}
-		l := uint32(len(buf))
-		for {
-			err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
-			if err == nil {
-				break
-			}
-			if err == syscall.ERROR_MORE_DATA {
-				// Double buffer size and try again.
-				l = uint32(2 * len(buf))
-				buf = make([]uint16, l)
-				continue
-			}
-			if err == _ERROR_NO_MORE_ITEMS {
-				break loopItems
-			}
-			return names, err
-		}
-		names = append(names, syscall.UTF16ToString(buf[:l]))
-	}
-	if n > len(names) {
-		return names, io.EOF
-	}
-	return names, nil
-}

+ 0 - 82
vendor/src/golang.org/x/sys/windows/registry/zsyscall_windows.go

@@ -1,82 +0,0 @@
-// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
-
-package registry
-
-import "unsafe"
-import "syscall"
-
-var _ unsafe.Pointer
-
-var (
-	modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
-	modkernel32 = syscall.NewLazyDLL("kernel32.dll")
-
-	procRegCreateKeyExW           = modadvapi32.NewProc("RegCreateKeyExW")
-	procRegDeleteKeyW             = modadvapi32.NewProc("RegDeleteKeyW")
-	procRegSetValueExW            = modadvapi32.NewProc("RegSetValueExW")
-	procRegEnumValueW             = modadvapi32.NewProc("RegEnumValueW")
-	procRegDeleteValueW           = modadvapi32.NewProc("RegDeleteValueW")
-	procRegLoadMUIStringW         = modadvapi32.NewProc("RegLoadMUIStringW")
-	procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW")
-)
-
-func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) {
-	r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition)))
-	if r0 != 0 {
-		regerrno = syscall.Errno(r0)
-	}
-	return
-}
-
-func regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) {
-	r0, _, _ := syscall.Syscall(procRegDeleteKeyW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(subkey)), 0)
-	if r0 != 0 {
-		regerrno = syscall.Errno(r0)
-	}
-	return
-}
-
-func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) {
-	r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize))
-	if r0 != 0 {
-		regerrno = syscall.Errno(r0)
-	}
-	return
-}
-
-func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) {
-	r0, _, _ := syscall.Syscall9(procRegEnumValueW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)), 0)
-	if r0 != 0 {
-		regerrno = syscall.Errno(r0)
-	}
-	return
-}
-
-func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) {
-	r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0)
-	if r0 != 0 {
-		regerrno = syscall.Errno(r0)
-	}
-	return
-}
-
-func regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) {
-	r0, _, _ := syscall.Syscall9(procRegLoadMUIStringW.Addr(), 7, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(unsafe.Pointer(buflenCopied)), uintptr(flags), uintptr(unsafe.Pointer(dir)), 0, 0)
-	if r0 != 0 {
-		regerrno = syscall.Errno(r0)
-	}
-	return
-}
-
-func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) {
-	r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size))
-	n = uint32(r0)
-	if n == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
-	}
-	return
-}