>From 5af28df87d7af0736b2ad5e09ae6b3784f6af3af Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 15 Dec 2018 12:13:58 -0800 Subject: [PATCH] shred,sort,split: fix ftruncate error reporting Problem reported for split by Scott Worley (Bug#33761): * src/shred.c (do_wipefd): Also report an error if ftruncate fails on a shared memory object. * src/sort.c (get_outstatus): New function. (stream_open, avoid_trashing_input): Use it. * src/sort.c (stream_open): * src/split.c (create): If ftruncate fails, do not report an error unless it is a regular file or a shared memory object. --- src/shred.c | 10 ++++++---- src/sort.c | 39 ++++++++++++++++++++++++++------------- src/split.c | 3 ++- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/shred.c b/src/shred.c index 270b1e942..3a6510cf3 100644 --- a/src/shred.c +++ b/src/shred.c @@ -975,11 +975,13 @@ do_wipefd (int fd, char const *qname, struct randint_source *s, } } - /* Now deallocate the data. The effect of ftruncate on - non-regular files is unspecified, so don't worry about any - errors reported for them. */ + /* Now deallocate the data. The effect of ftruncate is specified + on regular files and shared memory objects (also directories, but + they are not possible here); don't worry about errors reported + for other file types. */ + if (flags->remove_file && ftruncate (fd, 0) != 0 - && S_ISREG (st.st_mode)) + && (S_ISREG (st.st_mode) || S_TYPEISSHM (&st))) { error (0, errno, _("%s: error truncating"), qname); ok = false; diff --git a/src/sort.c b/src/sort.c index dd6bce47f..ebe86d3fb 100644 --- a/src/sort.c +++ b/src/sort.c @@ -895,8 +895,21 @@ create_temp_file (int *pfd, bool survive_fd_exhaustion) return node; } -/* Return a stream for FILE, opened with mode HOW. A null FILE means - standard output; HOW should be "w". When opening for input, "-" +/* Return a pointer to stdout status, or NULL on failure. */ + +static struct stat * +get_outstatus (void) +{ + static int outstat_errno; + static struct stat outstat; + if (outstat_errno == 0) + outstat_errno = fstat (STDOUT_FILENO, &outstat) == 0 ? -1 : errno; + return outstat_errno < 0 ? &outstat : NULL; +} + +/* Return a stream for FILE, opened with mode HOW. If HOW is "w", + the file is already open on standard output, and needs to be + truncated unless FILE is null. When opening for input, "-" means standard input. To avoid confusion, do not return file descriptors STDIN_FILENO, STDOUT_FILENO, or STDERR_FILENO when opening an ordinary FILE. Return NULL if unsuccessful. @@ -964,8 +977,13 @@ stream_open (char const *file, char const *how) else if (*how == 'w') { if (file && ftruncate (STDOUT_FILENO, 0) != 0) - die (SORT_FAILURE, errno, _("%s: error truncating"), - quotef (file)); + { + int ftruncate_errno = errno; + struct stat *outst = get_outstatus (); + if (!outst || S_ISREG (outst->st_mode) || S_TYPEISSHM (outst)) + die (SORT_FAILURE, ftruncate_errno, _("%s: error truncating"), + quotef (file)); + } fp = stdout; } else @@ -3699,8 +3717,6 @@ static void avoid_trashing_input (struct sortfile *files, size_t ntemps, size_t nfiles, char const *outfile) { - bool got_outstat = false; - struct stat outstat; struct tempnode *tempcopy = NULL; for (size_t i = ntemps; i < nfiles; i++) @@ -3713,18 +3729,15 @@ avoid_trashing_input (struct sortfile *files, size_t ntemps, same = true; else { - if (! got_outstat) - { - if (fstat (STDOUT_FILENO, &outstat) != 0) - break; - got_outstat = true; - } + struct stat *outst = get_outstatus (); + if (!outst) + break; same = (((is_stdin ? fstat (STDIN_FILENO, &instat) : stat (files[i].name, &instat)) == 0) - && SAME_INODE (instat, outstat)); + && SAME_INODE (instat, *outst)); } if (same) diff --git a/src/split.c b/src/split.c index 60c14d36c..1431bdf65 100644 --- a/src/split.c +++ b/src/split.c @@ -470,7 +470,8 @@ create (const char *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) + if (ftruncate (fd, 0) != 0 + && (S_ISREG (out_stat_buf.st_mode) || S_TYPEISSHM (&out_stat_buf))) die (EXIT_FAILURE, errno, _("%s: error truncating"), quotef (name)); return fd; -- 2.17.1