1 package afero
2
3 import (
4 "io"
5 "os"
6 "path/filepath"
7 "syscall"
8 )
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
33
34
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
49
50 if _, seekErr := f.Base.Seek(int64(n), io.SeekCurrent); seekErr != nil {
51
52
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), io.SeekStart)
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 {
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
128
129
130 type DirsMerger func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error)
131
132 var defaultUnionMergeDirsFn = func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error) {
133 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
158
159 func (f *UnionFile) Readdir(c int) (ofi []os.FileInfo, err error) {
160 var merge DirsMerger = f.Merger
161 if merge == nil {
162 merge = defaultUnionMergeDirsFn
163 }
164
165 if f.off == 0 {
166 var lfi []os.FileInfo
167 if f.Layer != nil {
168 lfi, err = f.Layer.Readdir(-1)
169 if err != nil {
170 return nil, err
171 }
172 }
173
174 var bfi []os.FileInfo
175 if f.Base != nil {
176 bfi, err = f.Base.Readdir(-1)
177 if err != nil {
178 return nil, err
179 }
180
181 }
182 merged, err := merge(lfi, bfi)
183 if err != nil {
184 return nil, err
185 }
186 f.files = append(f.files, merged...)
187 }
188 files := f.files[f.off:]
189
190 if c <= 0 {
191 return files, nil
192 }
193
194 if len(files) == 0 {
195 return nil, io.EOF
196 }
197
198 if c > len(files) {
199 c = len(files)
200 }
201
202 defer func() { f.off += c }()
203 return files[: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 copyFile(base Fs, layer Fs, name string, bfh File) error {
271
272 exists, err := Exists(layer, filepath.Dir(name))
273 if err != nil {
274 return err
275 }
276 if !exists {
277 err = layer.MkdirAll(filepath.Dir(name), 0o777)
278 if err != nil {
279 return err
280 }
281 }
282
283
284 lfh, err := layer.Create(name)
285 if err != nil {
286 return err
287 }
288 n, err := io.Copy(lfh, bfh)
289 if err != nil {
290
291 layer.Remove(name)
292 lfh.Close()
293 return err
294 }
295
296 bfi, err := bfh.Stat()
297 if err != nil || bfi.Size() != n {
298 layer.Remove(name)
299 lfh.Close()
300 return syscall.EIO
301 }
302
303 err = lfh.Close()
304 if err != nil {
305 layer.Remove(name)
306 lfh.Close()
307 return err
308 }
309 return layer.Chtimes(name, bfi.ModTime(), bfi.ModTime())
310 }
311
312 func copyToLayer(base Fs, layer Fs, name string) error {
313 bfh, err := base.Open(name)
314 if err != nil {
315 return err
316 }
317 defer bfh.Close()
318
319 return copyFile(base, layer, name, bfh)
320 }
321
322 func copyFileToLayer(base Fs, layer Fs, name string, flag int, perm os.FileMode) error {
323 bfh, err := base.OpenFile(name, flag, perm)
324 if err != nil {
325 return err
326 }
327 defer bfh.Close()
328
329 return copyFile(base, layer, name, bfh)
330 }
331
View as plain text