]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
shred,sort,split: fix ftruncate error reporting
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 15 Dec 2018 20:13:58 +0000 (12:13 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 15 Dec 2018 20:14:49 +0000 (12:14 -0800)
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
src/sort.c
src/split.c

index 270b1e942fd3bfc605a8cffa4a73031e28b6bc6c..3a6510cf365e296a6a1edcd26426afc0d8d1670e 100644 (file)
@@ -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;
index dd6bce47fd26e69ddccf1395d5c882e3409266f1..ebe86d3fbb867091df0b1d5932a70be82e2f6d41 100644 (file)
@@ -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)
index 60c14d36c1353fe181b3c5986fb216e140a1d30a..1431bdf654607b523740b71839f49d5e3a82ee2b 100644 (file)
@@ -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;