]> Dogcows Code - chaz/tar/blobdiff - src/incremen.c
Take into account chdir_fd when extracting from incremental dumps.
[chaz/tar] / src / incremen.c
index 5a7e23d795a56b66dcc252a34067f0aa247e6952..8aeefbeda86b403cb07399df6bdaba35d42ced6e 100644 (file)
@@ -1,21 +1,22 @@
 /* GNU dump extensions to tar.
 
-   Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
-   2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   Copyright 1988, 1992-1994, 1996-1997, 1999-2001, 2003-2009, 2013
+   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
-   Free Software Foundation; either version 3, or (at your option) any later
-   version.
+   This file is part of GNU tar.
 
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
-   Public License for more details.
+   GNU tar 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 3 of the License, or
+   (at your option) any later version.
 
-   You should have received a copy of the GNU General Public License along
-   with this program; if not, write to the Free Software Foundation, Inc.,
-   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   GNU tar is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <system.h>
 #include <hash.h>
@@ -608,6 +609,7 @@ procdir (const char *name_buffer, struct tar_stat_info *st,
          exclusion_tag_warning (name_buffer, tag_file_name,
                                 _("contents not dumped"));
          directory->children = NO_CHILDREN;
+         directory->tagfile = tag_file_name;
          break;
 
        case exclusion_tag_under:
@@ -679,15 +681,13 @@ makedumpdir (struct directory *directory, const char *dir)
       if (loc)
        {
          if (directory->tagfile)
-           *new_dump_ptr = strcmp (directory->tagfile, array[i]) == 0 ?
-                               ' ' : 'I';
+           *new_dump_ptr = 'I';
          else
            *new_dump_ptr = ' ';
          new_dump_ptr++;
        }
       else if (directory->tagfile)
-       *new_dump_ptr++ = strcmp (directory->tagfile, array[i]) == 0 ?
-                              ' ' : 'I';
+       *new_dump_ptr++ = 'I';
       else
        *new_dump_ptr++ = 'Y'; /* New entry */
 
@@ -698,9 +698,26 @@ makedumpdir (struct directory *directory, const char *dir)
   *new_dump_ptr = 0;
   directory->idump = directory->dump;
   directory->dump = dumpdir_create0 (new_dump, NULL);
+  free (new_dump);
   free (array);
 }
 
+/* Create a dumpdir containing only one entry: that for the
+   tagfile. */
+static void
+maketagdumpdir (struct directory *directory)
+{
+  size_t len = strlen (directory->tagfile) + 1;
+  char *new_dump = xmalloc (len + 2);
+  new_dump[0] = 'Y';
+  memcpy (new_dump + 1, directory->tagfile, len);
+  new_dump[len + 1] = 0;
+
+  directory->idump = directory->dump;
+  directory->dump = dumpdir_create0 (new_dump, NULL);
+  free (new_dump);
+}
+
 /* Recursively scan the directory identified by ST.  */
 struct directory *
 scan_directory (struct tar_stat_info *st)
@@ -728,86 +745,94 @@ scan_directory (struct tar_stat_info *st)
 
   nbuf = namebuf_create (dir);
 
