diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index fcae6a7f..5ae79923 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -196,6 +196,7 @@ static gboolean create_file_copy_from_input_at (OstreeRepo *repo, OstreeRepoCheckoutAtOptions *options, CheckoutState *state, + const char *checksum, GFileInfo *file_info, GVariant *xattrs, GInputStream *input, @@ -358,8 +359,35 @@ create_file_copy_from_input_at (OstreeRepo *repo, replace_mode = GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST; break; case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: - /* We don't support copying in union identical */ - g_assert_not_reached (); + { + replace_mode = GLNX_LINK_TMPFILE_NOREPLACE; + struct stat dest_stbuf; + if (!glnx_fstatat_allow_noent (destination_dfd, destination_name, &dest_stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (errno == 0) + { + /* We do a checksum comparison; see also equivalent code in + * checkout_file_hardlink(). + */ + OstreeChecksumFlags flags = 0; + if (repo->disable_xattrs) + flags |= OSTREE_CHECKSUM_FLAGS_IGNORE_XATTRS; + + g_autofree char *actual_checksum = NULL; + if (!ostree_checksum_file_at (destination_dfd, destination_name, + &dest_stbuf, OSTREE_OBJECT_TYPE_FILE, + flags, &actual_checksum, cancellable, error)) + return FALSE; + + if (g_str_equal (checksum, actual_checksum)) + return TRUE; + + /* Otherwise, fall through and do the link, we should + * get EEXIST. + */ + } + } break; } @@ -773,7 +801,7 @@ checkout_one_file_at (OstreeRepo *repo, cancellable, error)) return FALSE; - if (!create_file_copy_from_input_at (repo, options, state, source_info, xattrs, input, + if (!create_file_copy_from_input_at (repo, options, state, checksum, source_info, xattrs, input, destination_dfd, destination_name, cancellable, error)) return glnx_prefix_error (error, "Copy checkout of %s to %s", checksum, destination_name); diff --git a/tests/basic-test.sh b/tests/basic-test.sh index a817b9d1..3c4823d7 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -21,7 +21,7 @@ set -euo pipefail -echo "1..$((84 + ${extra_basic_tests:-0}))" +echo "1..$((85 + ${extra_basic_tests:-0}))" CHECKOUT_U_ARG="" CHECKOUT_H_ARGS="-H" @@ -709,6 +709,20 @@ assert_files_hardlinked tree-with-empty-files/an{,other}emptyfile rm tree-with-empty-files -rf echo "ok checkout --force-copy-zerosized" +# These should merge, they're identical +$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} --union-identical -z tree-with-empty-files tree-with-empty-files +$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} --union-identical -z tree-with-empty-files tree-with-empty-files +echo notempty > tree-with-empty-files/anemptyfile.new && mv tree-with-empty-files/anemptyfile{.new,} +$CMD_PREFIX ostree --repo=repo commit --consume -b tree-with-conflicting-empty-files --tree=dir=tree-with-empty-files +# Reset back to base +rm tree-with-empty-files -rf +$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} --union-identical -z tree-with-empty-files tree-with-empty-files +if $CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} --union-identical -z tree-with-conflicting-empty-files tree-with-empty-files 2>err.txt; then + fatal "--union-identical --force-copy-zerosized unexpectedly succeeded with non-identical files" +fi +assert_file_has_content err.txt 'error:.*File exists' +echo "ok checkout --union-identical --force-copy-zerosized" + cd ${test_tmpdir} rm files -rf && mkdir files mkdir files/worldwritable-dir