summaryrefslogtreecommitdiff
path: root/glnx-fdio.c
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2017-09-22 11:34:14 -0400
committerColin Walters <walters@verbum.org>2017-09-25 11:53:40 -0400
commit5ee2f1be7a10a3644168d7f9e6281d4c5bcabe87 (patch)
tree36db3dd2c7f761c25262d5890708d7a5a1f4f07e /glnx-fdio.c
parent56e7e728ab64b3798ff2867492d416219f3effe5 (diff)
downloadlibglnx-5ee2f1be7a10a3644168d7f9e6281d4c5bcabe87.tar.gz
fdio: Open target dirname for glnx_file_copy_at()
Particularly if `AT_FDCWD` is used, we need to open in the target dir, otherwise we can get `EXDEV` when trying to do the final link. (Theoretically we can cross a mountpoint even with fd-relative though this is a lot less likely)
Diffstat (limited to 'glnx-fdio.c')
-rw-r--r--glnx-fdio.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/glnx-fdio.c b/glnx-fdio.c
index 7113aeb..53f82e2 100644
--- a/glnx-fdio.c
+++ b/glnx-fdio.c
@@ -930,11 +930,16 @@ glnx_file_copy_at (int src_dfd,
if (!glnx_openat_rdonly (src_dfd, src_subpath, FALSE, &src_fd, error))
return FALSE;
- /* Open a tmpfile for dest */
+ /* Open a tmpfile for dest. Particularly for AT_FDCWD calls, we really want to
+ * open in the target directory, otherwise we may not be able to link.
+ */
g_auto(GLnxTmpfile) tmp_dest = { 0, };
- if (!glnx_open_tmpfile_linkable_at (dest_dfd, ".", O_WRONLY | O_CLOEXEC,
- &tmp_dest, error))
- return FALSE;
+ { char *dnbuf = strdupa (dest_subpath);
+ const char *dn = dirname (dnbuf);
+ if (!glnx_open_tmpfile_linkable_at (dest_dfd, dn, O_WRONLY | O_CLOEXEC,
+ &tmp_dest, error))
+ return FALSE;
+ }
if (glnx_regfile_copy_bytes (src_fd, tmp_dest.fd, (off_t) -1) < 0)
return glnx_throw_errno_prefix (error, "regfile copy");