baselayer.go 3.7 KB

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