Hello all. Resending now, after unlock, a not-so-big patch implementing recursive "nodump" flag handling in dump(8), for the case the flag is being set on a directory. Tested successfully for many months on i386. Patch is modelled after FreeBSD's dump(8) code.
-- WBR, Vadim Zhukov A: Because it messes up the order in which people normally read text. Q: Why is top-posting such a bad thing? A: Top-posting. Q: What is the most annoying thing in e-mail? Index: traverse.c =================================================================== RCS file: /cvs/src/sbin/dump/traverse.c,v retrieving revision 1.24 diff -u -p -r1.24 traverse.c --- traverse.c 27 Oct 2009 23:59:32 -0000 1.24 +++ traverse.c 16 Feb 2012 11:02:26 -0000 @@ -60,9 +60,9 @@ union dinode { #define HASDUMPEDFILE 0x1 #define HASSUBDIRS 0x2 -static int dirindir(ino_t ino, daddr64_t blkno, int level, off_t *size); -static void dmpindir(ino_t ino, daddr64_t blk, int level, off_t *size); -static int searchdir(ino_t ino, daddr64_t blkno, long size, off_t filesize); +static int dirindir(ino_t, daddr64_t, int, off_t *, off_t *, int); +static void dmpindir(ino_t, daddr64_t, int, off_t *); +static int searchdir(ino_t, daddr64_t, long, off_t, off_t *, int); /* * This is an estimation of the number of TP_BSIZE blocks in the file. @@ -103,18 +103,9 @@ blockest(union dinode *dp) return (blkest + 1); } -/* Auxiliary macro to pick up files changed since previous dump. */ -#define CHANGEDSINCE(dp, t) \ - (DIP(dp, di_mtime) >= (t) || DIP(dp, di_ctime) >= (t)) - -/* The WANTTODUMP macro decides whether a file should be dumped. */ -#ifdef UF_NODUMP -#define WANTTODUMP(dp) \ - (CHANGEDSINCE(dp, spcl.c_ddate) && \ - (nonodump || (DIP(dp, di_flags) & UF_NODUMP) != UF_NODUMP)) -#else -#define WANTTODUMP(dp) CHANGEDSINCE(dp, spcl.c_ddate) -#endif +/* true if "nodump" flag has no effect here, i.e. dumping allowed */ +#define CHECKNODUMP(dp) \ + (nonodump || (DIP((dp), di_flags) & UF_NODUMP) != UF_NODUMP) /* * Determine if given inode should be dumped @@ -131,7 +122,7 @@ mapfileino(ino_t ino, off_t *tapesize, i SETINO(ino, usedinomap); if (mode == IFDIR) SETINO(ino, dumpdirmap); - if (WANTTODUMP(dp)) { + if (CHECKNODUMP(dp) && DIP(dp, di_mtime) >= spcl.c_ddate) { SETINO(ino, dumpinomap); if (mode != IFREG && mode != IFDIR && mode != IFLNK) *tapesize += 1; @@ -139,8 +130,11 @@ mapfileino(ino_t ino, off_t *tapesize, i *tapesize += blockest(dp); return; } - if (mode == IFDIR) + if (mode == IFDIR) { + if (!CHECKNODUMP(dp)) + CLRINO(ino, usedinomap); *dirskipped = 1; + } } void @@ -307,7 +301,7 @@ int mapdirs(ino_t maxino, off_t *tapesize) { union dinode *dp; - int i, isdir; + int i, isdir, nodump; char *map; ino_t ino; union dinode di; @@ -320,7 +314,15 @@ mapdirs(ino_t maxino, off_t *tapesize) 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 = !nonodump && !TSTINO(ino, usedinomap); + if ((isdir & 1) == 0 || TSTINO(ino, dumpinomap) && !nodump) continue; dp = getino(ino, &i); /* @@ -335,7 +337,7 @@ mapdirs(ino_t maxino, off_t *tapesize) if (DIP(&di, di_db[i]) != 0) ret |= searchdir(ino, DIP(&di, di_db[i]), sblksize(sblock, DIP(dp, di_size), i), - filesize); + filesize, tapesize, nodump); if (ret & HASDUMPEDFILE) filesize = 0; else @@ -344,7 +346,8 @@ mapdirs(ino_t maxino, off_t *tapesize) for (i = 0; filesize > 0 && i < NIADDR; i++) { if (DIP(&di, di_ib[i]) == 0) continue; - ret |= dirindir(ino, DIP(&di, di_ib[i]), i, &filesize); + ret |= dirindir(ino, DIP(&di, di_ib[i]), i, &filesize, + tapesize, nodump); } if (ret & HASDUMPEDFILE) { SETINO(ino, dumpinomap); @@ -352,7 +355,11 @@ mapdirs(ino_t maxino, off_t *tapesize) 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; @@ -368,7 +375,8 @@ mapdirs(ino_t maxino, off_t *tapesize) * require the directory to be dumped. */ static int -dirindir(ino_t ino, daddr64_t blkno, int ind_level, off_t *filesize) +dirindir(ino_t ino, daddr64_t blkno, int ind_level, off_t *filesize, + off_t *tapesize, int nodump) { int ret = 0; int i; @@ -383,7 +391,7 @@ dirindir(ino_t ino, daddr64_t blkno, int blkno = ((int64_t *)idblk)[i]; if (blkno != 0) ret |= searchdir(ino, blkno, sblock->fs_bsize, - *filesize); + *filesize, tapesize, nodump); if (ret & HASDUMPEDFILE) *filesize = 0; else @@ -398,7 +406,8 @@ dirindir(ino_t ino, daddr64_t blkno, int else blkno = ((int64_t *)idblk)[i]; if (blkno != 0) - ret |= dirindir(ino, blkno, ind_level, filesize); + ret |= dirindir(ino, blkno, ind_level, filesize, + tapesize, nodump); } return (ret); } @@ -409,12 +418,14 @@ dirindir(ino_t ino, daddr64_t blkno, int * contains any subdirectories. */ static int -searchdir(ino_t ino, daddr64_t blkno, long size, off_t filesize) +searchdir(ino_t ino, daddr64_t blkno, long size, off_t filesize, + off_t *tapesize, int nodump) { struct direct *dp; + union dinode *ip; long loc; static caddr_t dblk; - int ret = 0; + int mode, ret = 0; if (dblk == NULL && (dblk = malloc(sblock->fs_bsize)) == NULL) quit("searchdir: cannot allocate indirect memory.\n"); @@ -436,15 +447,32 @@ searchdir(ino_t ino, daddr64_t blkno, lo 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, &mode); + if (TSTINO(dp->d_ino, dumpinomap)) { + CLRINO(dp->d_ino, dumpinomap); + *tapesize -= blockest(ip); + } + /* + * Add back to dumpdirmap and remove from usedinomap + * to propagate nodump. + */ + if (mode == IFDIR) { + SETINO(dp->d_ino, dumpdirmap); + CLRINO(dp->d_ino, usedinomap); + 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);