]> git.ipfire.org Git - thirdparty/tar.git/commitdiff
Prefer other types to int in buffer.c
authorPaul Eggert <eggert@cs.ucla.edu>
Fri, 1 Nov 2024 16:40:36 +0000 (09:40 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 2 Nov 2024 06:47:23 +0000 (23:47 -0700)
This increases the volume number maximum from 2**31 - 1 to 2**63 - 1.
* src/buffer.c (record_index, inhibit_map, new_volume):
Prefer bool to int for booleans.
* src/buffer.c (volno, global_volno):
* src/system.c (sys_exec_info_script):
Prefer intmax_t to int.
* src/buffer.c (increase_volume_number): Omit by-hand check for
overflow that relied on undefined behavior.
(new_volume): Check for that overflow here instead, without
relying on undefined behavior.
(print_stats): Avoid undefined behavior if printf sums overflow,
and reliably treat printf error like overflow.
* src/common.h (add_printf): New inline function.

src/buffer.c
src/common.h
src/system.c

index 25f0b17ec17c0e81565557427848ac1eb2dd5da7..7cadbde0c5d371c0f6c141b3e8662d650bc8f405 100644 (file)
@@ -46,7 +46,7 @@ enum { READ_ERROR_MAX = 10 };
 static tarlong prev_written;    /* bytes written on previous volumes */
 static tarlong bytes_written;   /* bytes written on this volume */
 static void *record_buffer[2];  /* allocated memory */
-static int record_index;
+static bool record_index;
 
 /* FIXME: The following variables should ideally be static to this
    module.  However, this cannot be done yet.  The cleanup continues!  */
@@ -101,10 +101,10 @@ off_t continued_file_size;
 off_t continued_file_offset;
 
 \f
-static int volno = 1;           /* which volume of a multi-volume tape we're
+static intmax_t volno = 1;     /* which volume of a multi-volume tape we're
                                    on */
-static int global_volno = 1;    /* volume number to print in external
-                                   messages */
+static intmax_t global_volno = 1; /* volume number to print in external
+                                     messages */
 
 bool write_archive_to_stdout;
 
@@ -142,7 +142,7 @@ static struct bufmap *bufmap_head, *bufmap_tail;
 
 /* This variable, when set, inhibits updating the bufmap chain after
    a write.  This is necessary when writing extended POSIX headers. */
-static int inhibit_map;
+static bool inhibit_map;
 
 void
 mv_begin_write (const char *file_name, off_t totsize, off_t sizeleft)
@@ -391,9 +391,8 @@ next_decompress_program (int *pstate)
 static const char *
 compress_option (enum compress_type type)
 {
-  struct zip_program const *zp;
   int i = 0;
-  zp = find_zip_program (type, &i);
+  struct zip_program const *zp = find_zip_program (type, &i);
   return zp ? zp->option : NULL;
 }
 
@@ -491,30 +490,31 @@ open_compressed_archive (void)
   return archive;
 }
 \f