-  if (dirp && directory->children != NO_CHILDREN)
+  if (dirp)
     {
-      char *entry;     /* directory entry being scanned */
-      struct dumpdir_iter *itr;
-
-      makedumpdir (directory, dirp);
-
-      for (entry = dumpdir_first (directory->dump, 1, &itr);
-          entry;
-          entry = dumpdir_next (itr))
+      if (directory->children != NO_CHILDREN)
        {
-         char *full_name = namebuf_name (nbuf, entry + 1);
-
-         if (*entry == 'I') /* Ignored entry */
-           *entry = 'N';
-         else if (excluded_name (full_name))
-           *entry = 'N';
-         else
-           {
-             int fd = st->fd;
-             void (*diag) (char const *) = 0;
-             struct tar_stat_info stsub;
-             tar_stat_init (&stsub);
+         char *entry;  /* directory entry being scanned */
+         struct dumpdir_iter *itr;
 
-             if (fd < 0)
-               {
-                 errno = - fd;
-                 diag = open_diag;
-               }
-             else if (fstatat (fd, entry + 1, &stsub.stat, fstatat_flags) != 0)
-               diag = stat_diag;
-             else if (S_ISDIR (stsub.stat.st_mode))
-               {
-                 int subfd = subfile_open (st, entry + 1, open_read_flags);
-                 if (subfd < 0)
-                   diag = open_diag;
-                 else
-                   {
-                     stsub.fd = subfd;
-                     if (fstat (subfd, &stsub.stat) != 0)
-                       diag = stat_diag;
-                   }
-               }
+         makedumpdir (directory, dirp);
 
-             if (diag)
-               {
-                 file_removed_diag (full_name, false, diag);
-                 *entry = 'N';
-               }
-             else if (S_ISDIR (stsub.stat.st_mode))
-               {
-                 int pd_flag = 0;
-                 if (!recursion_option)
-                   pd_flag |= PD_FORCE_CHILDREN | NO_CHILDREN;
-                 else if (directory->children == ALL_CHILDREN)
-                   pd_flag |= PD_FORCE_CHILDREN | ALL_CHILDREN;
-                 *entry = 'D';
-
-                 stsub.parent = st;
-                 procdir (full_name, &stsub, pd_flag, entry);
-                 restore_parent_fd (&stsub);
-               }
-             else if (one_file_system_option && device != stsub.stat.st_dev)
+         for (entry = dumpdir_first (directory->dump, 1, &itr);
+              entry;
+              entry = dumpdir_next (itr))
+           {
+             char *full_name = namebuf_name (nbuf, entry + 1);
+             
+             if (*entry == 'I') /* Ignored entry */
                *entry = 'N';
-             else if (*entry == 'Y')
-               /* New entry, skip further checks */;
-             /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */
-             else if (OLDER_STAT_TIME (stsub.stat, m)
-                      && (!after_date_option
-                          || OLDER_STAT_TIME (stsub.stat, c)))
+             else if (excluded_name (full_name))
                *entry = 'N';
              else
-               *entry = 'Y';
+               {
+                 int fd = st->fd;
+                 void (*diag) (char const *) = 0;
+                 struct tar_stat_info stsub;
+                 tar_stat_init (&stsub);
 
-             tar_stat_destroy (&stsub);
+                 if (fd < 0)
+                   {
+                     errno = - fd;
+                     diag = open_diag;
+                   }
+                 else if (fstatat (fd, entry + 1, &stsub.stat,
+                                   fstatat_flags) != 0)
+                   diag = stat_diag;
+                 else if (S_ISDIR (stsub.stat.st_mode))
+                   {
+                     int subfd = subfile_open (st, entry + 1,
+                                               open_read_flags);
+                     if (subfd < 0)
+                       diag = open_diag;
+                     else
+                       {
+                         stsub.fd = subfd;
+                         if (fstat (subfd, &stsub.stat) != 0)
+                           diag = stat_diag;
+                       }
+                   }
+                 
+                 if (diag)
+                   {
+                     file_removed_diag (full_name, false, diag);
+                     *entry = 'N';
+                   }
+                 else if (S_ISDIR (stsub.stat.st_mode))
+                   {
+                     int pd_flag = 0;
+                     if (!recursion_option)
+                       pd_flag |= PD_FORCE_CHILDREN | NO_CHILDREN;
+                     else if (directory->children == ALL_CHILDREN)
+                       pd_flag |= PD_FORCE_CHILDREN | ALL_CHILDREN;
+                     *entry = 'D';
+                     
+                     stsub.parent = st;
+                     procdir (full_name, &stsub, pd_flag, entry);
+                     restore_parent_fd (&stsub);
+                   }
+                 else if (one_file_system_option &&
+                          device != stsub.stat.st_dev)
+                   *entry = 'N';
+                 else if (*entry == 'Y')
+                   /* New entry, skip further checks */;
+                 /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */
+                 else if (OLDER_STAT_TIME (stsub.stat, m)
+                          && (!after_date_option
+                              || OLDER_STAT_TIME (stsub.stat, c)))
+                   *entry = 'N';
+                 else
+                   *entry = 'Y';
+                 
+                 tar_stat_destroy (&stsub);
+               }
            }
+         free (itr);
        }
-      free (itr);
+      else if (directory->tagfile)
+       maketagdumpdir (directory);
     }
-
+  
   namebuf_free (nbuf);
 
   free (dirp);
@@ -1078,106 +1103,84 @@ read_obstack (FILE *fp, struct obstack *stk, size_t *pcount)
   return c;
 }
 
