github.com/rhatdan/storage@v1.12.13/drivers/windows/windows.go (about)

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