summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2017-03-06 14:51:14 -0500
committerAtomic Bot <atomic-devel@projectatomic.io>2017-03-06 20:58:04 +0000
commitff34810097460a4cac7965213db54150e4e7ae06 (patch)
tree60efab30782e94e2dc1f2d61b41c092c372aff69
parent3219a5d0ee4bf10479363690e05400ebdab18be3 (diff)
downloadostree-ff34810097460a4cac7965213db54150e4e7ae06.tar.gz
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`. Closes: #714 Approved by: jlebon
-rw-r--r--src/libostree/ostree-repo-checkout.c21
-rwxr-xr-xtests/test-rofiles-fuse.sh2
2 files changed, 22 insertions, 1 deletions
diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c
index 9a151646..50bc7030 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 4dfec514..56045c61 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"