summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2012-06-22 09:32:34 +0100
committerPádraig Brady <P@draigBrady.com>2012-06-22 11:34:21 +0100
commitae5846448f73d90ba9bd01cc9edc94bc0b168e46 (patch)
tree86d73149007b304586c0d8604ab39d0436528089 /src
parent30a604e631291b80b9812e03e0f325489ae0d77e (diff)
downloadcoreutils-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.c27
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);