github.com/hustcat/docker@v1.3.3-0.20160314103604-901c67a8eeab/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  	"sync"
    17  	"syscall"
    18  	"time"
    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/vbatts/tar-split/tar/storage"
    31  )
    32  
    33  // init registers the windows graph drivers to the register.
    34  func init() {
    35  	graphdriver.Register("windowsfilter", InitFilter)
    36  	graphdriver.Register("windowsdiff", InitDiff)
    37  }
    38  
    39  const (
    40  	// diffDriver is an hcsshim driver type
    41  	diffDriver = iota
    42  	// filterDriver is an hcsshim driver type
    43  	filterDriver
    44  )
    45  
    46  // Driver represents a windows graph driver.
    47  type Driver struct {
    48  	// info stores the shim driver information
    49  	info hcsshim.DriverInfo
    50  	// Mutex protects concurrent modification to active
    51  	sync.Mutex
    52  	// active stores references to the activated layers
    53  	active map[string]int
    54  }
    55  
    56  var _ graphdriver.DiffGetterDriver = &Driver{}
    57  
    58  // InitFilter returns a new Windows storage filter driver.
    59  func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
    60  	logrus.Debugf("WindowsGraphDriver InitFilter at %s", home)
    61  	d := &Driver{
    62  		info: hcsshim.DriverInfo{
    63  			HomeDir: home,
    64  			Flavour: filterDriver,
    65  		},
    66  		active: make(map[string]int),
    67  	}
    68  	return d, nil
    69  }
    70  
    71  // InitDiff returns a new Windows differencing disk driver.
    72  func InitDiff(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
    73  	logrus.Debugf("WindowsGraphDriver InitDiff at %s", home)
    74  	d := &Driver{
    75  		info: hcsshim.DriverInfo{
    76  			HomeDir: home,
    77  			Flavour: diffDriver,
    78  		},
    79  		active: make(map[string]int),
    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  // Create creates a new layer with the given id.
   117  func (d *Driver) Create(id, parent, mountLabel string) error {
   118  	rPId, err := d.resolveID(parent)
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	parentChain, err := d.getLayerChain(rPId)
   124  	if err != nil {
   125  		return err
   126  	}
   127  
   128  	var layerChain []string
   129  
   130  	parentIsInit := strings.HasSuffix(rPId, "-init")
   131  
   132  	if !parentIsInit && rPId != "" {
   133  		parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
   134  		if err != nil {
   135  			return err
   136  		}
   137  		layerChain = []string{parentPath}
   138  	}
   139  
   140  	layerChain = append(layerChain, parentChain...)
   141  
   142  	if parentIsInit {
   143  		if len(layerChain) == 0 {
   144  			return fmt.Errorf("Cannot create a read/write layer without a parent layer.")
   145  		}
   146  		if err := hcsshim.CreateSandboxLayer(d.info, id, layerChain[0], layerChain); err != nil {
   147  			return err
   148  		}
   149  	} else {
   150  		if err := hcsshim.CreateLayer(d.info, id, rPId); err != nil {
   151  			return err
   152  		}
   153  	}
   154  
   155  	if _, err := os.Lstat(d.dir(parent)); err != nil {
   156  		if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
   157  			logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
   158  		}
   159  		return fmt.Errorf("Cannot create layer with missing parent %s: %s", parent, err)
   160  	}
   161  
   162  	if err := d.setLayerChain(id, layerChain); err != nil {
   163  		if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
   164  			logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
   165  		}
   166  		return err
   167  	}
   168  
   169  	return nil
   170  }
   171  
   172  // dir returns the absolute path to the layer.
   173  func (d *Driver) dir(id string) string {
   174  	return filepath.Join(d.info.HomeDir, filepath.Base(id))
   175  }
   176  
   177  // Remove unmounts and removes the dir information.
   178  func (d *Driver) Remove(id string) error {
   179  	rID, err := d.resolveID(id)
   180  	if err != nil {
   181  		return err
   182  	}
   183  	os.RemoveAll(filepath.Join(d.info.HomeDir, "sysfile-backups", rID)) // ok to fail
   184  	return hcsshim.DestroyLayer(d.info, rID)
   185  }
   186  
   187  // Get returns the rootfs path for the id. This will mount the dir at it's given path.
   188  func (d *Driver) Get(id, mountLabel string) (string, error) {
   189  	logrus.Debugf("WindowsGraphDriver Get() id %s mountLabel %s", id, mountLabel)
   190  	var dir string
   191  
   192  	d.Lock()
   193  	defer d.Unlock()
   194  
   195  	rID, err := d.resolveID(id)
   196  	if err != nil {
   197  		return "", err
   198  	}
   199  
   200  	// Getting the layer paths must be done outside of the lock.
   201  	layerChain, err := d.getLayerChain(rID)
   202  	if err != nil {
   203  		return "", err
   204  	}
   205  
   206  	if d.active[rID] == 0 {
   207  		if err := hcsshim.ActivateLayer(d.info, rID); err != nil {
   208  			return "", err
   209  		}
   210  		if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
   211  			if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
   212  				logrus.Warnf("Failed to Deactivate %s: %s", id, err)
   213  			}
   214  			return "", err
   215  		}
   216  	}
   217  
   218  	mountPath, err := hcsshim.GetLayerMountPath(d.info, rID)
   219  	if err != nil {
   220  		if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
   221  			logrus.Warnf("Failed to Deactivate %s: %s", id, err)
   222  		}
   223  		return "", err
   224  	}
   225  
   226  	d.active[rID]++
   227  
   228  	// If the layer has a mount path, use that. Otherwise, use the
   229  	// folder path.
   230  	if mountPath != "" {
   231  		dir = mountPath
   232  	} else {
   233  		dir = d.dir(id)
   234  	}
   235  
   236  	return dir, nil
   237  }
   238  
   239  // Put adds a new layer to the driver.
   240  func (d *Driver) Put(id string) error {
   241  	logrus.Debugf("WindowsGraphDriver Put() id %s", id)
   242  
   243  	rID, err := d.resolveID(id)
   244  	if err != nil {
   245  		return err
   246  	}
   247  
   248  	d.Lock()
   249  	defer d.Unlock()
   250  
   251  	if d.active[rID] > 1 {
   252  		d.active[rID]--
   253  	} else if d.active[rID] == 1 {
   254  		if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
   255  			return err
   256  		}
   257  		if err := hcsshim.DeactivateLayer(d.info, rID); err != nil {
   258  			return err
   259  		}
   260  		delete(d.active, rID)
   261  	}
   262  
   263  	return nil
   264  }
   265  
   266  // Cleanup ensures the information the driver stores is properly removed.
   267  func (d *Driver) Cleanup() error {
   268  	return nil
   269  }
   270  
   271  // Diff produces an archive of the changes between the specified
   272  // layer and its parent layer which may be "".
   273  func (d *Driver) Diff(id, parent string) (_ archive.Archive, err error) {
   274  	rID, err := d.resolveID(id)
   275  	if err != nil {
   276  		return
   277  	}
   278  
   279  	// Getting the layer paths must be done outside of the lock.
   280  	layerChain, err := d.getLayerChain(rID)
   281  	if err != nil {
   282  		return
   283  	}
   284  
   285  	var undo func()
   286  
   287  	d.Lock()
   288  
   289  	// To support export, a layer must be activated but not prepared.
   290  	if d.info.Flavour == filterDriver {
   291  		if d.active[rID] == 0 {
   292  			if err = hcsshim.ActivateLayer(d.info, rID); err != nil {
   293  				d.Unlock()
   294  				return
   295  			}
   296  			undo = func() {
   297  				if err := hcsshim.DeactivateLayer(d.info, rID); err != nil {
   298  					logrus.Warnf("Failed to Deactivate %s: %s", rID, err)
   299  				}
   300  			}
   301  		} else {
   302  			if err = hcsshim.UnprepareLayer(d.info, rID); err != nil {
   303  				d.Unlock()
   304  				return
   305  			}
   306  			undo = func() {
   307  				if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
   308  					logrus.Warnf("Failed to re-PrepareLayer %s: %s", rID, err)
   309  				}
   310  			}
   311  		}
   312  	}
   313  
   314  	d.Unlock()
   315  
   316  	arch, err := d.exportLayer(rID, layerChain)
   317  	if err != nil {
   318  		undo()
   319  		return
   320  	}
   321  	return ioutils.NewReadCloserWrapper(arch, func() error {
   322  		defer undo()
   323  		return arch.Close()
   324  	}), nil
   325  }
   326  
   327  // Changes produces a list of changes between the specified layer
   328  // and its parent layer. If parent is "", then all changes will be ADD changes.
   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  	d.Lock()
   340  	if d.info.Flavour == filterDriver {
   341  		if d.active[rID] == 0 {
   342  			if err = hcsshim.ActivateLayer(d.info, rID); err != nil {
   343  				d.Unlock()
   344  				return nil, err
   345  			}
   346  			defer func() {
   347  				if err := hcsshim.DeactivateLayer(d.info, rID); err != nil {
   348  					logrus.Warnf("Failed to Deactivate %s: %s", rID, err)
   349  				}
   350  			}()
   351  		} else {
   352  			if err = hcsshim.UnprepareLayer(d.info, rID); err != nil {
   353  				d.Unlock()
   354  				return nil, err
   355  			}
   356  			defer func() {
   357  				if err := hcsshim.PrepareLayer(d.info, rID, parentChain); err != nil {
   358  					logrus.Warnf("Failed to re-PrepareLayer %s: %s", rID, err)
   359  				}
   360  			}()
   361  		}
   362  	}
   363  	d.Unlock()
   364  
   365  	r, err := hcsshim.NewLayerReader(d.info, id, parentChain)
   366  	if err != nil {
   367  		return nil, err
   368  	}
   369  	defer r.Close()
   370  
   371  	var changes []archive.Change
   372  	for {
   373  		name, _, fileInfo, err := r.Next()
   374  		if err == io.EOF {
   375  			break
   376  		}
   377  		if err != nil {
   378  			return nil, err
   379  		}
   380  		name = filepath.ToSlash(name)
   381  		if fileInfo == nil {
   382  			changes = append(changes, archive.Change{name, archive.ChangeDelete})
   383  		} else {
   384  			// Currently there is no way to tell between an add and a modify.
   385  			changes = append(changes, archive.Change{name, archive.ChangeModify})
   386  		}
   387  	}
   388  	return changes, nil
   389  }
   390  
   391  // ApplyDiff extracts the changeset from the given diff into the
   392  // layer with the specified id and parent, returning the size of the
   393  // new layer in bytes.
   394  func (d *Driver) ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) {
   395  	rPId, err := d.resolveID(parent)
   396  	if err != nil {
   397  		return
   398  	}
   399  
   400  	if d.info.Flavour == diffDriver {
   401  		start := time.Now().UTC()
   402  		logrus.Debugf("WindowsGraphDriver ApplyDiff: Start untar layer")
   403  		destination := d.dir(id)
   404  		destination = filepath.Dir(destination)
   405  		if size, err = chrootarchive.ApplyUncompressedLayer(destination, diff, nil); err != nil {
   406  			return
   407  		}
   408  		logrus.Debugf("WindowsGraphDriver ApplyDiff: Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
   409  
   410  		return
   411  	}
   412  
   413  	parentChain, err := d.getLayerChain(rPId)
   414  	if err != nil {
   415  		return
   416  	}
   417  	parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
   418  	if err != nil {
   419  		return
   420  	}
   421  	layerChain := []string{parentPath}
   422  	layerChain = append(layerChain, parentChain...)
   423  
   424  	if size, err = d.importLayer(id, diff, layerChain); err != nil {
   425  		return
   426  	}
   427  
   428  	if err = d.setLayerChain(id, layerChain); err != nil {
   429  		return
   430  	}
   431  
   432  	return
   433  }
   434  
   435  // DiffSize calculates the changes between the specified layer
   436  // and its parent and returns the size in bytes of the changes
   437  // relative to its base filesystem directory.
   438  func (d *Driver) DiffSize(id, parent string) (size int64, err error) {
   439  	rPId, err := d.resolveID(parent)
   440  	if err != nil {
   441  		return
   442  	}
   443  
   444  	changes, err := d.Changes(id, rPId)
   445  	if err != nil {
   446  		return
   447  	}
   448  
   449  	layerFs, err := d.Get(id, "")
   450  	if err != nil {
   451  		return
   452  	}
   453  	defer d.Put(id)
   454  
   455  	return archive.ChangesSize(layerFs, changes), nil
   456  }
   457  
   458  // CustomImageInfo is the object returned by the driver describing the base
   459  // image.
   460  type CustomImageInfo struct {
   461  	ID          string
   462  	Name        string
   463  	Version     string
   464  	Path        string
   465  	Size        int64
   466  	CreatedTime time.Time
   467  }
   468  
   469  // GetCustomImageInfos returns the image infos for window specific
   470  // base images which should always be present.
   471  func (d *Driver) GetCustomImageInfos() ([]CustomImageInfo, error) {
   472  	strData, err := hcsshim.GetSharedBaseImages()
   473  	if err != nil {
   474  		return nil, fmt.Errorf("Failed to restore base images: %s", err)
   475  	}
   476  
   477  	type customImageInfoList struct {
   478  		Images []CustomImageInfo
   479  	}
   480  
   481  	var infoData customImageInfoList
   482  
   483  	if err = json.Unmarshal([]byte(strData), &infoData); err != nil {
   484  		err = fmt.Errorf("JSON unmarshal returned error=%s", err)
   485  		logrus.Error(err)
   486  		return nil, err
   487  	}
   488  
   489  	var images []CustomImageInfo
   490  
   491  	for _, imageData := range infoData.Images {
   492  		folderName := filepath.Base(imageData.Path)
   493  
   494  		// Use crypto hash of the foldername to generate a docker style id.
   495  		h := sha512.Sum384([]byte(folderName))
   496  		id := fmt.Sprintf("%x", h[:32])
   497  
   498  		if err := d.Create(id, "", ""); err != nil {
   499  			return nil, err
   500  		}
   501  		// Create the alternate ID file.
   502  		if err := d.setID(id, folderName); err != nil {
   503  			return nil, err
   504  		}
   505  
   506  		imageData.ID = id
   507  		images = append(images, imageData)
   508  	}
   509  
   510  	return images, nil
   511  }
   512  
   513  // GetMetadata returns custom driver information.
   514  func (d *Driver) GetMetadata(id string) (map[string]string, error) {
   515  	m := make(map[string]string)
   516  	m["dir"] = d.dir(id)
   517  	return m, nil
   518  }
   519  
   520  func writeTarFromLayer(r hcsshim.LayerReader, w io.Writer) error {
   521  	t := tar.NewWriter(w)
   522  	for {
   523  		name, size, fileInfo, err := r.Next()
   524  		if err == io.EOF {
   525  			break
   526  		}
   527  		if err != nil {
   528  			return err
   529  		}
   530  		if fileInfo == nil {
   531  			// Write a whiteout file.
   532  			hdr := &tar.Header{
   533  				Name: filepath.ToSlash(filepath.Join(filepath.Dir(name), archive.WhiteoutPrefix+filepath.Base(name))),
   534  			}
   535  			err := t.WriteHeader(hdr)
   536  			if err != nil {
   537  				return err
   538  			}
   539  		} else {
   540  			err = backuptar.WriteTarFileFromBackupStream(t, r, name, size, fileInfo)
   541  			if err != nil {
   542  				return err
   543  			}
   544  		}
   545  	}
   546  	return t.Close()
   547  }
   548  
   549  // exportLayer generates an archive from a layer based on the given ID.
   550  func (d *Driver) exportLayer(id string, parentLayerPaths []string) (archive.Archive, error) {
   551  	if hcsshim.IsTP4() {
   552  		// Export in TP4 format to maintain compatibility with existing images and
   553  		// because ExportLayer is somewhat broken on TP4 and can't work with the new
   554  		// scheme.
   555  		tempFolder, err := ioutil.TempDir("", "hcs")
   556  		if err != nil {
   557  			return nil, err
   558  		}
   559  		defer func() {
   560  			if err != nil {
   561  				os.RemoveAll(tempFolder)
   562  			}
   563  		}()
   564  
   565  		if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil {
   566  			return nil, err
   567  		}
   568  		archive, err := archive.Tar(tempFolder, archive.Uncompressed)
   569  		if err != nil {
   570  			return nil, err
   571  		}
   572  		return ioutils.NewReadCloserWrapper(archive, func() error {
   573  			err := archive.Close()
   574  			os.RemoveAll(tempFolder)
   575  			return err
   576  		}), nil
   577  	}
   578  
   579  	var r hcsshim.LayerReader
   580  	r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths)
   581  	if err != nil {
   582  		return nil, err
   583  	}
   584  
   585  	archive, w := io.Pipe()
   586  	go func() {
   587  		err := writeTarFromLayer(r, w)
   588  		cerr := r.Close()
   589  		if err == nil {
   590  			err = cerr
   591  		}
   592  		w.CloseWithError(err)
   593  	}()
   594  
   595  	return archive, nil
   596  }
   597  
   598  func writeLayerFromTar(r archive.Reader, w hcsshim.LayerWriter) (int64, error) {
   599  	t := tar.NewReader(r)
   600  	hdr, err := t.Next()
   601  	totalSize := int64(0)
   602  	buf := bufio.NewWriter(nil)
   603  	for err == nil {
   604  		base := path.Base(hdr.Name)
   605  		if strings.HasPrefix(base, archive.WhiteoutPrefix) {
   606  			name := path.Join(path.Dir(hdr.Name), base[len(archive.WhiteoutPrefix):])
   607  			err = w.Remove(filepath.FromSlash(name))
   608  			if err != nil {
   609  				return 0, err
   610  			}
   611  			hdr, err = t.Next()
   612  		} else {
   613  			var (
   614  				name     string
   615  				size     int64
   616  				fileInfo *winio.FileBasicInfo
   617  			)
   618  			name, size, fileInfo, err = backuptar.FileInfoFromHeader(hdr)
   619  			if err != nil {
   620  				return 0, err
   621  			}
   622  			err = w.Add(filepath.FromSlash(name), fileInfo)
   623  			if err != nil {
   624  				return 0, err
   625  			}
   626  			buf.Reset(w)
   627  			hdr, err = backuptar.WriteBackupStreamFromTarFile(buf, t, hdr)
   628  			ferr := buf.Flush()
   629  			if ferr != nil {
   630  				err = ferr
   631  			}
   632  			totalSize += size
   633  		}
   634  	}
   635  	if err != io.EOF {
   636  		return 0, err
   637  	}
   638  	return totalSize, nil
   639  }
   640  
   641  // importLayer adds a new layer to the tag and graph store based on the given data.
   642  func (d *Driver) importLayer(id string, layerData archive.Reader, parentLayerPaths []string) (size int64, err error) {
   643  	if hcsshim.IsTP4() {
   644  		// Import from TP4 format to maintain compatibility with existing images.
   645  		var tempFolder string
   646  		tempFolder, err = ioutil.TempDir("", "hcs")
   647  		if err != nil {
   648  			return
   649  		}
   650  		defer os.RemoveAll(tempFolder)
   651  
   652  		if size, err = chrootarchive.ApplyLayer(tempFolder, layerData); err != nil {
   653  			return
   654  		}
   655  		if err = hcsshim.ImportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil {
   656  			return
   657  		}
   658  		return
   659  	}
   660  
   661  	var w hcsshim.LayerWriter
   662  	w, err = hcsshim.NewLayerWriter(d.info, id, parentLayerPaths)
   663  	if err != nil {
   664  		return
   665  	}
   666  
   667  	size, err = writeLayerFromTar(layerData, w)
   668  	if err != nil {
   669  		w.Close()
   670  		return
   671  	}
   672  	err = w.Close()
   673  	if err != nil {
   674  		return
   675  	}
   676  	return
   677  }
   678  
   679  // resolveID computes the layerID information based on the given id.
   680  func (d *Driver) resolveID(id string) (string, error) {
   681  	content, err := ioutil.ReadFile(filepath.Join(d.dir(id), "layerID"))
   682  	if os.IsNotExist(err) {
   683  		return id, nil
   684  	} else if err != nil {
   685  		return "", err
   686  	}
   687  	return string(content), nil
   688  }
   689  
   690  // setID stores the layerId in disk.
   691  func (d *Driver) setID(id, altID string) error {
   692  	err := ioutil.WriteFile(filepath.Join(d.dir(id), "layerId"), []byte(altID), 0600)
   693  	if err != nil {
   694  		return err
   695  	}
   696  	return nil
   697  }
   698  
   699  // getLayerChain returns the layer chain information.
   700  func (d *Driver) getLayerChain(id string) ([]string, error) {
   701  	jPath := filepath.Join(d.dir(id), "layerchain.json")
   702  	content, err := ioutil.ReadFile(jPath)
   703  	if os.IsNotExist(err) {
   704  		return nil, nil
   705  	} else if err != nil {
   706  		return nil, fmt.Errorf("Unable to read layerchain file - %s", err)
   707  	}
   708  
   709  	var layerChain []string
   710  	err = json.Unmarshal(content, &layerChain)
   711  	if err != nil {
   712  		return nil, fmt.Errorf("Failed to unmarshall layerchain json - %s", err)
   713  	}
   714  
   715  	return layerChain, nil
   716  }
   717  
   718  // setLayerChain stores the layer chain information in disk.
   719  func (d *Driver) setLayerChain(id string, chain []string) error {
   720  	content, err := json.Marshal(&chain)
   721  	if err != nil {
   722  		return fmt.Errorf("Failed to marshall layerchain json - %s", err)
   723  	}
   724  
   725  	jPath := filepath.Join(d.dir(id), "layerchain.json")
   726  	err = ioutil.WriteFile(jPath, content, 0600)
   727  	if err != nil {
   728  		return fmt.Errorf("Unable to write layerchain file - %s", err)
   729  	}
   730  
   731  	return nil
   732  }
   733  
   734  type fileGetCloserWithBackupPrivileges struct {
   735  	path string
   736  }
   737  
   738  func (fg *fileGetCloserWithBackupPrivileges) Get(filename string) (io.ReadCloser, error) {
   739  	var f *os.File
   740  	// Open the file while holding the Windows backup privilege. This ensures that the
   741  	// file can be opened even if the caller does not actually have access to it according
   742  	// to the security descriptor.
   743  	err := winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
   744  		path := filepath.Join(fg.path, filename)
   745  		p, err := syscall.UTF16FromString(path)
   746  		if err != nil {
   747  			return err
   748  		}
   749  		h, err := syscall.CreateFile(&p[0], syscall.GENERIC_READ, syscall.FILE_SHARE_READ, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
   750  		if err != nil {
   751  			return &os.PathError{Op: "open", Path: path, Err: err}
   752  		}
   753  		f = os.NewFile(uintptr(h), path)
   754  		return nil
   755  	})
   756  	return f, err
   757  }
   758  
   759  func (fg *fileGetCloserWithBackupPrivileges) Close() error {
   760  	return nil
   761  }
   762  
   763  type fileGetDestroyCloser struct {
   764  	storage.FileGetter
   765  	path string
   766  }
   767  
   768  func (f *fileGetDestroyCloser) Close() error {
   769  	// TODO: activate layers and release here?
   770  	return os.RemoveAll(f.path)
   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  	if hcsshim.IsTP4() {
   782  		// The export format for TP4 is different from the contents of the layer, so
   783  		// fall back to exporting the layer and getting file contents from there.
   784  		layerChain, err := d.getLayerChain(id)
   785  		if err != nil {
   786  			return nil, err
   787  		}
   788  
   789  		var tempFolder string
   790  		tempFolder, err = ioutil.TempDir("", "hcs")
   791  		if err != nil {
   792  			return nil, err
   793  		}
   794  		defer func() {
   795  			if err != nil {
   796  				os.RemoveAll(tempFolder)
   797  			}
   798  		}()
   799  
   800  		if err = hcsshim.ExportLayer(d.info, id, tempFolder, layerChain); err != nil {
   801  			return nil, err
   802  		}
   803  
   804  		return &fileGetDestroyCloser{storage.NewPathFileGetter(tempFolder), tempFolder}, nil
   805  	}
   806  
   807  	return &fileGetCloserWithBackupPrivileges{d.dir(id)}, nil
   808  }