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