Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Feb 2001 20:12:34 -0800
From:      Dima Dorfman <dima@unixfreak.org>
To:        audit@freebsd.org
Subject:   Propagating the nodump flag
Message-ID:  <20010301041234.9F3D63E09@bazooka.unixfreak.org>

next in thread | raw e-mail | index | archive | help
Some time ago, on -arch, phk proposed that the nodump flag should be
propagated if it's set on a directory (see 'inheriting the "nodump"
flag ?' around Dec. 2000).  This was generally considered a good idea,
however, the patch to the kernel he proposed was thought an ugly hack.
In addition, jeroen pointed out that NetBSD had implemented this
functionality the Right Way(tm), in dump(8).

Attached below is a port of NetBSD's patch to FreeBSD's dump(8).  The
patch is probably more complex than it should have been due to dump's
obscure tree-walker.  For the technical details of what it does, see:
http://lists.openresources.com/NetBSD/tech-kern/msg00453.html (note
that the patch there is not identical to the one below, and should not
be used; the reference is provided for its excellent technical
explanation of the patch).

I've been using this on two of my hosts for a while, and it works as
expected.  Given the additional fact that NetBSD has had this for
almost two years, and that the patch below looks very similar to the
one they applied, I doubt it significantly breaks anything.

Comments?  Reviews?

Thanks in advance

					Dima Dorfman
					dima@unixfreak.org


Index: traverse.c
===================================================================
RCS file: /st/src/FreeBSD/src/sbin/dump/traverse.c,v
retrieving revision 1.11
diff -u -r1.11 traverse.c
--- traverse.c	2000/04/14 06:14:59	1.11
+++ traverse.c	2001/02/20 01:39:06
@@ -74,9 +74,11 @@
 typedef	long fsizeT;
 #endif
 
-static	int dirindir __P((ino_t ino, daddr_t blkno, int level, long *size));
+static	int dirindir __P((ino_t ino, daddr_t blkno, int level, long *size,
+    long *tapesize, int nodump));
 static	void dmpindir __P((ino_t ino, daddr_t blk, int level, fsizeT *size));
-static	int searchdir __P((ino_t ino, daddr_t blkno, long size, long filesize));
+static	int searchdir __P((ino_t ino, daddr_t blkno, long size, long filesize,
+    long *tapesize, int nodump));
 
 /*
  * This is an estimation of the number of TP_BSIZE blocks in the file.
@@ -152,10 +154,14 @@
 		dp = getino(ino);
 		if ((mode = (dp->di_mode & IFMT)) == 0)
 			continue;
-		SETINO(ino, usedinomap);
+		/*
+		 * All dirs go in dumpdirmap; only inodes that are to
+		 * be dumped go in usedinomap and dumpinomap, however.
+		 */
 		if (mode == IFDIR)
 			SETINO(ino, dumpdirmap);
 		if (WANTTODUMP(dp)) {
+			SETINO(ino, usedinomap);
 			SETINO(ino, dumpinomap);
 			if (mode != IFREG && mode != IFDIR && mode != IFLNK)
 				*tapesize += 1;
@@ -192,9 +198,10 @@
 	long *tapesize;
 {
 	register struct	dinode *dp;
-	register int i, isdir;
+	register int i, isdir, nodump;
 	register char *map;
 	register ino_t ino;
+	struct dinode di;
 	long filesize;
 	int ret, change = 0;
 
@@ -204,24 +211,34 @@
 			isdir = *map++;
 		else
 			isdir >>= 1;
-		if ((isdir & 1) == 0 || TSTINO(ino, dumpinomap))
+		/*
+		 * If a directory has been removed from usedinomap, it
+		 * either has the nodump flag set, or has inherited
+		 * it.  Although a directory can't be in dumpinomap if
+		 * it isn't in usedinomap, we have to go through it to
+		 * propagate the nodump flag.
+		 */
+		nodump = (TSTINO(ino, usedinomap) == 0);
+		if ((isdir & 1) == 0 || (TSTINO(ino, dumpinomap) && !nodump))
 			continue;
 		dp = getino(ino);
-		filesize = dp->di_size;
+		di = *dp;	/* inode buf may change in searchdir(). */
+		filesize = di.di_size;
 		for (ret = 0, i = 0; filesize > 0 && i < NDADDR; i++) {
-			if (dp->di_db[i] != 0)
-				ret |= searchdir(ino, dp->di_db[i],
+			if (di.di_db[i] != 0)
+				ret |= searchdir(ino, di.di_db[i],
 					(long)dblksize(sblock, dp, i),
-					filesize);
+					filesize, tapesize, nodump);
 			if (ret & HASDUMPEDFILE)
 				filesize = 0;
 			else
 				filesize -= sblock->fs_bsize;
 		}
 		for (i = 0; filesize > 0 && i < NIADDR; i++) {
-			if (dp->di_ib[i] == 0)
+			if (di.di_ib[i] == 0)
 				continue;
-			ret |= dirindir(ino, dp->di_ib[i], i, &filesize);
+			ret |= dirindir(ino, di.di_ib[i], i, &filesize,
+			    tapesize, nodump);
 		}
 		if (ret & HASDUMPEDFILE) {
 			SETINO(ino, dumpinomap);
@@ -229,12 +246,15 @@
 			change = 1;
 			continue;
 		}
-		if ((ret & HASSUBDIRS) == 0) {
+		if (nodump) {
+			if (ret & HASSUBDIRS)
+				change = 1;	/* subdirs inherit nodump */
+			CLRINO(ino, dumpdirmap);
+		} else if ((ret & HASSUBDIRS) == 0)
 			if (!TSTINO(ino, dumpinomap)) {
 				CLRINO(ino, dumpdirmap);
 				change = 1;
 			}
-		}
 	}
 	return (change);
 }
