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