]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
split: tune for when creating output files
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 4 Mar 2023 21:40:28 +0000 (13:40 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 4 Mar 2023 22:49:46 +0000 (14:49 -0800)
* src/split.c (create): Avoid fstat + ftruncate in the usual case
where the output file does not already exist, by trying
to create it with O_EXCL first.  This costs a failed open
in the unusual case where the output file already exists,
but that’s OK.

src/split.c

index 8550ef442036bc7caa426b6b82a8aedb92cfcf1b..cc581b6c65651416563e67f4d7a5ac547d235a31 100644 (file)
@@ -459,7 +459,11 @@ create (char const *name)
       if (verbose)
         fprintf (stdout, _("creating file %s\n"), quoteaf (name));
 
-      int fd = open (name, O_WRONLY | O_CREAT | O_BINARY, MODE_RW_UGO);
+      int oflags = O_WRONLY | O_CREAT | O_BINARY;
+      int fd = open (name, oflags | O_EXCL, MODE_RW_UGO);
+      if (0 <= fd || errno != EEXIST)
+        return fd;
+      fd = open (name, oflags, MODE_RW_UGO);
       if (fd < 0)
         return fd;
       struct stat out_stat_buf;
@@ -468,8 +472,10 @@ create (char const *name)
       if (SAME_INODE (in_stat_buf, out_stat_buf))
         die (EXIT_FAILURE, 0, _("%s would overwrite input; aborting"),
              quoteaf (name));
-      if (ftruncate (fd, 0) != 0
-          && (S_ISREG (out_stat_buf.st_mode) || S_TYPEISSHM (&out_stat_buf)))
+      bool regularish
+        = S_ISREG (out_stat_buf.st_mode) || S_TYPEISSHM (&out_stat_buf);
+      if (! (regularish && out_stat_buf.st_size == 0)
+          && ftruncate (fd, 0) < 0 && regularish)
         die (EXIT_FAILURE, errno, _("%s: error truncating"), quotef (name));
 
       return fd;