-$Id: TODO,v 1.6 1999/11/17 22:51:27 tiniou Exp $
+$Id: TODO,v 1.7 1999/11/21 00:17:12 tiniou Exp $
Need to verify:
---------------
-1. Verify that dump works correctly on rev 1 ext2fses (need success
- reports)
-
-2. Verify that dump works with kerberos authentification (this
+1. Verify that dump works with kerberos authentification (this
was ported from *BSD and was not tested - in fact, this
wasn't even compiled in!). Need success reports for this.
Urgent items (for the next stable version):
-------------------------------------------
-1. Make dump honor the no-dump attribute on directories. Currently, it
- honours it only on files. This means that a directory flagged with
- the no-dump attribute will be dumped if it contains a file without
- the no-dump flag.
-
All others:
-----------
2. More documentation? Examples, crontab?
-3. Explore and correct dump problems on a 4GB+ active
- filesystem (lseek/read negative count).
-
-4. Clean-up the code by removing all those #ifdef _BSD,
- since nobody would ever re-compile this on a BSD system.
- Since the tape format is the same, the native BSD
- restore can be used to restore tapes...
+3. Explore and correct dump problems on active filesystems
+ (lseek/read negative count).
-5. Reimplement the ext2 specific code in a "backend" and
+4. Reimplement the ext2 specific code in a "backend" and
make the dump code more generic. This would allow creation
of other backends for other filesystems. Implementing a
(v)fat backend should be quite easy, as for BSD ffs (we
- already have the code for this).
+ already have the code for this). The BSD code in traverse.c
+ (all those #ifdef _BSD) should go into the ffs backend.
-6. Implement a DEBUG option which doesn't fork on each tape, making
+5. Implement a DEBUG option which doesn't fork on each tape, making
it able to debug dump with gdb.
#ifndef lint
static const char rcsid[] =
- "$Id: traverse.c,v 1.8 1999/11/17 22:46:43 tiniou Exp $";
+ "$Id: traverse.c,v 1.9 1999/11/21 00:17:16 tiniou Exp $";
#endif /* not lint */
#include <sys/param.h>
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));
#endif
+static void mapfileino __P((ino_t ino, long *tapesize, int *dirskipped));
/*
* This is an estimation of the number of TP_BSIZE blocks in the file.
#define WANTTODUMP(dp) CHANGEDSINCE(dp, spcl.c_ddate)
#endif
+/*
+ * Determine if given inode should be dumped
+ */
+void
+mapfileino(ino_t ino, long *tapesize, int *dirskipped)
+{
+ register int mode;
+ register struct dinode *dp;
+
+ /*
+ * Skip inode if we've already marked it for dumping
+ */
+ if (TSTINO(ino, usedinomap))
+ return;
+ dp = getino(ino);
+ if ((mode = (dp->di_mode & IFMT)) == 0)
+ return;
+#ifdef __linux__
+ if (dp->di_nlink == 0 || dp->di_dtime != 0)
+ return;
+#endif
+ /*
+ * Put all dirs in dumpdirmap, inodes that are to be dumped in the
+ * used map. All inode but dirs who have the nodump attribute go
+ * to the usedinomap.
+ */
+ SETINO(ino, usedinomap);
+ if (mode == IFDIR)
+ SETINO(ino, dumpdirmap);
+ if (WANTTODUMP(dp)) {
+ SETINO(ino, dumpinomap);
+ if (mode != IFREG && mode != IFDIR && mode != IFLNK)
+ *tapesize += 1;
+ else
+ *tapesize += blockest(dp);
+ return;
+ }
+ if (mode == IFDIR) {
+#ifdef UF_NODUMP
+ if (!nonodump && (dp->di_flags & UF_NODUMP))
+ CLRINO(ino, usedinomap);
+#endif
+ *dirskipped = 1;
+ }
+}
+
/*
* Dump pass 1.
*
int
mapfiles(ino_t maxino, long *tapesize)
{
- register int mode;
register ino_t ino;
- register struct dinode *dp;
int anydirskipped = 0;
- for (ino = ROOTINO; ino < maxino; ino++) {
- dp = getino(ino);
- if ((mode = (dp->di_mode & IFMT)) == 0)
- continue;
-#ifdef __linux__
- if (dp->di_nlink == 0 || dp->di_dtime != 0)
- continue;
-#endif
- SETINO(ino, usedinomap);
- if (mode == IFDIR)
- SETINO(ino, dumpdirmap);
- if (WANTTODUMP(dp)) {
- SETINO(ino, dumpinomap);
- if (mode != IFREG && mode != IFDIR && mode != IFLNK)
- *tapesize += 1;
- else
- *tapesize += blockest(dp);
- continue;
- }
- if (mode == IFDIR)
- anydirskipped = 1;
- }
+ for (ino = ROOTINO; ino < maxino; ino++)
+ mapfileino(ino, tapesize, &anydirskipped);
+
/*
* Restore gets very upset if the root is not dumped,
* so ensure that it always is dumped.
#ifdef __linux__
struct mapfile_context {
long *tapesize;
- int anydirskipped;
+ int *anydirskipped;
};
static int
{
register struct dinode *dp;
register int mode;
- ino_t ino;
errcode_t retval;
struct mapfile_context *mfc;
+ ino_t ino;
ino = dirent->inode;
mfc = (struct mapfile_context *)private;
- dp = getino(ino);
- if ((mode = (dp->di_mode & IFMT)) != 0 &&
- dp->di_nlink != 0 && dp->di_dtime == 0) {
- SETINO(ino, usedinomap);
- if (mode == IFDIR)
- SETINO(ino, dumpdirmap);
- if (WANTTODUMP(dp)) {
- SETINO(ino, dumpinomap);
- if (mode != IFREG && mode != IFDIR && mode != IFLNK)
- *mfc->tapesize += 1;
- else
- *mfc->tapesize += blockest(dp);
- }
- if (mode == IFDIR) {
- mfc->anydirskipped = 1;
- if ((dirent->name[0] != '.' || dirent->name_len != 1) &&
- (dirent->name[0] != '.' || dirent->name[1] != '.' ||
- dirent->name_len != 2)) {
- retval = ext2fs_dir_iterate(fs, ino, 0, NULL,
- mapfilesindir, private);
- if (retval)
- return retval;
- }
+
+ mapfileino(dirent->inode, mfc->tapesize, mfc->anydirskipped);
+
+ dp = getino(dirent->inode);
+ mode = dp->di_mode & IFMT;
+ if (mode == IFDIR && dp->di_nlink != 0 && dp->di_dtime == 0) {
+ if ((dirent->name[0] != '.' || dirent->name_len != 1) &&
+ (dirent->name[0] != '.' || dirent->name[1] != '.' ||
+ dirent->name_len != 2)) {
+ retval = ext2fs_dir_iterate(fs, ino, 0, NULL,
+ mapfilesindir, private);
+ if (retval)
+ return retval;
}
}
return 0;
struct mapfile_context mfc;
ino_t dir_ino;
char dir_name [MAXPATHLEN];
- int i;
+ int i, anydirskipped = 0;
/*
* Mark every directory in the path as being dumped
dir_name);
exit(X_ABORT);
}
-/* SETINO(dir_ino, dumpinomap); */
- SETINO(dir_ino, dumpdirmap);
+ mapfileino(dir_ino, tapesize, &anydirskipped);
}
}
/*
com_err(disk, retval, "while translating %s", directory);
exit(X_ABORT);
}
-/* SETINO(dir_ino, dumpinomap); */
- SETINO(dir_ino, dumpdirmap);
+ mapfileino(dir_ino, tapesize, &anydirskipped);
mfc.tapesize = tapesize;
- mfc.anydirskipped = 0;
+ mfc.anydirskipped = &anydirskipped;
retval = ext2fs_dir_iterate(fs, dir_ino, 0, NULL, mapfilesindir,
(void *)&mfc);
com_err(disk, retval, "while mapping files in %s", directory);
exit(X_ABORT);
}
+ /*
+ * Ensure that the root inode actually appears in the file list
+ * for a subdir
+ */
+ mapfileino(ROOTINO, tapesize, &anydirskipped);
/*
* Restore gets very upset if the root is not dumped,
* so ensure that it always is dumped.
*/
-/* SETINO(ROOTINO, dumpinomap); */
- SETINO(ROOTINO, dumpdirmap);
- return (mfc.anydirskipped);
+ SETINO(ROOTINO, dumpinomap);
+ return anydirskipped;
}
#endif
+#ifdef __linux__
+struct mapdirs_context {
+ int *ret;
+ int nodump;
+ long *tapesize;
+};
+#endif
+
/*
* Dump pass 2.
*
#ifndef __linux__
register int i;
long filesize;
+#else
+ struct mapdirs_context mdc;
#endif
- int ret, change = 0;
+ int ret, change = 0, nodump;
isdir = 0; /* XXX just to get gcc to shut up */
for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
isdir = *map++;
else
isdir >>= 1;
- if ((isdir & 1) == 0 || TSTINO(ino, dumpinomap))
+ /*
+ * If dir has been removed from the used map, it's either
+ * because it had the nodump flag, or it herited it from
+ * its parent. A directory can't be in dumpinomap if not
+ * in usedinomap, but we have to go through it anyway
+ * to propagate the nodump attribute.
+ */
+ nodump = (TSTINO(ino, usedinomap) == 0);
+ if ((isdir & 1) == 0 ||
+ (TSTINO(ino, dumpinomap) && nodump == 0))
continue;
dp = getino(ino);
#ifdef __linux__
ret = 0;
- ext2fs_dir_iterate(fs, ino, 0, NULL, searchdir, (void *) &ret);
+ mdc.ret = &ret;
+ mdc.nodump = nodump;
+ mdc.tapesize = tapesize;
+ ext2fs_dir_iterate(fs, ino, 0, NULL, searchdir, (void *) &mdc);
#else /* __linux__ */
filesize = dp->di_size;
for (ret = 0, i = 0; filesize > 0 && i < NDADDR; i++) {
change = 1;
continue;
}
- if ((ret & HASSUBDIRS) == 0) {
+ if (nodump) {
+ if (ret & HASSUBDIRS)
+ change = 1; /* subdirs have inherited nodump */
+ CLRINO(ino, dumpdirmap);
+ } else if ((ret & HASSUBDIRS) == 0) {
if (!TSTINO(ino, dumpinomap)) {
CLRINO(ino, dumpdirmap);
change = 1;
static int
searchdir(struct ext2_dir_entry *dp, int offset, int blocksize, char *buf, void *private)
{
- int *ret = (int *) private;
+ struct mapdirs_context *mdc;
+ int *ret;
+ long *tapesize;
+ struct dinode *ip;
+
+ mdc = (struct mapdirs_context *)private;
+ ret = mdc->ret;
+ tapesize = mdc->tapesize;
if (dp->inode == 0)
return 0;
if (dp->name[1] == '.' && dp->name_len == 2)
return 0;
}
- if (TSTINO(dp->inode, dumpinomap)) {
- *ret |= HASDUMPEDFILE;
- if (*ret & HASSUBDIRS)
- return DIRENT_ABORT;
- }
- if (TSTINO(dp->inode, dumpdirmap)) {
- *ret |= HASSUBDIRS;
- if (*ret & HASDUMPEDFILE)
- return DIRENT_ABORT;
+ if (mdc->nodump) {
+ ip = getino(dp->inode);
+ if (TSTINO(dp->inode, dumpinomap)) {
+ CLRINO(dp->inode, dumpinomap);
+ CLRINO(dp->inode, usedinomap);
+ *tapesize -= blockest(ip);
+ }
+ /* Add dir back to the dir map, to propagate nodump */
+ if ((ip->di_mode & IFMT) == IFDIR) {
+ SETINO(dp->inode, dumpdirmap);
+ *ret |= HASSUBDIRS;
+ }
+ } else {
+ if (TSTINO(dp->inode, dumpinomap)) {
+ *ret |= HASDUMPEDFILE;
+ if (*ret & HASSUBDIRS)
+ return DIRENT_ABORT;
+ }
+ if (TSTINO(dp->inode, dumpdirmap)) {
+ *ret |= HASSUBDIRS;
+ if (*ret & HASDUMPEDFILE)
+ return DIRENT_ABORT;
+ }
}
return 0;
}