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