From bb6dfd3ab0bbd87497e58bc0dd0ec65c061c9a12 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 13 Mar 2024 12:50:28 -0400 Subject: [PATCH] checkout: Always replace existing content in overlay mode The combination of the "honor whiteout" and "union" flags are intended to basically be "merge trees like overlayfs does". But we were missing this case in order to support e.g. replacing a symlink with a directory. --- src/libostree/ostree-repo-checkout.c | 16 ++++++++++++++++ tests/basic-test.sh | 12 ++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index f506545529..650604446d 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -1062,6 +1062,22 @@ checkout_tree_at_recurse (OstreeRepo *self, OstreeRepoCheckoutAtOptions *options if (!glnx_shutil_rm_rf_at (destination_parent_fd, destination_name, cancellable, error)) return FALSE; } + else if (options->process_whiteouts + && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES) + { + /* In this mode, we're flattening in a manner similar to overlayfs, so ensure + * any non-directory content there is gone. / + */ + struct stat stbuf; + if (!glnx_fstatat_allow_noent (destination_parent_fd, destination_name, &stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (errno == 0 && !S_ISDIR (stbuf.st_mode)) + { + 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 diff --git a/tests/basic-test.sh b/tests/basic-test.sh index 7905e6ee68..c8f853f8d6 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -1159,6 +1159,18 @@ if touch overlay/baz/.wh.cow && touch overlay/.wh.deeper && touch overlay/baz/an assert_has_file overlay-co/baz test -L overlay-co/anewdir + rm overlay-co overlay -rf + mkdir -p overlay/somelink overlay/yet/ovlnewdir + echo ovlnewf > overlay/yet/ovlnewdir/ovlnewf + $OSTREE --repo=repo commit ${COMMIT_ARGS} -b overlay-symlink-convert --tree=dir=overlay + for branch in test2 overlay-symlink-convert; do + $OSTREE --repo=repo checkout --union --whiteouts ${branch} overlay-co + done + test -d overlay-co/somelink || fatal "should replace symlink with dir" + assert_has_dir overlay-co/yet/another + assert_has_dir overlay-co/yet/ovlnewdir + assert_file_has_content overlay-co/yet/ovlnewdir/ovlnewf ovlnewf + rm overlay-co overlay -rf echo "ok whiteouts enabled" # Now double check whiteouts are not processed without --whiteouts