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
14
15
16
17
18
19
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
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) Chown(name string, uid, gid int) error {
79 b, err := u.isBaseFile(name)
80 if err != nil {
81 return err
82 }
83 if b {
84 if err := u.copyToLayer(name); err != nil {
85 return err
86 }
87 }
88 return u.layer.Chown(name, uid, gid)
89 }
90
91 func (u *CopyOnWriteFs) Stat(name string) (os.FileInfo, error) {
92 fi, err := u.layer.Stat(name)
93 if err != nil {
94 isNotExist := u.isNotExist(err)
95 if isNotExist {
96 return u.base.Stat(name)
97 }
98 return nil, err
99 }
100 return fi, nil
101 }
102
103 func (u *CopyOnWriteFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
104 llayer, ok1 := u.layer.(Lstater)
105 lbase, ok2 := u.base.(Lstater)
106
107 if ok1 {
108 fi, b, err := llayer.LstatIfPossible(name)
109 if err == nil {
110 return fi, b, nil
111 }
112
113 if !u.isNotExist(err) {
114 return nil, b, err
115 }
116 }
117
118 if ok2 {
119 fi, b, err := lbase.LstatIfPossible(name)
120 if err == nil {
121 return fi, b, nil
122 }
123 if !u.isNotExist(err) {
124 return nil, b, err
125 }
126 }
127
128 fi, err := u.Stat(name)
129
130 return fi, false, err
131 }
132
133 func (u *CopyOnWriteFs) SymlinkIfPossible(oldname, newname string) error {
134 if slayer, ok := u.layer.(Linker); ok {
135 return slayer.SymlinkIfPossible(oldname, newname)
136 }
137
138 return &os.LinkError{Op: "symlink", Old: oldname, New: newname, Err: ErrNoSymlink}
139 }
140
141 func (u *CopyOnWriteFs) ReadlinkIfPossible(name string) (string, error) {
142 if rlayer, ok := u.layer.(LinkReader); ok {
143 return rlayer.ReadlinkIfPossible(name)
144 }
145
146 if rbase, ok := u.base.(LinkReader); ok {
147 return rbase.ReadlinkIfPossible(name)
148 }
149
150 return "", &os.PathError{Op: "readlink", Path: name, Err: ErrNoReadlink}
151 }
152
153 func (u *CopyOnWriteFs) isNotExist(err error) bool {
154 if e, ok := err.(*os.PathError); ok {
155 err = e.Err
156 }
157 if err == os.ErrNotExist || err == syscall.ENOENT || err == syscall.ENOTDIR {
158 return true
159 }
160 return false
161 }
162
163
164 func (u *CopyOnWriteFs) Rename(oldname, newname string) error {
165 b, err := u.isBaseFile(oldname)
166 if err != nil {
167 return err
168 }
169 if b {
170 return syscall.EPERM
171 }
172 return u.layer.Rename(oldname, newname)
173 }
174
175
176
177
178 func (u *CopyOnWriteFs) Remove(name string) error {
179 err := u.layer.Remove(name)
180 switch err {
181 case syscall.ENOENT:
182 _, err = u.base.Stat(name)
183 if err == nil {
184 return syscall.EPERM
185 }
186 return syscall.ENOENT
187 default:
188 return err
189 }
190 }
191
192 func (u *CopyOnWriteFs) RemoveAll(name string) error {
193 err := u.layer.RemoveAll(name)
194 switch err {
195 case syscall.ENOENT:
196 _, err = u.base.Stat(name)
197 if err == nil {
198 return syscall.EPERM
199 }
200 return syscall.ENOENT
201 default:
202 return err
203 }
204 }
205
206 func (u *CopyOnWriteFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
207 b, err := u.isBaseFile(name)
208 if err != nil {
209 return nil, err
210 }
211
212 if flag&(os.O_WRONLY|os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 {
213 if b {
214 if err = u.copyToLayer(name); err != nil {
215 return nil, err
216 }
217 return u.layer.OpenFile(name, flag, perm)
218 }
219
220 dir := filepath.Dir(name)
221 isaDir, err := IsDir(u.base, dir)
222 if err != nil && !os.IsNotExist(err) {
223 return nil, err
224 }
225 if isaDir {
226 if err = u.layer.MkdirAll(dir, 0o777); err != nil {
227 return nil, err
228 }
229 return u.layer.OpenFile(name, flag, perm)
230 }
231
232 isaDir, err = IsDir(u.layer, dir)
233 if err != nil {
234 return nil, err
235 }
236 if isaDir {
237 return u.layer.OpenFile(name, flag, perm)
238 }
239
240 return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOTDIR}
241 }
242 if b {
243 return u.base.OpenFile(name, flag, perm)
244 }
245 return u.layer.OpenFile(name, flag, perm)
246 }
247
248
249
250
251
252
253 func (u *CopyOnWriteFs) Open(name string) (File, error) {
254
255 b, err := u.isBaseFile(name)
256 if err != nil {
257 return nil, err
258 }
259
260
261 if b {
262 return u.base.Open(name)
263 }
264
265
266 dir, err := IsDir(u.layer, name)
267 if err != nil {
268 return nil, err
269 }
270 if !dir {
271 return u.layer.Open(name)
272 }
273
274
275
276
277
278
279
280 dir, err = IsDir(u.base, name)
281 if !dir || err != nil {
282 return u.layer.Open(name)
283 }
284
285
286
287 bfile, bErr := u.base.Open(name)
288 lfile, lErr := u.layer.Open(name)
289
290
291 if bErr != nil || lErr != nil {
292 return nil, fmt.Errorf("BaseErr: %v\nOverlayErr: %v", bErr, lErr)
293 }
294
295 return &UnionFile{Base: bfile, Layer: lfile}, nil
296 }
297
298 func (u *CopyOnWriteFs) Mkdir(name string, perm os.FileMode) error {
299 dir, err := IsDir(u.base, name)
300 if err != nil {
301 return u.layer.MkdirAll(name, perm)
302 }
303 if dir {
304 return ErrFileExists
305 }
306 return u.layer.MkdirAll(name, perm)
307 }
308
309 func (u *CopyOnWriteFs) Name() string {
310 return "CopyOnWriteFs"
311 }
312
313 func (u *CopyOnWriteFs) MkdirAll(name string, perm os.FileMode) error {
314 dir, err := IsDir(u.base, name)
315 if err != nil {
316 return u.layer.MkdirAll(name, perm)
317 }
318 if dir {
319
320 return nil
321 }
322 return u.layer.MkdirAll(name, perm)
323 }
324
325 func (u *CopyOnWriteFs) Create(name string) (File, error) {
326 return u.OpenFile(name, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0o666)
327 }
328
View as plain text