From 1aaf7d5534f644eaa524ede0b7f1573979b8c191 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 6 Mar 2017 14:51:14 -0500 Subject: [PATCH] repo/checkout: Verify early if src/destination are on same device At least in all Linux kernels up to today, one can never `link()` across devices, so we might as well verify that up front. This will help for a future patch to add a new type of union-add checkout, since Linux checks for `EEXIST` before `EXDEV`. --- src/libostree/ostree-repo-checkout.c | 21 +++++++++++++++++++++ tests/test-rofiles-fuse.sh | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index 9a1516464c..50bc7030db 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -641,6 +641,8 @@ checkout_tree_at (OstreeRepo *self, gboolean did_exist = FALSE; glnx_fd_close int destination_dfd = -1; int res; + struct stat repo_dfd_stat; + struct stat destination_stat; g_autoptr(GVariant) xattrs = NULL; g_autoptr(GFileEnumerator) dir_enum = NULL; @@ -666,6 +668,25 @@ checkout_tree_at (OstreeRepo *self, &destination_dfd, error)) goto out; + if (fstat (self->repo_dir_fd, &repo_dfd_stat) < 0) + { + glnx_set_error_from_errno (error); + goto out; + } + if (fstat (destination_dfd, &destination_stat) < 0) + { + glnx_set_error_from_errno (error); + goto out; + } + + if (options->no_copy_fallback && repo_dfd_stat.st_dev != destination_stat.st_dev) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unable to do hardlink checkout across devices (src=%lu destination=%lu)", + repo_dfd_stat.st_dev, destination_stat.st_dev); + goto out; + } + /* Set the xattrs now, so any derived labeling works */ if (!did_exist && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER) { diff --git a/tests/test-rofiles-fuse.sh b/tests/test-rofiles-fuse.sh index 4dfec5145a..56045c6102 100755 --- a/tests/test-rofiles-fuse.sh +++ b/tests/test-rofiles-fuse.sh @@ -78,6 +78,6 @@ assert_file_has_content mnt/test2-checkout-copy-fallback/anewfile-for-fuse anewf 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" +assert_file_has_content err.txt "Unable to do hardlink checkout across devices" echo "ok checkout copy fallback"