-static int
+static intmax_t
 print_stats (FILE *fp, const char *text, tarlong numbytes)
 {
   char abbr[LONGEST_HUMAN_READABLE + 1];
   int human_opts = human_autoscale | human_base_1024 | human_SI | human_B;
   double ulim = UINTMAX_MAX + 1.0;
 
-  int n = fprintf (fp, "%s: "TARLONG_FORMAT" (", gettext (text), numbytes);
+  intmax_t n = fprintf (fp, "%s: "TARLONG_FORMAT" (", gettext (text), numbytes);
 
   if (numbytes < ulim)
-    n += fprintf (fp, "%s", human_readable (numbytes, abbr, human_opts, 1, 1));
+    n = add_printf (n, fprintf (fp, "%s", human_readable (numbytes, abbr,
+                                                         human_opts, 1, 1)));
   else
-    n += fprintf (fp, "%g", numbytes);
+    n = add_printf (n, fprintf (fp, "%g", numbytes));
 
   if (!duration_ns)
-    n += fprintf (fp, ")");
+    n = add_printf (n, ! (fputc (')', fp) < 0));
   else
     {
       double rate = 1e9 * numbytes / duration_ns;
-      if (rate < ulim)
-       n += fprintf (fp, ", %s/s)",
-                     human_readable (rate, abbr, human_opts, 1, 1));
-      else
-       n += fprintf (fp, ", %g/s)", rate);
+      n = add_printf (n, (rate < ulim
+                         ? fprintf (fp, ", %s/s)",
+                                    human_readable (rate, abbr, human_opts,
+                                                    1, 1))
+                         : fprintf (fp, ", %g/s)", rate)));
     }
 
   return n;
@@ -525,10 +525,10 @@ print_stats (FILE *fp, const char *text, tarlong numbytes)
    EOR is a delimiter to output after each item (used only if deleting
    from the archive), EOL is a delimiter to add at the end of the output
    line. */
-int
-format_total_stats (FILE *fp, char const *const *formats, int eor, int eol)
+intmax_t
+format_total_stats (FILE *fp, char const *const *formats, char eor, char eol)
 {
-  int n;
+  intmax_t n;
 
   switch (subcommand_option)
     {
@@ -545,16 +545,15 @@ format_total_stats (FILE *fp, char const *const *formats, int eor, int eol)
         n = print_stats (fp, formats[TF_READ],
                         records_read * record_size);
 
-       fputc (eor, fp);
-       n++;
+       n = add_printf (n, ! (fputc (eor, fp) < 0));
 
-        n += print_stats (fp, formats[TF_WRITE],
-                         prev_written + bytes_written);
+       n = add_printf (n, print_stats (fp, formats[TF_WRITE],
+                                       prev_written + bytes_written));
 
        intmax_t deleted = ((records_read - records_skipped) * record_size
                            - (prev_written + bytes_written));
-       n += fprintf (fp, "%c%s: %jd", eor, gettext (formats[TF_DELETED]),
-                     deleted);
+       n = add_printf (n, fprintf (fp, "%c%s: %jd", eor,
+                                   gettext (formats[TF_DELETED]), deleted));
       }
       break;
 
@@ -569,10 +568,7 @@ format_total_stats (FILE *fp, char const *const *formats, int eor, int eol)
       abort ();
     }
   if (eol)
-    {
-      fputc (eol, fp);
-      n++;
-    }
+    n = add_printf (n, ! (fputc (eol, fp) < 0));
   return n;
 }
 
@@ -745,7 +741,7 @@ _open_archive (enum access_mode wanted_access)
 
   tar_stat_destroy (&current_stat_info);
 
-  record_index = 0;
+  record_index = false;
   init_buffer ();
 
   /* When updating the archive, we start with reading.  */
