func (d *Driver) importLayer(id string, layerData io.Reader, parentLayerPaths []string) (size int64, err error) {
	if !noreexec {
		cmd := reexec.Command(append([]string{"docker-windows-write-layer", d.info.HomeDir, id}, parentLayerPaths...)...)
		output := bytes.NewBuffer(nil)
		cmd.Stdin = layerData
		cmd.Stdout = output
		cmd.Stderr = output
		if err = cmd.Start(); err != nil {
			return
		}
		if err = cmd.Wait(); err != nil {
			return 0, fmt.Errorf("re-exec error: %v: output: %s", err, output)
		}
		return strconv.ParseInt(output.String(), 10, 64)
	}
	return writeLayer(layerData, d.info.HomeDir, id, parentLayerPaths...)
}
importLayer adds a new layer to the tag and graph store based on the given data.
package windows
import (
	"archive/tar"
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"
	"unsafe"
	"github.com/Microsoft/go-winio"
	"github.com/Microsoft/go-winio/backuptar"
	"github.com/Microsoft/hcsshim"
	"github.com/containers/storage/drivers"
	"github.com/containers/storage/pkg/archive"
	"github.com/containers/storage/pkg/directory"
	"github.com/containers/storage/pkg/idtools"
	"github.com/containers/storage/pkg/ioutils"
	"github.com/containers/storage/pkg/longpath"
	"github.com/containers/storage/pkg/reexec"
	"github.com/containers/storage/pkg/system"
	units "github.com/docker/go-units"
	"github.com/sirupsen/logrus"
	"golang.org/x/sys/windows"
)
const filterDriver = 1
var (
	mutatedFiles = map[string]string{
		"UtilityVM/Files/EFI/Microsoft/Boot/BCD":      "bcd.bak",
		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG":  "bcd.log.bak",
		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG1": "bcd.log1.bak",
		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG2": "bcd.log2.bak",
	}
	noreexec = false
)
func init() {
	graphdriver.Register("windowsfilter", InitFilter)
	if os.Getenv("DOCKER_WINDOWSFILTER_NOREEXEC") != "" {
		logrus.Warnf("WindowsGraphDriver is set to not re-exec. This is intended for debugging purposes only.")
		noreexec = true
	} else {
		reexec.Register("docker-windows-write-layer", writeLayerReexec)
	}
}
type checker struct {
}
func (c *checker) IsMounted(path string) bool {
	return false
}
type Driver struct {
	info hcsshim.DriverInfo
	ctr  *graphdriver.RefCounter
	cacheMu sync.Mutex
	cache   map[string]string
}
func InitFilter(home string, options graphdriver.Options) (graphdriver.Driver, error) {
	logrus.Debugf("WindowsGraphDriver InitFilter at %s", home)
	for _, option := range options.DriverOptions {
		if strings.HasPrefix(option, "windows.mountopt=") {
			return nil, fmt.Errorf("windows driver does not support mount options")
		} else {
			return nil, fmt.Errorf("option %s not supported", option)
		}
	}
	fsType, err := getFileSystemType(string(home[0]))
	if err != nil {
		return nil, err
	}
	if strings.ToLower(fsType) == "refs" {
		return nil, fmt.Errorf("%s is on an ReFS volume - ReFS volumes are not supported", home)
	}
	if err := idtools.MkdirAllAs(home, 0700, 0, 0); err != nil {
		return nil, fmt.Errorf("windowsfilter failed to create '%s': %v", home, err)
	}
	d := &Driver{
		info: hcsshim.DriverInfo{
			HomeDir: home,
			Flavour: filterDriver,
		},
		cache: make(map[string]string),
		ctr:   graphdriver.NewRefCounter(&checker{}),
	}
	return d, nil
}
func win32FromHresult(hr uintptr) uintptr {
	if hr&0x1fff0000 == 0x00070000 {
		return hr & 0xffff
	}
	return hr
}
func getFileSystemType(drive string) (fsType string, hr error) {
	var (
		modkernel32              = windows.NewLazySystemDLL("kernel32.dll")
		procGetVolumeInformation = modkernel32.NewProc("GetVolumeInformationW")
		buf                      = make([]uint16, 255)
		size                     = windows.MAX_PATH + 1
	)
	if len(drive) != 1 {
		hr = errors.New("getFileSystemType must be called with a drive letter")
		return
	}
	drive += `:\`
	n := uintptr(unsafe.Pointer(nil))
	r0, _, _ := syscall.Syscall9(procGetVolumeInformation.Addr(), 8, uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(drive))), n, n, n, n, n, uintptr(unsafe.Pointer(&buf[0])), uintptr(size), 0)
	if int32(r0) < 0 {
		hr = syscall.Errno(win32FromHresult(r0))
	}
	fsType = windows.UTF16ToString(buf)
	return
}
func (d *Driver) String() string {
	return "windowsfilter"
}
func (d *Driver) Status() [][2]string {
	return [][2]string{
		{"Windows", ""},
	}
}
func panicIfUsedByLcow() {
	if system.LCOWSupported() {
		panic("inconsistency - windowsfilter graphdriver should not be used when in LCOW mode")
	}
}
func (d *Driver) Exists(id string) bool {
	panicIfUsedByLcow()
	rID, err := d.resolveID(id)
	if err != nil {
		return false
	}
	result, err := hcsshim.LayerExists(d.info, rID)
	if err != nil {
		return false
	}
	return result
}
func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error {
	return graphdriver.NaiveCreateFromTemplate(d, id, template, templateIDMappings, parent, parentIDMappings, opts, readWrite)
}
func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
	panicIfUsedByLcow()
	if opts != nil {
		return d.create(id, parent, opts.MountLabel, false, opts.StorageOpt)
	}
	return d.create(id, parent, "", false, nil)
}
func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
	panicIfUsedByLcow()
	if opts != nil {
		return d.create(id, parent, opts.MountLabel, true, opts.StorageOpt)
	}
	return d.create(id, parent, "", true, nil)
}
func (d *Driver) create(id, parent, mountLabel string, readOnly bool, storageOpt map[string]string) error {
	rPId, err := d.resolveID(parent)
	if err != nil {
		return err
	}
	parentChain, err := d.getLayerChain(rPId)
	if err != nil {
		return err
	}
	var layerChain []string
	if rPId != "" {
		parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
		if err != nil {
			return err
		}
		if _, err := os.Stat(filepath.Join(parentPath, "Files")); err == nil {
			layerChain = []string{parentPath}
		}
	}
	layerChain = append(layerChain, parentChain...)
	if readOnly {
		if err := hcsshim.CreateLayer(d.info, id, rPId); err != nil {
			return err
		}
	} else {
		var parentPath string
		if len(layerChain) != 0 {
			parentPath = layerChain[0]
		}
		if err := hcsshim.CreateSandboxLayer(d.info, id, parentPath, layerChain); err != nil {
			return err
		}
		storageOptions, err := parseStorageOpt(storageOpt)
		if err != nil {
			return fmt.Errorf("Failed to parse storage options - %s", err)
		}
		if storageOptions.size != 0 {
			if err := hcsshim.ExpandSandboxSize(d.info, id, storageOptions.size); err != nil {
				return err
			}
		}
	}
	if _, err := os.Lstat(d.dir(parent)); err != nil {
		if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
			logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
		}
		return fmt.Errorf("Cannot create layer with missing parent %s: %s", parent, err)
	}
	if err := d.setLayerChain(id, layerChain); err != nil {
		if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
			logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
		}
		return err
	}
	return nil
}
func (d *Driver) dir(id string) string {
	return filepath.Join(d.info.HomeDir, filepath.Base(id))
}
func (d *Driver) Remove(id string) error {
	panicIfUsedByLcow()
	rID, err := d.resolveID(id)
	if err != nil {
		return err
	}
	var computeSystems []hcsshim.ContainerProperties
	retryCount := 0
	osv := system.GetOSVersion()
	for {
		computeSystems, err = hcsshim.GetContainers(hcsshim.ComputeSystemQuery{})
		if err != nil {
			if (osv.Build < 15139) &&
				((err == hcsshim.ErrVmcomputeOperationInvalidState) || (err == hcsshim.ErrVmcomputeOperationAccessIsDenied)) {
				if retryCount >= 500 {
					break
				}
				retryCount++
				time.Sleep(10 * time.Millisecond)
				continue
			}
			return err
		}
		break
	}
	for _, computeSystem := range computeSystems {
		if strings.Contains(computeSystem.RuntimeImagePath, id) && computeSystem.IsRuntimeTemplate {
			container, err := hcsshim.OpenContainer(computeSystem.ID)
			if err != nil {
				return err
			}
			defer container.Close()
			err = container.Terminate()
			if hcsshim.IsPending(err) {
				err = container.Wait()
			} else if hcsshim.IsAlreadyStopped(err) {
				err = nil
			}
			if err != nil {
				return err
			}
		}
	}
	layerPath := filepath.Join(d.info.HomeDir, rID)
	tmpID := fmt.Sprintf("%s-removing", rID)
	tmpLayerPath := filepath.Join(d.info.HomeDir, tmpID)
	if err := os.Rename(layerPath, tmpLayerPath); err != nil && !os.IsNotExist(err) {
		return err
	}
	if err := hcsshim.DestroyLayer(d.info, tmpID); err != nil {
		logrus.Errorf("Failed to DestroyLayer %s: %s", id, err)
	}
	return nil
}
func (d *Driver) Get(id string, options graphdriver.MountOpts) (string, error) {
	panicIfUsedByLcow()
	logrus.Debugf("WindowsGraphDriver Get() id %s mountLabel %s", id, options.MountLabel)
	var dir string
	switch len(options.Options) {
	case 0:
	case 1:
		if options.Options[0] == "ro" {
			break
		}
		fallthrough
	default:
		return "", fmt.Errorf("windows driver does not support mount options")
	}
	rID, err := d.resolveID(id)
	if err != nil {
		return "", err
	}
	if count := d.ctr.Increment(rID); count > 1 {
		return d.cache[rID], nil
	}
	layerChain, err := d.getLayerChain(rID)
	if err != nil {
		d.ctr.Decrement(rID)
		return "", err
	}
	if err := hcsshim.ActivateLayer(d.info, rID); err != nil {
		d.ctr.Decrement(rID)
		return "", err
	}
	if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
		d.ctr.Decrement(rID)
		if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
			logrus.Warnf("Failed to Deactivate %s: %s", id, err)
		}
		return "", err
	}
	mountPath, err := hcsshim.GetLayerMountPath(d.info, rID)
	if err != nil {
		d.ctr.Decrement(rID)
		if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
			logrus.Warnf("Failed to Unprepare %s: %s", id, err)
		}
		if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
			logrus.Warnf("Failed to Deactivate %s: %s", id, err)
		}
		return "", err
	}
	d.cacheMu.Lock()
	d.cache[rID] = mountPath
	d.cacheMu.Unlock()
	if mountPath != "" {
		dir = mountPath
	} else {
		dir = d.dir(id)
	}
	return dir, nil
}
func (d *Driver) ReadWriteDiskUsage(id string) (*directory.DiskUsage, error) {
	return directory.Usage(d.dir(id))
}
func (d *Driver) Put(id string) error {
	panicIfUsedByLcow()
	logrus.Debugf("WindowsGraphDriver Put() id %s", id)
	rID, err := d.resolveID(id)
	if err != nil {
		return err
	}
	if count := d.ctr.Decrement(rID); count > 0 {
		return nil
	}
	d.cacheMu.Lock()
	_, exists := d.cache[rID]
	delete(d.cache, rID)
	d.cacheMu.Unlock()
	if !exists {
		return nil
	}
	if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
		return err
	}
	return hcsshim.DeactivateLayer(d.info, rID)
}
func (d *Driver) Cleanup() error {
	items, err := ioutil.ReadDir(d.info.HomeDir)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return err
	}
	for _, item := range items {
		if item.IsDir() && strings.HasSuffix(item.Name(), "-removing") {
			if err := hcsshim.DestroyLayer(d.info, item.Name()); err != nil {
				logrus.Warnf("Failed to cleanup %s: %s", item.Name(), err)
			} else {
				logrus.Infof("Cleaned up %s", item.Name())
			}
		}
	}
	return nil
}
func (d *Driver) Diff(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) (_ io.ReadCloser, err error) {
	panicIfUsedByLcow()
	rID, err := d.resolveID(id)
	if err != nil {
		return
	}
	layerChain, err := d.getLayerChain(rID)
	if err != nil {
		return
	}
	if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
		return nil, err
	}
	prepare := func() {
		if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
			logrus.Warnf("Failed to Deactivate %s: %s", rID, err)
		}
	}
	arch, err := d.exportLayer(rID, layerChain)
	if err != nil {
		prepare()
		return
	}
	return ioutils.NewReadCloserWrapper(arch, func() error {
		err := arch.Close()
		prepare()
		return err
	}), nil
}
func (d *Driver) Changes(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) ([]archive.Change, error) {
	panicIfUsedByLcow()
	rID, err := d.resolveID(id)
	if err != nil {
		return nil, err
	}
	parentChain, err := d.getLayerChain(rID)
	if err != nil {
		return nil, err
	}
	if err := hcsshim.ActivateLayer(d.info, rID); err != nil {
		return nil, err
	}
	defer func() {
		if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
			logrus.Errorf("changes() failed to DeactivateLayer %s %s: %s", id, rID, err2)
		}
	}()
	var changes []archive.Change
	err = winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
		r, err := hcsshim.NewLayerReader(d.info, id, parentChain)
		if err != nil {
			return err
		}
		defer r.Close()
		for {
			name, _, fileInfo, err := r.Next()
			if err == io.EOF {
				return nil
			}
			if err != nil {
				return err
			}
			name = filepath.ToSlash(name)
			if fileInfo == nil {
				changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeDelete})
			} else {
				changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeModify})
			}
		}
	})
	if err != nil {
		return nil, err
	}
	return changes, nil
}
func (d *Driver) ApplyDiff(id, parent string, options graphdriver.ApplyDiffOpts) (int64, error) {
	panicIfUsedByLcow()
	var layerChain []string
	if parent != "" {
		rPId, err := d.resolveID(parent)
		if err != nil {
			return 0, err
		}
		parentChain, err := d.getLayerChain(rPId)
		if err != nil {
			return 0, err
		}
		parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
		if err != nil {
			return 0, err
		}
		layerChain = append(layerChain, parentPath)
		layerChain = append(layerChain, parentChain...)
	}
	size, err := d.importLayer(id, options.Diff, layerChain)
	if err != nil {
		return 0, err
	}
	if err = d.setLayerChain(id, layerChain); err != nil {
		return 0, err
	}
	return size, nil
}
func (d *Driver) DiffSize(id string, idMappings *idtools.IDMappings, parent string, parentMappings *idtools.IDMappings, mountLabel string) (size int64, err error) {
	panicIfUsedByLcow()
	rPId, err := d.resolveID(parent)
	if err != nil {
		return
	}
	changes, err := d.Changes(id, idMappings, rPId, parentMappings, mountLabel)
	if err != nil {
		return
	}
	layerFs, err := d.Get(id, graphdriver.MountOpts{})
	if err != nil {
		return
	}
	defer d.Put(id)
	return archive.ChangesSize(layerFs, changes), nil
}
func (d *Driver) Metadata(id string) (map[string]string, error) {
	panicIfUsedByLcow()
	m := make(map[string]string)
	m["dir"] = d.dir(id)
	return m, nil
}
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 {
			return err
		}
		if fileInfo == nil {
			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()
}
func (d *Driver) exportLayer(id string, parentLayerPaths []string) (io.ReadCloser, error) {
	archive, w := io.Pipe()
	go func() {
		err := winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
			r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths)
			if err != nil {
				return err
			}
			err = writeTarFromLayer(r, w)
			cerr := r.Close()
			if err == nil {
				err = cerr
			}
			return err
		})
		w.CloseWithError(err)
	}()
	return archive, nil
}
func writeBackupStreamFromTarAndSaveMutatedFiles(buf *bufio.Writer, w io.Writer, t *tar.Reader, hdr *tar.Header, root string) (nextHdr *tar.Header, err error) {
	var bcdBackup *os.File
	var bcdBackupWriter *winio.BackupFileWriter
	if backupPath, ok := mutatedFiles[hdr.Name]; ok {
		bcdBackup, err = os.Create(filepath.Join(root, backupPath))
		if err != nil {
			return nil, err
		}
		defer func() {
			cerr := bcdBackup.Close()
			if err == nil {
				err = cerr
			}
		}()
		bcdBackupWriter = winio.NewBackupFileWriter(bcdBackup, false)
		defer func() {
			cerr := bcdBackupWriter.Close()
			if err == nil {
				err = cerr
			}
		}()
		buf.Reset(io.MultiWriter(w, bcdBackupWriter))
	} else {
		buf.Reset(w)
	}
	defer func() {
		ferr := buf.Flush()
		if err == nil {
			err = ferr
		}
	}()
	return backuptar.WriteBackupStreamFromTarFile(buf, t, hdr)
}
func writeLayerFromTar(r io.Reader, w hcsshim.LayerWriter, root string) (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 if hdr.Typeflag == tar.TypeLink {
			err = w.AddLink(filepath.FromSlash(hdr.Name), filepath.FromSlash(hdr.Linkname))
			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
			}
			hdr, err = writeBackupStreamFromTarAndSaveMutatedFiles(buf, w, t, hdr, root)
			totalSize += size
		}
	}
	if err != io.EOF {
		return 0, err
	}
	return totalSize, nil
}