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
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.
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 {
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 ;-)
39 return f.Layer.Close()
44 func (f *UnionFile) Read(s []byte) (int, error) {
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
64 func (f *UnionFile) ReadAt(s []byte, o int64) (int, error) {
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)
73 return f.Base.ReadAt(s, o)
78 func (f *UnionFile) Seek(o int64, w int) (pos int64, err error) {
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)
87 return f.Base.Seek(o, w)
92 func (f *UnionFile) Write(s []byte) (n int, err error) {
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)
101 return f.Base.Write(s)
106 func (f *UnionFile) WriteAt(s []byte, o int64) (n int, err error) {
108 n, err = f.Layer.WriteAt(s, o)
109 if err == nil && f.Base != nil {
110 _, err = f.Base.WriteAt(s, o)
115 return f.Base.WriteAt(s, o)
120 func (f *UnionFile) Name() string {
122 return f.Layer.Name()
127 // DirsMerger is how UnionFile weaves two directories together.
128 // It takes the FileInfo slices from the layer and the base and returns a
130 type DirsMerger func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error)
132 var defaultUnionMergeDirsFn = func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error) {
133 var files = make(map[string]os.FileInfo)
135 for _, fi := range lofi {
136 files[fi.Name()] = fi
139 for _, fi := range bofi {
140 if _, exists := files[fi.Name()]; !exists {
141 files[fi.Name()] = fi
145 rfi := make([]os.FileInfo, len(files))
148 for _, fi := range files {
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
163 merge = defaultUnionMergeDirsFn
167 var lfi []os.FileInfo
169 lfi, err = f.Layer.Readdir(-1)
175 var bfi []os.FileInfo
177 bfi, err = f.Base.Readdir(-1)
183 merged, err := merge(lfi, bfi)
187 f.files = append(f.files, merged...)
190 if c <= 0 && len(f.files) == 0 {
194 if f.off >= len(f.files) {
199 return f.files[f.off:], nil
202 if c > len(f.files) {
206 defer func() { f.off += c }()
207 return f.files[f.off:c], nil
210 func (f *UnionFile) Readdirnames(c int) ([]string, error) {
211 rfi, err := f.Readdir(c)
216 for _, fi := range rfi {
217 names = append(names, fi.Name())
222 func (f *UnionFile) Stat() (os.FileInfo, error) {
224 return f.Layer.Stat()
232 func (f *UnionFile) Sync() (err error) {
235 if err == nil && f.Base != nil {
246 func (f *UnionFile) Truncate(s int64) (err error) {
248 err = f.Layer.Truncate(s)
249 if err == nil && f.Base != nil {
250 err = f.Base.Truncate(s)
255 return f.Base.Truncate(s)
260 func (f *UnionFile) WriteString(s string) (n int, err error) {
262 n, err = f.Layer.WriteString(s)
263 if err == nil && f.Base != nil {
264 _, err = f.Base.WriteString(s)
269 return f.Base.WriteString(s)
274 func copyToLayer(base Fs, layer Fs, name string) error {
275 bfh, err := base.Open(name)
281 // First make sure the directory exists
282 exists, err := Exists(layer, filepath.Dir(name))
287 err = layer.MkdirAll(filepath.Dir(name), 0777) // FIXME?
293 // Create the file on the overlay
294 lfh, err := layer.Create(name)
298 n, err := io.Copy(lfh, bfh)
300 // If anything fails, clean up the file
306 bfi, err := bfh.Stat()
307 if err != nil || bfi.Size() != n {
319 return layer.Chtimes(name, bfi.ModTime(), bfi.ModTime())