-/* Read from file FP a nul-terminated string and convert it to
-   intmax_t.  Return the resulting value in PVAL.  Assume '-' has
-   already been read.
+/* Read from file FP a null-terminated string and convert it to an
+   integer.  FIELDNAME is the intended use of the integer, useful for
+   diagnostics.  MIN_VAL and MAX_VAL are its minimum and maximum
+   permissible values; MIN_VAL must be nonpositive and MAX_VAL positive.
+   Store into *PVAL the resulting value, converted to intmax_t.
 
    Throw a fatal error if the string cannot be converted or if the
-   converted value is less than MIN_VAL.  */
+   converted value is out of range.
 
-static void
-read_negative_num (FILE *fp, intmax_t min_val, intmax_t *pval)
+   Return true if successful, false if end of file.  */
+
+static bool
+read_num (FILE *fp, char const *fieldname,
+         intmax_t min_val, uintmax_t max_val, intmax_t *pval)
 {
-  int c;
-  size_t i;
+  int i;
   char buf[INT_BUFSIZE_BOUND (intmax_t)];
-  char *ep;
-  buf[0] = '-';
+  char offbuf[INT_BUFSIZE_BOUND (off_t)];
+  char minbuf[INT_BUFSIZE_BOUND (intmax_t)];
+  char maxbuf[INT_BUFSIZE_BOUND (intmax_t)];
+  int conversion_errno;
+  int c = getc (fp);
+  bool negative = c == '-';
 
-  for (i = 1; ISDIGIT (c = getc (fp)); i++)
+  for (i = 0; (i == 0 && negative) || ISDIGIT (c); 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 an intmax_t representation of 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.
-
-   Return the last character read or EOF on end of file. */
-
-static int
-read_unsigned_num (int c, FILE *fp, uintmax_t max_val, intmax_t *pval)
-{
-  size_t i;
-  uintmax_t u;
-  char buf[UINTMAX_STRSIZE_BOUND], *ep;
-
-  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;
+       FATAL_ERROR ((0, 0,
+                     _("%s: byte %s: %s %.*s... too long"),
+                     quotearg_colon (listed_incremental_option),
+                     offtostr (ftello (fp), offbuf),
+                     fieldname, i + 1, buf));
       c = getc (fp);
     }
 
+  buf[i] = 0;
+
   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")));
+       read_fatal (listed_incremental_option);
+      if (i != 0)
+       FATAL_ERROR ((0, 0, "%s: %s",
+                     quotearg_colon (listed_incremental_option),
+                     _("Unexpected EOF in snapshot file")));
+      return false;
     }
 
-  buf[i] = 0;
-  errno = 0;
-  u = strtoumax (buf, &ep, 10);
-  if (c || errno || max_val < u)
-    FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file")));
-  *pval = represent_uintmax (u);
-  return c;
-}
-
-/* Read from file FP a nul-terminated string and convert it to
-   an integer in the range MIN_VAL..MAXVAL.  Return the resulting
-   value, converted to intmax_t, in PVAL.  MINVAL must be nonpositive.
-
-   Throw a fatal error if the string cannot be converted or if the
-   converted value is out of range.
+  if (c)
+    FATAL_ERROR ((0, 0,
+                 _("%s: byte %s: %s %s followed by invalid byte 0x%02x"),
+                 quotearg_colon (listed_incremental_option),
+                 offtostr (ftello (fp), offbuf),
+                 fieldname, buf, c));
 
-   Return the last character read or EOF on end of file. */
+  *pval = strtosysint (buf, NULL, min_val, max_val);
+  conversion_errno = errno;
 
