]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
cp: port better to old limited hosts
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 5 Aug 2025 22:45:35 +0000 (15:45 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Tue, 16 Sep 2025 06:17:34 +0000 (23:17 -0700)
Port better ancient platforms where OFF_T_MAX is only 2**31 - 1,
but some devices have more than that many bytes.
* src/copy-file-data.c (copy_file_data): Byte count is now
count_t, not off_t.  All callers changed.  Since we need to check
for overflow anyway, also check for too-small calls to fadvise.

src/copy-file-data.c
src/copy.c
src/copy.h

index 3a139689dea2b69e76404cca3dc869b949aa0786..2b72492c092db2b03ce1e92b5439f7dd3c334b83 100644 (file)
@@ -493,13 +493,13 @@ infer_scantype (int fd, struct stat const *sb, off_t pos,
 /* Copy data from input file (descriptor IFD, status IST, initial file
    offset IPOS, and name INAME) to output file (OFD, OST, OPOS, ONAME).
    Copy until IBYTES have been copied or until end of file;
-   if IBYTES is OFF_T_MAX that suffices to copy to end of file.
+   if IBYTES is COUNT_MAX that suffices to copy to end of file.
    Respect copy options X's sparse_mode and reflink_mode settings.
    Read and update *DEBUG as needed.  */
 bool
 copy_file_data (int ifd, struct stat const *ist, off_t ipos, char const *iname,
                 int ofd, struct stat const *ost, off_t opos, char const *oname,
-                off_t ibytes, struct cp_options const *x, struct copy_debug *debug)
+                count_t ibytes, struct cp_options const *x, struct copy_debug *debug)
 {
   /* Choose a suitable buffer size; it may be adjusted later.  */
   size_t buf_size = io_blksize (ost);
@@ -518,7 +518,11 @@ copy_file_data (int ifd, struct stat const *ist, off_t ipos, char const *iname,
            || (x->sparse_mode == SPARSE_AUTO
                && scantype != PLAIN_SCANTYPE)));
 
-  fdadvise (ifd, ipos, ibytes, FADVISE_SEQUENTIAL);
+  /* Don't bother calling fadvise for small copies, as it is not
+     likely to help performance and might even hurt it.  */
+  if (IO_BUFSIZE < ibytes)
+    fdadvise (ifd, ipos, ibytes <= OFF_T_MAX - ipos ? ibytes : 0,
+              FADVISE_SEQUENTIAL);
 
   /* If not making a sparse file, try to use a more-efficient
      buffer size.  */
index e9bfff9420071f4f9cde5695583e46308e686fcb..9d9a0079e631d423c29fbfec2bce1c0d13fb66bf 100644 (file)
@@ -1048,7 +1048,7 @@ copy_reg (char const *src_name, char const *dst_name,
     {
       return_val = copy_file_data (source_desc, &src_open_sb, 0, src_name,
                                    dest_desc, &sb, 0, dst_name,
-                                   OFF_T_MAX, x, &copy_debug);
+                                   COUNT_MAX, x, &copy_debug);
       if (!return_val)
         goto close_src_and_dst_desc;
     }
index ccb00d80736f4bde36030e8b9470defc05e70cd6..5b7af32f7643b9d031879e3dd44e710c6646d7f2 100644 (file)
@@ -321,6 +321,11 @@ struct copy_debug
   enum copy_debug_val sparse_detection;
 };
 
+/* The type of a large counter.  Although it is always nonnegative,
+   it is signed to help signed overflow checking catch any bugs.  */
+typedef intmax_t count_t;
+#define COUNT_MAX INTMAX_MAX
+
 bool copy (char const *src_name, char const *dst_name,
            int dst_dirfd, char const *dst_relname,
            int nonexistent_dst, const struct cp_options *options,
@@ -331,7 +336,7 @@ bool copy_file_data (int ifd, struct stat const *ist, off_t ipos,
                      char const *iname,
                      int ofd, struct stat const *ost, off_t opos,
                      char const *oname,
-                     off_t ibytes, struct cp_options const *x,
+                     count_t ibytes, struct cp_options const *x,
                      struct copy_debug *copy_debug)
   _GL_ATTRIBUTE_NONNULL ((2, 4, 6, 8, 10, 11));