@@ -245,11 +265,13 @@
  * require the directory to be dumped.
  */
 static int
-dirindir(ino, blkno, ind_level, filesize)
+dirindir(ino, blkno, ind_level, filesize, tapesize, nodump)
 	ino_t ino;
 	daddr_t blkno;
 	int ind_level;
 	long *filesize;
+	long *tapesize;
+	int nodump;
 {
 	int ret = 0;
 	register int i;
@@ -261,7 +283,7 @@
 			blkno = idblk[i];
 			if (blkno != 0)
 				ret |= searchdir(ino, blkno, sblock->fs_bsize,
-					*filesize);
+					*filesize, tapesize, nodump);
 			if (ret & HASDUMPEDFILE)
 				*filesize = 0;
 			else
@@ -273,7 +295,8 @@
 	for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
 		blkno = idblk[i];
 		if (blkno != 0)
-			ret |= dirindir(ino, blkno, ind_level, filesize);
+			ret |= dirindir(ino, blkno, ind_level, filesize,
+			    tapesize, nodump);
 	}
 	return (ret);
 }
@@ -284,13 +307,16 @@
  * contains any subdirectories.
  */
 static int
-searchdir(ino, blkno, size, filesize)
+searchdir(ino, blkno, size, filesize, tapesize, nodump)
 	ino_t ino;
 	daddr_t blkno;
 	register long size;
 	long filesize;
+	long *tapesize;
+	int nodump;
 {
 	register struct direct *dp;
+	register struct dinode *ip;
 	register long loc, ret = 0;
 	char dblk[MAXBSIZE];
 
@@ -311,16 +337,30 @@
 				continue;
 			if (dp->d_name[1] == '.' && dp->d_name[2] == '\0')
 				continue;
-		}
-		if (TSTINO(dp->d_ino, dumpinomap)) {
-			ret |= HASDUMPEDFILE;
-			if (ret & HASSUBDIRS)
-				break;
 		}
-		if (TSTINO(dp->d_ino, dumpdirmap)) {
-			ret |= HASSUBDIRS;
-			if (ret & HASDUMPEDFILE)
-				break;
+		if (nodump) {
+			ip = getino(dp->d_ino);
+			if (TSTINO(dp->d_ino, dumpinomap)) {
+				CLRINO(dp->d_ino, dumpinomap);
+				CLRINO(dp->d_ino, usedinomap);
+				*tapesize -= blockest(ip);
+			}
+			/* Add back to dumpdirmap to propagate nodump. */
+			if ((ip->di_mode & IFMT) == IFDIR) {
+				SETINO(dp->d_ino, dumpdirmap);
+				ret |= HASSUBDIRS;
+			}
+		} else {
+			if (TSTINO(dp->d_ino, dumpinomap)) {
+				ret |= HASDUMPEDFILE;
+				if (ret & HASSUBDIRS)
+					break;
+			}
+			if (TSTINO(dp->d_ino, dumpdirmap)) {
+				ret |= HASSUBDIRS;
+				if (ret & HASDUMPEDFILE)
+					break;
+			}
 		}
 	}
 	return (ret);

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-audit" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010301041234.9F3D63E09>