sort: fix hang with sort --compress
[platform/upstream/coreutils.git] / src / truncate.c
index 08090ab..faa83f1 100644 (file)
@@ -129,8 +129,8 @@ SIZE may also be prefixed by one of the following modifying characters:\n\
   exit (status);
 }
 
-/* return 1 on error, 0 on success */
-static int
+/* return true on success, false on error.  */
+static bool
 do_ftruncate (int fd, char const *fname, off_t ssize, off_t rsize,
               rel_mode_t rel_mode)
 {
@@ -140,7 +140,7 @@ do_ftruncate (int fd, char const *fname, off_t ssize, off_t rsize,
   if ((block_mode || (rel_mode && rsize < 0)) && fstat (fd, &sb) != 0)
     {
       error (0, errno, _("cannot fstat %s"), quote (fname));
-      return 1;
+      return false;
     }
   if (block_mode)
     {
@@ -152,7 +152,7 @@ do_ftruncate (int fd, char const *fname, off_t ssize, off_t rsize,
                    " * %" PRIdMAX " byte blocks for file %s"),
                  (intmax_t) ssize, (intmax_t) blksize,
                  quote (fname));
-          return 1;
+          return false;
         }
       ssize *= blksize;
     }
@@ -160,21 +160,21 @@ do_ftruncate (int fd, char const *fname, off_t ssize, off_t rsize,
     {
       uintmax_t const fsize = rsize < 0 ? sb.st_size : rsize;
 
-      if (rsize < 0 && sb.st_size < 0)
+      if (rsize < 0) /* fstat used above to get size.  */
         {
-          /* Complain only for a regular file, a directory,
-             or a shared memory object, as POSIX 1003.1-2004 specifies
-             ftruncate's behavior only for these file types.  */
-          if (S_ISREG (sb.st_mode) || S_ISDIR (sb.st_mode)
-              || S_TYPEISSHM (&sb))
+          if (!S_ISREG (sb.st_mode) && !S_TYPEISSHM (&sb))
+            {
+              error (0, 0, _("cannot get the size of %s"), quote (fname));
+              return false;
+            }
+          if (sb.st_size < 0)
             {
-              /* overflow is the only reason I can think
-                 this would ever go negative for the above types */
+              /* Sanity check. Overflow is the only reason I can think
+                 this would ever go negative. */
               error (0, 0, _("%s has unusable, apparently negative size"),
                      quote (fname));
-              return 1;
+              return false;
             }
-          return 0;
         }
 
       if (rel_mode == rm_min)
@@ -193,7 +193,7 @@ do_ftruncate (int fd, char const *fname, off_t ssize, off_t rsize,
             {
               error (0, 0, _("overflow rounding up size of file %s"),
                      quote (fname));
-              return 1;
+              return false;
             }
           nsize = overflow;
         }
@@ -203,7 +203,7 @@ do_ftruncate (int fd, char const *fname, off_t ssize, off_t rsize,
             {
               error (0, 0, _("overflow extending size of file %s"),
                      quote (fname));
-              return 1;
+              return false;
             }
           nsize = fsize + ssize;
         }
@@ -215,40 +215,25 @@ do_ftruncate (int fd, char const *fname, off_t ssize, off_t rsize,
 
   if (ftruncate (fd, nsize) == -1)      /* note updates mtime & ctime */
     {
-      /* Complain only when ftruncate fails on a regular file, a
-         directory, or a shared memory object, as POSIX 1003.1-2004
-         specifies ftruncate's behavior only for these file types.
-         For example, do not complain when Linux kernel 2.4 ftruncate
-         fails on /dev/fd0.  */
-      int const ftruncate_errno = errno;
-      if (fstat (fd, &sb) != 0)
-        {
-          error (0, errno, _("cannot fstat %s"), quote (fname));
-          return 1;
-        }
-      else if (S_ISREG (sb.st_mode) || S_ISDIR (sb.st_mode)
-               || S_TYPEISSHM (&sb))
-        {
-          error (0, ftruncate_errno,
-                 _("truncating %s at %" PRIdMAX " bytes"), quote (fname),
-                 (intmax_t) nsize);
-          return 1;
-        }
-      return 0;
+      error (0, errno,
+             _("failed to truncate %s at %" PRIdMAX " bytes"), quote (fname),
+             (intmax_t) nsize);
+      return false;
     }
 
-  return 0;
+  return true;
 }
 
 int
 main (int argc, char **argv)
 {
   bool got_size = false;
-  off_t size IF_LINT (= 0);
+  bool errors = false;
+  off_t size IF_LINT ( = 0);
   off_t rsize = -1;
   rel_mode_t rel_mode = rm_abs;
   mode_t omode;
-  int c, errors = 0, fd = -1, oflags;
+  int c, fd = -1, oflags;
   char const *fname;
 
   initialize_main (&argc, &argv);
@@ -362,9 +347,13 @@ main (int argc, char **argv)
 
   if (ref_file)
     {
+      /* FIXME: Maybe support getting size of block devices.  */
       struct stat sb;
       if (stat (ref_file, &sb) != 0)
         error (EXIT_FAILURE, errno, _("cannot stat %s"), quote (ref_file));
+      if (!S_ISREG (sb.st_mode) && !S_TYPEISSHM (&sb))
+        error (EXIT_FAILURE, 0, _("cannot get the size of %s"),
+               quote (ref_file));
       if (!got_size)
         size = sb.st_size;
       else
@@ -384,20 +373,9 @@ main (int argc, char **argv)
              `truncate -s0 .` should gen EISDIR error */
           if (!(no_create && errno == ENOENT))
             {
-              int const open_errno = errno;
-              struct stat sb;
-              if (stat (fname, &sb) == 0)
-                {
-                  /* Complain only for a regular file, a directory,
-                     or a shared memory object, as POSIX 1003.1-2004 specifies
-                     ftruncate's behavior only for these file types.  */
-                  if (!S_ISREG (sb.st_mode) && !S_ISDIR (sb.st_mode)
-                      && !S_TYPEISSHM (&sb))
-                    continue;
-                }
-              error (0, open_errno, _("cannot open %s for writing"),
+              error (0, errno, _("cannot open %s for writing"),
                      quote (fname));
-              errors++;
+              errors = true;
             }
           continue;
         }
@@ -405,11 +383,11 @@ main (int argc, char **argv)
 
       if (fd != -1)
         {
-          errors += do_ftruncate (fd, fname, size, rsize, rel_mode);
+          errors |= !do_ftruncate (fd, fname, size, rsize, rel_mode);
           if (close (fd) != 0)
             {
               error (0, errno, _("closing %s"), quote (fname));
-              errors++;
+              errors = true;
             }
         }
     }