]> Dogcows Code - chaz/tar/blobdiff - src/incremen.c
tar: live within system-supplied limits on file descriptors
[chaz/tar] / src / incremen.c
index 372061dd12a3aadb4f51524482e7066107dd6df9..c6d4f4c5849a2ecdb5e9633a36e718c95e195f93 100644 (file)
@@ -1,7 +1,7 @@
 /* GNU dump extensions to tar.
 
    Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
-   2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2009 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
@@ -43,7 +43,7 @@ enum children
 #define DIR_IS_INITED(d) ((d)->flags & DIRF_INIT)
 #define DIR_IS_NFS(d) ((d)->flags & DIRF_NFS)
 #define DIR_IS_FOUND(d) ((d)->flags & DIRF_FOUND)
-#define DIR_IS_NEW(d) ((d)->flags & DIRF_NEW)
+/* #define DIR_IS_NEW(d) ((d)->flags & DIRF_NEW) FIXME: not used */
 #define DIR_IS_RENAMED(d) ((d)->flags & DIRF_RENAMED)
 
 #define DIR_SET_FLAG(d,f) (d)->flags |= (f)
@@ -60,6 +60,7 @@ struct dumpdir                 /* Dump directory listing */
 /* Directory attributes.  */
 struct directory
   {
+    struct directory *next;
     struct timespec mtime;      /* Modification time */
     dev_t device_number;       /* device number for directory */
     ino_t inode_number;                /* inode number for directory */
@@ -72,21 +73,23 @@ struct directory
                                   the original directory structure */
     const char *tagfile;        /* Tag file, if the directory falls under
                                   exclusion_tag_under */
-    char name[1];              /* file name of directory */
+    char *caname;               /* canonical name */
+    char *name;                        /* file name of directory */
   };
 
-struct dumpdir *
+static struct dumpdir *
 dumpdir_create0 (const char *contents, const char *cmask)
 {
   struct dumpdir *dump;
   size_t i, total, ctsize, len;
-  const char *p;
-  
-  for (i = 0, total = 0, ctsize = 1, p = contents; *p; total++, p += len)
+  char *p;
+  const char *q;
+
+  for (i = 0, total = 0, ctsize = 1, q = contents; *q; total++, q += len)
     {
-      len = strlen (p) + 1;
+      len = strlen (q) + 1;
       ctsize += len;
-      if (!cmask || strchr (cmask, *p))
+      if (!cmask || strchr (cmask, *q))
        i++;
     }
   dump = xmalloc (sizeof (*dump) + ctsize);
@@ -105,13 +108,13 @@ dumpdir_create0 (const char *contents, const char *cmask)
   return dump;
 }
 
-struct dumpdir *
+static struct dumpdir *
 dumpdir_create (const char *contents)
 {
   return dumpdir_create0 (contents, "YND");
 }
 
