+ Throw fatal error if the string cannot be converted.
+
+ Return the last character read or EOF on end of file. */
+
+static int
+read_num (FILE *fp, uintmax_t *pval)
+{
+ int c;
+ size_t i;
+ char buf[UINTMAX_STRSIZE_BOUND], *ep;
+
+ for (i = 0, c = getc (fp); c != EOF && c != 0; c = getc (fp), i++)
+ {
+ if (i == sizeof buf - 1)
+ FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file")));
+ buf[i] = c;
+ }
+ buf[i] = 0;
+ *pval = strtoumax (buf, &ep, 10);
+ if (*ep)
+ FATAL_ERROR ((0, 0, _("Unexpected field value in snapshot file")));
+ return c;
+}
+
+/* Read incremental snapshot format 2 */
+static void
+read_incr_db_2 ()
+{
+ uintmax_t u;
+ struct obstack 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")));
+
+ for (;;)
+ {
+ struct timespec mtime;
+ dev_t dev;
+ ino_t ino;
+ bool nfs;
+ char *name;
+ char *content;
+ size_t s;
+
+ if (read_num (listed_incremental_stream, &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))
+ 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))
+ 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;
+
+ name = obstack_finish (&stk);
+
+ while (read_obstack (listed_incremental_stream, &stk, &s) == 0 && s > 1)
+ ;
+ if (getc (listed_incremental_stream) != 0)
+ FATAL_ERROR ((0, 0, "%s: %s",
+ quotearg_colon (listed_incremental_option),
+ _("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",
+ quotearg_colon (listed_incremental_option),
+ _("Unexpected EOF")));
+}
+
+/* Read incremental snapshot file (directory file).
+ If the file has older incremental version, make sure that it is processed
+ correctly and that tar will use the most conservative backup method among
+ possible alternatives (i.e. prefer ALL_CHILDREN over CHANGED_CHILDREN,
+ etc.) This ensures that the snapshots are updated to the recent version
+ without any loss of data. */