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