-void
+static void
 dumpdir_free (struct dumpdir *dump)
 {
   free (dump->elv);
@@ -128,7 +131,7 @@ compare_dirnames (const void *first, const void *second)
 
 /* Locate NAME in the dumpdir array DUMP.
    Return pointer to the slot in DUMP->contents, or NULL if not found */
-char *
+static char *
 dumpdir_locate (struct dumpdir *dump, const char *name)
 {
   char **ptr;
@@ -143,16 +146,16 @@ dumpdir_locate (struct dumpdir *dump, const char *name)
 struct dumpdir_iter
 {
   struct dumpdir *dump; /* Dumpdir being iterated */
-  int all;              /* Iterate over all entries, not only D/N/Y */ 
+  int all;              /* Iterate over all entries, not only D/N/Y */
   size_t next;          /* Index of the next element */
 };
 
-char *
+static char *
 dumpdir_next (struct dumpdir_iter *itr)
 {
   size_t cur = itr->next;
   char *ret = NULL;
-  
+
   if (itr->all)
     {
       ret = itr->dump->contents + cur;
@@ -169,7 +172,7 @@ dumpdir_next (struct dumpdir_iter *itr)
   return ret;
 }
 
-char *
+static char *
 dumpdir_first (struct dumpdir *dump, int all, struct dumpdir_iter **pitr)
 {
   struct dumpdir_iter *itr = xmalloc (sizeof (*itr));
@@ -196,6 +199,7 @@ dumpdir_size (const char *p)
 }
 
 \f
+static struct directory *dirhead, *dirtail;
 static Hash_table *directory_table;
 static Hash_table *directory_meta_table;
 
@@ -209,19 +213,19 @@ static Hash_table *directory_meta_table;
 
 /* Calculate the hash of a directory.  */
 static size_t
-hash_directory_name (void const *entry, size_t n_buckets)
+hash_directory_canonical_name (void const *entry, size_t n_buckets)
 {
   struct directory const *directory = entry;
-  return hash_string (directory->name, n_buckets);
+  return hash_string (directory->caname, n_buckets);
 }
 
 /* Compare two directories for equality of their names. */
 static bool
-compare_directory_names (void const *entry1, void const *entry2)
+compare_directory_canonical_names (void const *entry1, void const *entry2)
 {
   struct directory const *directory1 = entry1;
   struct directory const *directory2 = entry2;
-  return strcmp (directory1->name, directory2->name) == 0;
+  return strcmp (directory1->caname, directory2->caname) == 0;
 }
 
 static size_t
@@ -242,23 +246,60 @@ compare_directory_meta (void const *entry1, void const *entry2)
             && directory1->inode_number == directory2->inode_number;
 }
 
-/* Make a directory entry for given NAME */
+/* Make a directory entry for given relative NAME and canonical name CANAME.
+   The latter is "stolen", i.e. the returned directory contains pointer to
+   it. */
 static struct directory *
-make_directory (const char *name)
+make_directory (const char *name, char *caname)
 {
   size_t namelen = strlen (name);
-  size_t size = offsetof (struct directory, name) + namelen + 1;
-  struct directory *directory = xmalloc (size);
+  struct directory *directory = xmalloc (sizeof (*directory));
+  directory->next = NULL;
   directory->dump = directory->idump = NULL;
   directory->orig = NULL;
   directory->flags = false;
-  strcpy (directory->name, name);
-  if (namelen && ISSLASH (directory->name[namelen - 1]))
-    directory->name[namelen - 1] = 0;
+  if (namelen > 1 && ISSLASH (name[namelen - 1]))
+    namelen--;
+  directory->name = xmalloc (namelen + 1);
+  memcpy (directory->name, name, namelen);
+  directory->name[namelen] = 0;
+  directory->caname = caname;
   directory->tagfile = NULL;
   return directory;
 }
 
+static void
+free_directory (struct directory *dir)
+{
+  free (dir->caname);
+  free (dir->name);
+  free (dir);
+}
+
+static struct directory *
+attach_directory (const char *name)
+{
+  char *cname = normalize_filename (name);
+  struct directory *dir = make_directory (name, cname);
+  if (dirtail)
+    dirtail->next = dir;
+  else
+    dirhead = dir;
+  dirtail = dir;
+  return dir;
+}
+
+\f
+static void
+dirlist_replace_prefix (const char *pref, const char *repl)
+{
+  struct directory *dp;
+  size_t pref_len = strlen (pref);
+  size_t repl_len = strlen (repl);
+  for (dp = dirhead; dp; dp = dp->next)
+    replace_prefix (&dp->name, pref, pref_len, repl, repl_len);
+}
+
 /* 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
@@ -268,7 +309,7 @@ note_directory (char const *name, struct timespec mtime,
                dev_t dev, ino_t ino, bool nfs, bool found,
                const char *contents)
 {
-  struct directory *directory = make_directory (name);
+  struct directory *directory = attach_directory (name);
 
   directory->mtime = mtime;
   directory->device_number = dev;
@@ -285,8 +326,8 @@ note_directory (char const *name, struct timespec mtime,
 
   if (! ((directory_table
          || (directory_table = hash_initialize (0, 0,
-                                                hash_directory_name,
-                                                compare_directory_names, 0)))
+                                                hash_directory_canonical_name,
+                                                compare_directory_canonical_names, 0)))
         && hash_insert (directory_table, directory)))
     xalloc_die ();
 
@@ -309,13 +350,38 @@ find_directory (const char *name)
     return 0;
   else
     {
-      struct directory *dir = make_directory (name);
+      char *caname = normalize_filename (name);
+      struct directory *dir = make_directory (name, caname);
       struct directory *ret = hash_lookup (directory_table, dir);
-      free (dir);
+      free_directory (dir);
       return ret;
     }
 }
 
+#if 0
+/* Remove directory entry for the given CANAME */
+void
+remove_directory (const char *caname)
+{
+  struct directory *dir = make_directory (caname, xstrdup (caname));
+  struct directory *ret = hash_delete (directory_table, dir);
+  if (ret)
+    free_directory (ret);
+  free_directory (dir);
+}
+#endif
+
+/* If first OLD_PREFIX_LEN bytes of DIR->NAME name match OLD_PREFIX,
+   replace them with NEW_PREFIX. */
+void
+rebase_directory (struct directory *dir,
+                 const char *old_prefix, size_t old_prefix_len,
+                 const char *new_prefix, size_t new_prefix_len)
+{
+  replace_prefix (&dir->name, old_prefix, old_prefix_len,
+                 new_prefix, new_prefix_len);
+}
+
 /* Return a directory entry for a given combination of device and inode
    numbers, or zero if none found.  */
 static struct directory *
@@ -325,49 +391,64 @@ find_directory_meta (dev_t dev, ino_t ino)
     return 0;
   else
     {
-      struct directory *dir = make_directory ("");
+      struct directory *dir = make_directory ("", NULL);
       struct directory *ret;
       dir->device_number = dev;
       dir->inode_number = ino;
       ret = hash_lookup (directory_meta_table, dir);
-      free (dir);
+      free_directory (dir);
       return ret;
     }
 }
 
 void
-update_parent_directory (const char *name)
+update_parent_directory (struct tar_stat_info *parent)
 {
-  struct directory *directory;
-  char *p;
-
-  p = dir_name (name);
-  directory = find_directory (p);
+  struct directory *directory = find_directory (parent->orig_file_name);
   if (directory)
     {
       struct stat st;
-      if (deref_stat (dereference_option, p, &st) != 0)
-       stat_diag (name);
+      if (fstatat (parent->fd, ".", &st, fstatat_flags) != 0)
+       stat_diag (directory->name);
       else
        directory->mtime = get_stat_mtime (&st);
     }
-  free (p);
 }
 
+#define PD_FORCE_CHILDREN 0x10
+#define PD_FORCE_INIT     0x20
+#define PD_CHILDREN(f) ((f) & 3)
+
 static struct directory *
-procdir (char *name_buffer, struct stat *stat_data,
-        dev_t device,
-        enum children children,
-        bool verbose,
+procdir (const char *name_buffer, struct tar_stat_info *st,
+        int flag,
         char *entry)
 {
   struct directory *directory;
+  struct stat *stat_data = &st->stat;
+  dev_t device = st->parent ? st->parent->stat.st_dev : 0;
   bool nfs = NFS_FILE_STAT (*stat_data);
 
   if ((directory = find_directory (name_buffer)) != NULL)
     {
       if (DIR_IS_INITED (directory))
-       return directory;
+       {
+         if (flag & PD_FORCE_INIT)
+           {
+             assign_string (&directory->name, name_buffer);
+           }
+         else
+           {
+             *entry = 'N'; /* Avoid duplicating this directory */
+             return directory;
+           }
+       }
+
+      if (strcmp (directory->name, name_buffer))
+       {
+         *entry = 'N';
+         return directory;
+       }
 
       /* With NFS, the same file can have two different devices
         if an NFS directory is mounted in multiple locations,
@@ -386,19 +467,24 @@ procdir (char *name_buffer, struct stat *stat_data,
                                                     stat_data->st_ino);
          if (d)
            {
-             if (verbose_option)
-               WARN ((0, 0, _("%s: Directory has been renamed from %s"),
-                      quotearg_colon (name_buffer),
-                      quote_n (1, d->name)));
-             directory->orig = d;
-             DIR_SET_FLAG (directory, DIRF_RENAMED);
+             if (strcmp (d->name, name_buffer))
+               {
+                 WARNOPT (WARN_RENAME_DIRECTORY,
+                          (0, 0,
+                           _("%s: Directory has been renamed from %s"),
+                           quotearg_colon (name_buffer),
+                           quote_n (1, d->name)));
+                 directory->orig = d;
+                 DIR_SET_FLAG (directory, DIRF_RENAMED);
+                 dirlist_replace_prefix (d->name, name_buffer);
+               }
              directory->children = CHANGED_CHILDREN;
            }
          else
            {
-             if (verbose_option)
-               WARN ((0, 0, _("%s: Directory has been renamed"),
-                      quotearg_colon (name_buffer)));
+             WARNOPT (WARN_RENAME_DIRECTORY,
+                      (0, 0, _("%s: Directory has been renamed"),
+                       quotearg_colon (name_buffer)));
              directory->children = ALL_CHILDREN;
              directory->device_number = stat_data->st_dev;
              directory->inode_number = stat_data->st_ino;
@@ -426,20 +512,24 @@ procdir (char *name_buffer, struct stat *stat_data,
 
       if (d)
        {
-         if (verbose)
-           WARN ((0, 0, _("%s: Directory has been renamed from %s"),
-                  quotearg_colon (name_buffer),
-                  quote_n (1, d->name)));
-         directory->orig = d;
-         DIR_SET_FLAG (directory, DIRF_RENAMED);
+         if (strcmp (d->name, name_buffer))
+           {
+             WARNOPT (WARN_RENAME_DIRECTORY,
+                      (0, 0, _("%s: Directory has been renamed from %s"),
+                       quotearg_colon (name_buffer),
+                       quote_n (1, d->name)));
+             directory->orig = d;
+             DIR_SET_FLAG (directory, DIRF_RENAMED);
+             dirlist_replace_prefix (d->name, name_buffer);
+           }
          directory->children = CHANGED_CHILDREN;
        }
       else
        {
          DIR_SET_FLAG (directory, DIRF_NEW);
-         if (verbose)
-           WARN ((0, 0, _("%s: Directory is new"),
-                  quotearg_colon (name_buffer)));
+         WARNOPT (WARN_NEW_DIRECTORY,
+                  (0, 0, _("%s: Directory is new"),
+                   quotearg_colon (name_buffer)));
          directory->children =
            (listed_incremental_option
             || (OLDER_STAT_TIME (*stat_data, m)
@@ -455,44 +545,54 @@ procdir (char *name_buffer, struct stat *stat_data,
   if (one_file_system_option && device != stat_data->st_dev
       /* ... except if it was explicitely given in the command line */
       && !is_individual_file (name_buffer))
+    /* FIXME:
+       WARNOPT (WARN_XDEV,
+                (0, 0,
+                 _("%s: directory is on a different filesystem; not dumped"),
+                 quotearg_colon (directory->name)));
+    */
     directory->children = NO_CHILDREN;
-  else if (children == ALL_CHILDREN)
-    directory->children = ALL_CHILDREN;
+  else if (flag & PD_FORCE_CHILDREN)
+    {
+      directory->children = PD_CHILDREN(flag);
+      if (directory->children == NO_CHILDREN)
+       *entry = 'N';
+    }
 
   DIR_SET_FLAG (directory, DIRF_INIT);
 
-  {
-    const char *tag_file_name;
-
-    switch (check_exclusion_tags (name_buffer, &tag_file_name))
-      {
-      case exclusion_tag_all:
-       /* This warning can be duplicated by code in dump_file0, but only
-          in case when the topmost directory being archived contains
-          an exclusion tag. */
-       exclusion_tag_warning (name_buffer, tag_file_name,
-                              _("directory not dumped"));
-       if (entry)
+  if (directory->children != NO_CHILDREN)
+    {
+      const char *tag_file_name;
+
+      switch (check_exclusion_tags (st, &tag_file_name))
+       {
+       case exclusion_tag_all:
+         /* This warning can be duplicated by code in dump_file0, but only
+            in case when the topmost directory being archived contains
+            an exclusion tag. */
+         exclusion_tag_warning (name_buffer, tag_file_name,
+                                _("directory not dumped"));
          *entry = 'N';
-       directory->children = NO_CHILDREN;
-       break;
+         directory->children = NO_CHILDREN;
+         break;
 
-      case exclusion_tag_contents:
-       exclusion_tag_warning (name_buffer, tag_file_name,
-                              _("contents not dumped"));
-       directory->children = NO_CHILDREN;
-       break;
+       case exclusion_tag_contents:
+         exclusion_tag_warning (name_buffer, tag_file_name,
+                                _("contents not dumped"));
+         directory->children = NO_CHILDREN;
+         break;
 
-      case exclusion_tag_under:
-       exclusion_tag_warning (name_buffer, tag_file_name,
-                              _("contents not dumped"));
-       directory->tagfile = tag_file_name;
-       break;
+       case exclusion_tag_under:
+         exclusion_tag_warning (name_buffer, tag_file_name,
+                                _("contents not dumped"));
+         directory->tagfile = tag_file_name;
+         break;
 
-      case exclusion_tag_none:
-       break;
-      }
-  }
+       case exclusion_tag_none:
+         break;
+       }
+    }
 
   return directory;
 }
@@ -508,7 +608,7 @@ procdir (char *name_buffer, struct stat *stat_data,
    DIRECTORY->dump is replaced with the created template. Each entry is
    prefixed with ' ' if it was present in DUMP and with 'Y' otherwise. */
 
-void
+static void
 makedumpdir (struct directory *directory, const char *dir)
 {
   size_t i,
@@ -574,46 +674,37 @@ makedumpdir (struct directory *directory, const char *dir)
   free (array);
 }
 
-/* Recursively scan the given directory. */
-static const char *
-scan_directory (char *dir, dev_t device)
+/* Recursively scan the directory identified by ST.  */
+struct directory *
+scan_directory (struct tar_stat_info *st)
 {
-  char *dirp = savedir (dir);  /* for scanning directory */
-  char *name_buffer;           /* directory, `/', and directory member */
-  size_t name_buffer_size;     /* allocated size of name_buffer, minus 2 */
-  size_t name_length;          /* used length in name_buffer */
-  struct stat stat_data;
+  char const *dir = st->orig_file_name;
+  char *dirp = get_directory_entries (st);
+  dev_t device = st->stat.st_dev;
+  bool cmdline = ! st->parent;
+  namebuf_t nbuf;
+  char *tmp;
   struct directory *directory;
+  char ch;
 
   if (! dirp)
     savedir_error (dir);
 
-  name_buffer_size = strlen (dir) + NAME_FIELD_SIZE;
-  name_buffer = xmalloc (name_buffer_size + 2);
-  strcpy (name_buffer, dir);
-  if (! ISSLASH (dir[strlen (dir) - 1]))
-    strcat (name_buffer, "/");
-  name_length = strlen (name_buffer);
+  tmp = xstrdup (dir);
+  zap_slashes (tmp);
 
-  if (deref_stat (dereference_option, name_buffer, &stat_data))
-    {
-      stat_diag (name_buffer);
-      /* FIXME: used to be
-           children = CHANGED_CHILDREN;
-        but changed to: */
-      free (name_buffer);
-      free (dirp);
-      return NULL;
-    }
+  directory = procdir (tmp, st,
+                      (cmdline ? PD_FORCE_INIT : 0),
+                      &ch);
+
+  free (tmp);
 
-  directory = procdir (name_buffer, &stat_data, device, NO_CHILDREN, false,
-                      NULL);
+  nbuf = namebuf_create (dir);
 
   if (dirp && directory->children != NO_CHILDREN)
     {
       char *entry;     /* directory entry being scanned */
-      size_t entrylen; /* length of directory entry */
-      dumpdir_iter_t itr;
+      struct dumpdir_iter *itr;
 
       makedumpdir (directory, dirp);
 
@@ -621,74 +712,105 @@ scan_directory (char *dir, dev_t device)
           entry;
           entry = dumpdir_next (itr))
        {
-         entrylen = strlen (entry);
-         if (name_buffer_size <= entrylen - 1 + name_length)
-           {
-             do
-               name_buffer_size += NAME_FIELD_SIZE;
-             while (name_buffer_size <= entrylen - 1 + name_length);
-             name_buffer = xrealloc (name_buffer, name_buffer_size + 2);
-           }
-         strcpy (name_buffer + name_length, entry + 1);
+         char *full_name = namebuf_name (nbuf, entry + 1);
 
          if (*entry == 'I') /* Ignored entry */
            *entry = 'N';
-         else if (excluded_name (name_buffer))
+         else if (excluded_name (full_name))
            *entry = 'N';
          else
            {
-             if (deref_stat (dereference_option, name_buffer, &stat_data))
+             int fd = st->fd;
+             void (*diag) (char const *) = 0;
+             struct tar_stat_info stsub;
+             tar_stat_init (&stsub);
+
+             if (fd < 0)
                {
-                 stat_diag (name_buffer);
-                 *entry = 'N';
-                 continue;
+                 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 (S_ISDIR (stat_data.st_mode))
+             if (diag)
                {
-                 *entry = 'D';
-                 procdir (name_buffer, &stat_data, device,
-                          directory->children,
-                          verbose_option, entry);
+                 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';
 
-             else if (one_file_system_option && device != stat_data.st_dev)
+                 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 (stat_data, m)
+             else if (OLDER_STAT_TIME (stsub.stat, m)
                       && (!after_date_option
-                          || OLDER_STAT_TIME (stat_data, c)))
+                          || OLDER_STAT_TIME (stsub.stat, c)))
                *entry = 'N';
              else
                *entry = 'Y';
+
+             tar_stat_destroy (&stsub);
            }
        }
       free (itr);
     }
 
-  free (name_buffer);
+  namebuf_free (nbuf);
+
   if (dirp)
     free (dirp);
 
-  return directory->dump ? directory->dump->contents : NULL;
+  return directory;
+}
+
+/* Return pointer to the contents of the directory DIR */
+const char *
+directory_contents (struct directory *dir)
+{
+  if (!dir)
+    return NULL;
+  return dir->dump ? dir->dump->contents : NULL;
 }
 
+/* A "safe" version of directory_contents, which never returns NULL. */
 const char *
-get_directory_contents (char *dir, dev_t device)
+safe_directory_contents (struct directory *dir)
 {
-  return scan_directory (dir, device);
+  const char *ret = directory_contents (dir);
+  return ret ? ret : "\0\0\0\0";
 }
 
 \f
 static void
-obstack_code_rename (struct obstack *stk, char *from, char *to)
+obstack_code_rename (struct obstack *stk, char const *from, char const *to)
 {
-  char *s;
+  char const *s;
 
   s = from[0] == 0 ? from :
                      safer_name_suffix (from, false, absolute_names_option);
@@ -701,12 +823,9 @@ obstack_code_rename (struct obstack *stk, char *from, char *to)
   obstack_grow (stk, s, strlen (s) + 1);
 }
 
-static bool
-rename_handler (void *data, void *proc_data)
+static void
+store_rename (struct directory *dir, struct obstack *stk)
 {
-  struct directory *dir = data;
-  struct obstack *stk = proc_data;
-
   if (DIR_IS_RENAMED (dir))
     {
       struct directory *prev, *p;
@@ -745,19 +864,21 @@ rename_handler (void *data, void *proc_data)
          obstack_code_rename (stk, "", prev->name);
        }
     }
-  return true;
 }
 
-const char *
-append_incremental_renames (const char *dump)
+void
+append_incremental_renames (struct directory *dir)
 {
   struct obstack stk;
   size_t size;
+  struct directory *dp;
+  const char *dump;
 
-  if (directory_table == NULL)
-    return dump;
+  if (dirhead == NULL)
+    return;
 
   obstack_init (&stk);
+  dump = directory_contents (dir);
   if (dump)
     {
       size = dumpdir_size (dump) - 1;
@@ -766,15 +887,16 @@ append_incremental_renames (const char *dump)
   else
     size = 0;
 
-  hash_do_for_each (directory_table, rename_handler, &stk);
+  for (dp = dirhead; dp; dp = dp->next)
+    store_rename (dp, &stk);
+
   if (obstack_object_size (&stk) != size)
     {
       obstack_1grow (&stk, 0);
-      dump = obstack_finish (&stk);
+      dumpdir_free (dir->dump);
+      dir->dump = dumpdir_create (obstack_finish (&stk));
     }
-  else
-    obstack_free (&stk, NULL);
-  return dump;
+  obstack_free (&stk, NULL);
 }
 
 \f
@@ -799,8 +921,8 @@ read_incr_db_01 (int version, const char *initbuf)
   uintmax_t u;
   time_t sec;
   long int nsec;
-  char *buf = 0;
-  size_t bufsize;
+  char *buf = NULL;
+  size_t bufsize = 0;
   char *ebuf;
   long lineno = 1;
 
@@ -1094,7 +1216,7 @@ read_timespec (FILE *fp, struct timespec *pval)
 
 /* Read incremental snapshot format 2 */
 static void
-read_incr_db_2 ()
+read_incr_db_2 (void)
 {
   uintmax_t u;
   struct obstack stk;
@@ -1159,13 +1281,16 @@ void
 read_directory_file (void)
 {
   int fd;
-  char *buf = 0;
-  size_t bufsize;
+  char *buf = NULL;
+  size_t bufsize = 0;
+  int flags = O_RDWR | O_CREAT;
 
+  if (incremental_level == 0)
+    flags |= O_TRUNC;
   /* 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
      we chdir in the meantime.  */
-  fd = open (listed_incremental_option, O_RDWR | O_CREAT, MODE_RW);
+  fd = open (listed_incremental_option, flags, MODE_RW);
   if (fd < 0)
     {
       open_error (listed_incremental_option);
@@ -1180,6 +1305,13 @@ read_directory_file (void)
       return;
     }
 
+  /* Consume the first name from the name list and reset the
+     list afterwards.  This is done to change to the new
+     directory, if the first name is a chdir request (-C dir),
+     which is necessary to recreate absolute file names. */
+  name_from_list ();
+  blank_name_list ();
+
   if (0 < getline (&buf, &bufsize, listed_incremental_stream))
     {
       char *ebuf;
@@ -1234,7 +1366,7 @@ write_directory_file_entry (void *entry, void *data)
   if (DIR_IS_FOUND (directory))
     {
       char buf[UINTMAX_STRSIZE_BOUND];
-      char *s;
+      char const *s;
 
       s = DIR_IS_NFS (directory) ? "1" : "0";
       fwrite (s, 2, 1, fp);
@@ -1253,7 +1385,7 @@ write_directory_file_entry (void *entry, void *data)
       if (directory->dump)
        {
          const char *p;
-         dumpdir_iter_t itr;
+         struct dumpdir_iter *itr;
 
          for (p = dumpdir_first (directory->dump, 0, &itr);
               p;
@@ -1277,7 +1409,7 @@ write_directory_file (void)
   if (! fp)
     return;
 
-  if (fseek (fp, 0L, SEEK_SET) != 0)
+  if (fseeko (fp, 0L, SEEK_SET) != 0)
     seek_error (listed_incremental_option);
   if (sys_truncate (fileno (fp)) != 0)
     truncate_error (listed_incremental_option);
@@ -1319,7 +1451,7 @@ get_gnu_dumpdir (struct tar_stat_info *stat_info)
   to = archive_dir;
 
   set_next_block_after (current_header);
-  mv_begin (stat_info);
+  mv_begin_read (stat_info);
 
   for (; size > 0; size -= copied)
     {
@@ -1434,7 +1566,8 @@ dumpdir_ok (char *dumpdir)
     }
 
   if (has_tempdir)
-    WARN ((0, 0, _("Malformed dumpdir: 'X' never used")));
+    WARNOPT (WARN_BAD_DUMPDIR,
+            (0, 0, _("Malformed dumpdir: 'X' never used")));
 
   return true;
 }
@@ -1573,7 +1706,7 @@ try_purge_directory (char const *directory_name)
     }
   free (p);
   dumpdir_free (dump);
-  
+
   free (current_dir);
   return true;
 }
This page took 0.046922 seconds and 4 git commands to generate.