baselayerwriter.go 3.9 KB

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