github.com/uppal0016/docker_new@v0.0.0-20240123060250-1c98be13ac2c/daemon/graphdriver/windows/windows.go (about)

     1  //+build windows
     2  
     3  package windows
     4  
     5  import (
     6  	"bufio"
     7  	"crypto/sha512"
     8  	"encoding/json"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"os"
    13  	"path"
    14  	"path/filepath"
    15  	"strings"
    16  	"syscall"
    17  	"time"
    18  	"unsafe"
    19  
    20  	"github.com/Microsoft/go-winio"
    21  	"github.com/Microsoft/go-winio/archive/tar"
    22  	"github.com/Microsoft/go-winio/backuptar"
    23  	"github.com/Microsoft/hcsshim"
    24  	"github.com/Sirupsen/logrus"
    25  	"github.com/docker/docker/daemon/graphdriver"
    26  	"github.com/docker/docker/pkg/archive"
    27  	"github.com/docker/docker/pkg/chrootarchive"
    28  	"github.com/docker/docker/pkg/idtools"
    29  	"github.com/docker/docker/pkg/ioutils"
    30  	"github.com/docker/docker/pkg/longpath"
    31  	"github.com/docker/docker/pkg/system"
    32  	"github.com/vbatts/tar-split/tar/storage"
    33  )
    34  
    35  // init registers the windows graph drivers to the register.
    36  func init() {
    37  	graphdriver.Register("windowsfilter", InitFilter)
    38  	graphdriver.Register("windowsdiff", InitDiff)
    39  }
    40  
    41  const (
    42  	// diffDriver is an hcsshim driver type
    43  	diffDriver = iota
    44  	// filterDriver is an hcsshim driver type
    45  	filterDriver
    46  )
    47  
    48  // Driver represents a windows graph driver.
    49  type Driver struct {
    50  	// info stores the shim driver information
    51  	info hcsshim.DriverInfo
    52  }
    53  
    54  var _ graphdriver.DiffGetterDriver = &Driver{}
    55  
    56  func isTP5OrOlder() bool {
    57  	return system.GetOSVersion().Build <= 14300
    58  }
    59  
    60  // InitFilter returns a new Windows storage filter driver.
    61  func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
    62  	logrus.Debugf("WindowsGraphDriver InitFilter at %s", home)
    63  	d := &Driver{
    64  		info: hcsshim.DriverInfo{
    65  			HomeDir: home,
    66  			Flavour: filterDriver,
    67  		},
    68  	}
    69  	return d, nil
    70  }
    71  
    72  // InitDiff returns a new Windows differencing disk driver.
    73  func InitDiff(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
    74  	logrus.Debugf("WindowsGraphDriver InitDiff at %s", home)
    75  	d := &Driver{
    76  		info: hcsshim.DriverInfo{
    77  			HomeDir: home,
    78  			Flavour: diffDriver,
    79  		},
    80  	}
    81  	return d, nil
    82  }
    83  
    84  // String returns the string representation of a driver.
    85  func (d *Driver) String() string {
    86  	switch d.info.Flavour {
    87  	case diffDriver:
    88  		return "windowsdiff"
    89  	case filterDriver:
    90  		return "windowsfilter"
    91  	default:
    92  		return "Unknown driver flavour"
    93  	}
    94  }
    95  
    96  // Status returns the status of the driver.
    97  func (d *Driver) Status() [][2]string {
    98  	return [][2]string{
    99  		{"Windows", ""},
   100  	}
   101  }
   102  
   103  // Exists returns true if the given id is registered with this driver.
   104  func (d *Driver) Exists(id string) bool {
   105  	rID, err := d.resolveID(id)
   106  	if err != nil {
   107  		return false
   108  	}
   109  	result, err := hcsshim.LayerExists(d.info, rID)
   110  	if err != nil {
   111  		return false
   112  	}
   113  	return result
   114  }
   115  
   116  // CreateReadWrite creates a layer that is writable for use as a container
   117  // file system.
   118  func (d *Driver) CreateReadWrite(id, parent, mountLabel string, storageOpt map[string]string) error {
   119  	return d.create(id, parent, mountLabel, false, storageOpt)
   120  }
   121  
   122  // Create creates a new read-only layer with the given id.
   123  func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
   124  	return d.create(id, parent, mountLabel, true, storageOpt)
   125  }
   126  
   127  func (d *Driver) create(id, parent, mountLabel string, readOnly bool, storageOpt map[string]string) error {
   128  	if len(storageOpt) != 0 {
   129  		return fmt.Errorf("--storage-opt is not supported for windows")
   130  	}
   131  
   132  	rPId, err := d.resolveID(parent)
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	parentChain, err := d.getLayerChain(rPId)
   138  	if err != nil {
   139  		return err
   140  	}
   141  
   142  	var layerChain []string
   143  
   144  	if rPId != "" {
   145  		parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
   146  		if err != nil {
   147  			return err
   148  		}
   149  		if _, err := os.Stat(filepath.Join(parentPath, "Files")); err == nil {
   150  			// This is a legitimate parent layer (not the empty "-init" layer),
   151  			// so include it in the layer chain.
   152  			layerChain = []string{parentPath}
   153  		}
   154  	}
   155  
   156  	layerChain = append(layerChain, parentChain...)
   157  
   158  	if readOnly {
   159  		if err := hcsshim.CreateLayer(d.info, id, rPId); err != nil {
   160  			return err
   161  		}
   162  	} else {
   163  		var parentPath string
   164  		if len(layerChain) != 0 {
   165  			parentPath = layerChain[0]
   166  		}
   167  
   168  		if isTP5OrOlder() {
   169  			// Pre-create the layer directory, providing an ACL to give the Hyper-V Virtual Machines
   170  			// group access. This is necessary to ensure that Hyper-V containers can access the
   171  			// virtual machine data. This is not necessary post-TP5.
   172  			path, err := syscall.UTF16FromString(filepath.Join(d.info.HomeDir, id))
   173  			if err != nil {
   174  				return err
   175  			}
   176  			// Give system and administrators full control, and VMs read, write, and execute.
   177  			// Mark these ACEs as inherited.
   178  			sd, err := winio.SddlToSecurityDescriptor("D:(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FRFWFX;;;S-1-5-83-0)")
   179  			if err != nil {
   180  				return err
   181  			}
   182  			err = syscall.CreateDirectory(&path[0], &syscall.SecurityAttributes{
   183  				Length:             uint32(unsafe.Sizeof(syscall.SecurityAttributes{})),
   184  				SecurityDescriptor: uintptr(unsafe.Pointer(&sd[0])),
   185  			})
   186  			if err != nil {
   187  				return err
   188  			}
   189  		}
   190  
   191  		if err := hcsshim.CreateSandboxLayer(d.info, id, parentPath, layerChain); err != nil {
   192  			return err
   193  		}
   194  	}
   195  
   196  	if _, err := os.Lstat(d.dir(parent)); err != nil {
   197  		if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
   198  			logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
   199  		}
   200  		return fmt.Errorf("Cannot create layer with missing parent %s: %s", parent, err)
   201  	}
   202  
   203  	if err := d.setLayerChain(id, layerChain); err != nil {
   204  		if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
   205  			logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
   206  		}
   207  		return err
   208  	}
   209  
   210  	return nil
   211  }
   212  
   213  // dir returns the absolute path to the layer.
   214  func (d *Driver) dir(id string) string {
   215  	return filepath.Join(d.info.HomeDir, filepath.Base(id))
   216  }
   217  
   218  // Remove unmounts and removes the dir information.
   219  func (d *Driver) Remove(id string) error {
   220  	rID, err := d.resolveID(id)
   221  	if err != nil {
   222  		return err
   223  	}
   224  	os.RemoveAll(filepath.Join(d.info.HomeDir, "sysfile-backups", rID)) // ok to fail
   225  	return hcsshim.DestroyLayer(d.info, rID)
   226  }
   227  
   228  // Get returns the rootfs path for the id. This will mount the dir at it's given path.
   229  func (d *Driver) Get(id, mountLabel string) (string, error) {
   230  	logrus.Debugf("WindowsGraphDriver Get() id %s mountLabel %s", id, mountLabel)
   231  	var dir string
   232  
   233  	rID, err := d.resolveID(id)
   234  	if err != nil {
   235  		return "", err
   236  	}
   237  
   238  	// Getting the layer paths must be done outside of the lock.
   239  	layerChain, err := d.getLayerChain(rID)
   240  	if err != nil {
   241  		return "", err
   242  	}
   243  
   244  	if err := hcsshim.ActivateLayer(d.info, rID); err != nil {
   245  		return "", err
   246  	}
   247  	if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
   248  		if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
   249  			logrus.Warnf("Failed to Deactivate %s: %s", id, err)
   250  		}
   251  		return "", err
   252  	}
   253  
   254  	mountPath, err := hcsshim.GetLayerMountPath(d.info, rID)
   255  	if err != nil {
   256  		if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
   257  			logrus.Warnf("Failed to Deactivate %s: %s", id, err)
   258  		}
   259  		return "", err
   260  	}
   261  
   262  	// If the layer has a mount path, use that. Otherwise, use the
   263  	// folder path.
   264  	if mountPath != "" {
   265  		dir = mountPath
   266  	} else {
   267  		dir = d.dir(id)
   268  	}
   269  
   270  	return dir, nil
   271  }
   272  
   273  // Put adds a new layer to the driver.
   274  func (d *Driver) Put(id string) error {
   275  	logrus.Debugf("WindowsGraphDriver Put() id %s", id)
   276  
   277  	rID, err := d.resolveID(id)
   278  	if err != nil {
   279  		return err
   280  	}
   281  
   282  	if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
   283  		return err
   284  	}
   285  	return hcsshim.DeactivateLayer(d.info, rID)
   286  }
   287  
   288  // Cleanup ensures the information the driver stores is properly removed.
   289  func (d *Driver) Cleanup() error {
   290  	return nil
   291  }
   292  
   293  // Diff produces an archive of the changes between the specified
   294  // layer and its parent layer which may be "".
   295  // The layer should be mounted when calling this function
   296  func (d *Driver) Diff(id, parent string) (_ archive.Archive, err error) {
   297  	rID, err := d.resolveID(id)
   298  	if err != nil {
   299  		return
   300  	}
   301  
   302  	layerChain, err := d.getLayerChain(rID)
   303  	if err != nil {
   304  		return
   305  	}
   306  
   307  	// this is assuming that the layer is unmounted
   308  	if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
   309  		return nil, err
   310  	}
   311  	defer func() {
   312  		if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
   313  			logrus.Warnf("Failed to Deactivate %s: %s", rID, err)
   314  		}
   315  	}()
   316  
   317  	arch, err := d.exportLayer(rID, layerChain)
   318  	if err != nil {
   319  		return
   320  	}
   321  	return ioutils.NewReadCloserWrapper(arch, func() error {
   322  		return arch.Close()
   323  	}), nil
   324  }
   325  
   326  // Changes produces a list of changes between the specified layer
   327  // and its parent layer. If parent is "", then all changes will be ADD changes.
   328  // The layer should be mounted when calling this function
   329  func (d *Driver) Changes(id, parent string) ([]archive.Change, error) {
   330  	rID, err := d.resolveID(id)
   331  	if err != nil {
   332  		return nil, err
   333  	}
   334  	parentChain, err := d.getLayerChain(rID)
   335  	if err != nil {
   336  		return nil, err
   337  	}
   338  
   339  	// this is assuming that the layer is unmounted
   340  	if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
   341  		return nil, err
   342  	}
   343  	defer func() {
   344  		if err := hcsshim.PrepareLayer(d.info, rID, parentChain); err != nil {
   345  			logrus.Warnf("Failed to Deactivate %s: %s", rID, err)
   346  		}
   347  	}()
   348  
   349  	r, err := hcsshim.NewLayerReader(d.info, id, parentChain)
   350  	if err != nil {
   351  		return nil, err
   352  	}
   353  	defer r.Close()
   354  
   355  	var changes []archive.Change
   356  	for {
   357  		name, _, fileInfo, err := r.Next()
   358  		if err == io.EOF {
   359  			break
   360  		}
   361  		if err != nil {
   362  			return nil, err
   363  		}
   364  		name = filepath.ToSlash(name)
   365  		if fileInfo == nil {
   366  			changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeDelete})
   367  		} else {
   368  			// Currently there is no way to tell between an add and a modify.
   369  			changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeModify})
   370  		}
   371  	}
   372  	return changes, nil
   373  }
   374  
   375  // ApplyDiff extracts the changeset from the given diff into the
   376  // layer with the specified id and parent, returning the size of the
   377  // new layer in bytes.
   378  // The layer should not be mounted when calling this function
   379  func (d *Driver) ApplyDiff(id, parent string, diff archive.Reader) (int64, error) {
   380  	if d.info.Flavour == diffDriver {
   381  		start := time.Now().UTC()
   382  		logrus.Debugf("WindowsGraphDriver ApplyDiff: Start untar layer")
   383  		destination := d.dir(id)
   384  		destination = filepath.Dir(destination)
   385  		size, err := chrootarchive.ApplyUncompressedLayer(destination, diff, nil)
   386  		if err != nil {
   387  			return 0, err
   388  		}
   389  		logrus.Debugf("WindowsGraphDriver ApplyDiff: Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
   390  
   391  		return size, nil
   392  	}
   393  
   394  	var layerChain []string
   395  	if parent != "" {
   396  		rPId, err := d.resolveID(parent)
   397  		if err != nil {
   398  			return 0, err
   399  		}
   400  		parentChain, err := d.getLayerChain(rPId)
   401  		if err != nil {
   402  			return 0, err
   403  		}
   404  		parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
   405  		if err != nil {
   406  			return 0, err
   407  		}
   408  		layerChain = append(layerChain, parentPath)
   409  		layerChain = append(layerChain, parentChain...)
   410  	}
   411  
   412  	size, err := d.importLayer(id, diff, layerChain)
   413  	if err != nil {
   414  		return 0, err
   415  	}
   416  
   417  	if err = d.setLayerChain(id, layerChain); err != nil {
   418  		return 0, err
   419  	}
   420  
   421  	return size, nil
   422  }
   423  
   424  // DiffSize calculates the changes between the specified layer
   425  // and its parent and returns the size in bytes of the changes
   426  // relative to its base filesystem directory.
   427  func (d *Driver) DiffSize(id, parent string) (size int64, err error) {
   428  	rPId, err := d.resolveID(parent)
   429  	if err != nil {
   430  		return
   431  	}
   432  
   433  	changes, err := d.Changes(id, rPId)
   434  	if err != nil {
   435  		return
   436  	}
   437  
   438  	layerFs, err := d.Get(id, "")
   439  	if err != nil {
   440  		return
   441  	}
   442  	defer d.Put(id)
   443  
   444  	return archive.ChangesSize(layerFs, changes), nil
   445  }
   446  
   447  // CustomImageInfo is the object returned by the driver describing the base
   448  // image.
   449  type CustomImageInfo struct {
   450  	ID          string
   451  	Name        string
   452  	Version     string
   453  	Path        string
   454  	Size        int64
   455  	CreatedTime time.Time
   456  	OSVersion   string   `json:"-"`
   457  	OSFeatures  []string `json:"-"`
   458  }
   459  
   460  // GetCustomImageInfos returns the image infos for window specific
   461  // base images which should always be present.
   462  func (d *Driver) GetCustomImageInfos() ([]CustomImageInfo, error) {
   463  	strData, err := hcsshim.GetSharedBaseImages()
   464  	if err != nil {
   465  		return nil, fmt.Errorf("Failed to restore base images: %s", err)
   466  	}
   467  
   468  	type customImageInfoList struct {
   469  		Images []CustomImageInfo
   470  	}
   471  
   472  	var infoData customImageInfoList
   473  
   474  	if err = json.Unmarshal([]byte(strData), &infoData); err != nil {
   475  		err = fmt.Errorf("JSON unmarshal returned error=%s", err)
   476  		logrus.Error(err)
   477  		return nil, err
   478  	}
   479  
   480  	var images []CustomImageInfo
   481  
   482  	for _, imageData := range infoData.Images {
   483  		folderName := filepath.Base(imageData.Path)
   484  
   485  		// Use crypto hash of the foldername to generate a docker style id.
   486  		h := sha512.Sum384([]byte(folderName))
   487  		id := fmt.Sprintf("%x", h[:32])
   488  
   489  		if err := d.Create(id, "", "", nil); err != nil {
   490  			return nil, err
   491  		}
   492  		// Create the alternate ID file.
   493  		if err := d.setID(id, folderName); err != nil {
   494  			return nil, err
   495  		}
   496  
   497  		imageData.ID = id
   498  
   499  		// For now, hard code that all base images except nanoserver depend on win32k support
   500  		if imageData.Name != "NanoServer" {
   501  			imageData.OSFeatures = append(imageData.OSFeatures, "win32k")
   502  		}
   503  
   504  		versionData := strings.Split(imageData.Version, ".")
   505  		if len(versionData) != 4 {
   506  			logrus.Warn("Could not parse Windows version %s", imageData.Version)
   507  		} else {
   508  			// Include just major.minor.build, skip the fourth version field, which does not influence
   509  			// OS compatibility.
   510  			imageData.OSVersion = strings.Join(versionData[:3], ".")
   511  		}
   512  
   513  		images = append(images, imageData)
   514  	}
   515  
   516  	return images, nil
   517  }
   518  
   519  // GetMetadata returns custom driver information.
   520  func (d *Driver) GetMetadata(id string) (map[string]string, error) {
   521  	m := make(map[string]string)
   522  	m["dir"] = d.dir(id)
   523  	return m, nil
   524  }
   525  
   526  func writeTarFromLayer(r hcsshim.LayerReader, w io.Writer) error {
   527  	t := tar.NewWriter(w)
   528  	for {
   529  		name, size, fileInfo, err := r.Next()
   530  		if err == io.EOF {
   531  			break
   532  		}
   533  		if err != nil {
   534  			return err
   535  		}
   536  		if fileInfo == nil {
   537  			// Write a whiteout file.
   538  			hdr := &tar.Header{
   539  				Name: filepath.ToSlash(filepath.Join(filepath.Dir(name), archive.WhiteoutPrefix+filepath.Base(name))),
   540  			}
   541  			err := t.WriteHeader(hdr)
   542  			if err != nil {
   543  				return err
   544  			}
   545  		} else {
   546  			err = backuptar.WriteTarFileFromBackupStream(t, r, name, size, fileInfo)
   547  			if err != nil {
   548  				return err
   549  			}
   550  		}
   551  	}
   552  	return t.Close()
   553  }
   554  
   555  // exportLayer generates an archive from a layer based on the given ID.
   556  func (d *Driver) exportLayer(id string, parentLayerPaths []string) (archive.Archive, error) {
   557  	var r hcsshim.LayerReader
   558  	r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths)
   559  	if err != nil {
   560  		return nil, err
   561  	}
   562  
   563  	archive, w := io.Pipe()
   564  	go func() {
   565  		err := writeTarFromLayer(r, w)
   566  		cerr := r.Close()
   567  		if err == nil {
   568  			err = cerr
   569  		}
   570  		w.CloseWithError(err)
   571  	}()
   572  
   573  	return archive, nil
   574  }
   575  
   576  func writeLayerFromTar(r archive.Reader, w hcsshim.LayerWriter) (int64, error) {
   577  	t := tar.NewReader(r)
   578  	hdr, err := t.Next()
   579  	totalSize := int64(0)
   580  	buf := bufio.NewWriter(nil)
   581  	for err == nil {
   582  		base := path.Base(hdr.Name)
   583  		if strings.HasPrefix(base, archive.WhiteoutPrefix) {
   584  			name := path.Join(path.Dir(hdr.Name), base[len(archive.WhiteoutPrefix):])
   585  			err = w.Remove(filepath.FromSlash(name))
   586  			if err != nil {
   587  				return 0, err
   588  			}
   589  			hdr, err = t.Next()
   590  		} else if hdr.Typeflag == tar.TypeLink {
   591  			err = w.AddLink(filepath.FromSlash(hdr.Name), filepath.FromSlash(hdr.Linkname))
   592  			if err != nil {
   593  				return 0, err
   594  			}
   595  			hdr, err = t.Next()
   596  		} else {
   597  			var (
   598  				name     string
   599  				size     int64
   600  				fileInfo *winio.FileBasicInfo
   601  			)
   602  			name, size, fileInfo, err = backuptar.FileInfoFromHeader(hdr)
   603  			if err != nil {
   604  				return 0, err
   605  			}
   606  			err = w.Add(filepath.FromSlash(name), fileInfo)
   607  			if err != nil {
   608  				return 0, err
   609  			}
   610  			buf.Reset(w)
   611  
   612  			// Add the Hyper-V Virutal Machine group ACE to the security descriptor
   613  			// for TP5 so that Xenons can access all files. This is not necessary
   614  			// for post-TP5 builds.
   615  			if isTP5OrOlder() {
   616  				if sddl, ok := hdr.Winheaders["sd"]; ok {
   617  					var ace string
   618  					if hdr.Typeflag == tar.TypeDir {
   619  						ace = "(A;OICI;0x1200a9;;;S-1-5-83-0)"
   620  					} else {
   621  						ace = "(A;;0x1200a9;;;S-1-5-83-0)"
   622  					}
   623  					if hdr.Winheaders["sd"], ok = addAceToSddlDacl(sddl, ace); !ok {
   624  						logrus.Debugf("failed to add VM ACE to %s", sddl)
   625  					}
   626  				}
   627  			}
   628  
   629  			hdr, err = backuptar.WriteBackupStreamFromTarFile(buf, t, hdr)
   630  			ferr := buf.Flush()
   631  			if ferr != nil {
   632  				err = ferr
   633  			}
   634  			totalSize += size
   635  		}
   636  	}
   637  	if err != io.EOF {
   638  		return 0, err
   639  	}
   640  	return totalSize, nil
   641  }
   642  
   643  func addAceToSddlDacl(sddl, ace string) (string, bool) {
   644  	daclStart := strings.Index(sddl, "D:")
   645  	if daclStart < 0 {
   646  		return sddl, false
   647  	}
   648  
   649  	dacl := sddl[daclStart:]
   650  	daclEnd := strings.Index(dacl, "S:")
   651  	if daclEnd < 0 {
   652  		daclEnd = len(dacl)
   653  	}
   654  	dacl = dacl[:daclEnd]
   655  
   656  	if strings.Contains(dacl, ace) {
   657  		return sddl, true
   658  	}
   659  
   660  	i := 2
   661  	for i+1 < len(dacl) {
   662  		if dacl[i] != '(' {
   663  			return sddl, false
   664  		}
   665  
   666  		if dacl[i+1] == 'A' {
   667  			break
   668  		}
   669  
   670  		i += 2
   671  		for p := 1; i < len(dacl) && p > 0; i++ {
   672  			if dacl[i] == '(' {
   673  				p++
   674  			} else if dacl[i] == ')' {
   675  				p--
   676  			}
   677  		}
   678  	}
   679  
   680  	return sddl[:daclStart+i] + ace + sddl[daclStart+i:], true
   681  }
   682  
   683  // importLayer adds a new layer to the tag and graph store based on the given data.
   684  func (d *Driver) importLayer(id string, layerData archive.Reader, parentLayerPaths []string) (size int64, err error) {
   685  	var w hcsshim.LayerWriter
   686  	w, err = hcsshim.NewLayerWriter(d.info, id, parentLayerPaths)
   687  	if err != nil {
   688  		return
   689  	}
   690  	size, err = writeLayerFromTar(layerData, w)
   691  	if err != nil {
   692  		w.Close()
   693  		return
   694  	}
   695  	err = w.Close()
   696  	if err != nil {
   697  		return
   698  	}
   699  	return
   700  }
   701  
   702  // resolveID computes the layerID information based on the given id.
   703  func (d *Driver) resolveID(id string) (string, error) {
   704  	content, err := ioutil.ReadFile(filepath.Join(d.dir(id), "layerID"))
   705  	if os.IsNotExist(err) {
   706  		return id, nil
   707  	} else if err != nil {
   708  		return "", err
   709  	}
   710  	return string(content), nil
   711  }
   712  
   713  // setID stores the layerId in disk.
   714  func (d *Driver) setID(id, altID string) error {
   715  	err := ioutil.WriteFile(filepath.Join(d.dir(id), "layerId"), []byte(altID), 0600)
   716  	if err != nil {
   717  		return err
   718  	}
   719  	return nil
   720  }
   721  
   722  // getLayerChain returns the layer chain information.
   723  func (d *Driver) getLayerChain(id string) ([]string, error) {
   724  	jPath := filepath.Join(d.dir(id), "layerchain.json")
   725  	content, err := ioutil.ReadFile(jPath)
   726  	if os.IsNotExist(err) {
   727  		return nil, nil
   728  	} else if err != nil {
   729  		return nil, fmt.Errorf("Unable to read layerchain file - %s", err)
   730  	}
   731  
   732  	var layerChain []string
   733  	err = json.Unmarshal(content, &layerChain)
   734  	if err != nil {
   735  		return nil, fmt.Errorf("Failed to unmarshall layerchain json - %s", err)
   736  	}
   737  
   738  	return layerChain, nil
   739  }
   740  
   741  // setLayerChain stores the layer chain information in disk.
   742  func (d *Driver) setLayerChain(id string, chain []string) error {
   743  	content, err := json.Marshal(&chain)
   744  	if err != nil {
   745  		return fmt.Errorf("Failed to marshall layerchain json - %s", err)
   746  	}
   747  
   748  	jPath := filepath.Join(d.dir(id), "layerchain.json")
   749  	err = ioutil.WriteFile(jPath, content, 0600)
   750  	if err != nil {
   751  		return fmt.Errorf("Unable to write layerchain file - %s", err)
   752  	}
   753  
   754  	return nil
   755  }
   756  
   757  type fileGetCloserWithBackupPrivileges struct {
   758  	path string
   759  }
   760  
   761  func (fg *fileGetCloserWithBackupPrivileges) Get(filename string) (io.ReadCloser, error) {
   762  	var f *os.File
   763  	// Open the file while holding the Windows backup privilege. This ensures that the
   764  	// file can be opened even if the caller does not actually have access to it according
   765  	// to the security descriptor.
   766  	err := winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
   767  		path := longpath.AddPrefix(filepath.Join(fg.path, filename))
   768  		p, err := syscall.UTF16FromString(path)
   769  		if err != nil {
   770  			return err
   771  		}
   772  		h, err := syscall.CreateFile(&p[0], syscall.GENERIC_READ, syscall.FILE_SHARE_READ, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
   773  		if err != nil {
   774  			return &os.PathError{Op: "open", Path: path, Err: err}
   775  		}
   776  		f = os.NewFile(uintptr(h), path)
   777  		return nil
   778  	})
   779  	return f, err
   780  }
   781  
   782  func (fg *fileGetCloserWithBackupPrivileges) Close() error {
   783  	return nil
   784  }
   785  
   786  type fileGetDestroyCloser struct {
   787  	storage.FileGetter
   788  	path string
   789  }
   790  
   791  func (f *fileGetDestroyCloser) Close() error {
   792  	// TODO: activate layers and release here?
   793  	return os.RemoveAll(f.path)
   794  }
   795  
   796  // DiffGetter returns a FileGetCloser that can read files from the directory that
   797  // contains files for the layer differences. Used for direct access for tar-split.
   798  func (d *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) {
   799  	id, err := d.resolveID(id)
   800  	if err != nil {
   801  		return nil, err
   802  	}
   803  
   804  	return &fileGetCloserWithBackupPrivileges{d.dir(id)}, nil
   805  }