Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / spf13 / afero / unionFile.go
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 if c > 0.
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 c <= 0 && len(f.files) == 0 {
191                 return f.files, nil
192         }
193
194         if f.off >= len(f.files) {
195                 return nil, io.EOF
196         }
197
198         if c <= 0 {
199                 return f.files[f.off:], nil
200         }
201
202         if c > len(f.files) {
203                 c = len(f.files)
204         }
205
206         defer func() { f.off += c }()
207         return f.files[f.off:c], nil
208 }
209
210 func (f *UnionFile) Readdirnames(c int) ([]string, error) {
211         rfi, err := f.Readdir(c)
212         if err != nil {
213                 return nil, err
214         }
215         var names []string
216         for _, fi := range rfi {
217                 names = append(names, fi.Name())
218         }
219         return names, nil
220 }
221
222 func (f *UnionFile) Stat() (os.FileInfo, error) {
223         if f.Layer != nil {
224                 return f.Layer.Stat()
225         }
226         if f.Base != nil {
227                 return f.Base.Stat()
228         }
229         return nil, BADFD
230 }
231
232 func (f *UnionFile) Sync() (err error) {
233         if f.Layer != nil {
234                 err = f.Layer.Sync()
235                 if err == nil && f.Base != nil {
236                         err = f.Base.Sync()
237                 }
238                 return err
239         }
240         if f.Base != nil {
241                 return f.Base.Sync()
242         }
243         return BADFD
244 }
245
246 func (f *UnionFile) Truncate(s int64) (err error) {
247         if f.Layer != nil {
248                 err = f.Layer.Truncate(s)
249                 if err == nil && f.Base != nil {
250                         err = f.Base.Truncate(s)
251                 }
252                 return err
253         }
254         if f.Base != nil {
255                 return f.Base.Truncate(s)
256         }
257         return BADFD
258 }
259
260 func (f *UnionFile) WriteString(s string) (n int, err error) {
261         if f.Layer != nil {
262                 n, err = f.Layer.WriteString(s)
263                 if err == nil && f.Base != nil {
264                         _, err = f.Base.WriteString(s)
265                 }
266                 return n, err
267         }
268         if f.Base != nil {
269                 return f.Base.WriteString(s)
270         }
271         return 0, BADFD
272 }
273
274 func copyToLayer(base Fs, layer Fs, name string) error {
275         bfh, err := base.Open(name)
276         if err != nil {
277                 return err
278         }
279         defer bfh.Close()
280
281         // First make sure the directory exists
282         exists, err := Exists(layer, filepath.Dir(name))
283         if err != nil {
284                 return err
285         }
286         if !exists {
287                 err = layer.MkdirAll(filepath.Dir(name), 0777) // FIXME?
288                 if err != nil {
289                         return err
290                 }
291         }
292
293         // Create the file on the overlay
294         lfh, err := layer.Create(name)
295         if err != nil {
296                 return err
297         }
298         n, err := io.Copy(lfh, bfh)
299         if err != nil {
300                 // If anything fails, clean up the file
301                 layer.Remove(name)
302                 lfh.Close()
303                 return err
304         }
305
306         bfi, err := bfh.Stat()
307         if err != nil || bfi.Size() != n {
308                 layer.Remove(name)
309                 lfh.Close()
310                 return syscall.EIO
311         }
312
313         err = lfh.Close()
314         if err != nil {
315                 layer.Remove(name)
316                 lfh.Close()
317                 return err
318         }
319         return layer.Chtimes(name, bfi.ModTime(), bfi.ModTime())
320 }