From f6e1ffa4b425c735543d6c87f93c2e4bf207f1bb Mon Sep 17 00:00:00 2001
From: Stelian Pop <stelian@popies.net>
Date: Mon, 22 Mar 2010 16:08:10 +0000
Subject: [PATCH] Properly deal with inodes excluded from incremental dump

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           |  7 ++++++-
 restore/restore.c | 29 +++++++++++++++++++++++++----
 2 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/CHANGES b/CHANGES
index ae9f283..b31b75a 100644
--- 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)
 ===================================================================
diff --git a/restore/restore.c b/restore/restore.c
index c87b532..780fd76 100644
--- a/restore/restore.c
+++ b/restore/restore.c
@@ -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;
+					}
 				}
 			}
 		}
-- 
2.39.5