Properly deal with inodes excluded from incremental dump
authorStelian Pop <stelian@popies.net>
Mon, 22 Mar 2010 16:08:10 +0000 (16:08 +0000)
committerStelian Pop <stelian@popies.net>
Mon, 22 Mar 2010 16:08:10 +0000 (16:08 +0000)
Files which are excluded from a dump (via -e or the nodump attribute)
still have their inode marked as in-use in the dump header.  This can
cause problems when restoring from an incremental dump, if that inode is
currently assigned in the symtable:

  - If assigned to a file that is being overwritten by another inode,
    the old entry will be renamed away, but never reclaimed, thus
    leaving the TMPNAME flag turned on and preventing its removal.

  - If assigned to a directory, that directory will not be removed by
    removeoldleaves(), and its entry will linger on in its parent's
    e_entries.

    - If its parent is being updated, removeleaf() will wrongly be
      called on the entry.  The above comment about TMPNAME also
      applies.

    - If its parent is being deleted, this will fail due to the entry's
      presence.

CHANGES
restore/restore.c

diff --git a/CHANGES b/CHANGES
index ae9f2836b0148fd09f94c4e6dac8c630360916a8..b31b75a3b8966f8ca70979df705bf72d31bdad16 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,4 @@
-$Id: CHANGES,v 1.309 2010/03/22 15:40:55 stelian Exp $
+$Id: CHANGES,v 1.310 2010/03/22 16:08:10 stelian Exp $
 
 Changes between versions 0.4b42 and 0.4b43 (released ?????????????)
 ===================================================================
@@ -33,6 +33,11 @@ Changes between versions 0.4b42 and 0.4b43 (released ?????????????)
        to John Austin <jaustin1@users.sourceforge.net> for reporting
        the bug.
 
+8.     Fix some issues when restoring a dump which was generated using
+       exclusion patterns (either via -e or via the nodump attribute)
+       (see the Debian bug #574667 for details. Thanks to Frédéric
+       Brière <fbriere@fbriere.net> for the bug report and the associated
+       patch.
 
 Changes between versions 0.4b41 and 0.4b42 (released June 18, 2009)
 ===================================================================
index c87b532d39cfc9046650febb5195e17400a2b4ef..780fd76f04bdd0a3d61297acf9719c0295a6a805 100644 (file)
@@ -37,7 +37,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-       "$Id: restore.c,v 1.38 2008/04/17 15:22:56 stelian Exp $";
+       "$Id: restore.c,v 1.39 2010/03/22 16:08:10 stelian Exp $";
 #endif /* not lint */
 
 #include <config.h>
@@ -566,6 +566,9 @@ keyval(int key)
 
 /*
  * Find unreferenced link names.
+ *
+ * This also takes care of directories which were missed by removeoldleaves(),
+ * because their inode has been reused, but excluded from the dump.
  */
 void
 findunreflinks(void)
@@ -583,12 +586,19 @@ findunreflinks(void)
                        continue;
                for (j = 0; j < dirhash_size; j++) {
                        for (np = ep->e_entries[j]; np != NULL; np = np->e_sibling) {
-                               if (np->e_flags == 0) {
+                               if ((np->e_flags & ~TMPNAME) == 0) {
                                        Dprintf(stdout,
                                            "%s: remove unreferenced name\n",
                                            myname(np));
-                                       removeleaf(np);
-                                       freeentry(np);
+                                       if (np->e_type == LEAF) {
+                                               removeleaf(np);
+                                               freeentry(np);
+                                       } else {
+                                               np->e_flags |= TMPNAME;
+                                               deleteino(np->e_ino);
+                                               np->e_next = removelist;
+                                               removelist = np;
+                                       }
                                }
                        }
                }
@@ -609,6 +619,17 @@ findunreflinks(void)
                                            myname(np));
                                        removeleaf(np);
                                        freeentry(np);
+                               } else {
+                                       if ((np->e_flags & ~TMPNAME) != 0)
+                                               badentry(np, "unreferenced with flags");
+
+                                       if (np->e_flags == 0) {
+                                               Dprintf(stdout,
+                                                   "%s: remove unreferenced name\n",
+                                                   myname(np));
+                                               np->e_next = ep->e_next;
+                                               ep->e_next = np;
+                                       }
                                }
                        }
                }