[libglnx: 1/2] fdio: fix fd offset handling with `FICLONE`




commit 7a2f26a312c92e335652962bb99bf2e160720c8d
Author: Jonathan Lebon <jonathan jlebon com>
Date:   Fri Jul 29 17:29:28 2022 -0400

    fdio: fix fd offset handling with `FICLONE`
    
    When using `FICLONE`, the kernel does a full file clone and disregards the
    fd offsets. Users of this API however assume that it *is*
    offset-sensitive. So we need to verify that the fd offsets are at the
    start of the files before we call `FICLONE`. This was done in systemd also
    in:
    
    https://github.com/systemd/systemd/commit/c622fbdb8d37
    
    The commit message does not explain this but `ioctl_ficlone(2)` says:
    
        The `FICLONE` ioctl clones entire files.
    
    (Compare with `FICLONERANGE`, which takes a struct with offsets and the
    length).
    
    Similarly, we need to seek to the end of the file descriptors on success
    so that we're consistent with the behaviour of the other backends
    available (`copy_file_range`, `sendfile` and manual copying). This also
    matches what systemd does nowadays:
    
    https://github.com/systemd/systemd/blob/80f967311ac5/src/shared/copy.c#L199

 glnx-fdio.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)
---
diff --git a/glnx-fdio.c b/glnx-fdio.c
index ee69aa1..b1af679 100644
--- a/glnx-fdio.c
+++ b/glnx-fdio.c
@@ -794,10 +794,21 @@ glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes)
 
   /* If we've requested to copy the whole range, try a full-file clone first.
    */
-  if (max_bytes == (off_t) -1)
+  if (max_bytes == (off_t) -1 &&
+      lseek (fdf, 0, SEEK_CUR) == 0 &&
+      lseek (fdt, 0, SEEK_CUR) == 0)
     {
       if (ioctl (fdt, FICLONE, fdf) == 0)
-        return 0;
+        {
+          /* All the other methods advance the fds. Do it here too for consistency. */
+          if (lseek (fdf, 0, SEEK_END) < 0)
+            return -1;
+          if (lseek (fdt, 0, SEEK_END) < 0)
+            return -1;
+
+          return 0;
+        }
+
       /* Fall through */
       struct stat stbuf;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]