1 package afero
2
3 import (
4 "os"
5 "syscall"
6 "time"
7 )
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 type CacheOnReadFs struct {
23 base Fs
24 layer Fs
25 cacheTime time.Duration
26 }
27
28 func NewCacheOnReadFs(base Fs, layer Fs, cacheTime time.Duration) Fs {
29 return &CacheOnReadFs{base: base, layer: layer, cacheTime: cacheTime}
30 }
31
32 type cacheState int
33
34 const (
35
36 cacheMiss cacheState = iota
37
38 cacheStale
39
40
41
42 cacheHit
43
44
45 cacheLocal
46 )
47
48 func (u *CacheOnReadFs) cacheStatus(name string) (state cacheState, fi os.FileInfo, err error) {
49 var lfi, bfi os.FileInfo
50 lfi, err = u.layer.Stat(name)
51 if err == nil {
52 if u.cacheTime == 0 {
53 return cacheHit, lfi, nil
54 }
55 if lfi.ModTime().Add(u.cacheTime).Before(time.Now()) {
56 bfi, err = u.base.Stat(name)
57 if err != nil {
58 return cacheLocal, lfi, nil
59 }
60 if bfi.ModTime().After(lfi.ModTime()) {
61 return cacheStale, bfi, nil
62 }
63 }
64 return cacheHit, lfi, nil
65 }
66
67 if err == syscall.ENOENT || os.IsNotExist(err) {
68 return cacheMiss, nil, nil
69 }
70
71 return cacheMiss, nil, err
72 }
73
74 func (u *CacheOnReadFs) copyToLayer(name string) error {
75 return copyToLayer(u.base, u.layer, name)
76 }
77
78 func (u *CacheOnReadFs) copyFileToLayer(name string, flag int, perm os.FileMode) error {
79 return copyFileToLayer(u.base, u.layer, name, flag, perm)
80 }
81
82 func (u *CacheOnReadFs) Chtimes(name string, atime, mtime time.Time) error {
83 st, _, err := u.cacheStatus(name)
84 if err != nil {
85 return err
86 }
87 switch st {
88 case cacheLocal:
89 case cacheHit:
90 err = u.base.Chtimes(name, atime, mtime)
91 case cacheStale, cacheMiss:
92 if err := u.copyToLayer(name); err != nil {
93 return err
94 }
95 err = u.base.Chtimes(name, atime, mtime)
96 }
97 if err != nil {
98 return err
99 }
100 return u.layer.Chtimes(name, atime, mtime)
101 }
102
103 func (u *CacheOnReadFs) Chmod(name string, mode os.FileMode) error {
104 st, _, err := u.cacheStatus(name)
105 if err != nil {
106 return err
107 }
108 switch st {
109 case cacheLocal:
110 case cacheHit:
111 err = u.base.Chmod(name, mode)
112 case cacheStale, cacheMiss:
113 if err := u.copyToLayer(name); err != nil {
114 return err
115 }
116 err = u.base.Chmod(name, mode)
117 }
118 if err != nil {
119 return err
120 }
121 return u.layer.Chmod(name, mode)
122 }
123
124 func (u *CacheOnReadFs) Chown(name string, uid, gid int) error {
125 st, _, err := u.cacheStatus(name)
126 if err != nil {
127 return err
128 }
129 switch st {
130 case cacheLocal:
131 case cacheHit:
132 err = u.base.Chown(name, uid, gid)
133 case cacheStale, cacheMiss:
134 if err := u.copyToLayer(name); err != nil {
135 return err
136 }
137 err = u.base.Chown(name, uid, gid)
138 }
139 if err != nil {
140 return err
141 }
142 return u.layer.Chown(name, uid, gid)
143 }
144
145 func (u *CacheOnReadFs) Stat(name string) (os.FileInfo, error) {
146 st, fi, err := u.cacheStatus(name)
147 if err != nil {
148 return nil, err
149 }
150 switch st {
151 case cacheMiss:
152 return u.base.Stat(name)
153 default:
154 return fi, nil
155 }
156 }
157
158 func (u *CacheOnReadFs) Rename(oldname, newname string) error {
159 st, _, err := u.cacheStatus(oldname)
160 if err != nil {
161 return err
162 }
163 switch st {
164 case cacheLocal:
165 case cacheHit:
166 err = u.base.Rename(oldname, newname)
167 case cacheStale, cacheMiss:
168 if err := u.copyToLayer(oldname); err != nil {
169 return err
170 }
171 err = u.base.Rename(oldname, newname)
172 }
173 if err != nil {
174 return err
175 }
176 return u.layer.Rename(oldname, newname)
177 }
178
179 func (u *CacheOnReadFs) Remove(name string) error {
180 st, _, err := u.cacheStatus(name)
181 if err != nil {
182 return err
183 }
184 switch st {
185 case cacheLocal:
186 case cacheHit, cacheStale, cacheMiss:
187 err = u.base.Remove(name)
188 }
189 if err != nil {
190 return err
191 }
192 return u.layer.Remove(name)
193 }
194
195 func (u *CacheOnReadFs) RemoveAll(name string) error {
196 st, _, err := u.cacheStatus(name)
197 if err != nil {
198 return err
199 }
200 switch st {
201 case cacheLocal:
202 case cacheHit, cacheStale, cacheMiss:
203 err = u.base.RemoveAll(name)
204 }
205 if err != nil {
206 return err
207 }
208 return u.layer.RemoveAll(name)
209 }
210
211 func (u *CacheOnReadFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
212 st, _, err := u.cacheStatus(name)
213 if err != nil {
214 return nil, err
215 }
216 switch st {
217 case cacheLocal, cacheHit:
218 default:
219 if err := u.copyFileToLayer(name, flag, perm); err != nil {
220 return nil, err
221 }
222 }
223 if flag&(os.O_WRONLY|syscall.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 {
224 bfi, err := u.base.OpenFile(name, flag, perm)
225 if err != nil {
226 return nil, err
227 }
228 lfi, err := u.layer.OpenFile(name, flag, perm)
229 if err != nil {
230 bfi.Close()
231 return nil, err
232 }
233 return &UnionFile{Base: bfi, Layer: lfi}, nil
234 }
235 return u.layer.OpenFile(name, flag, perm)
236 }
237
238 func (u *CacheOnReadFs) Open(name string) (File, error) {
239 st, fi, err := u.cacheStatus(name)
240 if err != nil {
241 return nil, err
242 }
243
244 switch st {
245 case cacheLocal:
246 return u.layer.Open(name)
247
248 case cacheMiss:
249 bfi, err := u.base.Stat(name)
250 if err != nil {
251 return nil, err
252 }
253 if bfi.IsDir() {
254 return u.base.Open(name)
255 }
256 if err := u.copyToLayer(name); err != nil {
257 return nil, err
258 }
259 return u.layer.Open(name)
260
261 case cacheStale:
262 if !fi.IsDir() {
263 if err := u.copyToLayer(name); err != nil {
264 return nil, err
265 }
266 return u.layer.Open(name)
267 }
268 case cacheHit:
269 if !fi.IsDir() {
270 return u.layer.Open(name)
271 }
272 }
273
274 bfile, _ := u.base.Open(name)
275 lfile, err := u.layer.Open(name)
276 if err != nil && bfile == nil {
277 return nil, err
278 }
279 return &UnionFile{Base: bfile, Layer: lfile}, nil
280 }
281
282 func (u *CacheOnReadFs) Mkdir(name string, perm os.FileMode) error {
283 err := u.base.Mkdir(name, perm)
284 if err != nil {
285 return err
286 }
287 return u.layer.MkdirAll(name, perm)
288 }
289
290 func (u *CacheOnReadFs) Name() string {
291 return "CacheOnReadFs"
292 }
293
294 func (u *CacheOnReadFs) MkdirAll(name string, perm os.FileMode) error {
295 err := u.base.MkdirAll(name, perm)
296 if err != nil {
297 return err
298 }
299 return u.layer.MkdirAll(name, perm)
300 }
301
302 func (u *CacheOnReadFs) Create(name string) (File, error) {
303 bfh, err := u.base.Create(name)
304 if err != nil {
305 return nil, err
306 }
307 lfh, err := u.layer.Create(name)
308 if err != nil {
309
310
311 bfh.Close()
312 return nil, err
313 }
314 return &UnionFile{Base: bfh, Layer: lfh}, nil
315 }
316
View as plain text