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>
... | ... |
@@ -322,7 +322,7 @@ func (a *Driver) Diff(id, parent string) (archive.Archive, error) { |
322 | 322 |
// AUFS doesn't need the parent layer to produce a diff. |
323 | 323 |
return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{ |
324 | 324 |
Compression: archive.Uncompressed, |
325 |
- ExcludePatterns: []string{".wh..wh.*"}, |
|
325 |
+ ExcludePatterns: []string{".wh..wh.*", "!.wh..wh..opq"}, |
|
326 | 326 |
}) |
327 | 327 |
} |
328 | 328 |
|
... | ... |
@@ -100,7 +100,10 @@ func UnpackLayer(dest string, layer Reader) (size int64, err error) { |
100 | 100 |
return 0, err |
101 | 101 |
} |
102 | 102 |
} |
103 |
- continue |
|
103 |
+ |
|
104 |
+ if hdr.Name != ".wh..wh..opq" { |
|
105 |
+ continue |
|
106 |
+ } |
|
104 | 107 |
} |
105 | 108 |
path := filepath.Join(dest, hdr.Name) |
106 | 109 |
rel, err := filepath.Rel(dest, path) |
... | ... |
@@ -116,9 +119,23 @@ func UnpackLayer(dest string, layer Reader) (size int64, err error) { |
116 | 116 |
|
117 | 117 |
if strings.HasPrefix(base, ".wh.") { |
118 | 118 |
originalBase := base[len(".wh."):] |
119 |
- originalPath := filepath.Join(filepath.Dir(path), originalBase) |
|
120 |
- if err := os.RemoveAll(originalPath); err != nil { |
|
121 |
- return 0, err |
|
119 |
+ dir := filepath.Dir(path) |
|
120 |
+ if originalBase == ".wh..opq" { |
|
121 |
+ fi, err := os.Lstat(dir) |
|
122 |
+ if err != nil && !os.IsNotExist(err) { |
|
123 |
+ return 0, err |
|
124 |
+ } |
|
125 |
+ if err := os.RemoveAll(dir); err != nil { |
|
126 |
+ return 0, err |
|
127 |
+ } |
|
128 |
+ if err := os.Mkdir(dir, fi.Mode()&os.ModePerm); err != nil { |
|
129 |
+ return 0, err |
|
130 |
+ } |
|
131 |
+ } else { |
|
132 |
+ originalPath := filepath.Join(dir, originalBase) |
|
133 |
+ if err := os.RemoveAll(originalPath); err != nil { |
|
134 |
+ return 0, err |
|
135 |
+ } |
|
122 | 136 |
} |
123 | 137 |
} else { |
124 | 138 |
// If path exits we almost always just want to remove and replace it. |