From 05fc07064c0910667b24dc91ff76a17399af1a85 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 6 Mar 2018 00:01:14 +0100 Subject: [PATCH] checkout: honor opaque checkouts Signed-off-by: Giuseppe Scrivano --- src/libostree/ostree-repo-checkout.c | 25 +++++++++++++++++++++++++ tests/basic-test.sh | 3 ++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index 5ae799231c..e190a14a38 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 { @@ -879,6 +880,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; @@ -912,6 +914,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(). */ @@ -931,6 +949,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 3c4823d747..de4348c21f 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -1034,7 +1034,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 @@ -1050,6 +1050,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