Add basic support for .wh..wh..opq

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 <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi 2015-09-21 14:36:35 -07:00
parent 30ae8b046b
commit 4c53da8f9a

View file

@ -100,7 +100,10 @@ func UnpackLayer(dest string, layer Reader) (size int64, err error) {
return 0, err return 0, err
} }
} }
continue
if hdr.Name != ".wh..wh..opq" {
continue
}
} }
path := filepath.Join(dest, hdr.Name) path := filepath.Join(dest, hdr.Name)
rel, err := filepath.Rel(dest, path) 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.") { if strings.HasPrefix(base, ".wh.") {
originalBase := base[len(".wh."):] originalBase := base[len(".wh."):]
originalPath := filepath.Join(filepath.Dir(path), originalBase) dir := filepath.Dir(path)
if err := os.RemoveAll(originalPath); err != nil { if originalBase == ".wh..opq" {
return 0, err 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 { } else {
// If path exits we almost always just want to remove and replace it. // If path exits we almost always just want to remove and replace it.