diff options
author | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
---|---|---|
committer | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
commit | 107c1cdb09c575aa2f61d97f48d8587eb6bada4c (patch) | |
tree | ca7d008643efc555c388baeaf1d986e0b6b3e28c /vendor/github.com/spf13/afero/unionFile.go | |
parent | 844b5a68d8af4791755b8f0ad293cc99f5959183 (diff) | |
download | terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.gz terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.zst terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.zip |
Upgrade to 0.12
Diffstat (limited to 'vendor/github.com/spf13/afero/unionFile.go')
-rw-r--r-- | vendor/github.com/spf13/afero/unionFile.go | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/vendor/github.com/spf13/afero/unionFile.go b/vendor/github.com/spf13/afero/unionFile.go new file mode 100644 index 0000000..abcf12d --- /dev/null +++ b/vendor/github.com/spf13/afero/unionFile.go | |||
@@ -0,0 +1,316 @@ | |||
1 | package afero | ||
2 | |||
3 | import ( | ||
4 | "io" | ||
5 | "os" | ||
6 | "path/filepath" | ||
7 | "syscall" | ||
8 | ) | ||
9 | |||
10 | // The UnionFile implements the afero.File interface and will be returned | ||
11 | // when reading a directory present at least in the overlay or opening a file | ||
12 | // for writing. | ||
13 | // | ||
14 | // The calls to | ||
15 | // Readdir() and Readdirnames() merge the file os.FileInfo / names from the | ||
16 | // base and the overlay - for files present in both layers, only those | ||
17 | // from the overlay will be used. | ||
18 | // | ||
19 | // When opening files for writing (Create() / OpenFile() with the right flags) | ||
20 | // the operations will be done in both layers, starting with the overlay. A | ||
21 | // successful read in the overlay will move the cursor position in the base layer | ||
22 | // by the number of bytes read. | ||
23 | type UnionFile struct { | ||
24 | Base File | ||
25 | Layer File | ||
26 | Merger DirsMerger | ||
27 | off int | ||
28 | files []os.FileInfo | ||
29 | } | ||
30 | |||
31 | func (f *UnionFile) Close() error { | ||
32 | // first close base, so we have a newer timestamp in the overlay. If we'd close | ||
33 | // the overlay first, we'd get a cacheStale the next time we access this file | ||
34 | // -> cache would be useless ;-) | ||
35 | if f.Base != nil { | ||
36 | f.Base.Close() | ||
37 | } | ||
38 | if f.Layer != nil { | ||
39 | return f.Layer.Close() | ||
40 | } | ||
41 | return BADFD | ||
42 | } | ||
43 | |||
44 | func (f *UnionFile) Read(s []byte) (int, error) { | ||
45 | if f.Layer != nil { | ||
46 | n, err := f.Layer.Read(s) | ||
47 | if (err == nil || err == io.EOF) && f.Base != nil { | ||
48 | // advance the file position also in the base file, the next | ||
49 | // call may be a write at this position (or a seek with SEEK_CUR) | ||
50 | if _, seekErr := f.Base.Seek(int64(n), os.SEEK_CUR); seekErr != nil { | ||
51 | // only overwrite err in case the seek fails: we need to | ||
52 | // report an eventual io.EOF to the caller | ||
53 | err = seekErr | ||
54 | } | ||
55 | } | ||
56 | return n, err | ||
57 | } | ||
58 | if f.Base != nil { | ||
59 | return f.Base.Read(s) | ||
60 | } | ||
61 | return 0, BADFD | ||
62 | } | ||
63 | |||
64 | func (f *UnionFile) ReadAt(s []byte, o int64) (int, error) { | ||
65 | if f.Layer != nil { | ||
66 | n, err := f.Layer.ReadAt(s, o) | ||
67 | if (err == nil || err == io.EOF) && f.Base != nil { | ||
68 | _, err = f.Base.Seek(o+int64(n), os.SEEK_SET) | ||
69 | } | ||
70 | return n, err | ||
71 | } | ||
72 | if f.Base != nil { | ||
73 | return f.Base.ReadAt(s, o) | ||
74 | } | ||
75 | return 0, BADFD | ||
76 | } | ||
77 | |||
78 | func (f *UnionFile) Seek(o int64, w int) (pos int64, err error) { | ||
79 | if f.Layer != nil { | ||
80 | pos, err = f.Layer.Seek(o, w) | ||
81 | if (err == nil || err == io.EOF) && f.Base != nil { | ||
82 | _, err = f.Base.Seek(o, w) | ||
83 | } | ||
84 | return pos, err | ||
85 | } | ||
86 | if f.Base != nil { | ||
87 | return f.Base.Seek(o, w) | ||
88 | } | ||
89 | return 0, BADFD | ||
90 | } | ||
91 | |||
92 | func (f *UnionFile) Write(s []byte) (n int, err error) { | ||
93 | if f.Layer != nil { | ||
94 | n, err = f.Layer.Write(s) | ||
95 | if err == nil && f.Base != nil { // hmm, do we have fixed size files where a write may hit the EOF mark? | ||
96 | _, err = f.Base.Write(s) | ||
97 | } | ||
98 | return n, err | ||
99 | } | ||
100 | if f.Base != nil { | ||
101 | return f.Base.Write(s) | ||
102 | } | ||
103 | return 0, BADFD | ||
104 | } | ||
105 | |||
106 | func (f *UnionFile) WriteAt(s []byte, o int64) (n int, err error) { | ||
107 | if f.Layer != nil { | ||
108 | n, err = f.Layer.WriteAt(s, o) | ||
109 | if err == nil && f.Base != nil { | ||
110 | _, err = f.Base.WriteAt(s, o) | ||
111 | } | ||
112 | return n, err | ||
113 | } | ||
114 | if f.Base != nil { | ||
115 | return f.Base.WriteAt(s, o) | ||
116 | } | ||
117 | return 0, BADFD | ||
118 | } | ||
119 | |||
120 | func (f *UnionFile) Name() string { | ||
121 | if f.Layer != nil { | ||
122 | return f.Layer.Name() | ||
123 | } | ||
124 | return f.Base.Name() | ||
125 | } | ||
126 | |||
127 | // DirsMerger is how UnionFile weaves two directories together. | ||
128 | // It takes the FileInfo slices from the layer and the base and returns a | ||
129 | // single view. | ||
130 | type DirsMerger func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error) | ||
131 | |||
132 | var defaultUnionMergeDirsFn = func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error) { | ||
133 | var files = make(map[string]os.FileInfo) | ||
134 | |||
135 | for _, fi := range lofi { | ||
136 | files[fi.Name()] = fi | ||
137 | } | ||
138 | |||
139 | for _, fi := range bofi { | ||
140 | if _, exists := files[fi.Name()]; !exists { | ||
141 | files[fi.Name()] = fi | ||
142 | } | ||
143 | } | ||
144 | |||
145 | rfi := make([]os.FileInfo, len(files)) | ||
146 | |||
147 | i := 0 | ||
148 | for _, fi := range files { | ||
149 | rfi[i] = fi | ||
150 | i++ | ||
151 | } | ||
152 | |||
153 | return rfi, nil | ||
154 | |||
155 | } | ||
156 | |||
157 | // Readdir will weave the two directories together and | ||
158 | // return a single view of the overlayed directories | ||
159 | // At the end of the directory view, the error is io.EOF. | ||
160 | func (f *UnionFile) Readdir(c int) (ofi []os.FileInfo, err error) { | ||
161 | var merge DirsMerger = f.Merger | ||
162 | if merge == nil { | ||
163 | merge = defaultUnionMergeDirsFn | ||
164 | } | ||
165 | |||
166 | if f.off == 0 { | ||
167 | var lfi []os.FileInfo | ||
168 | if f.Layer != nil { | ||
169 | lfi, err = f.Layer.Readdir(-1) | ||
170 | if err != nil { | ||
171 | return nil, err | ||
172 | } | ||
173 | } | ||
174 | |||
175 | var bfi []os.FileInfo | ||
176 | if f.Base != nil { | ||
177 | bfi, err = f.Base.Readdir(-1) | ||
178 | if err != nil { | ||
179 | return nil, err | ||
180 | } | ||
181 | |||
182 | } | ||
183 | merged, err := merge(lfi, bfi) | ||
184 | if err != nil { | ||
185 | return nil, err | ||
186 | } | ||
187 | f.files = append(f.files, merged...) | ||
188 | } | ||
189 | |||
190 | if f.off >= len(f.files) { | ||
191 | return nil, io.EOF | ||
192 | } | ||
193 | |||
194 | if c == -1 { | ||
195 | return f.files[f.off:], nil | ||
196 | } | ||
197 | |||
198 | if c > len(f.files) { | ||
199 | c = len(f.files) | ||
200 | } | ||
201 | |||
202 | defer func() { f.off += c }() | ||
203 | return f.files[f.off:c], nil | ||
204 | } | ||
205 | |||
206 | func (f *UnionFile) Readdirnames(c int) ([]string, error) { | ||
207 | rfi, err := f.Readdir(c) | ||
208 | if err != nil { | ||
209 | return nil, err | ||
210 | } | ||
211 | var names []string | ||
212 | for _, fi := range rfi { | ||
213 | names = append(names, fi.Name()) | ||
214 | } | ||
215 | return names, nil | ||
216 | } | ||
217 | |||
218 | func (f *UnionFile) Stat() (os.FileInfo, error) { | ||
219 | if f.Layer != nil { | ||
220 | return f.Layer.Stat() | ||
221 | } | ||
222 | if f.Base != nil { | ||
223 | return f.Base.Stat() | ||
224 | } | ||
225 | return nil, BADFD | ||
226 | } | ||
227 | |||
228 | func (f *UnionFile) Sync() (err error) { | ||
229 | if f.Layer != nil { | ||
230 | err = f.Layer.Sync() | ||
231 | if err == nil && f.Base != nil { | ||
232 | err = f.Base.Sync() | ||
233 | } | ||
234 | return err | ||
235 | } | ||
236 | if f.Base != nil { | ||
237 | return f.Base.Sync() | ||
238 | } | ||
239 | return BADFD | ||
240 | } | ||
241 | |||
242 | func (f *UnionFile) Truncate(s int64) (err error) { | ||
243 | if f.Layer != nil { | ||
244 | err = f.Layer.Truncate(s) | ||
245 | if err == nil && f.Base != nil { | ||
246 | err = f.Base.Truncate(s) | ||
247 | } | ||
248 | return err | ||
249 | } | ||
250 | if f.Base != nil { | ||
251 | return f.Base.Truncate(s) | ||
252 | } | ||
253 | return BADFD | ||
254 | } | ||
255 | |||
256 | func (f *UnionFile) WriteString(s string) (n int, err error) { | ||
257 | if f.Layer != nil { | ||
258 | n, err = f.Layer.WriteString(s) | ||
259 | if err == nil && f.Base != nil { | ||
260 | _, err = f.Base.WriteString(s) | ||
261 | } | ||
262 | return n, err | ||
263 | } | ||
264 | if f.Base != nil { | ||
265 | return f.Base.WriteString(s) | ||
266 | } | ||
267 | return 0, BADFD | ||
268 | } | ||
269 | |||
270 | func copyToLayer(base Fs, layer Fs, name string) error { | ||
271 | bfh, err := base.Open(name) | ||
272 | if err != nil { | ||
273 | return err | ||
274 | } | ||
275 | defer bfh.Close() | ||
276 | |||
277 | // First make sure the directory exists | ||
278 | exists, err := Exists(layer, filepath.Dir(name)) | ||
279 | if err != nil { | ||
280 | return err | ||
281 | } | ||
282 | if !exists { | ||
283 | err = layer.MkdirAll(filepath.Dir(name), 0777) // FIXME? | ||
284 | if err != nil { | ||
285 | return err | ||
286 | } | ||
287 | } | ||
288 | |||
289 | // Create the file on the overlay | ||
290 | lfh, err := layer.Create(name) | ||
291 | if err != nil { | ||
292 | return err | ||
293 | } | ||
294 | n, err := io.Copy(lfh, bfh) | ||
295 | if err != nil { | ||
296 | // If anything fails, clean up the file | ||
297 | layer.Remove(name) | ||
298 | lfh.Close() | ||
299 | return err | ||
300 | } | ||
301 | |||
302 | bfi, err := bfh.Stat() | ||
303 | if err != nil || bfi.Size() != n { | ||
304 | layer.Remove(name) | ||
305 | lfh.Close() | ||
306 | return syscall.EIO | ||
307 | } | ||
308 | |||
309 | err = lfh.Close() | ||
310 | if err != nil { | ||
311 | layer.Remove(name) | ||
312 | lfh.Close() | ||
313 | return err | ||
314 | } | ||
315 | return layer.Chtimes(name, bfi.ModTime(), bfi.ModTime()) | ||
316 | } | ||