@@ -1176,7 +1172,7 @@ init_volume_number (void)
 
   if (file)
     {
-      if (fscanf (file, "%d", &global_volno) != 1
+      if (fscanf (file, "%jd", &global_volno) != 1
           || global_volno < 0)
        paxfatal (0, _("%s: contains invalid volume number"),
                  quotearg_colon (volno_file_option));
@@ -1197,7 +1193,7 @@ closeout_volume_number (void)
 
   if (file)
     {
-      fprintf (file, "%d\n", global_volno);
+      fprintf (file, "%jd\n", global_volno);
       if (ferror (file))
         write_error (volno_file_option);
       if (fclose (file) != 0)
@@ -1212,8 +1208,6 @@ static void
 increase_volume_number (void)
 {
   global_volno++;
-  if (global_volno < 0)
-    paxfatal (0, _("Volume number overflow"));
   volno++;
 }
 
@@ -1228,7 +1222,7 @@ change_tape_menu (FILE *read_file)
     {
       fputc ('\007', stderr);
       fprintf (stderr,
-               _("Prepare volume #%d for %s and hit return: "),
+               _("Prepare volume #%jd for %s and hit return: "),
                global_volno + 1, quote (*archive_name_cursor));
       fflush (stderr);
 
@@ -1318,14 +1312,17 @@ change_tape_menu (FILE *read_file)
 }
 
 /* We've hit the end of the old volume.  Close it and open the next one.
-   Return nonzero on success.
+   Return true on success.
 */
 static bool
 new_volume (enum access_mode mode)
 {
   static FILE *read_file;
-  static int looped;
-  int prompt;
+  static bool looped;
+  bool prompt;
+
+  if (global_volno == INTMAX_MAX)
+    paxfatal (0, _("Volume number overflow"));
 
   if (!read_file && !info_script_option)
     /* FIXME: if fopen is used, it will never be closed.  */
@@ -1348,7 +1345,7 @@ new_volume (enum access_mode mode)
   if (archive_name_cursor == archive_name_array + archive_names)
     {
       archive_name_cursor = archive_name_array;
-      looped = 1;
+      looped = true;
     }
   prompt = looped;
 
@@ -1361,7 +1358,7 @@ new_volume (enum access_mode mode)
         {
           if (volno_file_option)
             closeout_volume_number ();
-          if (sys_exec_info_script (archive_name_cursor, global_volno+1))
+         if (sys_exec_info_script (archive_name_cursor, global_volno + 1))
            paxfatal (0, _("%s command failed"), quote (info_script_option));
         }
       else
@@ -1402,7 +1399,7 @@ new_volume (enum access_mode mode)
       open_warn (*archive_name_cursor);
       if (!verify_option && mode == ACCESS_WRITE && backup_option)
         undo_last_backup ();
-      prompt = 1;
+      prompt = true;
       goto tryagain;
     }
 
@@ -1697,8 +1694,8 @@ add_volume_label (void)
 {
   static char const VOL_SUFFIX[] = "Volume";
   char *s = xmalloc (strlen (volume_label_option) + sizeof VOL_SUFFIX
-                    + INT_BUFSIZE_BOUND (int) + 2);
-  sprintf (s, "%s %s %d", volume_label_option, VOL_SUFFIX, volno);
+                    + INT_BUFSIZE_BOUND (intmax_t) + 2);
+  sprintf (s, "%s %s %jd", volume_label_option, VOL_SUFFIX, volno);
   _write_volume_label (s);
   free (s);
 }
@@ -1941,7 +1938,7 @@ _gnu_flush_write (idx_t buffer_level)
   record_index = !record_index;
   init_buffer ();
 
-  inhibit_map = 1;
+  inhibit_map = true;
 
   if (volume_label_option)
     add_volume_label ();
@@ -1957,7 +1954,7 @@ _gnu_flush_write (idx_t buffer_level)
   header = find_next_block ();
   bufmap_reset (map, header - record_start);
   bufsize = available_space_after (header);
-  inhibit_map = 0;
+  inhibit_map = false;
   while (bufsize < copy_size)
     {
       memcpy (header->buffer, copy_ptr, bufsize);
index e8e94bde9732ac422411f93795fa8f2b10f36ee6..0d5e7d6c104e446cea5e097f6b23cb1eda4afe1c 100644 (file)
@@ -466,7 +466,8 @@ off_t seek_archive (off_t size);
 void set_start_time (void);
 
 enum { TF_READ, TF_WRITE, TF_DELETED };
-int format_total_stats (FILE *fp, char const *const *formats, int eor, int eol);
+intmax_t format_total_stats (FILE *fp, char const *const *formats,
+                            char eor, char eol);
 void print_total_stats (void);
 
 void mv_begin_write (const char *file_name, off_t totsize, off_t sizeleft);
@@ -480,6 +481,15 @@ void buffer_write_global_xheader (void);
 const char *first_decompress_program (int *pstate);
 const char *next_decompress_program (int *pstate);
 
+/* Sum values returned by printf to estimate the total bytes output.
+   Estimate -1 if there was a problem, e.g., int overflow or I/O error.  */
+COMMON_INLINE intmax_t
+add_printf (intmax_t a, intmax_t b)
+{
+  intmax_t sum;
+  return (a < 0) | (b < 0) | ckd_add (&sum, a, b) ? -1 : sum;
+}
+
 /* Module create.c.  */
 
 enum dump_status
@@ -925,7 +935,7 @@ idx_t sys_write_archive_buffer (void);
 bool sys_get_archive_stat (void);
 int sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st);
 void sys_wait_command (void);
-int sys_exec_info_script (const char **archive_name, int volume_number);
+int sys_exec_info_script (const char **archive_name, intmax_t volume_number);
 void sys_exec_checkpoint_script (const char *script_name,
                                 const char *archive_name,
                                 intmax_t checkpoint_number);
index 208917848b7a37df0c6dad0ade1b7eb1e5eee7ac..eaca1824f32af3003782f2f286702d0ce72f9008 100644 (file)
@@ -807,7 +807,7 @@ sys_wait_command (void)
 }
 
 int
-sys_exec_info_script (const char **archive_name, int volume_number)
+sys_exec_info_script (const char **archive_name, intmax_t volume_number)
 {
   int p[2];
   static void (*saved_handler) (int sig);