...

Source file src/github.com/Microsoft/hcsshim/internal/wclayer/baselayerwriter.go

Documentation: github.com/Microsoft/hcsshim/internal/wclayer

     1  //go:build windows
     2  
     3  package wclayer
     4  
     5  import (
     6  	"context"
     7  	"errors"
     8  	"os"
     9  	"path/filepath"
    10  	"syscall"
    11  
    12  	"github.com/Microsoft/go-winio"
    13  	"github.com/Microsoft/hcsshim/internal/hcserror"
    14  	"github.com/Microsoft/hcsshim/internal/oc"
    15  	"github.com/Microsoft/hcsshim/internal/safefile"
    16  	"github.com/Microsoft/hcsshim/internal/winapi"
    17  	"go.opencensus.io/trace"
    18  )
    19  
    20  type baseLayerWriter struct {
    21  	ctx context.Context
    22  	s   *trace.Span
    23  
    24  	root         *os.File
    25  	f            *os.File
    26  	bw           *winio.BackupFileWriter
    27  	err          error
    28  	hasUtilityVM bool
    29  	dirInfo      []dirInfo
    30  }
    31  
    32  type dirInfo struct {
    33  	path     string
    34  	fileInfo winio.FileBasicInfo
    35  }
    36  
    37  // reapplyDirectoryTimes reapplies directory modification, creation, etc. times
    38  // after processing of the directory tree has completed. The times are expected
    39  // to be ordered such that parent directories come before child directories.
    40  func reapplyDirectoryTimes(root *os.File, dis []dirInfo) error {
    41  	for i := range dis {
    42  		di := &dis[len(dis)-i-1] // reverse order: process child directories first
    43  		f, err := safefile.OpenRelative(di.path, root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, winapi.FILE_OPEN, winapi.FILE_DIRECTORY_FILE|syscall.FILE_FLAG_OPEN_REPARSE_POINT)
    44  		if err != nil {
    45  			return err
    46  		}
    47  
    48  		err = winio.SetFileBasicInfo(f, &di.fileInfo)
    49  		f.Close()
    50  		if err != nil {
    51  			return err
    52  		}
    53  	}
    54  	return nil
    55  }
    56  
    57  func (w *baseLayerWriter) closeCurrentFile() error {
    58  	if w.f != nil {
    59  		err := w.bw.Close()
    60  		err2 := w.f.Close()
    61  		w.f = nil
    62  		w.bw = nil
    63  		if err != nil {
    64  			return err
    65  		}
    66  		if err2 != nil {
    67  			return err2
    68  		}
    69  	}
    70  	return nil
    71  }
    72  
    73  func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err error) {
    74  	defer func() {
    75  		if err != nil {
    76  			w.err = err
    77  		}
    78  	}()
    79  
    80  	err = w.closeCurrentFile()
    81  	if err != nil {
    82  		return err
    83  	}
    84  
    85  	if filepath.ToSlash(name) == `UtilityVM/Files` {
    86  		w.hasUtilityVM = true
    87  	}
    88  
    89  	var f *os.File
    90  	defer func() {
    91  		if f != nil {
    92  			f.Close()
    93  		}
    94  	}()
    95  
    96  	extraFlags := uint32(0)
    97  	if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
    98  		extraFlags |= winapi.FILE_DIRECTORY_FILE
    99  		w.dirInfo = append(w.dirInfo, dirInfo{name, *fileInfo})
   100  	}
   101  
   102  	mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY)
   103  	f, err = safefile.OpenRelative(name, w.root, mode, syscall.FILE_SHARE_READ, winapi.FILE_CREATE, extraFlags)
   104  	if err != nil {
   105  		return hcserror.New(err, "Failed to safefile.OpenRelative", name)
   106  	}
   107  
   108  	err = winio.SetFileBasicInfo(f, fileInfo)
   109  	if err != nil {
   110  		return hcserror.New(err, "Failed to SetFileBasicInfo", name)
   111  	}
   112  
   113  	w.f = f
   114  	w.bw = winio.NewBackupFileWriter(f, true)
   115  	f = nil
   116  	return nil
   117  }
   118  
   119  func (w *baseLayerWriter) AddLink(name string, target string) (err error) {
   120  	defer func() {
   121  		if err != nil {
   122  			w.err = err
   123  		}
   124  	}()
   125  
   126  	err = w.closeCurrentFile()
   127  	if err != nil {
   128  		return err
   129  	}
   130  
   131  	return safefile.LinkRelative(target, w.root, name, w.root)
   132  }
   133  
   134  func (w *baseLayerWriter) Remove(name string) error {
   135  	return errors.New("base layer cannot have tombstones")
   136  }
   137  
   138  func (w *baseLayerWriter) Write(b []byte) (int, error) {
   139  	n, err := w.bw.Write(b)
   140  	if err != nil {
   141  		w.err = err
   142  	}
   143  	return n, err
   144  }
   145  
   146  func (w *baseLayerWriter) Close() (err error) {
   147  	defer w.s.End()
   148  	defer func() { oc.SetSpanStatus(w.s, err) }()
   149  	defer func() {
   150  		w.root.Close()
   151  		w.root = nil
   152  	}()
   153  
   154  	err = w.closeCurrentFile()
   155  	if err != nil {
   156  		return err
   157  	}
   158  	if w.err == nil {
   159  		// Restore the file times of all the directories, since they may have
   160  		// been modified by creating child directories.
   161  		err = reapplyDirectoryTimes(w.root, w.dirInfo)
   162  		if err != nil {
   163  			return err
   164  		}
   165  
   166  		err = ProcessBaseLayer(w.ctx, w.root.Name())
   167  		if err != nil {
   168  			return err
   169  		}
   170  
   171  		if w.hasUtilityVM {
   172  			err := safefile.EnsureNotReparsePointRelative("UtilityVM", w.root)
   173  			if err != nil {
   174  				return err
   175  			}
   176  			err = ProcessUtilityVMImage(w.ctx, filepath.Join(w.root.Name(), "UtilityVM"))
   177  			if err != nil {
   178  				return err
   179  			}
   180  		}
   181  	}
   182  	return w.err
   183  }
   184  

View as plain text