...
1
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
38
39
40 func reapplyDirectoryTimes(root *os.File, dis []dirInfo) error {
41 for i := range dis {
42 di := &dis[len(dis)-i-1]
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
160
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