github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/daemon/graphdriver/windows/windows.go (about)

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