]> Dogcows Code - chaz/tar/blobdiff - src/incremen.c
Relicense under GPLv3
[chaz/tar] / src / incremen.c
index bc8128f3c259e1d884400b199ee882c18f88359e..4400008a87787eb172c958e35abcb6ecd411d563 100644 (file)
@@ -1,11 +1,11 @@
 /* GNU dump extensions to tar.
 
    Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
 /* GNU dump extensions to tar.
 
    Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
-   2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 2, or (at your option) any later
+   Free Software Foundation; either version 3, or (at your option) any later
    version.
 
    This program is distributed in the hope that it will be useful, but
    version.
 
    This program is distributed in the hope that it will be useful, but
@@ -46,7 +46,7 @@ enum children
 #define DIR_IS_FOUND(d) ((d)->flags & DIRF_FOUND)
 #define DIR_IS_NEW(d) ((d)->flags & DIRF_NEW)
 #define DIR_IS_RENAMED(d) ((d)->flags & DIRF_RENAMED)
 #define DIR_IS_FOUND(d) ((d)->flags & DIRF_FOUND)
 #define DIR_IS_NEW(d) ((d)->flags & DIRF_NEW)
 #define DIR_IS_RENAMED(d) ((d)->flags & DIRF_RENAMED)
-                      
+
 #define DIR_SET_FLAG(d,f) (d)->flags |= (f)
 #define DIR_CLEAR_FLAG(d,f) (d)->flags &= ~(f)
 
 #define DIR_SET_FLAG(d,f) (d)->flags |= (f)
 #define DIR_CLEAR_FLAG(d,f) (d)->flags &= ~(f)
 
@@ -127,7 +127,7 @@ make_directory (const char *name)
     directory->name[namelen-1] = 0;
   return directory;
 }
     directory->name[namelen-1] = 0;
   return directory;
 }
-  
+
 /* Create and link a new directory entry for directory NAME, having a
    device number DEV and an inode number INO, with NFS indicating
    whether it is an NFS device and FOUND indicating whether we have
 /* Create and link a new directory entry for directory NAME, having a
    device number DEV and an inode number INO, with NFS indicating
    whether it is an NFS device and FOUND indicating whether we have
@@ -154,7 +154,7 @@ note_directory (char const *name, struct timespec mtime,
     }
   else
     directory->contents = NULL;
     }
   else
     directory->contents = NULL;
-  
+
   if (! ((directory_table
          || (directory_table = hash_initialize (0, 0,
                                                 hash_directory_name,
   if (! ((directory_table
          || (directory_table = hash_initialize (0, 0,
                                                 hash_directory_name,
@@ -211,7 +211,7 @@ void
 update_parent_directory (const char *name)
 {
   struct directory *directory;
 update_parent_directory (const char *name)
 {
   struct directory *directory;
-  char *p, *name_buffer;
+  char *p;
 
   p = dir_name (name);
   directory = find_directory (p);
 
   p = dir_name (name);
   directory = find_directory (p);
@@ -234,13 +234,12 @@ procdir (char *name_buffer, struct stat *stat_data,
 {
   struct directory *directory;
   bool nfs = NFS_FILE_STAT (*stat_data);
 {
   struct directory *directory;
   bool nfs = NFS_FILE_STAT (*stat_data);
-  struct name *np;
 
   if ((directory = find_directory (name_buffer)) != NULL)
     {
       if (DIR_IS_INITED (directory))
        return directory;
 
   if ((directory = find_directory (name_buffer)) != NULL)
     {
       if (DIR_IS_INITED (directory))
        return directory;
-      
+
       /* With NFS, the same file can have two different devices
         if an NFS directory is mounted in multiple locations,
         which is relatively common when automounting.
       /* With NFS, the same file can have two different devices
         if an NFS directory is mounted in multiple locations,
         which is relatively common when automounting.
@@ -279,7 +278,7 @@ procdir (char *name_buffer, struct stat *stat_data,
        }
       else
        directory->children = CHANGED_CHILDREN;
        }
       else
        directory->children = CHANGED_CHILDREN;
-      
+
       DIR_SET_FLAG (directory, DIRF_FOUND);
     }
   else
       DIR_SET_FLAG (directory, DIRF_FOUND);
     }
   else
@@ -311,7 +310,7 @@ procdir (char *name_buffer, struct stat *stat_data,
          if (verbose)
            WARN ((0, 0, _("%s: Directory is new"),
                   quotearg_colon (name_buffer)));
          if (verbose)
            WARN ((0, 0, _("%s: Directory is new"),
                   quotearg_colon (name_buffer)));
-         directory->children = 
+         directory->children =
            (listed_incremental_option
             || (OLDER_STAT_TIME (*stat_data, m)
                 || (after_date_option
            (listed_incremental_option
             || (OLDER_STAT_TIME (*stat_data, m)
                 || (after_date_option
@@ -327,11 +326,11 @@ procdir (char *name_buffer, struct stat *stat_data,
       /* ... except if it was explicitely given in the command line */
       && !is_individual_file (name_buffer))
     directory->children = NO_CHILDREN;
       /* ... except if it was explicitely given in the command line */
       && !is_individual_file (name_buffer))
     directory->children = NO_CHILDREN;
-  else if (children == ALL_CHILDREN) 
+  else if (children == ALL_CHILDREN)
     directory->children = ALL_CHILDREN;
 
   DIR_SET_FLAG (directory, DIRF_INIT);
     directory->children = ALL_CHILDREN;
 
   DIR_SET_FLAG (directory, DIRF_INIT);
