From 4c53da8f9a18a228c6c209b9a80003f0d164822a Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Mon, 21 Sep 2015 14:36:35 -0700 Subject: [PATCH] Add basic support for .wh..wh..opq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the case where directory is removed in aufs and then the same layer is imported to a different graphdriver. Currently when you do `rm -rf /foo && mkdir /foo` in a layer in aufs the files under `foo` would only be be hidden on aufs. The problems with this fix: 1) When a new diff is recreated from non-aufs driver the `opq` files would not be there. This should not mean layer differences for the user but still different content in the tar (one would have one `opq` file, the others would have `.wh.*` for every file inside that folder). This difference also only happens if the tar-split file isn’t stored for the layer. 2) New files that have the filenames before `.wh..wh..opq` when they are sorted do not get picked up by non-aufs graphdrivers. Fixing this would require a bigger refactoring that is planned in the future. Signed-off-by: Tonis Tiigi --- archive/diff.go | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/archive/diff.go b/archive/diff.go index 50656cb..c343d8a 100644 --- a/archive/diff.go +++ b/archive/diff.go @@ -100,7 +100,10 @@ func UnpackLayer(dest string, layer Reader) (size int64, err error) { return 0, err } } - continue + + if hdr.Name != ".wh..wh..opq" { + continue + } } path := filepath.Join(dest, hdr.Name) rel, err := filepath.Rel(dest, path) @@ -116,9 +119,23 @@ func UnpackLayer(dest string, layer Reader) (size int64, err error) { if strings.HasPrefix(base, ".wh.") { originalBase := base[len(".wh."):] - originalPath := filepath.Join(filepath.Dir(path), originalBase) - if err := os.RemoveAll(originalPath); err != nil { - return 0, err + dir := filepath.Dir(path) + if originalBase == ".wh..opq" { + fi, err := os.Lstat(dir) + if err != nil && !os.IsNotExist(err) { + return 0, err + } + if err := os.RemoveAll(dir); err != nil { + return 0, err + } + if err := os.Mkdir(dir, fi.Mode()&os.ModePerm); err != nil { + return 0, err + } + } else { + originalPath := filepath.Join(dir, originalBase) + if err := os.RemoveAll(originalPath); err != nil { + return 0, err + } } } else { // If path exits we almost always just want to remove and replace it.