summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2023-03-04 13:40:28 -0800
committerPaul Eggert <eggert@cs.ucla.edu>2023-03-04 14:49:46 -0800
commit8022874d1242f3b094b6bd001e83845e289d2bb1 (patch)
tree5cc1713dda09c25a301faff6d6af4fdb983ecd68
parent788654dd82ec204ccdcb84cc20c7595d20a5e5a1 (diff)
downloadcoreutils-8022874d1242f3b094b6bd001e83845e289d2bb1.tar.gz
split: tune for when creating output files
* 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.
-rw-r--r--src/split.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/src/split.c b/src/split.c
index 8550ef442..cc581b6c6 100644
--- a/src/split.c
+++ b/src/split.c
@@ -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;