diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index a3dd68878c..1c923d3e0f 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -374,7 +374,8 @@ hardlink_add_tmp_name (OstreeRepo *self, static gboolean checkout_file_hardlink (OstreeRepo *self, - OstreeRepoCheckoutAtOptions *options, + const char *checksum, + OstreeRepoCheckoutAtOptions *options, const char *loose_path, int destination_dfd, const char *destination_name, @@ -436,10 +437,25 @@ checkout_file_hardlink (OstreeRepo *self, if (!glnx_fstatat (destination_dfd, destination_name, &dest_stbuf, AT_SYMLINK_NOFOLLOW, error)) return FALSE; - const gboolean is_identical = + gboolean is_identical = (src_stbuf.st_dev == dest_stbuf.st_dev && src_stbuf.st_ino == dest_stbuf.st_ino); + if (!is_identical && (src_stbuf.st_size == dest_stbuf.st_size)) + { + /* resort to a checksum check */ + g_autofree char *abspath = + glnx_fdrel_abspath (destination_dfd, destination_name); + g_autoptr(GFile) dest_file = g_file_new_for_path (abspath); + + /* XXX: need an fd-relative version of this API */ + g_autofree guchar *csum = NULL; + if (!ostree_checksum_file (dest_file, OSTREE_OBJECT_TYPE_FILE, + &csum, cancellable, error)) + return FALSE; + g_autofree char *actual_checksum = ostree_checksum_from_bytes (csum); + is_identical = g_str_equal (checksum, actual_checksum); + } if (is_identical) ret_result = HARDLINK_RESULT_SKIP_EXISTED; else if (options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES) @@ -563,6 +579,7 @@ checkout_one_file_at (OstreeRepo *repo, the cache, which is in "bare" form */ _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, OSTREE_REPO_MODE_BARE); if (!checkout_file_hardlink (current_repo, + checksum, options, loose_path_buf, destination_dfd, destination_name, @@ -652,7 +669,7 @@ checkout_one_file_at (OstreeRepo *repo, } g_mutex_unlock (&repo->cache_lock); - if (!checkout_file_hardlink (repo, options, loose_path_buf, + if (!checkout_file_hardlink (repo, checksum, options, loose_path_buf, destination_dfd, destination_name, FALSE, &hardlink_res, cancellable, error)) diff --git a/tests/basic-test.sh b/tests/basic-test.sh index 037f7b45f5..9d969b85b7 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -511,6 +511,12 @@ for x in $(seq 3); do assert_file_has_content union-identical-test/usr/share/licenses/${v} GPL done done +# now checkout the first pkg in force copy mode to make sure we can checksum +rm union-identical-test -rf +$OSTREE checkout --force-copy union-identical-pkg${x} union-identical-test +for x in 2 3; do + $OSTREE checkout ${CHECKOUT_H_ARGS} --union-identical union-identical-pkg${x} union-identical-test +done echo "ok checkout union identical merges" # Make conflicting packages, one with regfile, one with symlink