diff --git a/README.md b/README.md index edf0999..da4c956 100644 --- a/README.md +++ b/README.md @@ -357,8 +357,6 @@ Removing and Renaming files present only in the base layer is not currently permitted. If a file is present in the base layer and the overlay, only the overlay will be removed/renamed. -The writable overlay layer is currently limited to MemMapFs. - ```go base := afero.NewOsFs() roBase := afero.NewReadOnlyFs(base) diff --git a/copyOnWriteFs.go b/copyOnWriteFs.go index 9f5a2ef..e0d7870 100644 --- a/copyOnWriteFs.go +++ b/copyOnWriteFs.go @@ -2,6 +2,7 @@ package afero import ( "os" + "path/filepath" "syscall" "time" "fmt" @@ -12,10 +13,6 @@ import ( // be made in the overlay: Changing an existing file in the base layer which // is not present in the overlay will copy the file to the overlay ("changing" // includes also calls to e.g. Chtimes() and Chmod()). -// The overlay is currently limited to MemMapFs: -// - missing MkdirAll() calls in the code below, MemMapFs creates them -// implicitly (or better: records the full path and afero.Readdir() -// can handle this). // // Reading directories is currently only supported via Open(), not OpenFile(). type CopyOnWriteFs struct { @@ -132,8 +129,30 @@ func (u *CopyOnWriteFs) OpenFile(name string, flag int, perm os.FileMode) (File, if err = u.copyToLayer(name); err != nil { return nil, err } + return u.layer.OpenFile(name, flag, perm) } - return u.layer.OpenFile(name, flag, perm) + + dir := filepath.Dir(name) + isaDir, err := IsDir(u.base, dir) + if err != nil { + return nil, err + } + if isaDir { + if err = u.layer.MkdirAll(dir, 0777); err != nil { + return nil, err + } + return u.layer.OpenFile(name, flag, perm) + } + + isaDir, err = IsDir(u.layer, dir) + if err != nil { + return nil, err + } + if isaDir { + return u.layer.OpenFile(name, flag, perm) + } + + return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOTDIR} // ...or os.ErrNotExist? } if b { return u.base.OpenFile(name, flag, perm) @@ -217,11 +236,5 @@ func (u *CopyOnWriteFs) MkdirAll(name string, perm os.FileMode) error { } func (u *CopyOnWriteFs) Create(name string) (File, error) { - b, err := u.isBaseFile(name) - if err == nil && b { - if err = u.copyToLayer(name); err != nil { - return nil, err - } - } - return u.layer.Create(name) + return u.OpenFile(name, os.O_TRUNC|os.O_RDWR, 0666) }