OSDN Git Service

Hulk did something
[bytom/vapor.git] / 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         off   int
27         files []os.FileInfo
28 }
29
30 func (f *UnionFile) Close() error {
31         // first close base, so we have a newer timestamp in the overlay. If we'd close
32         // the overlay first, we'd get a cacheStale the next time we access this file
33         // -> cache would be useless ;-)
34         if f.base != nil {
35                 f.base.Close()
36         }
37         if f.layer != nil {
38                 return f.layer.Close()
39         }
40         return BADFD
41 }
42
43 func (f *UnionFile) Read(s []byte) (int, error) {
44         if f.layer != nil {
45                 n, err := f.layer.Read(s)
46                 if (err == nil || err == io.EOF) && f.base != nil {
47                         // advance the file position also in the base file, the next
48                         // call may be a write at this position (or a seek with SEEK_CUR)
49                         if _, seekErr := f.base.Seek(int64(n), os.SEEK_CUR); seekErr != nil {
50                                 // only overwrite err in case the seek fails: we need to
51                                 // report an eventual io.EOF to the caller
52                                 err = seekErr
53                         }
54                 }
55                 return n, err
56         }
57         if f.base != nil {
58                 return f.base.Read(s)
59         }
60         return 0, BADFD
61 }
62
63 func (f *UnionFile) ReadAt(s []byte, o int64) (int, error) {
64         if f.layer != nil {
65                 n, err := f.layer.ReadAt(s, o)
66                 if (err == nil || err == io.EOF) && f.base != nil {
67                         _, err = f.base.Seek(o+int64(n), os.SEEK_SET)
68                 }
69                 return n, err
70         }
71         if f.base != nil {
72                 return f.base.ReadAt(s, o)
73         }
74         return 0, BADFD
75 }
76
77 func (f *UnionFile) Seek(o int64, w int) (pos int64, err error) {
78         if f.layer != nil {
79                 pos, err = f.layer.Seek(o, w)
80                 if (err == nil || err == io.EOF) && f.base != nil {
81                         _, err = f.base.Seek(o, w)
82                 }
83                 return pos, err
84         }
85         if f.base != nil {
86                 return f.base.Seek(o, w)
87         }
88         return 0, BADFD
89 }
90
91 func (f *UnionFile) Write(s []byte) (n int, err error) {
92         if f.layer != nil {
93                 n, err = f.layer.Write(s)
94                 if err == nil && f.base != nil { // hmm, do we have fixed size files where a write may hit the EOF mark?
95                         _, err = f.base.Write(s)
96                 }
97                 return n, err
98         }
99         if f.base != nil {
100                 return f.base.Write(s)
101         }
102         return 0, BADFD
103 }
104
105 func (f *UnionFile) WriteAt(s []byte, o int64) (n int, err error) {
106         if f.layer != nil {
107                 n, err = f.layer.WriteAt(s, o)
108                 if err == nil && f.base != nil {
109                         _, err = f.base.WriteAt(s, o)
110                 }
111                 return n, err
112         }
113         if f.base != nil {
114                 return f.base.WriteAt(s, o)
115         }
116         return 0, BADFD
117 }
118
119 func (f *UnionFile) Name() string {
120         if f.layer != nil {
121                 return f.layer.Name()
122         }
123         return f.base.Name()
124 }
125
126 // Readdir will weave the two directories together and
127 // return a single view of the overlayed directories
128 func (f *UnionFile) Readdir(c int) (ofi []os.FileInfo, err error) {
129         if f.off == 0 {
130                 var files = make(map[string]os.FileInfo)
131                 var rfi []os.FileInfo
132                 if f.layer != nil {
133                         rfi, err = f.layer.Readdir(-1)
134                         if err != nil {
135                                 return nil, err
136                         }
137                         for _, fi := range rfi {
138                                 files[fi.Name()] = fi
139                         }
140                 }
141
142                 if f.base != nil {
143                         rfi, err = f.base.Readdir(-1)
144                         if err != nil {
145                                 return nil, err
146                         }
147                         for _, fi := range rfi {
148                                 if _, exists := files[fi.Name()]; !exists {
149                                         files[fi.Name()] = fi
150                                 }
151                         }
152                 }
153                 for _, fi := range files {
154                         f.files = append(f.files, fi)
155                 }
156         }
157         if c == -1 {
158                 return f.files[f.off:], nil
159         }
160         defer func() { f.off += c }()
161         return f.files[f.off:c], nil
162 }
163
164 func (f *UnionFile) Readdirnames(c int) ([]string, error) {
165         rfi, err := f.Readdir(c)
166         if err != nil {
167                 return nil, err
168         }
169         var names []string
170         for _, fi := range rfi {
171                 names = append(names, fi.Name())
172         }
173         return names, nil
174 }
175
176 func (f *UnionFile) Stat() (os.FileInfo, error) {
177         if f.layer != nil {
178                 return f.layer.Stat()
179         }
180         if f.base != nil {
181                 return f.base.Stat()
182         }
183         return nil, BADFD
184 }
185
186 func (f *UnionFile) Sync() (err error) {
187         if f.layer != nil {
188                 err = f.layer.Sync()
189                 if err == nil && f.base != nil {
190                         err = f.base.Sync()
191                 }
192                 return err
193         }
194         if f.base != nil {
195                 return f.base.Sync()
196         }
197         return BADFD
198 }
199
200 func (f *UnionFile) Truncate(s int64) (err error) {
201         if f.layer != nil {
202                 err = f.layer.Truncate(s)
203                 if err == nil && f.base != nil {
204                         err = f.base.Truncate(s)
205                 }
206                 return err
207         }
208         if f.base != nil {
209                 return f.base.Truncate(s)
210         }
211         return BADFD
212 }
213
214 func (f *UnionFile) WriteString(s string) (n int, err error) {
215         if f.layer != nil {
216                 n, err = f.layer.WriteString(s)
217                 if err == nil && f.base != nil {
218                         _, err = f.base.WriteString(s)
219                 }
220                 return n, err
221         }
222         if f.base != nil {
223                 return f.base.WriteString(s)
224         }
225         return 0, BADFD
226 }
227
228 func copyToLayer(base Fs, layer Fs, name string) error {
229         bfh, err := base.Open(name)
230         if err != nil {
231                 return err
232         }
233         defer bfh.Close()
234
235         // First make sure the directory exists
236         exists, err := Exists(layer, filepath.Dir(name))
237         if err != nil {
238                 return err
239         }
240         if !exists {
241                 err = layer.MkdirAll(filepath.Dir(name), 0777) // FIXME?
242                 if err != nil {
243                         return err
244                 }
245         }
246
247         // Create the file on the overlay
248         lfh, err := layer.Create(name)
249         if err != nil {
250                 return err
251         }
252         n, err := io.Copy(lfh, bfh)
253         if err != nil {
254                 // If anything fails, clean up the file
255                 layer.Remove(name)
256                 lfh.Close()
257                 return err
258         }
259
260         bfi, err := bfh.Stat()
261         if err != nil || bfi.Size() != n {
262                 layer.Remove(name)
263                 lfh.Close()
264                 return syscall.EIO
265         }
266
267         err = lfh.Close()
268         if err != nil {
269                 layer.Remove(name)
270                 lfh.Close()
271                 return err
272         }
273         return layer.Chtimes(name, bfi.ModTime(), bfi.ModTime())
274 }