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/copyOnWriteFs.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/copyOnWriteFs.go')
-rw-r--r-- | vendor/github.com/spf13/afero/copyOnWriteFs.go | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/vendor/github.com/spf13/afero/copyOnWriteFs.go b/vendor/github.com/spf13/afero/copyOnWriteFs.go new file mode 100644 index 0000000..e8108a8 --- /dev/null +++ b/vendor/github.com/spf13/afero/copyOnWriteFs.go | |||
@@ -0,0 +1,293 @@ | |||
1 | package afero | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "os" | ||
6 | "path/filepath" | ||
7 | "syscall" | ||
8 | "time" | ||
9 | ) | ||
10 | |||
11 | var _ Lstater = (*CopyOnWriteFs)(nil) | ||
12 | |||
13 | // The CopyOnWriteFs is a union filesystem: a read only base file system with | ||
14 | // a possibly writeable layer on top. Changes to the file system will only | ||
15 | // be made in the overlay: Changing an existing file in the base layer which | ||
16 | // is not present in the overlay will copy the file to the overlay ("changing" | ||
17 | // includes also calls to e.g. Chtimes() and Chmod()). | ||
18 | // | ||
19 | // Reading directories is currently only supported via Open(), not OpenFile(). | ||
20 | type CopyOnWriteFs struct { | ||
21 | base Fs | ||
22 | layer Fs | ||
23 | } | ||
24 | |||
25 | func NewCopyOnWriteFs(base Fs, layer Fs) Fs { | ||
26 | return &CopyOnWriteFs{base: base, layer: layer} | ||
27 | } | ||
28 | |||
29 | // Returns true if the file is not in the overlay | ||
30 | func (u *CopyOnWriteFs) isBaseFile(name string) (bool, error) { | ||
31 | if _, err := u.layer.Stat(name); err == nil { | ||
32 | return false, nil | ||
33 | } | ||
34 | _, err := u.base.Stat(name) | ||
35 | if err != nil { | ||
36 | if oerr, ok := err.(*os.PathError); ok { | ||
37 | if oerr.Err == os.ErrNotExist || oerr.Err == syscall.ENOENT || oerr.Err == syscall.ENOTDIR { | ||
38 | return false, nil | ||
39 | } | ||
40 | } | ||
41 | if err == syscall.ENOENT { | ||
42 | return false, nil | ||
43 | } | ||
44 | } | ||
45 | return true, err | ||
46 | } | ||
47 | |||
48 | func (u *CopyOnWriteFs) copyToLayer(name string) error { | ||
49 | return copyToLayer(u.base, u.layer, name) | ||
50 | } | ||
51 | |||
52 | func (u *CopyOnWriteFs) Chtimes(name string, atime, mtime time.Time) error { | ||
53 | b, err := u.isBaseFile(name) | ||
54 | if err != nil { | ||
55 | return err | ||
56 | } | ||
57 | if b { | ||
58 | if err := u.copyToLayer(name); err != nil { | ||
59 | return err | ||
60 | } | ||
61 | } | ||
62 | return u.layer.Chtimes(name, atime, mtime) | ||
63 | } | ||
64 | |||
65 | func (u *CopyOnWriteFs) Chmod(name string, mode os.FileMode) error { | ||
66 | b, err := u.isBaseFile(name) | ||
67 | if err != nil { | ||
68 | return err | ||
69 | } | ||
70 | if b { | ||
71 | if err := u.copyToLayer(name); err != nil { | ||
72 | return err | ||
73 | } | ||
74 | } | ||
75 | return u.layer.Chmod(name, mode) | ||
76 | } | ||
77 | |||
78 | func (u *CopyOnWriteFs) Stat(name string) (os.FileInfo, error) { | ||
79 | fi, err := u.layer.Stat(name) | ||
80 | if err != nil { | ||
81 | isNotExist := u.isNotExist(err) | ||
82 | if isNotExist { | ||
83 | return u.base.Stat(name) | ||
84 | } | ||
85 | return nil, err | ||
86 | } | ||
87 | return fi, nil | ||
88 | } | ||
89 | |||
90 | func (u *CopyOnWriteFs) LstatIfPossible(name string) (os.FileInfo, bool, error) { | ||
91 | llayer, ok1 := u.layer.(Lstater) | ||
92 | lbase, ok2 := u.base.(Lstater) | ||
93 | |||
94 | if ok1 { | ||
95 | fi, b, err := llayer.LstatIfPossible(name) | ||
96 | if err == nil { | ||
97 | return fi, b, nil | ||
98 | } | ||
99 | |||
100 | if !u.isNotExist(err) { | ||
101 | return nil, b, err | ||
102 | } | ||
103 | } | ||
104 | |||
105 | if ok2 { | ||
106 | fi, b, err := lbase.LstatIfPossible(name) | ||
107 | if err == nil { | ||
108 | return fi, b, nil | ||
109 | } | ||
110 | if !u.isNotExist(err) { | ||
111 | return nil, b, err | ||
112 | } | ||
113 | } | ||
114 | |||
115 | fi, err := u.Stat(name) | ||
116 | |||
117 | return fi, false, err | ||
118 | } | ||
119 | |||
120 | func (u *CopyOnWriteFs) isNotExist(err error) bool { | ||
121 | if e, ok := err.(*os.PathError); ok { | ||
122 | err = e.Err | ||
123 | } | ||
124 | if err == os.ErrNotExist || err == syscall.ENOENT || err == syscall.ENOTDIR { | ||
125 | return true | ||
126 | } | ||
127 | return false | ||
128 | } | ||
129 | |||
130 | // Renaming files present only in the base layer is not permitted | ||
131 | func (u *CopyOnWriteFs) Rename(oldname, newname string) error { | ||
132 | b, err := u.isBaseFile(oldname) | ||
133 | if err != nil { | ||
134 | return err | ||
135 | } | ||
136 | if b { | ||
137 | return syscall.EPERM | ||
138 | } | ||
139 | return u.layer.Rename(oldname, newname) | ||
140 | } | ||
141 | |||
142 | // Removing files present only in the base layer is not permitted. If | ||
143 | // a file is present in the base layer and the overlay, only the overlay | ||
144 | // will be removed. | ||
145 | func (u *CopyOnWriteFs) Remove(name string) error { | ||
146 | err := u.layer.Remove(name) | ||
147 | switch err { | ||
148 | case syscall.ENOENT: | ||
149 | _, err = u.base.Stat(name) | ||
150 | if err == nil { | ||
151 | return syscall.EPERM | ||
152 | } | ||
153 | return syscall.ENOENT | ||
154 | default: | ||
155 | return err | ||
156 | } | ||
157 | } | ||
158 | |||
159 | func (u *CopyOnWriteFs) RemoveAll(name string) error { | ||
160 | err := u.layer.RemoveAll(name) | ||
161 | switch err { | ||
162 | case syscall.ENOENT: | ||
163 | _, err = u.base.Stat(name) | ||
164 | if err == nil { | ||
165 | return syscall.EPERM | ||
166 | } | ||
167 | return syscall.ENOENT | ||
168 | default: | ||
169 | return err | ||
170 | } | ||
171 | } | ||
172 | |||
173 | func (u *CopyOnWriteFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { | ||
174 | b, err := u.isBaseFile(name) | ||
175 | if err != nil { | ||
176 | return nil, err | ||
177 | } | ||
178 | |||
179 | if flag&(os.O_WRONLY|os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 { | ||
180 | if b { | ||
181 | if err = u.copyToLayer(name); err != nil { | ||
182 | return nil, err | ||
183 | } | ||
184 | return u.layer.OpenFile(name, flag, perm) | ||
185 | } | ||
186 | |||
187 | dir := filepath.Dir(name) | ||
188 | isaDir, err := IsDir(u.base, dir) | ||
189 | if err != nil && !os.IsNotExist(err) { | ||
190 | return nil, err | ||
191 | } | ||
192 | if isaDir { | ||
193 | if err = u.layer.MkdirAll(dir, 0777); err != nil { | ||
194 | return nil, err | ||
195 | } | ||
196 | return u.layer.OpenFile(name, flag, perm) | ||
197 | } | ||
198 | |||
199 | isaDir, err = IsDir(u.layer, dir) | ||
200 | if err != nil { | ||
201 | return nil, err | ||
202 | } | ||
203 | if isaDir { | ||
204 | return u.layer.OpenFile(name, flag, perm) | ||
205 | } | ||
206 | |||
207 | return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOTDIR} // ...or os.ErrNotExist? | ||
208 | } | ||
209 | if b { | ||
210 | return u.base.OpenFile(name, flag, perm) | ||
211 | } | ||
212 | return u.layer.OpenFile(name, flag, perm) | ||
213 | } | ||
214 | |||
215 | // This function handles the 9 different possibilities caused | ||
216 | // by the union which are the intersection of the following... | ||
217 | // layer: doesn't exist, exists as a file, and exists as a directory | ||
218 | // base: doesn't exist, exists as a file, and exists as a directory | ||
219 | func (u *CopyOnWriteFs) Open(name string) (File, error) { | ||
220 | // Since the overlay overrides the base we check that first | ||
221 | b, err := u.isBaseFile(name) | ||
222 | if err != nil { | ||
223 | return nil, err | ||
224 | } | ||
225 | |||
226 | // If overlay doesn't exist, return the base (base state irrelevant) | ||
227 | if b { | ||
228 | return u.base.Open(name) | ||
229 | } | ||
230 | |||
231 | // If overlay is a file, return it (base state irrelevant) | ||
232 | dir, err := IsDir(u.layer, name) | ||
233 | if err != nil { | ||
234 | return nil, err | ||
235 | } | ||
236 | if !dir { | ||
237 | return u.layer.Open(name) | ||
238 | } | ||
239 | |||
240 | // Overlay is a directory, base state now matters. | ||
241 | // Base state has 3 states to check but 2 outcomes: | ||
242 | // A. It's a file or non-readable in the base (return just the overlay) | ||
243 | // B. It's an accessible directory in the base (return a UnionFile) | ||
244 | |||
245 | // If base is file or nonreadable, return overlay | ||
246 | dir, err = IsDir(u.base, name) | ||
247 | if !dir || err != nil { | ||
248 | return u.layer.Open(name) | ||
249 | } | ||
250 | |||
251 | // Both base & layer are directories | ||
252 | // Return union file (if opens are without error) | ||
253 | bfile, bErr := u.base.Open(name) | ||
254 | lfile, lErr := u.layer.Open(name) | ||
255 | |||
256 | // If either have errors at this point something is very wrong. Return nil and the errors | ||
257 | if bErr != nil || lErr != nil { | ||
258 | return nil, fmt.Errorf("BaseErr: %v\nOverlayErr: %v", bErr, lErr) | ||
259 | } | ||
260 | |||
261 | return &UnionFile{Base: bfile, Layer: lfile}, nil | ||
262 | } | ||
263 | |||
264 | func (u *CopyOnWriteFs) Mkdir(name string, perm os.FileMode) error { | ||
265 | dir, err := IsDir(u.base, name) | ||
266 | if err != nil { | ||
267 | return u.layer.MkdirAll(name, perm) | ||
268 | } | ||
269 | if dir { | ||
270 | return ErrFileExists | ||
271 | } | ||
272 | return u.layer.MkdirAll(name, perm) | ||
273 | } | ||
274 | |||
275 | func (u *CopyOnWriteFs) Name() string { | ||
276 | return "CopyOnWriteFs" | ||
277 | } | ||
278 | |||
279 | func (u *CopyOnWriteFs) MkdirAll(name string, perm os.FileMode) error { | ||
280 | dir, err := IsDir(u.base, name) | ||
281 | if err != nil { | ||
282 | return u.layer.MkdirAll(name, perm) | ||
283 | } | ||
284 | if dir { | ||
285 | // This is in line with how os.MkdirAll behaves. | ||
286 | return nil | ||
287 | } | ||
288 | return u.layer.MkdirAll(name, perm) | ||
289 | } | ||
290 | |||
291 | func (u *CopyOnWriteFs) Create(name string) (File, error) { | ||
292 | return u.OpenFile(name, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0666) | ||
293 | } | ||