1 package wclayer
2
3 import (
4 "errors"
5 "io"
6 "os"
7 "path/filepath"
8 "strings"
9 "syscall"
10
11 "github.com/Microsoft/go-winio"
12 "github.com/Microsoft/hcsshim/internal/longpath"
13 "github.com/Microsoft/hcsshim/internal/oc"
14 "go.opencensus.io/trace"
15 )
16
17 type baseLayerReader struct {
18 s *trace.Span
19 root string
20 result chan *fileEntry
21 proceed chan bool
22 currentFile *os.File
23 backupReader *winio.BackupFileReader
24 }
25
26 func newBaseLayerReader(root string, s *trace.Span) (r *baseLayerReader) {
27 r = &baseLayerReader{
28 s: s,
29 root: root,
30 result: make(chan *fileEntry),
31 proceed: make(chan bool),
32 }
33 go r.walk()
34 return r
35 }
36
37 func (r *baseLayerReader) walkUntilCancelled() error {
38 root, err := longpath.LongAbs(r.root)
39 if err != nil {
40 return err
41 }
42
43 r.root = root
44
45 err = filepath.Walk(filepath.Join(r.root, filesPath), func(path string, info os.FileInfo, err error) error {
46 if err != nil {
47 return err
48 }
49
50
51
52
53
54
55 if strings.EqualFold(path, filepath.Join(r.root, `Files\$Recycle.Bin`)) && info.IsDir() {
56 return filepath.SkipDir
57 }
58
59 r.result <- &fileEntry{path, info, nil}
60 if !<-r.proceed {
61 return errorIterationCanceled
62 }
63
64 return nil
65 })
66
67 if err == errorIterationCanceled {
68 return nil
69 }
70
71 if err != nil {
72 return err
73 }
74
75 utilityVMAbsPath := filepath.Join(r.root, utilityVMPath)
76 utilityVMFilesAbsPath := filepath.Join(r.root, utilityVMFilesPath)
77
78
79 if _, err = os.Lstat(utilityVMFilesAbsPath); err != nil {
80 if os.IsNotExist(err) {
81 return io.EOF
82 }
83 return err
84 }
85
86 err = filepath.Walk(utilityVMAbsPath, func(path string, info os.FileInfo, err error) error {
87 if err != nil {
88 return err
89 }
90
91 if path != utilityVMAbsPath && path != utilityVMFilesAbsPath && !hasPathPrefix(path, utilityVMFilesAbsPath) {
92 if info.IsDir() {
93 return filepath.SkipDir
94 }
95 return nil
96 }
97
98 r.result <- &fileEntry{path, info, nil}
99 if !<-r.proceed {
100 return errorIterationCanceled
101 }
102
103 return nil
104 })
105
106 if err == errorIterationCanceled {
107 return nil
108 }
109
110 if err != nil {
111 return err
112 }
113
114 return io.EOF
115 }
116
117 func (r *baseLayerReader) walk() {
118 defer close(r.result)
119 if !<-r.proceed {
120 return
121 }
122
123 err := r.walkUntilCancelled()
124 if err != nil {
125 for {
126 r.result <- &fileEntry{err: err}
127 if !<-r.proceed {
128 return
129 }
130 }
131 }
132 }
133
134 func (r *baseLayerReader) reset() {
135 if r.backupReader != nil {
136 r.backupReader.Close()
137 r.backupReader = nil
138 }
139 if r.currentFile != nil {
140 r.currentFile.Close()
141 r.currentFile = nil
142 }
143 }
144
145 func (r *baseLayerReader) Next() (path string, size int64, fileInfo *winio.FileBasicInfo, err error) {
146 r.reset()
147 r.proceed <- true
148 fe := <-r.result
149 if fe == nil {
150 err = errors.New("BaseLayerReader closed")
151 return
152 }
153 if fe.err != nil {
154 err = fe.err
155 return
156 }
157
158 path, err = filepath.Rel(r.root, fe.path)
159 if err != nil {
160 return
161 }
162
163 f, err := openFileOrDir(fe.path, syscall.GENERIC_READ, syscall.OPEN_EXISTING)
164 if err != nil {
165 return
166 }
167 defer func() {
168 if f != nil {
169 f.Close()
170 }
171 }()
172
173 fileInfo, err = winio.GetFileBasicInfo(f)
174 if err != nil {
175 return
176 }
177
178 size = fe.fi.Size()
179 r.backupReader = winio.NewBackupFileReader(f, true)
180
181 r.currentFile = f
182 f = nil
183 return
184 }
185
186 func (r *baseLayerReader) LinkInfo() (uint32, *winio.FileIDInfo, error) {
187 fileStandardInfo, err := winio.GetFileStandardInfo(r.currentFile)
188 if err != nil {
189 return 0, nil, err
190 }
191 fileIDInfo, err := winio.GetFileID(r.currentFile)
192 if err != nil {
193 return 0, nil, err
194 }
195 return fileStandardInfo.NumberOfLinks, fileIDInfo, nil
196 }
197
198 func (r *baseLayerReader) Read(b []byte) (int, error) {
199 if r.backupReader == nil {
200 return 0, io.EOF
201 }
202 return r.backupReader.Read(b)
203 }
204
205 func (r *baseLayerReader) Close() (err error) {
206 defer r.s.End()
207 defer func() {
208 oc.SetSpanStatus(r.s, err)
209 close(r.proceed)
210 }()
211 r.proceed <- false
212
213 <-r.result
214 r.reset()
215 return nil
216 }
217
View as plain text