baselayer.go 3.7 KB

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