diff options
author | Pádraig Brady <P@draigBrady.com> | 2012-06-22 09:32:34 +0100 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2012-06-22 11:34:21 +0100 |
commit | ae5846448f73d90ba9bd01cc9edc94bc0b168e46 (patch) | |
tree | 86d73149007b304586c0d8604ab39d0436528089 /src | |
parent | 30a604e631291b80b9812e03e0f325489ae0d77e (diff) | |
download | coreutils-ae5846448f73d90ba9bd01cc9edc94bc0b168e46.tar.xz |
split: ensure output doesn't overwrite input
* src/split.c (create): Check if output file is the
same inode as the input file.
* tests/split/guard-input: New test case.
* tests/Makefile.am: Reference new test case.
* NEWS: Mention the fix.
Improved-by: Jim Meyering
Reported-by: François Pinard
Diffstat (limited to 'src')
-rw-r--r-- | src/split.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/src/split.c b/src/split.c index 46d2511ae..7ba743cb0 100644 --- a/src/split.c +++ b/src/split.c @@ -92,6 +92,9 @@ static char const *additional_suffix; /* Name of input file. May be "-". */ static char *infile; +/* stat buf for input file. */ +static struct stat in_stat_buf; + /* Descriptor on which output file is open. */ static int output_desc = -1; @@ -362,7 +365,20 @@ create (const char *name) { if (verbose) fprintf (stdout, _("creating file %s\n"), quote (name)); - return open (name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, MODE_RW_UGO); + + int fd = open (name, O_WRONLY | O_CREAT | O_BINARY, MODE_RW_UGO); + if (fd < 0) + return fd; + struct stat out_stat_buf; + if (fstat (fd, &out_stat_buf) != 0) + error (EXIT_FAILURE, errno, _("failed to stat %s"), quote (name)); + if (SAME_INODE (in_stat_buf, out_stat_buf)) + error (EXIT_FAILURE, 0, _("%s would overwrite input; aborting"), + quote (name)); + if (ftruncate (fd, 0) != 0) + error (EXIT_FAILURE, errno, _("%s: error truncating"), quote (name)); + + return fd; } else { @@ -1057,7 +1073,6 @@ parse_chunk (uintmax_t *k_units, uintmax_t *n_units, char *slash) int main (int argc, char **argv) { - struct stat stat_buf; enum Split_type split_type = type_undef; size_t in_blk_size = 0; /* optimal block size of input file device */ char *buf; /* file i/o buffer */ @@ -1334,16 +1349,16 @@ main (int argc, char **argv) /* Get the optimal block size of input device and make a buffer. */ - if (fstat (STDIN_FILENO, &stat_buf) != 0) + if (fstat (STDIN_FILENO, &in_stat_buf) != 0) error (EXIT_FAILURE, errno, "%s", infile); if (in_blk_size == 0) - in_blk_size = io_blksize (stat_buf); + in_blk_size = io_blksize (in_stat_buf); if (split_type == type_chunk_bytes || split_type == type_chunk_lines) { off_t input_offset = lseek (STDIN_FILENO, 0, SEEK_CUR); - if (usable_st_size (&stat_buf)) - file_size = stat_buf.st_size; + if (usable_st_size (&in_stat_buf)) + file_size = in_stat_buf.st_size; else if (0 <= input_offset) { file_size = lseek (STDIN_FILENO, 0, SEEK_END); |