123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- package wclayer
- import (
- "errors"
- "os"
- "path/filepath"
- "syscall"
- "github.com/Microsoft/go-winio"
- "github.com/Microsoft/hcsshim/internal/hcserror"
- "github.com/Microsoft/hcsshim/internal/safefile"
- )
- type baseLayerWriter struct {
- root *os.File
- f *os.File
- bw *winio.BackupFileWriter
- err error
- hasUtilityVM bool
- dirInfo []dirInfo
- }
- type dirInfo struct {
- path string
- fileInfo winio.FileBasicInfo
- }
- // reapplyDirectoryTimes reapplies directory modification, creation, etc. times
- // after processing of the directory tree has completed. The times are expected
- // to be ordered such that parent directories come before child directories.
- func reapplyDirectoryTimes(root *os.File, dis []dirInfo) error {
- for i := range dis {
- di := &dis[len(dis)-i-1] // reverse order: process child directories first
- f, err := safefile.OpenRelative(di.path, root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, safefile.FILE_OPEN, safefile.FILE_DIRECTORY_FILE)
- if err != nil {
- return err
- }
- err = winio.SetFileBasicInfo(f, &di.fileInfo)
- f.Close()
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (w *baseLayerWriter) closeCurrentFile() error {
- if w.f != nil {
- err := w.bw.Close()
- err2 := w.f.Close()
- w.f = nil
- w.bw = nil
- if err != nil {
- return err
- }
- if err2 != nil {
- return err2
- }
- }
- return nil
- }
- func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err error) {
- defer func() {
- if err != nil {
- w.err = err
- }
- }()
- err = w.closeCurrentFile()
- if err != nil {
- return err
- }
- if filepath.ToSlash(name) == `UtilityVM/Files` {
- w.hasUtilityVM = true
- }
- var f *os.File
- defer func() {
- if f != nil {
- f.Close()
- }
- }()
- extraFlags := uint32(0)
- if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
- extraFlags |= safefile.FILE_DIRECTORY_FILE
- if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
- w.dirInfo = append(w.dirInfo, dirInfo{name, *fileInfo})
- }
- }
- mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY)
- f, err = safefile.OpenRelative(name, w.root, mode, syscall.FILE_SHARE_READ, safefile.FILE_CREATE, extraFlags)
- if err != nil {
- return hcserror.New(err, "Failed to safefile.OpenRelative", name)
- }
- err = winio.SetFileBasicInfo(f, fileInfo)
- if err != nil {
- return hcserror.New(err, "Failed to SetFileBasicInfo", name)
- }
- w.f = f
- w.bw = winio.NewBackupFileWriter(f, true)
- f = nil
- return nil
- }
- func (w *baseLayerWriter) AddLink(name string, target string) (err error) {
- defer func() {
- if err != nil {
- w.err = err
- }
- }()
- err = w.closeCurrentFile()
- if err != nil {
- return err
- }
- return safefile.LinkRelative(target, w.root, name, w.root)
- }
- func (w *baseLayerWriter) Remove(name string) error {
- return errors.New("base layer cannot have tombstones")
- }
- func (w *baseLayerWriter) Write(b []byte) (int, error) {
- n, err := w.bw.Write(b)
- if err != nil {
- w.err = err
- }
- return n, err
- }
- func (w *baseLayerWriter) Close() error {
- defer func() {
- w.root.Close()
- w.root = nil
- }()
- err := w.closeCurrentFile()
- if err != nil {
- return err
- }
- if w.err == nil {
- // Restore the file times of all the directories, since they may have
- // been modified by creating child directories.
- err = reapplyDirectoryTimes(w.root, w.dirInfo)
- if err != nil {
- return err
- }
- err = ProcessBaseLayer(w.root.Name())
- if err != nil {
- return err
- }
- if w.hasUtilityVM {
- err := safefile.EnsureNotReparsePointRelative("UtilityVM", w.root)
- if err != nil {
- return err
- }
- err = ProcessUtilityVMImage(filepath.Join(w.root.Name(), "UtilityVM"))
- if err != nil {
- return err
- }
- }
- }
- return w.err
- }
|