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