From 0cedbda5e645e6a30ef47fa3e0fae683160d4431 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Thu, 4 Apr 2002 08:20:19 +0000 Subject: [PATCH] dump -m implementation. --- CHANGES | 12 ++- compat/include/protocols/dumprestore.h | 4 +- dump/dump.8.in | 18 +++- dump/dump.h | 7 +- dump/main.c | 19 +++-- dump/traverse.c | 29 ++++++- restore/extern.h | 4 +- restore/restore.c | 15 ++-- restore/tape.c | 109 ++++++++++++++++--------- 9 files changed, 156 insertions(+), 61 deletions(-) diff --git a/CHANGES b/CHANGES index 9c18c53..c29c393 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -$Id: CHANGES,v 1.169 2002/03/28 14:53:01 stelian Exp $ +$Id: CHANGES,v 1.170 2002/04/04 08:20:19 stelian Exp $ Changes between versions 0.4b27 and 0.4b28 (released ?????????????????) ======================================================================= @@ -39,6 +39,16 @@ Changes between versions 0.4b27 and 0.4b28 (released ?????????????????) Thanks to Uwe Gohlke for reporting the bug and providing a test case. +8. Added the -m parameter to dump which optimises the output for + inodes having been changed but not modified since the last dump + ('changed' and 'modified' have the meaning defined in stat(2)). + For those inodes, dump will save only the metadata, instead of + saving the entire inode contents. Inodes which are either + directories or have been modified since the last dump are saved + in a regular way. Uses of this flag must be consistent, meaning + that either every dump in an incremental dump set have the flag, + or no one has it. + Changes between versions 0.4b26 and 0.4b27 (released February 15, 2002) ======================================================================= diff --git a/compat/include/protocols/dumprestore.h b/compat/include/protocols/dumprestore.h index 2c3a945..d9e72fe 100644 --- a/compat/include/protocols/dumprestore.h +++ b/compat/include/protocols/dumprestore.h @@ -5,7 +5,7 @@ * Stelian Pop , 1999-2000 * Stelian Pop - Alcôve , 2000-2002 * - * $Id: dumprestore.h,v 1.16 2002/01/25 14:59:53 stelian Exp $ + * $Id: dumprestore.h,v 1.17 2002/04/04 08:20:23 stelian Exp $ */ /* @@ -131,6 +131,8 @@ union u_spcl { #define DR_NEWHEADER 0x0001 /* new format tape header */ #define DR_NEWINODEFMT 0x0002 /* new format inodes on tape */ #define DR_COMPRESSED 0x0080 /* dump tape is compressed */ +#define DR_METAONLY 0x0100 /* only the metadata of the inode has + been dumped */ #define DR_INODEINFO 0x0002 /* TS_END header contains c_inos information */ diff --git a/dump/dump.8.in b/dump/dump.8.in index 5cb450e..657f780 100644 --- a/dump/dump.8.in +++ b/dump/dump.8.in @@ -30,7 +30,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: dump.8.in,v 1.39 2002/02/25 10:00:44 stelian Exp $ +.\" $Id: dump.8.in,v 1.40 2002/04/04 08:20:23 stelian Exp $ .\" .Dd __DATE__ .Dt DUMP 8 @@ -270,6 +270,22 @@ Note that this label is limited to be at most LBLSIZE (currently 16) characters, which must include the terminating .Ql \e0 . +.It Fl m +If this flag is specified, +.Nm +will optimise the output for inodes having been changed but not +modified since the last dump ('changed' and 'modified' have the +meaning defined in stat(2)). For those inodes, +.Nm +will save only the metadata, instead of saving the entire inode +contents. Inodes which are either directories or have been modified +since the last dump are saved in a regular way. +Uses of this flag must be consistent, meaning that either every dump +in an incremental dump set have the flag, or no one has it. +.Pp +Tapes written using such 'metadata only' inodes will not be compatible +with the BSD tape format or older versions of +.Nm restore. .It Fl M Enable the multi-volume feature. The name specified with .Fl f diff --git a/dump/dump.h b/dump/dump.h index 2ce50e3..177329b 100644 --- a/dump/dump.h +++ b/dump/dump.h @@ -5,7 +5,7 @@ * Stelian Pop , 1999-2000 * Stelian Pop - Alcôve , 2000-2002 * - * $Id: dump.h,v 1.36 2002/01/25 14:59:53 stelian Exp $ + * $Id: dump.h,v 1.37 2002/04/04 08:20:23 stelian Exp $ */ /*- @@ -54,6 +54,8 @@ extern int mapsize; /* size of the state maps */ extern char *usedinomap; /* map of allocated inodes */ extern char *dumpdirmap; /* map of directories to be dumped */ extern char *dumpinomap; /* map of files to be dumped */ +extern char *metainomap; /* which of the inodes in dumpinomap + will get only their metadata dumped */ /* * Map manipulation macros. */ @@ -77,6 +79,7 @@ extern char level; /* dump level of this dump */ extern int Afile; /* archive file descriptor */ extern int bzipflag; /* compression is done using bzlib */ extern int uflag; /* update flag */ +extern int mflag; /* dump metadata only if possible flag */ extern int Mflag; /* multi-volume flag */ extern int qflag; /* quit on errors flag */ extern int breademax; /* maximum number of bread errors before we quit */ @@ -155,7 +158,7 @@ int mapdirs __P((dump_ino_t maxino, long *tapesize)); /* file dumping routines */ void blksout __P((daddr_t *blkp, int frags, dump_ino_t ino)); void bread __P((daddr_t blkno, char *buf, int size)); -void dumpino __P((struct dinode *dp, dump_ino_t ino)); +void dumpino __P((struct dinode *dp, dump_ino_t ino, int metaonly)); #ifdef __linux__ void dumpdirino __P((struct dinode *dp, dump_ino_t ino)); #endif diff --git a/dump/main.c b/dump/main.c index 3d4e693..93c175c 100644 --- a/dump/main.c +++ b/dump/main.c @@ -41,7 +41,7 @@ #ifndef lint static const char rcsid[] = - "$Id: main.c,v 1.70 2002/03/11 10:17:43 stelian Exp $"; + "$Id: main.c,v 1.71 2002/04/04 08:20:23 stelian Exp $"; #endif /* not lint */ #include @@ -96,6 +96,8 @@ int mapsize; /* size of the state maps */ char *usedinomap; /* map of allocated inodes */ char *dumpdirmap; /* map of directories to be dumped */ char *dumpinomap; /* map of files to be dumped */ +char *metainomap; /* which of the inodes in dumpinomap will get + only their metadata dumped */ const char *disk; /* name of the disk file */ char tape[MAXPATHLEN];/* name of the tape file */ @@ -106,6 +108,7 @@ char level; /* dump level of this dump */ int bzipflag; /* compression is done using bzlib */ int Afile = 0; /* archive file descriptor */ int uflag; /* update flag */ +int mflag; /* dump metadata only if possible */ int Mflag; /* multi-volume flag */ int qflag; /* quit on errors flag */ int breademax = 32; /* maximum number of bread errors before we quit */ @@ -248,7 +251,7 @@ main(int argc, char *argv[]) #ifdef KERBEROS "k" #endif - "Mnq" + "mMnq" #ifdef USE_QFA "Q:" #endif @@ -377,6 +380,10 @@ main(int argc, char *argv[]) } break; + case 'm': /* metadata only flag */ + mflag = 1; + break; + case 'M': /* multi-volume flag */ Mflag = 1; break; @@ -730,7 +737,9 @@ main(int argc, char *argv[]) usedinomap = (char *)calloc((unsigned) mapsize, sizeof(char)); dumpdirmap = (char *)calloc((unsigned) mapsize, sizeof(char)); dumpinomap = (char *)calloc((unsigned) mapsize, sizeof(char)); - if (usedinomap == NULL || dumpdirmap == NULL || dumpinomap == NULL) + metainomap = (char *)calloc((unsigned) mapsize, sizeof(char)); + if (usedinomap == NULL || dumpdirmap == NULL || + dumpinomap == NULL || metainomap == NULL) quit("out of memory allocating inode maps\n"); tapesize = 2 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1); @@ -933,7 +942,7 @@ main(int argc, char *argv[]) * inodes since this is done in dumpino(). */ #endif - (void)dumpino(dp, ino); + (void)dumpino(dp, ino, mflag && TSTINO(ino, metainomap)); } tend_writing = time(NULL); @@ -1016,7 +1025,7 @@ usage(void) #ifdef KERBEROS "k" #endif - "MnqSu" + "mMnqSu" "] [-A file] [-B records] [-b blocksize]\n" "\t%s [-d density] [-e inode#,inode#,...] [-E file] [-f file]\n" "\t%s [-h level] [-I nr errors] " diff --git a/dump/traverse.c b/dump/traverse.c index eda65e1..c854760 100644 --- a/dump/traverse.c +++ b/dump/traverse.c @@ -41,7 +41,7 @@ #ifndef lint static const char rcsid[] = - "$Id: traverse.c,v 1.43 2002/02/04 11:18:46 stelian Exp $"; + "$Id: traverse.c,v 1.44 2002/04/04 08:20:23 stelian Exp $"; #endif /* not lint */ #include @@ -217,8 +217,12 @@ blockest(struct dinode const *dp) } /* Auxiliary macro to pick up files changed since previous dump. */ +#define CSINCE(dp, t) \ + ((dp)->di_ctime >= (t)) +#define MSINCE(dp, t) \ + ((dp)->di_mtime >= (t)) #define CHANGEDSINCE(dp, t) \ - ((dp)->di_mtime >= (t) || (dp)->di_ctime >= (t)) + (CSINCE(dp, t) || MSINCE(dp, t)) /* The NODUMP_FLAG macro tests if a file has the nodump flag. */ #ifdef UF_NODUMP @@ -266,6 +270,8 @@ mapfileino(dump_ino_t ino, struct dinode const *dp, long *tapesize, int *dirskip SETINO(ino, dumpdirmap); if (WANTTODUMP(dp, ino)) { SETINO(ino, dumpinomap); + if (!MSINCE(dp, spcl.c_ddate)) + SETINO(ino, metainomap); if (mode != IFREG && mode != IFDIR && mode != IFLNK) *tapesize += 1; else @@ -773,7 +779,7 @@ dumponeblock(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt, * Dump the contents of an inode to tape. */ void -dumpino(struct dinode *dp, dump_ino_t ino) +dumpino(struct dinode *dp, dump_ino_t ino, int metaonly) { unsigned long cnt; fsizeT size, remaining; @@ -785,7 +791,12 @@ dumpino(struct dinode *dp, dump_ino_t ino) #else int ind_level; #endif - u_quad_t i_size = dp->di_size + ((u_quad_t) dp->di_size_high << 32); + u_quad_t i_size; + + if (metaonly) + i_size = 0; + else + i_size = dp->di_size + ((u_quad_t) dp->di_size_high << 32); if (newtape) { newtape = 0; @@ -814,6 +825,16 @@ dumpino(struct dinode *dp, dump_ino_t ino) #endif /* __linux__ */ spcl.c_type = TS_INODE; spcl.c_count = 0; + + if (metaonly && (dp->di_mode & S_IFMT)) { + printf("Write header with spcl.c_count=%d\n",spcl.c_count); + spcl.c_flags |= DR_METAONLY; + spcl.c_count = 0; + writeheader(ino); + spcl.c_flags &= ~DR_METAONLY; + return; + } + switch (dp->di_mode & S_IFMT) { case 0: diff --git a/restore/extern.h b/restore/extern.h index 408169f..0a4cbb1 100644 --- a/restore/extern.h +++ b/restore/extern.h @@ -5,7 +5,7 @@ * Stelian Pop , 1999-2000 * Stelian Pop - Alcôve , 2000-2002 * - * $Id: extern.h,v 1.16 2002/02/04 11:18:46 stelian Exp $ + * $Id: extern.h,v 1.17 2002/04/04 08:20:23 stelian Exp $ */ /*- @@ -62,7 +62,7 @@ void delwhiteout __P((struct entry *)); dump_ino_t dirlookup __P((const char *)); void dumpsymtable __P((char *, long)); void extractdirs __P((int)); -int extractfile __P((char *)); +int extractfile __P((struct entry *, int)); void findunreflinks __P((void)); char *flagvalues __P((struct entry *)); void freeentry __P((struct entry *)); diff --git a/restore/restore.c b/restore/restore.c index eba23e1..854c3fc 100644 --- a/restore/restore.c +++ b/restore/restore.c @@ -41,7 +41,7 @@ #ifndef lint static const char rcsid[] = - "$Id: restore.c,v 1.28 2002/02/04 11:21:20 stelian Exp $"; + "$Id: restore.c,v 1.29 2002/04/04 08:20:23 stelian Exp $"; #endif /* not lint */ #include @@ -746,6 +746,7 @@ createleaves(char *symtabfile) struct entry *ep; dump_ino_t first; long curvol; + int doremove; if (command == 'R') { Vprintf(stdout, "Continue extraction of new leaves\n"); @@ -796,11 +797,11 @@ createleaves(char *symtabfile) * be removed since its type may change from one leaf type * to another (e.g. "file" to "character special"). */ - if ((ep->e_flags & EXTRACT) != 0) { - removeleaf(ep); - ep->e_flags &= ~REMOVED; - } - (void) extractfile(myname(ep)); + if ((ep->e_flags & EXTRACT) != 0) + doremove = 1; + else + doremove = 0; + (void) extractfile(ep, doremove); ep->e_flags &= ~(NEW|EXTRACT); /* * We checkpoint the restore after every tape reel, so @@ -1029,7 +1030,7 @@ createfiles(void) else { msg("restoring %s\n", myname(ep)); #endif /* USE_QFA */ - (void) extractfile(myname(ep)); + (void) extractfile(ep, 0); #ifdef USE_QFA } #endif /* USE_QFA */ diff --git a/restore/tape.c b/restore/tape.c index 43ce99e..453b7eb 100644 --- a/restore/tape.c +++ b/restore/tape.c @@ -46,7 +46,7 @@ #ifndef lint static const char rcsid[] = - "$Id: tape.c,v 1.59 2002/03/28 14:53:01 stelian Exp $"; + "$Id: tape.c,v 1.60 2002/04/04 08:20:23 stelian Exp $"; #endif /* not lint */ #include @@ -718,12 +718,24 @@ struct timeval #endif int -extractfile(char *name) +extractfile(struct entry *ep, int doremove) { unsigned int flags; mode_t mode; struct timeval timep[2]; - struct entry *ep; + char *name = myname(ep); + + /* If removal is requested (-r mode) do remove it unless + * we are extracting a metadata only inode */ + if (spcl.c_flags & DR_METAONLY) { + Vprintf(stdout, "file %s is metadata only\n", name); + } + else { + if (doremove) { + removeleaf(ep); + ep->e_flags &= ~REMOVED; + } + } curfile.name = name; curfile.action = USING; @@ -754,7 +766,6 @@ extractfile(char *name) case IFDIR: if (mflag) { - ep = lookupname(name); if (ep == NULL || ep->e_flags & EXTRACT) panic("unextracted directory %s\n", name); skipfile(); @@ -769,16 +780,21 @@ extractfile(char *name) uid_t luid = curfile.dip->di_uid; gid_t lgid = curfile.dip->di_gid; #endif - lnkbuf[0] = '\0'; - pathlen = 0; - getfile(xtrlnkfile, xtrlnkskip); - if (pathlen == 0) { - Vprintf(stdout, - "%s: zero length symbolic link (ignored)\n", name); - return (GOOD); + if (! (spcl.c_flags & DR_METAONLY)) { + lnkbuf[0] = '\0'; + pathlen = 0; + getfile(xtrlnkfile, xtrlnkskip); + if (pathlen == 0) { + Vprintf(stdout, + "%s: zero length symbolic link (ignored)\n", name); + return (GOOD); + } + if (linkit(lnkbuf, name, SYMLINK) == FAIL) + return (FAIL); } - if (linkit(lnkbuf, name, SYMLINK) == FAIL) - return (FAIL); + else + skipfile(); + #ifdef HAVE_LCHOWN (void) lchown(name, luid, lgid); #endif @@ -791,12 +807,14 @@ extractfile(char *name) skipfile(); return (GOOD); } - if (uflag && !Nflag) - (void)unlink(name); - if (mkfifo(name, mode) < 0) { - warn("%s: cannot create fifo", name); - skipfile(); - return (FAIL); + if (! (spcl.c_flags & DR_METAONLY)) { + if (uflag && !Nflag) + (void)unlink(name); + if (mkfifo(name, mode) < 0) { + warn("%s: cannot create fifo", name); + skipfile(); + return (FAIL); + } } (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); (void) chmod(name, mode); @@ -817,12 +835,14 @@ extractfile(char *name) skipfile(); return (GOOD); } - if (uflag) - (void)unlink(name); - if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { - warn("%s: cannot create special file", name); - skipfile(); - return (FAIL); + if (! (spcl.c_flags & DR_METAONLY)) { + if (uflag) + (void)unlink(name); + if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { + warn("%s: cannot create special file", name); + skipfile(); + return (FAIL); + } } (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); (void) chmod(name, mode); @@ -840,32 +860,41 @@ extractfile(char *name) return (GOOD); case IFREG: + { + uid_t luid = curfile.dip->di_uid; + gid_t lgid = curfile.dip->di_gid; + Vprintf(stdout, "extract file %s\n", name); if (Nflag) { skipfile(); return (GOOD); } - if (uflag) - (void)unlink(name); - if ((ofile = OPEN(name, O_WRONLY | O_CREAT | O_TRUNC, - 0666)) < 0) { - warn("%s: cannot create file", name); - skipfile(); - return (FAIL); + if (! (spcl.c_flags & DR_METAONLY)) { + if (uflag) + (void)unlink(name); + if ((ofile = OPEN(name, O_WRONLY | O_CREAT | O_TRUNC, + 0666)) < 0) { + warn("%s: cannot create file", name); + skipfile(); + return (FAIL); + } + getfile(xtrfile, xtrskip); + (void) close(ofile); } - (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid); - (void) fchmod(ofile, mode); + else + skipfile(); + (void) chown(name, luid, lgid); + (void) chmod(name, mode); if (flags) #ifdef __linux__ - (void) setflags(ofile, flags); + (void) fsetflags(name, flags); #else - (void) fchflags(ofile, flags); + (void) chflags(name, flags); #endif - getfile(xtrfile, xtrskip); - (void) close(ofile); utimes(name, timep); return (GOOD); } + } /* NOTREACHED */ } @@ -1260,6 +1289,10 @@ comparefile(char *name) name, mode & 07777, sb.st_mode & 07777); do_compare_error; } + if (spcl.c_flags & DR_METAONLY) { + skipfile(); + return; + } switch (mode & IFMT) { default: skipfile(); -- 2.39.2