-  
+
   return directory;
 }
 
   return directory;
 }
 
@@ -344,7 +343,7 @@ dumpdir_locate (const char *dump, const char *name)
     while (*dump)
       {
        /* Ignore 'R' (rename) and 'X' (tempname) entries, since they break
     while (*dump)
       {
        /* Ignore 'R' (rename) and 'X' (tempname) entries, since they break
-          alphabetical ordering. 
+          alphabetical ordering.
           They normally do not occur in dumpdirs from the snapshot files,
           but this function is also used by purge_directory, which operates
           on a dumpdir from the archive, hence the need for this test. */
           They normally do not occur in dumpdirs from the snapshot files,
           but this function is also used by purge_directory, which operates
           on a dumpdir from the archive, hence the need for this test. */
@@ -379,7 +378,9 @@ dumpdir_size (const char *p)
 static int
 compare_dirnames (const void *first, const void *second)
 {
 static int
 compare_dirnames (const void *first, const void *second)
 {
-  return strcmp (*(const char**)first, *(const char**)second);
+  char const *const *name1 = first;
+  char const *const *name2 = second;
+  return strcmp (*name1, *name2);
 }
 
 /* Compare dumpdir array from DIRECTORY with directory listing DIR and
 }
 
 /* Compare dumpdir array from DIRECTORY with directory listing DIR and
@@ -388,7 +389,7 @@ compare_dirnames (const void *first, const void *second)
    DIR must be returned by a previous call to savedir().
 
    File names in DIRECTORY->contents must be sorted
    DIR must be returned by a previous call to savedir().
 
    File names in DIRECTORY->contents must be sorted
-   alphabetically. 
+   alphabetically.
 
    DIRECTORY->contents is replaced with the created template. Each entry is
    prefixed with ' ' if it was present in DUMP and with 'Y' otherwise. */
 
    DIRECTORY->contents is replaced with the created template. Each entry is
    prefixed with ' ' if it was present in DUMP and with 'Y' otherwise. */
@@ -462,7 +463,7 @@ scan_directory (char *dir_name, dev_t device)
   size_t name_length;          /* used length in name_buffer */
   struct stat stat_data;
   struct directory *directory;
   size_t name_length;          /* used length in name_buffer */
   struct stat stat_data;
   struct directory *directory;
-  
+
   if (! dirp)
     savedir_error (dir_name);
 
   if (! dirp)
     savedir_error (dir_name);
 
@@ -476,7 +477,7 @@ scan_directory (char *dir_name, dev_t device)
   if (deref_stat (dereference_option, name_buffer, &stat_data))
     {
       stat_diag (name_buffer);
   if (deref_stat (dereference_option, name_buffer, &stat_data))
     {
       stat_diag (name_buffer);
-      /* FIXME: used to be 
+      /* FIXME: used to be
            children = CHANGED_CHILDREN;
         but changed to: */
       free (name_buffer);
            children = CHANGED_CHILDREN;
         but changed to: */
       free (name_buffer);
@@ -485,7 +486,7 @@ scan_directory (char *dir_name, dev_t device)
     }
 
   directory = procdir (name_buffer, &stat_data, device, NO_CHILDREN, false);
     }
 
   directory = procdir (name_buffer, &stat_data, device, NO_CHILDREN, false);
-    
+
   if (dirp && directory->children != NO_CHILDREN)
     {
       char  *entry;    /* directory entry being scanned */
   if (dirp && directory->children != NO_CHILDREN)
     {
       char  *entry;    /* directory entry being scanned */
@@ -505,7 +506,7 @@ scan_directory (char *dir_name, dev_t device)
              name_buffer = xrealloc (name_buffer, name_buffer_size + 2);
            }
          strcpy (name_buffer + name_length, entry + 1);
              name_buffer = xrealloc (name_buffer, name_buffer_size + 2);
            }
          strcpy (name_buffer + name_length, entry + 1);
-         
+
          if (excluded_name (name_buffer))
            *entry = 'N';
          else
          if (excluded_name (name_buffer))
            *entry = 'N';
          else
@@ -516,7 +517,7 @@ scan_directory (char *dir_name, dev_t device)
                  *entry = 'N';
                  continue;
                }
                  *entry = 'N';
                  continue;
                }
-             
+
              if (S_ISDIR (stat_data.st_mode))
                {
                  procdir (name_buffer, &stat_data, device,
              if (S_ISDIR (stat_data.st_mode))
                {
                  procdir (name_buffer, &stat_data, device,
@@ -524,15 +525,15 @@ scan_directory (char *dir_name, dev_t device)
                           verbose_option);
                  *entry = 'D';
                }
                           verbose_option);
                  *entry = 'D';
                }
-             
+
              else if (one_file_system_option && device != stat_data.st_dev)
                *entry = 'N';
 
              else if (*entry == 'Y')
                /* New entry, skip further checks */;
              else if (one_file_system_option && device != stat_data.st_dev)
                *entry = 'N';
 
              else if (*entry == 'Y')
                /* New entry, skip further checks */;
-             
+
              /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */
              /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */
-             
+
              else if (OLDER_STAT_TIME (stat_data, m)
                       && (!after_date_option
                           || OLDER_STAT_TIME (stat_data, c)))
              else if (OLDER_STAT_TIME (stat_data, m)
                       && (!after_date_option
                           || OLDER_STAT_TIME (stat_data, c)))
