github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/daemon/graphdriver/windows/windows.go (about)

     1  //+build windows
     2  
     3  package windows // import "github.com/docker/docker/daemon/graphdriver/windows"
     4  
     5  import (
     6  	"archive/tar"
     7  	"bufio"
     8  	"bytes"
     9  	"encoding/json"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"os"
    14  	"path"
    15  	"path/filepath"
    16  	"strconv"
    17  	"strings"
    18  	"sync"
    19  	"syscall"
    20  	"time"
    21  	"unsafe"
    22  
    23  	winio "github.com/Microsoft/go-winio"
    24  	"github.com/Microsoft/go-winio/backuptar"
    25  	"github.com/Microsoft/go-winio/vhd"
    26  	"github.com/Microsoft/hcsshim"
    27  	"github.com/Microsoft/hcsshim/osversion"
    28  	"github.com/docker/docker/daemon/graphdriver"
    29  	"github.com/docker/docker/pkg/archive"
    30  	"github.com/docker/docker/pkg/containerfs"
    31  	"github.com/docker/docker/pkg/idtools"
    32  	"github.com/docker/docker/pkg/ioutils"
    33  	"github.com/docker/docker/pkg/longpath"
    34  	"github.com/docker/docker/pkg/reexec"
    35  	units "github.com/docker/go-units"
    36  	"github.com/pkg/errors"
    37  	"github.com/sirupsen/logrus"
    38  	"golang.org/x/sys/windows"
    39  )
    40  
    41  const (
    42  	// filterDriver is an HCSShim driver type for the Windows Filter driver.
    43  	filterDriver = 1
    44  	// For WCOW, the default of 20GB hard-coded in the platform
    45  	// is too small for builder scenarios where many users are
    46  	// using RUN or COPY statements to install large amounts of data.
    47  	// Use 127GB as that's the default size of a VHD in Hyper-V.
    48  	defaultSandboxSize = "127GB"
    49  )
    50  
    51  var (
    52  	// mutatedFiles is a list of files that are mutated by the import process
    53  	// and must be backed up and restored.
    54  	mutatedFiles = map[string]string{
    55  		"UtilityVM/Files/EFI/Microsoft/Boot/BCD":      "bcd.bak",
    56  		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG":  "bcd.log.bak",
    57  		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG1": "bcd.log1.bak",
    58  		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG2": "bcd.log2.bak",
    59  	}
    60  	noreexec = false
    61  )
    62  
    63  // init registers the windows graph drivers to the register.
    64  func init() {
    65  	graphdriver.Register("windowsfilter", InitFilter)
    66  	// DOCKER_WINDOWSFILTER_NOREEXEC allows for inline processing which makes
    67  	// debugging issues in the re-exec codepath significantly easier.
    68  	if os.Getenv("DOCKER_WINDOWSFILTER_NOREEXEC") != "" {
    69  		logrus.Warnf("WindowsGraphDriver is set to not re-exec. This is intended for debugging purposes only.")
    70  		noreexec = true
    71  	} else {
    72  		reexec.Register("docker-windows-write-layer", writeLayerReexec)
    73  	}
    74  }
    75  
    76  type checker struct {
    77  }
    78  
    79  func (c *checker) IsMounted(path string) bool {
    80  	return false
    81  }
    82  
    83  type storageOptions struct {
    84  	size uint64
    85  }
    86  
    87  // Driver represents a windows graph driver.
    88  type Driver struct {
    89  	// info stores the shim driver information
    90  	info hcsshim.DriverInfo
    91  	ctr  *graphdriver.RefCounter
    92  	// it is safe for windows to use a cache here because it does not support
    93  	// restoring containers when the daemon dies.
    94  	cacheMu            sync.Mutex
    95  	cache              map[string]string
    96  	defaultStorageOpts *storageOptions
    97  }
    98  
    99  // InitFilter returns a new Windows storage filter driver.
   100  func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
   101  	logrus.Debugf("WindowsGraphDriver InitFilter at %s", home)
   102  
   103  	fsType, err := getFileSystemType(string(home[0]))
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	if strings.ToLower(fsType) == "refs" {
   108  		return nil, fmt.Errorf("%s is on an ReFS volume - ReFS volumes are not supported", home)
   109  	}
   110  
   111  	if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
   112  		return nil, fmt.Errorf("windowsfilter failed to create '%s': %v", home, err)
   113  	}
   114  
   115  	storageOpt := make(map[string]string)
   116  	storageOpt["size"] = defaultSandboxSize
   117  
   118  	for _, v := range options {
   119  		opt := strings.SplitN(v, "=", 2)
   120  		storageOpt[strings.ToLower(opt[0])] = opt[1]
   121  	}
   122  
   123  	storageOptions, err := parseStorageOpt(storageOpt)
   124  	if err != nil {
   125  		return nil, fmt.Errorf("windowsfilter failed to parse default storage options - %s", err)
   126  	}
   127  
   128  	d := &Driver{
   129  		info: hcsshim.DriverInfo{
   130  			HomeDir: home,
   131  			Flavour: filterDriver,
   132  		},
   133  		cache:              make(map[string]string),
   134  		ctr:                graphdriver.NewRefCounter(&checker{}),
   135  		defaultStorageOpts: storageOptions,
   136  	}
   137  	return d, nil
   138  }
   139  
   140  // win32FromHresult is a helper function to get the win32 error code from an HRESULT
   141  func win32FromHresult(hr uintptr) uintptr {
   142  	if hr&0x1fff0000 == 0x00070000 {
   143  		return hr & 0xffff
   144  	}
   145  	return hr
   146  }
   147  
   148  // getFileSystemType obtains the type of a file system through GetVolumeInformation
   149  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx
   150  func getFileSystemType(drive string) (fsType string, hr error) {
   151  	var (
   152  		modkernel32              = windows.NewLazySystemDLL("kernel32.dll")
   153  		procGetVolumeInformation = modkernel32.NewProc("GetVolumeInformationW")
   154  		buf                      = make([]uint16, 255)
   155  		size                     = windows.MAX_PATH + 1
   156  	)
   157  	if len(drive) != 1 {
   158  		hr = errors.New("getFileSystemType must be called with a drive letter")
   159  		return
   160  	}
   161  	drive += `:\`
   162  	n := uintptr(unsafe.Pointer(nil))
   163  	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)
   164  	if int32(r0) < 0 {
   165  		hr = syscall.Errno(win32FromHresult(r0))
   166  	}
   167  	fsType = windows.UTF16ToString(buf)
   168  	return
   169  }
   170  
   171  // String returns the string representation of a driver. This should match
   172  // the name the graph driver has been registered with.
   173  func (d *Driver) String() string {
   174  	return "windowsfilter"
   175  }
   176  
   177  // Status returns the status of the driver.
   178  func (d *Driver) Status() [][2]string {
   179  	return [][2]string{
   180  		{"Windows", ""},
   181  	}
   182  }
   183  
   184  // Exists returns true if the given id is registered with this driver.
   185  func (d *Driver) Exists(id string) bool {
   186  	rID, err := d.resolveID(id)
   187  	if err != nil {
   188  		return false
   189  	}
   190  	result, err := hcsshim.LayerExists(d.info, rID)
   191  	if err != nil {
   192  		return false
   193  	}
   194  	return result
   195  }
   196  
   197  // CreateReadWrite creates a layer that is writable for use as a container
   198  // file system.
   199  func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
   200  	if opts != nil {
   201  		return d.create(id, parent, opts.MountLabel, false, opts.StorageOpt)
   202  	}
   203  	return d.create(id, parent, "", false, nil)
   204  }
   205  
   206  // Create creates a new read-only layer with the given id.
   207  func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
   208  	if opts != nil {
   209  		return d.create(id, parent, opts.MountLabel, true, opts.StorageOpt)
   210  	}
   211  	return d.create(id, parent, "", true, nil)
   212  }
   213  
   214  func (d *Driver) create(id, parent, mountLabel string, readOnly bool, storageOpt map[string]string) error {
   215  	rPId, err := d.resolveID(parent)
   216  	if err != nil {
   217  		return err
   218  	}
   219  
   220  	parentChain, err := d.getLayerChain(rPId)
   221  	if err != nil {
   222  		return err
   223  	}
   224  
   225  	var layerChain []string
   226  
   227  	if rPId != "" {
   228  		parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
   229  		if err != nil {
   230  			return err
   231  		}
   232  		if _, err := os.Stat(filepath.Join(parentPath, "Files")); err == nil {
   233  			// This is a legitimate parent layer (not the empty "-init" layer),
   234  			// so include it in the layer chain.
   235  			layerChain = []string{parentPath}
   236  		}
   237  	}
   238  
   239  	layerChain = append(layerChain, parentChain...)
   240  
   241  	if readOnly {
   242  		if err := hcsshim.CreateLayer(d.info, id, rPId); err != nil {
   243  			return err
   244  		}
   245  	} else {
   246  		var parentPath string
   247  		if len(layerChain) != 0 {
   248  			parentPath = layerChain[0]
   249  		}
   250  
   251  		if err := hcsshim.CreateSandboxLayer(d.info, id, parentPath, layerChain); err != nil {
   252  			return err
   253  		}
   254  
   255  		storageOptions, err := parseStorageOpt(storageOpt)
   256  		if err != nil {
   257  			return fmt.Errorf("Failed to parse storage options - %s", err)
   258  		}
   259  
   260  		sandboxSize := d.defaultStorageOpts.size
   261  		if storageOptions.size != 0 {
   262  			sandboxSize = storageOptions.size
   263  		}
   264  
   265  		if sandboxSize != 0 {
   266  			if err := hcsshim.ExpandSandboxSize(d.info, id, sandboxSize); err != nil {
   267  				return err
   268  			}
   269  		}
   270  	}
   271  
   272  	if _, err := os.Lstat(d.dir(parent)); err != nil {
   273  		if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
   274  			logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
   275  		}
   276  		return fmt.Errorf("Cannot create layer with missing parent %s: %s", parent, err)
   277  	}
   278  
   279  	if err := d.setLayerChain(id, layerChain); err != nil {
   280  		if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
   281  			logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
   282  		}
   283  		return err
   284  	}
   285  
   286  	return nil
   287  }
   288  
   289  // dir returns the absolute path to the layer.
   290  func (d *Driver) dir(id string) string {
   291  	return filepath.Join(d.info.HomeDir, filepath.Base(id))
   292  }
   293  
   294  // Remove unmounts and removes the dir information.
   295  func (d *Driver) Remove(id string) error {
   296  	rID, err := d.resolveID(id)
   297  	if err != nil {
   298  		return err
   299  	}
   300  
   301  	// This retry loop is due to a bug in Windows (Internal bug #9432268)
   302  	// if GetContainers fails with ErrVmcomputeOperationInvalidState
   303  	// it is a transient error. Retry until it succeeds.
   304  	var computeSystems []hcsshim.ContainerProperties
   305  	retryCount := 0
   306  	for {
   307  		// Get and terminate any template VMs that are currently using the layer.
   308  		// Note: It is unfortunate that we end up in the graphdrivers Remove() call
   309  		// for both containers and images, but the logic for template VMs is only
   310  		// needed for images - specifically we are looking to see if a base layer
   311  		// is in use by a template VM as a result of having started a Hyper-V
   312  		// container at some point.
   313  		//
   314  		// We have a retry loop for ErrVmcomputeOperationInvalidState and
   315  		// ErrVmcomputeOperationAccessIsDenied as there is a race condition
   316  		// in RS1 and RS2 building during enumeration when a silo is going away
   317  		// for example under it, in HCS. AccessIsDenied added to fix 30278.
   318  		//
   319  		// TODO: For RS3, we can remove the retries. Also consider
   320  		// using platform APIs (if available) to get this more succinctly. Also
   321  		// consider enhancing the Remove() interface to have context of why
   322  		// the remove is being called - that could improve efficiency by not
   323  		// enumerating compute systems during a remove of a container as it's
   324  		// not required.
   325  		computeSystems, err = hcsshim.GetContainers(hcsshim.ComputeSystemQuery{})
   326  		if err != nil {
   327  			if osversion.Build() >= osversion.RS3 {
   328  				return err
   329  			}
   330  			if (err == hcsshim.ErrVmcomputeOperationInvalidState) || (err == hcsshim.ErrVmcomputeOperationAccessIsDenied) {
   331  				if retryCount >= 500 {
   332  					break
   333  				}
   334  				retryCount++
   335  				time.Sleep(10 * time.Millisecond)
   336  				continue
   337  			}
   338  			return err
   339  		}
   340  		break
   341  	}
   342  
   343  	for _, computeSystem := range computeSystems {
   344  		if strings.Contains(computeSystem.RuntimeImagePath, id) && computeSystem.IsRuntimeTemplate {
   345  			container, err := hcsshim.OpenContainer(computeSystem.ID)
   346  			if err != nil {
   347  				return err
   348  			}
   349  			defer container.Close()
   350  			err = container.Terminate()
   351  			if hcsshim.IsPending(err) {
   352  				err = container.Wait()
   353  			} else if hcsshim.IsAlreadyStopped(err) {
   354  				err = nil
   355  			}
   356  
   357  			if err != nil {
   358  				return err
   359  			}
   360  		}
   361  	}
   362  
   363  	layerPath := filepath.Join(d.info.HomeDir, rID)
   364  	tmpID := fmt.Sprintf("%s-removing", rID)
   365  	tmpLayerPath := filepath.Join(d.info.HomeDir, tmpID)
   366  	if err := os.Rename(layerPath, tmpLayerPath); err != nil && !os.IsNotExist(err) {
   367  		if !os.IsPermission(err) {
   368  			return err
   369  		}
   370  		// If permission denied, it's possible that the scratch is still mounted, an
   371  		// artifact after a hard daemon crash for example. Worth a shot to try detaching it
   372  		// before retrying the rename.
   373  		sandbox := filepath.Join(layerPath, "sandbox.vhdx")
   374  		if _, statErr := os.Stat(sandbox); statErr == nil {
   375  			if detachErr := vhd.DetachVhd(sandbox); detachErr != nil {
   376  				return errors.Wrapf(err, "failed to detach VHD: %s", detachErr)
   377  			}
   378  			if renameErr := os.Rename(layerPath, tmpLayerPath); renameErr != nil && !os.IsNotExist(renameErr) {
   379  				return errors.Wrapf(err, "second rename attempt following detach failed: %s", renameErr)
   380  			}
   381  		}
   382  	}
   383  	if err := hcsshim.DestroyLayer(d.info, tmpID); err != nil {
   384  		logrus.Errorf("Failed to DestroyLayer %s: %s", id, err)
   385  	}
   386  
   387  	return nil
   388  }
   389  
   390  // GetLayerPath gets the layer path on host
   391  func (d *Driver) GetLayerPath(id string) (string, error) {
   392  	return d.dir(id), nil
   393  }
   394  
   395  // Get returns the rootfs path for the id. This will mount the dir at its given path.
   396  func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
   397  	logrus.Debugf("WindowsGraphDriver Get() id %s mountLabel %s", id, mountLabel)
   398  	var dir string
   399  
   400  	rID, err := d.resolveID(id)
   401  	if err != nil {
   402  		return nil, err
   403  	}
   404  	if count := d.ctr.Increment(rID); count > 1 {
   405  		return containerfs.NewLocalContainerFS(d.cache[rID]), nil
   406  	}
   407  
   408  	// Getting the layer paths must be done outside of the lock.
   409  	layerChain, err := d.getLayerChain(rID)
   410  	if err != nil {
   411  		d.ctr.Decrement(rID)
   412  		return nil, err
   413  	}
   414  
   415  	if err := hcsshim.ActivateLayer(d.info, rID); err != nil {
   416  		d.ctr.Decrement(rID)
   417  		return nil, err
   418  	}
   419  	if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
   420  		d.ctr.Decrement(rID)
   421  		if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
   422  			logrus.Warnf("Failed to Deactivate %s: %s", id, err)
   423  		}
   424  		return nil, err
   425  	}
   426  
   427  	mountPath, err := hcsshim.GetLayerMountPath(d.info, rID)
   428  	if err != nil {
   429  		d.ctr.Decrement(rID)
   430  		if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
   431  			logrus.Warnf("Failed to Unprepare %s: %s", id, err)
   432  		}
   433  		if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
   434  			logrus.Warnf("Failed to Deactivate %s: %s", id, err)
   435  		}
   436  		return nil, err
   437  	}
   438  	d.cacheMu.Lock()
   439  	d.cache[rID] = mountPath
   440  	d.cacheMu.Unlock()
   441  
   442  	// If the layer has a mount path, use that. Otherwise, use the
   443  	// folder path.
   444  	if mountPath != "" {
   445  		dir = mountPath
   446  	} else {
   447  		dir = d.dir(id)
   448  	}
   449  
   450  	return containerfs.NewLocalContainerFS(dir), nil
   451  }
   452  
   453  // Put adds a new layer to the driver.
   454  func (d *Driver) Put(id string) error {
   455  	logrus.Debugf("WindowsGraphDriver Put() id %s", id)
   456  
   457  	rID, err := d.resolveID(id)
   458  	if err != nil {
   459  		return err
   460  	}
   461  	if count := d.ctr.Decrement(rID); count > 0 {
   462  		return nil
   463  	}
   464  	d.cacheMu.Lock()
   465  	_, exists := d.cache[rID]
   466  	delete(d.cache, rID)
   467  	d.cacheMu.Unlock()
   468  
   469  	// If the cache was not populated, then the layer was left unprepared and deactivated
   470  	if !exists {
   471  		return nil
   472  	}
   473  
   474  	if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
   475  		return err
   476  	}
   477  	return hcsshim.DeactivateLayer(d.info, rID)
   478  }
   479  
   480  // Cleanup ensures the information the driver stores is properly removed.
   481  // We use this opportunity to cleanup any -removing folders which may be
   482  // still left if the daemon was killed while it was removing a layer.
   483  func (d *Driver) Cleanup() error {
   484  	items, err := ioutil.ReadDir(d.info.HomeDir)
   485  	if err != nil {
   486  		if os.IsNotExist(err) {
   487  			return nil
   488  		}
   489  		return err
   490  	}
   491  
   492  	// Note we don't return an error below - it's possible the files
   493  	// are locked. However, next time around after the daemon exits,
   494  	// we likely will be able to cleanup successfully. Instead we log
   495  	// warnings if there are errors.
   496  	for _, item := range items {
   497  		if item.IsDir() && strings.HasSuffix(item.Name(), "-removing") {
   498  			if err := hcsshim.DestroyLayer(d.info, item.Name()); err != nil {
   499  				logrus.Warnf("Failed to cleanup %s: %s", item.Name(), err)
   500  			} else {
   501  				logrus.Infof("Cleaned up %s", item.Name())
   502  			}
   503  		}
   504  	}
   505  
   506  	return nil
   507  }
   508  
   509  // Diff produces an archive of the changes between the specified
   510  // layer and its parent layer which may be "".
   511  // The layer should be mounted when calling this function
   512  func (d *Driver) Diff(id, parent string) (_ io.ReadCloser, err error) {
   513  	rID, err := d.resolveID(id)
   514  	if err != nil {
   515  		return
   516  	}
   517  
   518  	layerChain, err := d.getLayerChain(rID)
   519  	if err != nil {
   520  		return
   521  	}
   522  
   523  	// this is assuming that the layer is unmounted
   524  	if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
   525  		return nil, err
   526  	}
   527  	prepare := func() {
   528  		if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
   529  			logrus.Warnf("Failed to Deactivate %s: %s", rID, err)
   530  		}
   531  	}
   532  
   533  	arch, err := d.exportLayer(rID, layerChain)
   534  	if err != nil {
   535  		prepare()
   536  		return
   537  	}
   538  	return ioutils.NewReadCloserWrapper(arch, func() error {
   539  		err := arch.Close()
   540  		prepare()
   541  		return err
   542  	}), nil
   543  }
   544  
   545  // Changes produces a list of changes between the specified layer
   546  // and its parent layer. If parent is "", then all changes will be ADD changes.
   547  // The layer should not be mounted when calling this function.
   548  func (d *Driver) Changes(id, parent string) ([]archive.Change, error) {
   549  	rID, err := d.resolveID(id)
   550  	if err != nil {
   551  		return nil, err
   552  	}
   553  	parentChain, err := d.getLayerChain(rID)
   554  	if err != nil {
   555  		return nil, err
   556  	}
   557  
   558  	if err := hcsshim.ActivateLayer(d.info, rID); err != nil {
   559  		return nil, err
   560  	}
   561  	defer func() {
   562  		if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
   563  			logrus.Errorf("changes() failed to DeactivateLayer %s %s: %s", id, rID, err2)
   564  		}
   565  	}()
   566  
   567  	var changes []archive.Change
   568  	err = winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
   569  		r, err := hcsshim.NewLayerReader(d.info, id, parentChain)
   570  		if err != nil {
   571  			return err
   572  		}
   573  		defer r.Close()
   574  
   575  		for {
   576  			name, _, fileInfo, err := r.Next()
   577  			if err == io.EOF {
   578  				return nil
   579  			}
   580  			if err != nil {
   581  				return err
   582  			}
   583  			name = filepath.ToSlash(name)
   584  			if fileInfo == nil {
   585  				changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeDelete})
   586  			} else {
   587  				// Currently there is no way to tell between an add and a modify.
   588  				changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeModify})
   589  			}
   590  		}
   591  	})
   592  	if err != nil {
   593  		return nil, err
   594  	}
   595  
   596  	return changes, nil
   597  }
   598  
   599  // ApplyDiff extracts the changeset from the given diff into the
   600  // layer with the specified id and parent, returning the size of the
   601  // new layer in bytes.
   602  // The layer should not be mounted when calling this function
   603  func (d *Driver) ApplyDiff(id, parent string, diff io.Reader) (int64, error) {
   604  	var layerChain []string
   605  	if parent != "" {
   606  		rPId, err := d.resolveID(parent)
   607  		if err != nil {
   608  			return 0, err
   609  		}
   610  		parentChain, err := d.getLayerChain(rPId)
   611  		if err != nil {
   612  			return 0, err
   613  		}
   614  		parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
   615  		if err != nil {
   616  			return 0, err
   617  		}
   618  		layerChain = append(layerChain, parentPath)
   619  		layerChain = append(layerChain, parentChain...)
   620  	}
   621  
   622  	size, err := d.importLayer(id, diff, layerChain)
   623  	if err != nil {
   624  		return 0, err
   625  	}
   626  
   627  	if err = d.setLayerChain(id, layerChain); err != nil {
   628  		return 0, err
   629  	}
   630  
   631  	return size, nil
   632  }
   633  
   634  // DiffSize calculates the changes between the specified layer
   635  // and its parent and returns the size in bytes of the changes
   636  // relative to its base filesystem directory.
   637  func (d *Driver) DiffSize(id, parent string) (size int64, err error) {
   638  	rPId, err := d.resolveID(parent)
   639  	if err != nil {
   640  		return
   641  	}
   642  
   643  	changes, err := d.Changes(id, rPId)
   644  	if err != nil {
   645  		return
   646  	}
   647  
   648  	layerFs, err := d.Get(id, "")
   649  	if err != nil {
   650  		return
   651  	}
   652  	defer d.Put(id)
   653  
   654  	return archive.ChangesSize(layerFs.Path(), changes), nil
   655  }
   656  
   657  // GetMetadata returns custom driver information.
   658  func (d *Driver) GetMetadata(id string) (map[string]string, error) {
   659  	m := make(map[string]string)
   660  	m["dir"] = d.dir(id)
   661  	return m, nil
   662  }
   663  
   664  func writeTarFromLayer(r hcsshim.LayerReader, w io.Writer) error {
   665  	t := tar.NewWriter(w)
   666  	for {
   667  		name, size, fileInfo, err := r.Next()
   668  		if err == io.EOF {
   669  			break
   670  		}
   671  		if err != nil {
   672  			return err
   673  		}
   674  		if fileInfo == nil {
   675  			// Write a whiteout file.
   676  			hdr := &tar.Header{
   677  				Name: filepath.ToSlash(filepath.Join(filepath.Dir(name), archive.WhiteoutPrefix+filepath.Base(name))),
   678  			}
   679  			err := t.WriteHeader(hdr)
   680  			if err != nil {
   681  				return err
   682  			}
   683  		} else {
   684  			err = backuptar.WriteTarFileFromBackupStream(t, r, name, size, fileInfo)
   685  			if err != nil {
   686  				return err
   687  			}
   688  		}
   689  	}
   690  	return t.Close()
   691  }
   692  
   693  // exportLayer generates an archive from a layer based on the given ID.
   694  func (d *Driver) exportLayer(id string, parentLayerPaths []string) (io.ReadCloser, error) {
   695  	archive, w := io.Pipe()
   696  	go func() {
   697  		err := winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
   698  			r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths)
   699  			if err != nil {
   700  				return err
   701  			}
   702  
   703  			err = writeTarFromLayer(r, w)
   704  			cerr := r.Close()
   705  			if err == nil {
   706  				err = cerr
   707  			}
   708  			return err
   709  		})
   710  		w.CloseWithError(err)
   711  	}()
   712  
   713  	return archive, nil
   714  }
   715  
   716  // writeBackupStreamFromTarAndSaveMutatedFiles reads data from a tar stream and
   717  // writes it to a backup stream, and also saves any files that will be mutated
   718  // by the import layer process to a backup location.
   719  func writeBackupStreamFromTarAndSaveMutatedFiles(buf *bufio.Writer, w io.Writer, t *tar.Reader, hdr *tar.Header, root string) (nextHdr *tar.Header, err error) {
   720  	var bcdBackup *os.File
   721  	var bcdBackupWriter *winio.BackupFileWriter
   722  	if backupPath, ok := mutatedFiles[hdr.Name]; ok {
   723  		bcdBackup, err = os.Create(filepath.Join(root, backupPath))
   724  		if err != nil {
   725  			return nil, err
   726  		}
   727  		defer func() {
   728  			cerr := bcdBackup.Close()
   729  			if err == nil {
   730  				err = cerr
   731  			}
   732  		}()
   733  
   734  		bcdBackupWriter = winio.NewBackupFileWriter(bcdBackup, false)
   735  		defer func() {
   736  			cerr := bcdBackupWriter.Close()
   737  			if err == nil {
   738  				err = cerr
   739  			}
   740  		}()
   741  
   742  		buf.Reset(io.MultiWriter(w, bcdBackupWriter))
   743  	} else {
   744  		buf.Reset(w)
   745  	}
   746  
   747  	defer func() {
   748  		ferr := buf.Flush()
   749  		if err == nil {
   750  			err = ferr
   751  		}
   752  	}()
   753  
   754  	return backuptar.WriteBackupStreamFromTarFile(buf, t, hdr)
   755  }
   756  
   757  func writeLayerFromTar(r io.Reader, w hcsshim.LayerWriter, root string) (int64, error) {
   758  	t := tar.NewReader(r)
   759  	hdr, err := t.Next()
   760  	totalSize := int64(0)
   761  	buf := bufio.NewWriter(nil)
   762  	for err == nil {
   763  		base := path.Base(hdr.Name)
   764  		if strings.HasPrefix(base, archive.WhiteoutPrefix) {
   765  			name := path.Join(path.Dir(hdr.Name), base[len(archive.WhiteoutPrefix):])
   766  			err = w.Remove(filepath.FromSlash(name))
   767  			if err != nil {
   768  				return 0, err
   769  			}
   770  			hdr, err = t.Next()
   771  		} else if hdr.Typeflag == tar.TypeLink {
   772  			err = w.AddLink(filepath.FromSlash(hdr.Name), filepath.FromSlash(hdr.Linkname))
   773  			if err != nil {
   774  				return 0, err
   775  			}
   776  			hdr, err = t.Next()
   777  		} else {
   778  			var (
   779  				name     string
   780  				size     int64
   781  				fileInfo *winio.FileBasicInfo
   782  			)
   783  			name, size, fileInfo, err = backuptar.FileInfoFromHeader(hdr)
   784  			if err != nil {
   785  				return 0, err
   786  			}
   787  			err = w.Add(filepath.FromSlash(name), fileInfo)
   788  			if err != nil {
   789  				return 0, err
   790  			}
   791  			hdr, err = writeBackupStreamFromTarAndSaveMutatedFiles(buf, w, t, hdr, root)
   792  			totalSize += size
   793  		}
   794  	}
   795  	if err != io.EOF {
   796  		return 0, err
   797  	}
   798  	return totalSize, nil
   799  }
   800  
   801  // importLayer adds a new layer to the tag and graph store based on the given data.
   802  func (d *Driver) importLayer(id string, layerData io.Reader, parentLayerPaths []string) (size int64, err error) {
   803  	if !noreexec {
   804  		cmd := reexec.Command(append([]string{"docker-windows-write-layer", d.info.HomeDir, id}, parentLayerPaths...)...)
   805  		output := bytes.NewBuffer(nil)
   806  		cmd.Stdin = layerData
   807  		cmd.Stdout = output
   808  		cmd.Stderr = output
   809  
   810  		if err = cmd.Start(); err != nil {
   811  			return
   812  		}
   813  
   814  		if err = cmd.Wait(); err != nil {
   815  			return 0, fmt.Errorf("re-exec error: %v: output: %s", err, output)
   816  		}
   817  
   818  		return strconv.ParseInt(output.String(), 10, 64)
   819  	}
   820  	return writeLayer(layerData, d.info.HomeDir, id, parentLayerPaths...)
   821  }
   822  
   823  // writeLayerReexec is the re-exec entry point for writing a layer from a tar file
   824  func writeLayerReexec() {
   825  	size, err := writeLayer(os.Stdin, os.Args[1], os.Args[2], os.Args[3:]...)
   826  	if err != nil {
   827  		fmt.Fprint(os.Stderr, err)
   828  		os.Exit(1)
   829  	}
   830  	fmt.Fprint(os.Stdout, size)
   831  }
   832  
   833  // writeLayer writes a layer from a tar file.
   834  func writeLayer(layerData io.Reader, home string, id string, parentLayerPaths ...string) (size int64, retErr error) {
   835  	err := winio.EnableProcessPrivileges([]string{winio.SeSecurityPrivilege, winio.SeBackupPrivilege, winio.SeRestorePrivilege})
   836  	if err != nil {
   837  		return 0, err
   838  	}
   839  	if noreexec {
   840  		defer func() {
   841  			if err := winio.DisableProcessPrivileges([]string{winio.SeSecurityPrivilege, winio.SeBackupPrivilege, winio.SeRestorePrivilege}); err != nil {
   842  				// This should never happen, but just in case when in debugging mode.
   843  				// See https://github.com/docker/docker/pull/28002#discussion_r86259241 for rationale.
   844  				panic("Failed to disabled process privileges while in non re-exec mode")
   845  			}
   846  		}()
   847  	}
   848  
   849  	info := hcsshim.DriverInfo{
   850  		Flavour: filterDriver,
   851  		HomeDir: home,
   852  	}
   853  
   854  	w, err := hcsshim.NewLayerWriter(info, id, parentLayerPaths)
   855  	if err != nil {
   856  		return 0, err
   857  	}
   858  
   859  	defer func() {
   860  		if err := w.Close(); err != nil {
   861  			// This error should not be discarded as a failure here
   862  			// could result in an invalid layer on disk
   863  			if retErr == nil {
   864  				retErr = err
   865  			}
   866  		}
   867  	}()
   868  
   869  	return writeLayerFromTar(layerData, w, filepath.Join(home, id))
   870  }
   871  
   872  // resolveID computes the layerID information based on the given id.
   873  func (d *Driver) resolveID(id string) (string, error) {
   874  	content, err := ioutil.ReadFile(filepath.Join(d.dir(id), "layerID"))
   875  	if os.IsNotExist(err) {
   876  		return id, nil
   877  	} else if err != nil {
   878  		return "", err
   879  	}
   880  	return string(content), nil
   881  }
   882  
   883  // setID stores the layerId in disk.
   884  func (d *Driver) setID(id, altID string) error {
   885  	return ioutil.WriteFile(filepath.Join(d.dir(id), "layerId"), []byte(altID), 0600)
   886  }
   887  
   888  // getLayerChain returns the layer chain information.
   889  func (d *Driver) getLayerChain(id string) ([]string, error) {
   890  	jPath := filepath.Join(d.dir(id), "layerchain.json")
   891  	content, err := ioutil.ReadFile(jPath)
   892  	if os.IsNotExist(err) {
   893  		return nil, nil
   894  	} else if err != nil {
   895  		return nil, fmt.Errorf("Unable to read layerchain file - %s", err)
   896  	}
   897  
   898  	var layerChain []string
   899  	err = json.Unmarshal(content, &layerChain)
   900  	if err != nil {
   901  		return nil, fmt.Errorf("Failed to unmarshall layerchain json - %s", err)
   902  	}
   903  
   904  	return layerChain, nil
   905  }
   906  
   907  // setLayerChain stores the layer chain information in disk.
   908  func (d *Driver) setLayerChain(id string, chain []string) error {
   909  	content, err := json.Marshal(&chain)
   910  	if err != nil {
   911  		return fmt.Errorf("Failed to marshall layerchain json - %s", err)
   912  	}
   913  
   914  	jPath := filepath.Join(d.dir(id), "layerchain.json")
   915  	err = ioutil.WriteFile(jPath, content, 0600)
   916  	if err != nil {
   917  		return fmt.Errorf("Unable to write layerchain file - %s", err)
   918  	}
   919  
   920  	return nil
   921  }
   922  
   923  type fileGetCloserWithBackupPrivileges struct {
   924  	path string
   925  }
   926  
   927  func (fg *fileGetCloserWithBackupPrivileges) Get(filename string) (io.ReadCloser, error) {
   928  	if backupPath, ok := mutatedFiles[filename]; ok {
   929  		return os.Open(filepath.Join(fg.path, backupPath))
   930  	}
   931  
   932  	var f *os.File
   933  	// Open the file while holding the Windows backup privilege. This ensures that the
   934  	// file can be opened even if the caller does not actually have access to it according
   935  	// to the security descriptor. Also use sequential file access to avoid depleting the
   936  	// standby list - Microsoft VSO Bug Tracker #9900466
   937  	err := winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
   938  		path := longpath.AddPrefix(filepath.Join(fg.path, filename))
   939  		p, err := windows.UTF16FromString(path)
   940  		if err != nil {
   941  			return err
   942  		}
   943  		const fileFlagSequentialScan = 0x08000000 // FILE_FLAG_SEQUENTIAL_SCAN
   944  		h, err := windows.CreateFile(&p[0], windows.GENERIC_READ, windows.FILE_SHARE_READ, nil, windows.OPEN_EXISTING, windows.FILE_FLAG_BACKUP_SEMANTICS|fileFlagSequentialScan, 0)
   945  		if err != nil {
   946  			return &os.PathError{Op: "open", Path: path, Err: err}
   947  		}
   948  		f = os.NewFile(uintptr(h), path)
   949  		return nil
   950  	})
   951  	return f, err
   952  }
   953  
   954  func (fg *fileGetCloserWithBackupPrivileges) Close() error {
   955  	return nil
   956  }
   957  
   958  // DiffGetter returns a FileGetCloser that can read files from the directory that
   959  // contains files for the layer differences. Used for direct access for tar-split.
   960  func (d *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) {
   961  	id, err := d.resolveID(id)
   962  	if err != nil {
   963  		return nil, err
   964  	}
   965  
   966  	return &fileGetCloserWithBackupPrivileges{d.dir(id)}, nil
   967  }
   968  
   969  func parseStorageOpt(storageOpt map[string]string) (*storageOptions, error) {
   970  	options := storageOptions{}
   971  
   972  	// Read size to change the block device size per container.
   973  	for key, val := range storageOpt {
   974  		key := strings.ToLower(key)
   975  		switch key {
   976  		case "size":
   977  			size, err := units.RAMInBytes(val)
   978  			if err != nil {
   979  				return nil, err
   980  			}
   981  			options.size = uint64(size)
   982  		}
   983  	}
   984  	return &options, nil
   985  }