diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index 6317c9e85e..9e033d4689 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -35,6 +35,7 @@ #include "ostree-repo-private.h" #define WHITEOUT_PREFIX ".wh." +#define OPAQUE_WHITEOUT_NAME ".wh..wh..opq" /* Per-checkout call state/caching */ typedef struct { @@ -845,6 +846,7 @@ checkout_tree_at_recurse (OstreeRepo *self, GError **error) { gboolean did_exist = FALSE; + gboolean is_opaque_whiteout = FALSE; const gboolean sepolicy_enabled = options->sepolicy && !self->disable_xattrs; g_autoptr(GVariant) dirtree = NULL; g_autoptr(GVariant) dirmeta = NULL; @@ -878,6 +880,22 @@ checkout_tree_at_recurse (OstreeRepo *self, return TRUE; /* Note early return */ } + if (options->process_whiteouts) + { + g_autoptr(GVariant) dir_file_contents = g_variant_get_child_value (dirtree, 0); + GVariantIter viter; + const char *fname; + g_autoptr(GVariant) contents_csum_v = NULL; + g_variant_iter_init (&viter, dir_file_contents); + while (g_variant_iter_loop (&viter, "(&s@ay)", &fname, &contents_csum_v)) + { + is_opaque_whiteout = (g_str_equal (fname, OPAQUE_WHITEOUT_NAME)); + if (is_opaque_whiteout) + break; + } + contents_csum_v = NULL; /* iter_loop freed it */ + } + /* First, make the directory. Push a new scope in case we end up using * setfscreatecon(). */ @@ -897,6 +915,13 @@ checkout_tree_at_recurse (OstreeRepo *self, return FALSE; } + /* If it is an opaque whiteout, ensure the destination is empty first. */ + if (is_opaque_whiteout) + { + if (!glnx_shutil_rm_rf_at (destination_parent_fd, destination_name, cancellable, error)) + return FALSE; + } + /* Create initially with mode 0700, then chown/chmod only when we're * done. This avoids anyone else being able to operate on partially * constructed dirs. diff --git a/tests/basic-test.sh b/tests/basic-test.sh index a0c2f1f763..2c6f90f57d 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -1005,7 +1005,7 @@ echo "ok test error pre commit/bootid" # Whiteouts cd ${test_tmpdir} mkdir -p overlay/baz/ -if touch overlay/baz/.wh.cow && touch overlay/.wh.deeper; then +if touch overlay/baz/.wh.cow && touch overlay/.wh.deeper && touch overlay/baz/another/.wh..wh..opq; then touch overlay/anewfile mkdir overlay/anewdir/ touch overlay/anewdir/blah @@ -1021,6 +1021,7 @@ if touch overlay/baz/.wh.cow && touch overlay/.wh.deeper; then assert_not_has_dir overlay-co/deeper assert_has_file overlay-co/anewdir/blah assert_has_file overlay-co/anewfile + assert_not_has_file overlay-co/baz/another/y # And test replacing a directory wholesale with a symlink as well as a regular file mkdir overlay