@@ -542,7 +543,7 @@ scan_directory (char *dir_name, dev_t device)
            }
        }
     }
            }
        }
     }
-  
+
   free (name_buffer);
   if (dirp)
     free (dirp);
   free (name_buffer);
   if (dirp)
     free (dirp);
@@ -571,12 +572,12 @@ rename_handler (void *data, void *proc_data)
 {
   struct directory *dir = data;
   struct obstack *stk = proc_data;
 {
   struct directory *dir = data;
   struct obstack *stk = proc_data;
-  
+
   if (DIR_IS_RENAMED (dir))
     {
       struct directory *prev, *p;
 
   if (DIR_IS_RENAMED (dir))
     {
       struct directory *prev, *p;
 
-      /* Detect eventual cycles and clear DIRF_RENAMED flag, so this entries
+      /* Detect eventual cycles and clear DIRF_RENAMED flag, so these entries
         are ignored when hit by this function next time.
         If the chain forms a cycle, prev points to the entry DIR is renamed
         from. In this case it still retains DIRF_RENAMED flag, which will be
         are ignored when hit by this function next time.
         If the chain forms a cycle, prev points to the entry DIR is renamed
         from. In this case it still retains DIRF_RENAMED flag, which will be
@@ -621,7 +622,7 @@ append_incremental_renames (const char *dump)
 
   if (directory_table == NULL)
     return dump;
 
   if (directory_table == NULL)
     return dump;
-  
+
   obstack_init (&stk);
   if (dump)
     {
   obstack_init (&stk);
   if (dump)
     {
@@ -630,7 +631,7 @@ append_incremental_renames (const char *dump)
     }
   else
     size = 0;
     }
   else
     size = 0;
-  
+
   hash_do_for_each (directory_table, rename_handler, &stk);
   if (obstack_object_size (&stk) != size)
     {
   hash_do_for_each (directory_table, rename_handler, &stk);
   if (obstack_object_size (&stk) != size)
     {
@@ -662,7 +663,8 @@ read_incr_db_01 (int version, const char *initbuf)
 {
   int n;
   uintmax_t u;
 {
   int n;
   uintmax_t u;
-  time_t t = u;
+  time_t sec;
+  long int nsec;
   char *buf = 0;
   size_t bufsize;
   char *ebuf;
   char *buf = 0;
   size_t bufsize;
   char *ebuf;
@@ -683,41 +685,49 @@ read_incr_db_01 (int version, const char *initbuf)
       buf = strdup (initbuf);
       bufsize = strlen (buf) + 1;
     }
       buf = strdup (initbuf);
       bufsize = strlen (buf) + 1;
     }
-  
-  t = u = (errno = 0, strtoumax (buf, &ebuf, 10));
-  if (buf == ebuf || (u == 0 && errno == EINVAL))
-    ERROR ((0, 0, "%s:%ld: %s",
+
+  sec = TYPE_MINIMUM (time_t);
+  nsec = -1;
+  errno = 0;
+  u = strtoumax (buf, &ebuf, 10);
+  if (!errno && TYPE_MAXIMUM (time_t) < u)
+    errno = ERANGE;
+  if (errno || buf == ebuf)
+    ERROR ((0, errno, "%s:%ld: %s",
            quotearg_colon (listed_incremental_option),
            lineno,
            _("Invalid time stamp")));
            quotearg_colon (listed_incremental_option),
            lineno,
            _("Invalid time stamp")));
-  else if (t != u)
-    ERROR ((0, 0, "%s:%ld: %s",
-           quotearg_colon (listed_incremental_option),
-           lineno,
-           _("Time stamp out of range")));
-  else if (version == 1)
-    {
-      newer_mtime_option.tv_sec = t;
-
-      t = u = (errno = 0, strtoumax (buf, &ebuf, 10));
-      if (buf == ebuf || (u == 0 && errno == EINVAL))
-       ERROR ((0, 0, "%s:%ld: %s",
-               quotearg_colon (listed_incremental_option),
-               lineno,
-               _("Invalid time stamp")));
-      else if (t != u)
-       ERROR ((0, 0, "%s:%ld: %s",
-               quotearg_colon (listed_incremental_option),
-               lineno,
-               _("Time stamp out of range")));
-      newer_mtime_option.tv_nsec = t;
-    }
   else
     {
   else
     {
-      /* pre-1 incremental format does not contain nanoseconds */
-      newer_mtime_option.tv_sec = t;
-      newer_mtime_option.tv_nsec = 0;
+      sec = u;
+
+      if (version == 1 && *ebuf)
+       {
+         char const *buf_ns = ebuf + 1;
+         errno = 0;
+         u = strtoumax (buf_ns, &ebuf, 10);
+         if (!errno && BILLION <= u)
+           errno = ERANGE;
+         if (errno || buf_ns == ebuf)
+           {
+             ERROR ((0, errno, "%s:%ld: %s",
+                     quotearg_colon (listed_incremental_option),
+                     lineno,
+                     _("Invalid time stamp")));
+             sec = TYPE_MINIMUM (time_t);
+           }
+         else
+           nsec = u;
+       }
+      else
+       {
+         /* pre-1 incremental format does not contain nanoseconds */
+         nsec = 0;
+       }
     }
     }
+  newer_mtime_option.tv_sec = sec;
+  newer_mtime_option.tv_nsec = nsec;
+
 
   while (0 < (n = getline (&buf, &bufsize, listed_incremental_stream)))
     {
 
   while (0 < (n = getline (&buf, &bufsize, listed_incremental_stream)))
     {
@@ -726,65 +736,79 @@ read_incr_db_01 (int version, const char *initbuf)
       bool nfs = buf[0] == '+';
       char *strp = buf + nfs;
       struct timespec mtime;
       bool nfs = buf[0] == '+';
       char *strp = buf + nfs;
       struct timespec mtime;
-      
+
       lineno++;
       lineno++;
-      
+
       if (buf[n - 1] == '\n')
        buf[n - 1] = '\0';
       if (buf[n - 1] == '\n')
        buf[n - 1] = '\0';
-      
+
       if (version == 1)
        {
          errno = 0;
       if (version == 1)
        {
          errno = 0;
-         mtime.tv_sec = u = strtoumax (strp, &ebuf, 10);
-         if (!isspace (*ebuf))
-           ERROR ((0, 0, "%s:%ld: %s",
-                   quotearg_colon (listed_incremental_option), lineno,
-                   _("Invalid modification time (seconds)")));
-         else if (mtime.tv_sec != u)
-           ERROR ((0, 0, "%s:%ld: %s",
-                   quotearg_colon (listed_incremental_option), lineno,
-                   _("Modification time (seconds) out of range")));
+         u = strtoumax (strp, &ebuf, 10);
+         if (!errno && TYPE_MAXIMUM (time_t) < u)
+           errno = ERANGE;
+         if (errno || strp == ebuf || *ebuf != ' ')
+           {
+             ERROR ((0, errno, "%s:%ld: %s",
+                     quotearg_colon (listed_incremental_option), lineno,
+                     _("Invalid modification time (seconds)")));
+             sec = (time_t) -1;
+           }
+         else
+           sec = u;
          strp = ebuf;
          strp = ebuf;
-         
+
          errno = 0;
          errno = 0;
-         mtime.tv_nsec = u = strtoumax (strp, &ebuf, 10);
-         if (!isspace (*ebuf))
-           ERROR ((0, 0, "%s:%ld: %s",
-                   quotearg_colon (listed_incremental_option), lineno,
-                   _("Invalid modification time (nanoseconds)")));
-         else if (mtime.tv_nsec != u)
-           ERROR ((0, 0, "%s:%ld: %s",
-                   quotearg_colon (listed_incremental_option), lineno,
-                   _("Modification time (nanoseconds) out of range")));
+         u = strtoumax (strp, &ebuf, 10);
+         if (!errno && BILLION <= u)
+           errno = ERANGE;
+         if (errno || strp == ebuf || *ebuf != ' ')
+           {
+             ERROR ((0, errno, "%s:%ld: %s",
+                     quotearg_colon (listed_incremental_option), lineno,
+                     _("Invalid modification time (nanoseconds)")));
+             nsec = -1;
+           }
+         else
+           nsec = u;
+         mtime.tv_sec = sec;
+         mtime.tv_nsec = nsec;
          strp = ebuf;
        }
       else
        memset (&mtime, 0, sizeof mtime);
          strp = ebuf;
        }
       else
        memset (&mtime, 0, sizeof mtime);
-      
+
       errno = 0;
       errno = 0;
-      dev = u = strtoumax (strp, &ebuf, 10);
-      if (!isspace (*ebuf))
-       ERROR ((0, 0, "%s:%ld: %s",
-               quotearg_colon (listed_incremental_option), lineno,
-               _("Invalid device number")));
-      else if (dev != u)
-       ERROR ((0, 0, "%s:%ld: %s",
-               quotearg_colon (listed_incremental_option), lineno,
-               _("Device number out of range")));
+      u = strtoumax (strp, &ebuf, 10);
+      if (!errno && TYPE_MAXIMUM (dev_t) < u)
+       errno = ERANGE;
+      if (errno || strp == ebuf || *ebuf != ' ')
+       {
+         ERROR ((0, errno, "%s:%ld: %s",
+                 quotearg_colon (listed_incremental_option), lineno,
+                 _("Invalid device number")));
+         dev = (dev_t) -1;
+       }
+      else
+       dev = u;
       strp = ebuf;
 
       errno = 0;
       strp = ebuf;
 
       errno = 0;
-      ino = u = strtoumax (strp, &ebuf, 10);
-      if (!isspace (*ebuf))
-       ERROR ((0, 0, "%s:%ld: %s",
-               quotearg_colon (listed_incremental_option), lineno,
-               _("Invalid inode number")));
-      else if (ino != u)
-       ERROR ((0, 0, "%s:%ld: %s",
-               quotearg_colon (listed_incremental_option), lineno,
-               _("Inode number out of range")));
+      u = strtoumax (strp, &ebuf, 10);
+      if (!errno && TYPE_MAXIMUM (ino_t) < u)
+       errno = ERANGE;
+      if (errno || strp == ebuf || *ebuf != ' ')
+       {
+         ERROR ((0, errno, "%s:%ld: %s",
+                 quotearg_colon (listed_incremental_option), lineno,
+                 _("Invalid inode number")));
+         ino = (ino_t) -1;
+       }
+      else
+       ino = u;
       strp = ebuf;
       strp = ebuf;
-      
+
       strp++;
       unquote_string (strp);
       note_directory (strp, mtime, dev, ino, nfs, false, NULL);
       strp++;
       unquote_string (strp);
       note_directory (strp, mtime, dev, ino, nfs, false, NULL);
@@ -811,31 +835,128 @@ read_obstack (FILE *fp, struct obstack *stk, size_t *pcount)
 }
 
 /* Read from file FP a nul-terminated string and convert it to
 }
 
 /* Read from file FP a nul-terminated string and convert it to
-   uintmax_t. Return the resulting value in PVAL.
+   intmax_t.  Return the resulting value in PVAL.  Assume '-' has
+   already been read.
+
+   Throw a fatal error if the string cannot be converted or if the
+   converted value is less than MIN_VAL.  */
+
+static void
+read_negative_num (FILE *fp, intmax_t min_val, intmax_t *pval)
+{
+  int c;
+  size_t i;
+  char buf[INT_BUFSIZE_BOUND (intmax_t)];
+  char *ep;
+  buf[0] = '-';
+
+  for (i = 1; ISDIGIT (c = getc (fp)); i++)
+    {
+      if (i == sizeof buf - 1)
+       FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file")));
+      buf[i] = c;
+    }
+
+  if (c < 0)
+    {
+      if (ferror (fp))
+       FATAL_ERROR ((0, errno, _("Read error in snapshot file")));
+      else
+       FATAL_ERROR ((0, 0, _("Unexpected EOF in snapshot file")));
+    }
+
+  buf[i] = 0;
+  errno = 0;
+  *pval = strtoimax (buf, &ep, 10);
+  if (c || errno || *pval < min_val)
+    FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file")));
+}
+
+/* Read from file FP a nul-terminated string and convert it to
+   uintmax_t.  Return the resulting value in PVAL.  Assume C has
+   already been read.
+
+   Throw a fatal error if the string cannot be converted or if the
+   converted value exceeds MAX_VAL.
 
 
-   Throw fatal error if the string cannot be converted.
-   
    Return the last character read or EOF on end of file. */
 
 static int
    Return the last character read or EOF on end of file. */
 
 static int
-read_num (FILE *fp, uintmax_t *pval)
+read_unsigned_num (int c, FILE *fp, uintmax_t max_val, uintmax_t *pval)
 {
 {
-  int c;
   size_t i;
   char buf[UINTMAX_STRSIZE_BOUND], *ep;
 
   size_t i;
   char buf[UINTMAX_STRSIZE_BOUND], *ep;
 
-  for (i = 0, c = getc (fp); c != EOF && c != 0; c = getc (fp), i++)
+  for (i = 0; ISDIGIT (c); i++)
     {
       if (i == sizeof buf - 1)
        FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file")));
       buf[i] = c;
     {
       if (i == sizeof buf - 1)
        FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file")));
       buf[i] = c;
+      c = getc (fp);
+    }
+
+  if (c < 0)
+    {
+      if (ferror (fp))
+       FATAL_ERROR ((0, errno, _("Read error in snapshot file")));
+      else if (i == 0)
+       return c;
+      else
+       FATAL_ERROR ((0, 0, _("Unexpected EOF in snapshot file")));
     }
     }
+
   buf[i] = 0;
   buf[i] = 0;
+  errno = 0;
   *pval = strtoumax (buf, &ep, 10);
   *pval = strtoumax (buf, &ep, 10);
-  if (*ep)
-    FATAL_ERROR ((0, 0, _("Unexpected field value in snapshot file")));
+  if (c || errno || max_val < *pval)
+    FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file")));
   return c;
   return c;
-}  
+}
+
+/* Read from file FP a nul-terminated string and convert it to
+   uintmax_t.  Return the resulting value in PVAL.
+
+   Throw a fatal error if the string cannot be converted or if the
+   converted value exceeds MAX_VAL.
+
+   Return the last character read or EOF on end of file. */
+
+static int
+read_num (FILE *fp, uintmax_t max_val, uintmax_t *pval)
+{
+  return read_unsigned_num (getc (fp), fp, max_val, pval);
+}
+
+/* Read from FP two NUL-terminated strings representing a struct
+   timespec.  Return the resulting value in PVAL.
+
+   Throw a fatal error if the string cannot be converted.  */
+
+static void
+read_timespec (FILE *fp, struct timespec *pval)
+{
+  int c = getc (fp);
+  intmax_t i;
+  uintmax_t u;
+
+  if (c == '-')
+    {
+      read_negative_num (fp, TYPE_MINIMUM (time_t), &i);
+      c = 0;
+      pval->tv_sec = i;
+    }
+  else
+    {
+      c = read_unsigned_num (c, fp, TYPE_MAXIMUM (time_t), &u);
+      pval->tv_sec = u;
+    }
+
+  if (c || read_num (fp, BILLION - 1, &u))
+    FATAL_ERROR ((0, 0, "%s: %s",
+                 quotearg_colon (listed_incremental_option),
+                 _("Unexpected EOF in snapshot file")));
+  pval->tv_nsec = u;
+}
 
 /* Read incremental snapshot format 2 */
 static void
 
 /* Read incremental snapshot format 2 */
 static void
@@ -843,28 +964,10 @@ read_incr_db_2 ()
 {
   uintmax_t u;
   struct obstack stk;
 {
   uintmax_t u;
   struct obstack stk;
-  
+
   obstack_init (&stk);
 
   obstack_init (&stk);
 
-  if (read_num (listed_incremental_stream, &u))
-    FATAL_ERROR ((0, 0, "%s: %s",
-                 quotearg_colon (listed_incremental_option), 
-                 _("Error reading time stamp")));
-  newer_mtime_option.tv_sec = u;
-  if (newer_mtime_option.tv_sec != u)
-    FATAL_ERROR ((0, 0, "%s: %s",
-                 quotearg_colon (listed_incremental_option),
-                 _("Time stamp out of range")));
-
-  if (read_num (listed_incremental_stream, &u))
-    FATAL_ERROR ((0, 0, "%s: %s",
-                 quotearg_colon (listed_incremental_option), 
-                 _("Error reading time stamp")));
-  newer_mtime_option.tv_nsec = u;
-  if (newer_mtime_option.tv_nsec != u)
-    FATAL_ERROR ((0, 0, "%s: %s",
-                 quotearg_colon (listed_incremental_option),
-                 _("Time stamp out of range")));
+  read_timespec (listed_incremental_stream, &newer_mtime_option);
 
   for (;;)
     {
 
   for (;;)
     {
@@ -875,43 +978,21 @@ read_incr_db_2 ()
       char *name;
       char *content;
       size_t s;
       char *name;
       char *content;
       size_t s;
-      
-      if (read_num (listed_incremental_stream, &u))
+
+      if (read_num (listed_incremental_stream, 1, &u))
        return; /* Normal return */
 
       nfs = u;
        return; /* Normal return */
 
       nfs = u;
-      
-      if (read_num (listed_incremental_stream, &u))
-       break;
-      mtime.tv_sec = u;
-      if (mtime.tv_sec != u)
-       FATAL_ERROR ((0, 0, "%s: %s",
-                     quotearg_colon (listed_incremental_option), 
-                     _("Modification time (seconds) out of range")));
-      
-      if (read_num (listed_incremental_stream, &u))
-       break;
-      mtime.tv_nsec = u;
-      if (mtime.tv_nsec != u)
-       FATAL_ERROR ((0, 0, "%s: %s",
-                     quotearg_colon (listed_incremental_option), 
-                     _("Modification time (nanoseconds) out of range")));
 
 
-      if (read_num (listed_incremental_stream, &u))
+      read_timespec (listed_incremental_stream, &mtime);
+
+      if (read_num (listed_incremental_stream, TYPE_MAXIMUM (dev_t), &u))
        break;
       dev = u;
        break;
       dev = u;
-      if (dev != u)
-       FATAL_ERROR ((0, 0, "%s: %s",
-                     quotearg_colon (listed_incremental_option), 
-                     _("Device number out of range")));
 
 
-      if (read_num (listed_incremental_stream, &u))
+      if (read_num (listed_incremental_stream, TYPE_MAXIMUM (ino_t), &u))
        break;
       ino = u;
        break;
       ino = u;
-      if (ino != u)
-       FATAL_ERROR ((0, 0, "%s: %s",
-                     quotearg_colon (listed_incremental_option), 
-                     _("Inode number out of range")));
 
       if (read_obstack (listed_incremental_stream, &stk, &s))
        break;
 
       if (read_obstack (listed_incremental_stream, &stk, &s))
        break;
@@ -922,16 +1003,16 @@ read_incr_db_2 ()
        ;
       if (getc (listed_incremental_stream) != 0)
        FATAL_ERROR ((0, 0, "%s: %s",
        ;
       if (getc (listed_incremental_stream) != 0)
        FATAL_ERROR ((0, 0, "%s: %s",
-                     quotearg_colon (listed_incremental_option), 
+                     quotearg_colon (listed_incremental_option),
                      _("Missing record terminator")));
                      _("Missing record terminator")));
-      
+
       content = obstack_finish (&stk);
       note_directory (name, mtime, dev, ino, nfs, false, content);
       obstack_free (&stk, content);
     }
   FATAL_ERROR ((0, 0, "%s: %s",
       content = obstack_finish (&stk);
       note_directory (name, mtime, dev, ino, nfs, false, content);
       obstack_free (&stk, content);
     }
   FATAL_ERROR ((0, 0, "%s: %s",
-               quotearg_colon (listed_incremental_option), 
-               _("Unexpected EOF")));
+               quotearg_colon (listed_incremental_option),
+               _("Unexpected EOF in snapshot file")));
 }
 
 /* Read incremental snapshot file (directory file).
 }
 
 /* Read incremental snapshot file (directory file).
@@ -946,7 +1027,6 @@ read_directory_file (void)
   int fd;
   char *buf = 0;
   size_t bufsize;
   int fd;
   char *buf = 0;
   size_t bufsize;
-  long lineno = 1;
 
   /* Open the file for both read and write.  That way, we can write
      it later without having to reopen it, and don't have to worry if
 
   /* Open the file for both read and write.  That way, we can write
      it later without having to reopen it, and don't have to worry if
@@ -969,7 +1049,7 @@ read_directory_file (void)
   if (0 < getline (&buf, &bufsize, listed_incremental_stream))
     {
       char *ebuf;
   if (0 < getline (&buf, &bufsize, listed_incremental_stream))
     {
       char *ebuf;
-      int incremental_version;
+      uintmax_t incremental_version;
 
       if (strncmp (buf, PACKAGE_NAME, sizeof PACKAGE_NAME - 1) == 0)
        {
 
       if (strncmp (buf, PACKAGE_NAME, sizeof PACKAGE_NAME - 1) == 0)
        {
@@ -980,7 +1060,7 @@ read_directory_file (void)
            if (!*ebuf)
              ERROR((1, 0, _("Bad incremental file format")));
 
            if (!*ebuf)
              ERROR((1, 0, _("Bad incremental file format")));
 
-         incremental_version = (errno = 0, strtoumax (ebuf+1, &ebuf, 10));
+         incremental_version = strtoumax (ebuf + 1, NULL, 10);
        }
       else
        incremental_version = 0;
        }
       else
        incremental_version = 0;
@@ -995,12 +1075,12 @@ read_directory_file (void)
        case TAR_INCREMENTAL_VERSION:
          read_incr_db_2 ();
          break;
        case TAR_INCREMENTAL_VERSION:
          read_incr_db_2 ();
          break;
-         
+
        default:
        default:
-         ERROR ((1, 0, _("Unsupported incremental format version: %d"),
+         ERROR ((1, 0, _("Unsupported incremental format version: %"PRIuMAX),
                  incremental_version));
        }
                  incremental_version));
        }
-      
+
     }
 
   if (ferror (listed_incremental_stream))
     }
 
   if (ferror (listed_incremental_stream))
@@ -1024,7 +1104,9 @@ write_directory_file_entry (void *entry, void *data)
 
       s = DIR_IS_NFS (directory) ? "1" : "0";
       fwrite (s, 2, 1, fp);
 
       s = DIR_IS_NFS (directory) ? "1" : "0";
       fwrite (s, 2, 1, fp);
-      s = umaxtostr (directory->mtime.tv_sec, buf);
+      s = (TYPE_SIGNED (time_t)
+          ? imaxtostr (directory->mtime.tv_sec, buf)
+          : umaxtostr (directory->mtime.tv_sec, buf));
       fwrite (s, strlen (s) + 1, 1, fp);
       s = umaxtostr (directory->mtime.tv_nsec, buf);
       fwrite (s, strlen (s) + 1, 1, fp);
       fwrite (s, strlen (s) + 1, 1, fp);
       s = umaxtostr (directory->mtime.tv_nsec, buf);
       fwrite (s, strlen (s) + 1, 1, fp);
@@ -1067,7 +1149,9 @@ write_directory_file (void)
   fprintf (fp, "%s-%s-%d\n", PACKAGE_NAME, PACKAGE_VERSION,
           TAR_INCREMENTAL_VERSION);
 
   fprintf (fp, "%s-%s-%d\n", PACKAGE_NAME, PACKAGE_VERSION,
           TAR_INCREMENTAL_VERSION);
 
-  s = umaxtostr (start_time.tv_sec, buf);
+  s = (TYPE_SIGNED (time_t)
+       ? imaxtostr (start_time.tv_sec, buf)
+       : umaxtostr (start_time.tv_sec, buf));
   fwrite (s, strlen (s) + 1, 1, fp);
   s = umaxtostr (start_time.tv_nsec, buf);
   fwrite (s, strlen (s) + 1, 1, fp);
   fwrite (s, strlen (s) + 1, 1, fp);
   s = umaxtostr (start_time.tv_nsec, buf);
   fwrite (s, strlen (s) + 1, 1, fp);
@@ -1140,7 +1224,7 @@ dumpdir_ok (char *dumpdir)
   char *p;
   int has_tempdir = 0;
   int expect = 0;
   char *p;
   int has_tempdir = 0;
   int expect = 0;
-  
+
   for (p = dumpdir; *p; p += strlen (p) + 1)
     {
       if (expect && *p != expect)
   for (p = dumpdir; *p; p += strlen (p) + 1)
     {
       if (expect && *p != expect)
@@ -1162,7 +1246,7 @@ dumpdir_ok (char *dumpdir)
          else
            has_tempdir = 1;
          break;
          else
            has_tempdir = 1;
          break;
-         
+
        case 'R':
          if (p[1] == 0)
            {
        case 'R':
          if (p[1] == 0)
            {
@@ -1177,14 +1261,14 @@ dumpdir_ok (char *dumpdir)
            }
          expect = 'T';
          break;
            }
          expect = 'T';
          break;
-           
+
        case 'T':
          if (expect != 'T')
            {
              ERROR ((0, 0,
                      _("Malformed dumpdir: 'T' not preceeded by 'R'")));
              return false;
        case 'T':
          if (expect != 'T')
            {
              ERROR ((0, 0,
                      _("Malformed dumpdir: 'T' not preceeded by 'R'")));
              return false;
-           }  
+           }
          if (p[1] == 0 && !has_tempdir)
            {
              ERROR ((0, 0,
          if (p[1] == 0 && !has_tempdir)
            {
              ERROR ((0, 0,
@@ -1193,7 +1277,7 @@ dumpdir_ok (char *dumpdir)
            }
          expect = 0;
          break;
            }
          expect = 0;
          break;
-         
+
        case 'N':
        case 'Y':
        case 'D':
        case 'N':
        case 'Y':
        case 'D':
@@ -1218,7 +1302,7 @@ dumpdir_ok (char *dumpdir)
 
   return true;
 }
 
   return true;
 }
-      
+
 /* Examine the directories under directory_name and delete any
    files that were not there at the time of the back-up. */
 static bool
 /* Examine the directories under directory_name and delete any
    files that were not there at the time of the back-up. */
 static bool
@@ -1227,7 +1311,7 @@ try_purge_directory (char const *directory_name)
   char *current_dir;
   char *cur, *arc, *p;
   char *temp_stub = NULL;
   char *current_dir;
   char *cur, *arc, *p;
   char *temp_stub = NULL;
-  
+
   if (!is_dumpdir (&current_stat_info))
     return false;
 
   if (!is_dumpdir (&current_stat_info))
     return false;
 
@@ -1241,13 +1325,13 @@ try_purge_directory (char const *directory_name)
   /* Verify if dump directory is sane */
   if (!dumpdir_ok (current_stat_info.dumpdir))
     return false;
   /* Verify if dump directory is sane */
   if (!dumpdir_ok (current_stat_info.dumpdir))
     return false;
-       
+
   /* Process renames */
   for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)
     {
       if (*arc == 'X')
        {
   /* Process renames */
   for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)
     {
       if (*arc == 'X')
        {
-#define TEMP_DIR_TEMPLATE "tar.XXXXXX"   
+#define TEMP_DIR_TEMPLATE "tar.XXXXXX"
          size_t len = strlen (arc + 1);
          temp_stub = xrealloc (temp_stub, len + 1 + sizeof TEMP_DIR_TEMPLATE);
          memcpy (temp_stub, arc + 1, len);
          size_t len = strlen (arc + 1);
          temp_stub = xrealloc (temp_stub, len + 1 + sizeof TEMP_DIR_TEMPLATE);
          memcpy (temp_stub, arc + 1, len);
@@ -1275,7 +1359,7 @@ try_purge_directory (char const *directory_name)
            src = temp_stub;
          else if (*dst == 0)
            dst = temp_stub;
            src = temp_stub;
          else if (*dst == 0)
            dst = temp_stub;
-           
+
          if (!rename_directory (src, dst))
            {
              free (temp_stub);
          if (!rename_directory (src, dst))
            {
              free (temp_stub);
@@ -1288,7 +1372,7 @@ try_purge_directory (char const *directory_name)
     }
 
   free (temp_stub);
     }
 
   free (temp_stub);
-  
+
   /* Process deletes */
   p = NULL;
   for (cur = current_dir; *cur; cur += strlen (cur) + 1)
   /* Process deletes */
   p = NULL;
   for (cur = current_dir; *cur; cur += strlen (cur) + 1)
@@ -1299,22 +1383,23 @@ try_purge_directory (char const *directory_name)
        free (p);
       p = new_name (directory_name, cur);
 
        free (p);
       p = new_name (directory_name, cur);
 
-      if (!(entry = dumpdir_locate (current_stat_info.dumpdir, cur))
-         || (*entry == 'D' && S_ISDIR (st.st_mode))
-         || (*entry == 'Y' && !S_ISDIR (st.st_mode)))
+      if (deref_stat (false, p, &st))
        {
        {
-         if (deref_stat (false, p, &st))
+         if (errno != ENOENT) /* FIXME: Maybe keep a list of renamed
+                                 dirs and check it here? */
            {
            {
-             if (errno != ENOENT) /* FIXME: Maybe keep a list of renamed
-                                     dirs and check it here? */
-               {
-                 stat_diag (p);
-                 WARN ((0, 0, _("%s: Not purging directory: unable to stat"),
-                        quotearg_colon (p)));
-               }
-             continue;
+             stat_diag (p);
+             WARN ((0, 0, _("%s: Not purging directory: unable to stat"),
+                    quotearg_colon (p)));
            }
            }
-         else if (one_file_system_option && st.st_dev != root_device)
+         continue;
+       }
+
+      if (!(entry = dumpdir_locate (current_stat_info.dumpdir, cur))
+         || (*entry == 'D' && !S_ISDIR (st.st_mode))
+         || (*entry == 'Y' && S_ISDIR (st.st_mode)))
+       {
+         if (one_file_system_option && st.st_dev != root_device)
            {
              WARN ((0, 0,
                     _("%s: directory is on a different device: not purging"),
            {
              WARN ((0, 0,
                     _("%s: directory is on a different device: not purging"),
@@ -1336,7 +1421,7 @@ try_purge_directory (char const *directory_name)
        }
     }
   free (p);
        }
     }
   free (p);
-  
+
   free (current_dir);
   return true;
 }
   free (current_dir);
   return true;
 }
@@ -1347,10 +1432,11 @@ purge_directory (char const *directory_name)
   if (!try_purge_directory (directory_name))
     skip_member ();
 }
   if (!try_purge_directory (directory_name))
     skip_member ();
 }
-     
+
 void
 list_dumpdir (char *buffer, size_t size)
 {
 void
 list_dumpdir (char *buffer, size_t size)
 {
+  int state = 0;
   while (size)
     {
       switch (*buffer)
   while (size)
     {
       switch (*buffer)
@@ -1361,7 +1447,12 @@ list_dumpdir (char *buffer, size_t size)
        case 'R':
        case 'T':
        case 'X':
        case 'R':
        case 'T':
        case 'X':
-         fprintf (stdlis, "%c ", *buffer);
+         fprintf (stdlis, "%c", *buffer);
+         if (state == 0)
+           {
+             fprintf (stdlis, " ");
+             state = 1;
+           }
          buffer++;
          size--;
          break;
          buffer++;
          size--;
          break;
@@ -1370,6 +1461,7 @@ list_dumpdir (char *buffer, size_t size)
          fputc ('\n', stdlis);
          buffer++;
          size--;
          fputc ('\n', stdlis);
          buffer++;
          size--;
+         state = 0;
          break;
 
        default:
          break;
 
        default:
This page took 0.043038 seconds and 4 git commands to generate.