diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index a6d69c42..0094aefd 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -346,7 +346,7 @@ checkout_file_hardlink (OstreeRepo *self, again: if (linkat (srcfd, loose_path, destination_dfd, destination_name, 0) != -1) ret_was_supported = TRUE; - else if (errno == EMLINK || errno == EXDEV || errno == EPERM) + else if (!options->no_copy_fallback && (errno == EMLINK || errno == EXDEV || errno == EPERM)) { /* EMLINK, EXDEV and EPERM shouldn't be fatal; we just can't do the * optimization of hardlinking instead of copying. diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index 2f60e633..872f9b81 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -750,7 +750,8 @@ typedef struct { guint enable_uncompressed_cache : 1; guint disable_fsync : 1; guint process_whiteouts : 1; - guint reserved : 29; + guint no_copy_fallback : 1; + guint reserved : 28; const char *subpath; diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c index 810a8f72..c6fdf1fc 100644 --- a/src/ostree/ot-builtin-checkout.c +++ b/src/ostree/ot-builtin-checkout.c @@ -40,6 +40,7 @@ static gboolean opt_whiteouts; static gboolean opt_from_stdin; static char *opt_from_file; static gboolean opt_disable_fsync; +static gboolean opt_require_hardlinks; static gboolean parse_fsync_cb (const char *option_name, @@ -67,6 +68,7 @@ static GOptionEntry options[] = { { "from-stdin", 0, 0, G_OPTION_ARG_NONE, &opt_from_stdin, "Process many checkouts from standard input", NULL }, { "from-file", 0, 0, G_OPTION_ARG_STRING, &opt_from_file, "Process many checkouts from input file", "FILE" }, { "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" }, + { "require-hardlinks", 'H', 0, G_OPTION_ARG_NONE, &opt_require_hardlinks, "Do not fall back to full copies if hardlinking fails", NULL }, { NULL } }; @@ -85,7 +87,7 @@ process_one_checkout (OstreeRepo *repo, * `ostree_repo_checkout_tree_at` until such time as we have a more * convenient infrastructure for testing C APIs with data. */ - if (opt_disable_cache || opt_whiteouts) + if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks) { OstreeRepoCheckoutOptions options = { 0, }; @@ -97,6 +99,7 @@ process_one_checkout (OstreeRepo *repo, options.process_whiteouts = TRUE; if (subpath) options.subpath = subpath; + options.no_copy_fallback = opt_require_hardlinks; if (!ostree_repo_checkout_tree_at (repo, &options, AT_FDCWD, destination, diff --git a/tests/test-rofiles-fuse.sh b/tests/test-rofiles-fuse.sh index d021df09..736747f7 100755 --- a/tests/test-rofiles-fuse.sh +++ b/tests/test-rofiles-fuse.sh @@ -26,7 +26,7 @@ skip_without_user_xattrs setup_test_repository "bare-user" -echo "1..5" +echo "1..6" mkdir mnt @@ -71,3 +71,13 @@ echo "ok deletion" ${CMD_PREFIX} ostree --repo=repo commit -b test2 -s fromfuse --link-checkout-speedup --tree=dir=checkout-test2 echo "ok commit" + +${CMD_PREFIX} ostree --repo=repo checkout -U test2 mnt/test2-checkout-copy-fallback +assert_file_has_content mnt/test2-checkout-copy-fallback/anewfile-for-fuse anewfile-for-fuse + +if ${CMD_PREFIX} ostree --repo=repo checkout -UH test2 mnt/test2-checkout-copy-hardlinked 2>err.txt; then + assert_not_reached "Checking out via hardlinks across mountpoint unexpectedly succeeded!" +fi +assert_file_has_content err.txt "Invalid cross-device link" + +echo "ok checkout copy fallback"