-static int
-read_num (FILE *fp, intmax_t min_val, uintmax_t max_val, intmax_t *pval)
-{
-  int c = getc (fp);
-  if (c == '-')
+  switch (conversion_errno)
     {
-      read_negative_num (fp, min_val, pval);
-      return 0;
+    case ERANGE:
+      FATAL_ERROR ((0, conversion_errno,
+                   _("%s: byte %s: (valid range %s..%s)\n\t%s %s"),
+                   quotearg_colon (listed_incremental_option),
+                   offtostr (ftello (fp), offbuf),
+                   imaxtostr (min_val, minbuf),
+                   umaxtostr (max_val, maxbuf), fieldname, buf));
+    default:
+      FATAL_ERROR ((0, conversion_errno,
+                   _("%s: byte %s: %s %s"),
+                   quotearg_colon (listed_incremental_option),
+                   offtostr (ftello (fp), offbuf), fieldname, buf));
+    case 0:
+      break;
     }
-  return read_unsigned_num (c, fp, max_val, pval);
+
+  return true;
 }
 
 /* Read from FP two NUL-terminated strings representing a struct
@@ -1188,15 +1191,20 @@ read_num (FILE *fp, intmax_t min_val, uintmax_t max_val, intmax_t *pval)
 static void
 read_timespec (FILE *fp, struct timespec *pval)
 {
-  intmax_t i;
-  int c = read_num (fp, TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t), &i);
-  pval->tv_sec = i;
+  intmax_t s, ns;
 
-  if (c || read_num (fp, 0, BILLION - 1, &i))
-    FATAL_ERROR ((0, 0, "%s: %s",
-                 quotearg_colon (listed_incremental_option),
-                 _("Unexpected EOF in snapshot file")));
-  pval->tv_nsec = i;
+  if (read_num (fp, "sec", TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t), &s)
+      && read_num (fp, "nsec", 0, BILLION - 1, &ns))
+    {
+      pval->tv_sec = s;
+      pval->tv_nsec = ns;
+    }
+  else
+    {
+      FATAL_ERROR ((0, 0, "%s: %s",
+                   quotearg_colon (listed_incremental_option),
+                   _("Unexpected EOF in snapshot file")));
+    }
 }
 
 /* Read incremental snapshot format 2 */
@@ -1204,6 +1212,7 @@ static void
 read_incr_db_2 (void)
 {
   struct obstack stk;
+  char offbuf[INT_BUFSIZE_BOUND (off_t)];
 
   obstack_init (&stk);
 
@@ -1220,20 +1229,20 @@ read_incr_db_2 (void)
       char *content;
       size_t s;
 
-      if (read_num (listed_incremental_stream, 0, 1, &i))
+      if (! read_num (listed_incremental_stream, "nfs", 0, 1, &i))
        return; /* Normal return */
 
       nfs = i;
 
       read_timespec (listed_incremental_stream, &mtime);
 
-      if (read_num (listed_incremental_stream,
-                   TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t), &i))
+      if (! read_num (listed_incremental_stream, "dev",
+                     TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t), &i))
        break;
       dev = i;
 
-      if (read_num (listed_incremental_stream,
-                   TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t), &i))
+      if (! read_num (listed_incremental_stream, "ino",
+                     TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t), &i))
        break;
       ino = i;
 
@@ -1245,8 +1254,9 @@ read_incr_db_2 (void)
       while (read_obstack (listed_incremental_stream, &stk, &s) == 0 && s > 1)
        ;
       if (getc (listed_incremental_stream) != 0)
-       FATAL_ERROR ((0, 0, "%s: %s",
+       FATAL_ERROR ((0, 0, _("%s: byte %s: %s"),
                      quotearg_colon (listed_incremental_option),
+                     offtostr (ftello (listed_incremental_stream), offbuf),
                      _("Missing record terminator")));
 
       content = obstack_finish (&stk);
@@ -1572,7 +1582,7 @@ try_purge_directory (char const *directory_name)
   if (!is_dumpdir (&current_stat_info))
     return false;
 
-  current_dir = savedir (directory_name);
+  current_dir = tar_savedir (directory_name, 0);
 
   if (!current_dir)
     /* The directory doesn't exist now.  It'll be created.  In any
This page took 0.035247 seconds and 4 git commands to generate.