github.com/rawahars/moby@v24.0.4+incompatible/daemon/graphdriver/windows/windows.go (about)

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