From a55ce9149e3f4a5f848a20b7593dbe8cd7b0bbd1 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Wed, 15 Dec 2004 11:00:00 +0000 Subject: [PATCH] Better comparision (including directories). Made restore understand tapes with EA/ACLs. --- CHANGES | 11 +- compat/include/protocols/dumprestore.h | 4 +- restore/dirs.c | 139 ++++++++++++++++++++++--- restore/extern.h | 9 +- restore/main.c | 5 +- restore/restore.c | 71 ++----------- restore/tape.c | 134 ++++++++++++++++++++++-- restore/utilities.c | 47 ++++++++- 8 files changed, 319 insertions(+), 101 deletions(-) diff --git a/CHANGES b/CHANGES index 27a8696..c17e1ed 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -$Id: CHANGES,v 1.261 2004/12/14 14:07:56 stelian Exp $ +$Id: CHANGES,v 1.262 2004/12/15 11:00:00 stelian Exp $ Changes between versions 0.4b37 and 0.4b38 (released ????????????) ================================================================== @@ -33,6 +33,15 @@ Changes between versions 0.4b37 and 0.4b38 (released ????????????) entries. Thanks to Brian Ristuccia for reporting the bug. +8. Improved restore -C, this time including the directory + attributes into the comparision. + +9. Made restore understand tapes containing EA/ACLs (which will + be dumped by the next version of dump). In this version + extended attributes on the tape are ignored, for full EA/ACL + support wait for the next version or try the experimental EA + patch. + Changes between versions 0.4b36 and 0.4b37 (released July 7, 2004) ================================================================== diff --git a/compat/include/protocols/dumprestore.h b/compat/include/protocols/dumprestore.h index fc43715..981b9f6 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.22 2004/07/01 09:14:49 stelian Exp $ + * $Id: dumprestore.h,v 1.23 2004/12/15 11:00:01 stelian Exp $ */ /* @@ -150,7 +150,7 @@ union u_spcl { #define EXT_REGULAR 0 #define EXT_MACOSFNDRINFO 1 #define EXT_MACOSRESFORK 2 -#define EXT_ACL 3 +#define EXT_XATTR 3 /* diff --git a/restore/dirs.c b/restore/dirs.c index 2a23f94..423fe6e 100644 --- a/restore/dirs.c +++ b/restore/dirs.c @@ -42,7 +42,7 @@ #ifndef lint static const char rcsid[] = - "$Id: dirs.c,v 1.28 2004/05/25 10:39:30 stelian Exp $"; + "$Id: dirs.c,v 1.29 2004/12/15 11:00:01 stelian Exp $"; #endif /* not lint */ #include @@ -148,9 +148,11 @@ struct odirect { }; #if defined(__linux__) || defined(sunos) -static struct inotab *allocinotab __P((dump_ino_t, struct new_bsd_inode *, OFF_T)); +static struct inotab *allocinotab __P((dump_ino_t, OFF_T)); +static void savemodeinfo __P((dump_ino_t, struct new_bsd_inode *)); #else -static struct inotab *allocinotab __P((dump_ino_t, struct dinode *, OFF_T)); +static struct inotab *allocinotab __P((dump_ino_t, OFF_T)); +static void savemodeinfo __P((dump_ino_t, struct dinode *)); #endif static void dcvt __P((struct odirect *, struct direct *)); static void flushent __P((void)); @@ -177,13 +179,14 @@ extractdirs(int genmode) { int i; #if defined(__linux__) || defined(sunos) - struct new_bsd_inode *ip; + struct new_bsd_inode ip; #else - struct dinode *ip; + struct dinode ip; #endif struct inotab *itp; struct direct nulldir; int fd; + dump_ino_t ino; Vprintf(stdout, "Extract directories from tape\n"); (void) snprintf(dirfile, sizeof(dirfile), "%s/rstdir%ld", tmpdir, @@ -222,8 +225,8 @@ extractdirs(int genmode) for (;;) { curfile.name = ""; curfile.action = USING; - ip = curfile.dip; - if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { + ino = curfile.ino; + if (curfile.dip == NULL || (curfile.dip->di_mode & IFMT) != IFDIR) { if ( fclose(df) == EOF ) err(1, "cannot write to file %s", dirfile); dirp = opendirfile(dirfile); @@ -236,8 +239,26 @@ extractdirs(int genmode) panic("Root directory is not on tape\n"); return; } - itp = allocinotab(curfile.ino, ip, seekpt); + memcpy(&ip, curfile.dip, sizeof(ip)); + itp = allocinotab(ino, seekpt); getfile(putdir, xtrnull); + while (spcl.c_flags & DR_EXTATTRIBUTES) { + switch (spcl.c_extattributes) { + case EXT_MACOSFNDRINFO: + msg("MacOSX attributes not supported, skipping\n"); + skipfile(); + break; + case EXT_MACOSRESFORK: + msg("MacOSX attributes not supported, skipping\n"); + skipfile(); + break; + case EXT_XATTR: + msg("EA/ACLs attributes not supported, skipping\n"); + skipfile(); + break; + } + } + savemodeinfo(ino, &ip); putent(&nulldir); flushent(); itp->t_size = seekpt - itp->t_seekpt; @@ -678,7 +699,7 @@ setdirmodes(int flags) (void) chmod(cp, node.mode); if (node.flags) #ifdef __linux__ - (void) fsetflags(cp, node.flags); + (void) lsetflags(cp, node.flags); #else #ifdef sunos #else @@ -694,6 +715,87 @@ setdirmodes(int flags) (void) fclose(mf); } +/* + * In restore -C mode, tests the attributes for all directories + */ +void +comparedirmodes(void) +{ + FILE *mf; + struct modeinfo node; + struct entry *ep; + char *cp; + + Vprintf(stdout, "Compare directories modes, owner, attributes.\n"); + if (modefile[0] == '#') { + panic("modefile not defined\n"); + fprintf(stderr, "directory mode, owner, and times not set\n"); + return; + } + mf = fopen(modefile, "r"); + if (mf == NULL) { + warn("fopen"); + fprintf(stderr, "cannot open mode file %s\n", modefile); + fprintf(stderr, "directory mode, owner, and times not set\n"); + return; + } + clearerr(mf); + for (;;) { + (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); + if (feof(mf)) + break; + ep = lookupino(node.ino); + if (ep == NULL) { + panic("cannot find directory inode %d\n", node.ino); + } else { + cp = myname(ep); + struct STAT sb; + unsigned long newflags; + + if (LSTAT(cp, &sb) < 0) { + warn("%s: does not exist", cp); + do_compare_error; + continue; + } + + Vprintf(stdout, "comparing directory %s\n", cp); + + if (sb.st_mode != node.mode) { + fprintf(stderr, "%s: mode changed from 0%o to 0%o.\n", + cp, node.mode & 07777, sb.st_mode & 07777); + do_compare_error; + } + if (sb.st_uid != node.uid) { + fprintf(stderr, "%s: uid changed from %d to %d.\n", + cp, node.uid, sb.st_uid); + do_compare_error; + } + if (sb.st_gid != node.gid) { + fprintf(stderr, "%s: gid changed from %d to %d.\n", + cp, node.gid, sb.st_gid); + do_compare_error; + } +#ifdef __linux__ + if (lgetflags(cp, &newflags) < 0) { + warn("%s: lgetflags failed", cp); + do_compare_error; + } + else { + if (newflags != node.flags) { + fprintf(stderr, "%s: flags changed from 0x%08x to 0x%08lx.\n", + cp, node.flags, newflags); + do_compare_error; + } + } +#endif + ep->e_flags &= ~NEW; + } + } + if (ferror(mf)) + panic("error setting directory modes\n"); + (void) fclose(mf); +} + /* * Generate a literal copy of a directory. */ @@ -751,13 +853,12 @@ inodetype(dump_ino_t ino) */ static struct inotab * #if defined(__linux__) || defined(sunos) -allocinotab(dump_ino_t ino, struct new_bsd_inode *dip, OFF_T seekpt) +allocinotab(dump_ino_t ino, OFF_T seekpt) #else -allocinotab(dump_ino_t ino, struct dinode *dip, OFF_T seekpt) +allocinotab(dump_ino_t ino, OFF_T seekpt) #endif { struct inotab *itp; - struct modeinfo node; itp = calloc(1, sizeof(struct inotab)); if (itp == NULL) @@ -766,8 +867,19 @@ allocinotab(dump_ino_t ino, struct dinode *dip, OFF_T seekpt) inotab[INOHASH(ino)] = itp; itp->t_ino = ino; itp->t_seekpt = seekpt; + return itp; +} + +static void +#if defined(__linux__) || defined(sunos) +savemodeinfo(dump_ino_t ino, struct new_bsd_inode *dip) { +#else +savemodeinfo(dump_ino_t ino, struct dinode *dip) { +#endif + struct modeinfo node; + if (mf == NULL) - return (itp); + return; node.ino = ino; #if defined(__linux__) || defined(sunos) node.timep[0].tv_sec = dip->di_atime.tv_sec; @@ -786,7 +898,6 @@ allocinotab(dump_ino_t ino, struct dinode *dip, OFF_T seekpt) node.gid = dip->di_gid; if ( fwrite((char *)&node, 1, sizeof(struct modeinfo), mf) != sizeof(struct modeinfo) ) err(1,"cannot write to file %s", modefile); - return (itp); } /* diff --git a/restore/extern.h b/restore/extern.h index e2702ed..60f2f26 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.23 2003/10/26 16:05:48 stelian Exp $ + * $Id: extern.h,v 1.24 2004/12/15 11:00:01 stelian Exp $ */ /*- @@ -107,6 +107,7 @@ void rst_closedir __P((RST_DIR *dirp)); void runcmdshell __P((void)); char *savename __P((char *)); void setdirmodes __P((int)); +void comparedirmodes __P((void)); void setinput __P((char *)); void setup __P((void)); void skipdirs __P((void)); @@ -131,6 +132,9 @@ int fsetflags __P((const char *, unsigned long)); int fgetflags __P((const char *, unsigned long *)); int setflags __P((int, unsigned long)); +int lsetflags __P((const char *, unsigned long)); +int lgetflags __P((const char *, unsigned long *)); + #ifdef USE_QFA int Inode2Tapepos __P((dump_ino_t, long *, long long *, int)); int GetTapePos __P((long long *)); @@ -152,5 +156,4 @@ int extractresourceufs __P((char *)); int CreateAppleDoubleFileRes __P((char *, FndrFileInfo *, mode_t, int, struct timeval *, u_int32_t, u_int32_t)); #endif - - +void skipxattr __P((void)); diff --git a/restore/main.c b/restore/main.c index f53d740..361c4ec 100644 --- a/restore/main.c +++ b/restore/main.c @@ -37,7 +37,7 @@ #ifndef lint static const char rcsid[] = - "$Id: main.c,v 1.46 2004/04/13 13:04:33 stelian Exp $"; + "$Id: main.c,v 1.47 2004/12/15 11:00:01 stelian Exp $"; #endif /* not lint */ #include @@ -427,9 +427,10 @@ main(int argc, char *argv[]) err(1, "cannot cd to %s", filesys); compare_ignore_not_found = dumptime > 0; initsymtable((char *)0); - extractdirs(0); + extractdirs(1); treescan(".", ROOTINO, nodeupdates); compareleaves(); + comparedirmodes(); checkrestore(); if (compare_errors) { printf("Some files were modified!\n"); diff --git a/restore/restore.c b/restore/restore.c index e8b9027..5fcff70 100644 --- a/restore/restore.c +++ b/restore/restore.c @@ -37,7 +37,7 @@ #ifndef lint static const char rcsid[] = - "$Id: restore.c,v 1.34 2004/12/14 14:07:57 stelian Exp $"; + "$Id: restore.c,v 1.35 2004/12/15 11:00:01 stelian Exp $"; #endif /* not lint */ #include @@ -665,7 +665,10 @@ compare_entry(struct entry *ep, int do_compare) badentry(ep, "unexpected file on tape"); do_compare_error; } - if (do_compare) (void) comparefile(myname(ep)); + if (do_compare) { + (void) comparefile(myname(ep)); + skipxattr(); + } ep->e_flags &= ~(NEW|EXTRACT); } @@ -821,39 +824,9 @@ createleaves(char *symtabfile) else doremove = 0; (void) extractfile(ep, doremove); + skipxattr(); ep->e_flags &= ~(NEW|EXTRACT); -finderres: - if ((first == curfile.ino) && (spcl.c_flags & DR_EXTATTRIBUTES)) { - switch (spcl.c_extattributes) { - case EXT_MACOSFNDRINFO: -#ifdef DUMP_MACOSX - (void)extractfinderinfoufs(myname(ep)); -#else - msg("MacOSX not supported in this version, skipping\n"); - skipfile(); -#endif - break; - case EXT_MACOSRESFORK: -#ifdef DUMP_MACOSX - (void)extractresourceufs(myname(ep)); -#else - msg("MacOSX not supported in this version, skipping\n"); - skipfile(); -#endif - break; - case EXT_ACL: - msg("ACLs not supported in this version, skipping\n"); - skipfile(); - break; - default: - msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes); - skipfile(); - break; - } - goto finderres; - } - /* * We checkpoint the restore after every tape reel, so * as to simplify the amount of work required by the @@ -1084,37 +1057,7 @@ createfiles(void) } else { #endif /* USE_QFA */ (void) extractfile(ep, 0); - -finderres: - if ((next == curfile.ino) && (spcl.c_flags & DR_EXTATTRIBUTES)) { - switch (spcl.c_extattributes) { - case EXT_MACOSFNDRINFO: -#ifdef DUMP_MACOSX - (void)extractfinderinfoufs(myname(ep)); -#else - msg("MacOSX not supported in this version, skipping\n"); - skipfile(); -#endif - break; - case EXT_MACOSRESFORK: -#ifdef DUMP_MACOSX - (void)extractresourceufs(myname(ep)); -#else - msg("MacOSX not supported in this version, skipping\n"); - skipfile(); -#endif - break; - case EXT_ACL: - msg("ACLs not supported in this version, skipping\n"); - skipfile(); - break; - default: - msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes); - skipfile(); - break; - } - goto finderres; - } + skipxattr(); #ifdef USE_QFA } diff --git a/restore/tape.c b/restore/tape.c index b383866..aa0dbd7 100644 --- a/restore/tape.c +++ b/restore/tape.c @@ -42,7 +42,7 @@ #ifndef lint static const char rcsid[] = - "$Id: tape.c,v 1.83 2004/12/10 13:31:21 stelian Exp $"; + "$Id: tape.c,v 1.84 2004/12/15 11:00:01 stelian Exp $"; #endif /* not lint */ #include @@ -168,6 +168,8 @@ static void xtrmap __P((char *, size_t)); static void xtrmapskip __P((char *, size_t)); static void xtrskip __P((char *, size_t)); static void setmagtapein __P((void)); +static int extractattr __P((char *)); +static void compareattr __P((char *)); #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO) static void newcomprbuf __P((int)); @@ -840,14 +842,19 @@ extractfile(struct entry *ep, int doremove) return (GOOD); case IFDIR: + { + int ret; if (mflag) { if (ep == NULL || ep->e_flags & EXTRACT) panic("unextracted directory %s\n", name); skipfile(); return (GOOD); } - Vprintf(stdout, "extract file %s\n", name); - return (genliteraldir(name, curfile.ino)); + Vprintf(stdout, "extract dir %s\n", name); + ret = genliteraldir(name, curfile.ino); + extractattr(name); + return ret; + } case IFLNK: { @@ -873,6 +880,7 @@ extractfile(struct entry *ep, int doremove) #ifdef HAVE_LCHOWN (void) lchown(name, luid, lgid); #endif + extractattr(name); return (GOOD); } @@ -895,7 +903,7 @@ extractfile(struct entry *ep, int doremove) (void) chmod(name, mode); if (flags) #ifdef __linux__ - (void) fsetflags(name, flags); + (void) lsetflags(name, flags); #else #ifdef sunos { @@ -907,6 +915,7 @@ extractfile(struct entry *ep, int doremove) #endif #endif skipfile(); + extractattr(name); utimes(name, timep); return (GOOD); @@ -931,8 +940,8 @@ extractfile(struct entry *ep, int doremove) if (flags) #ifdef __linux__ { - warn("%s: fsetflags called on a special file", name); - (void) fsetflags(name, flags); + warn("%s: lsetflags called on a special file", name); + (void) lsetflags(name, flags); } #else #ifdef sunos @@ -948,6 +957,7 @@ extractfile(struct entry *ep, int doremove) #endif #endif skipfile(); + extractattr(name); utimes(name, timep); return (GOOD); @@ -979,7 +989,7 @@ extractfile(struct entry *ep, int doremove) (void) chmod(name, mode); if (flags) #ifdef __linux__ - (void) fsetflags(name, flags); + (void) lsetflags(name, flags); #else #ifdef sunos { @@ -990,6 +1000,7 @@ extractfile(struct entry *ep, int doremove) (void) chflags(name, flags); #endif #endif + extractattr(name); utimes(name, timep); return (GOOD); } @@ -997,6 +1008,40 @@ extractfile(struct entry *ep, int doremove) /* NOTREACHED */ } +static int +extractattr(char *path) +{ + while (spcl.c_flags & DR_EXTATTRIBUTES) { + switch (spcl.c_extattributes) { + case EXT_MACOSFNDRINFO: +#ifdef DUMP_MACOSX + (void)extractfinderinfoufs(path); +#else + msg("MacOSX not supported in this version, skipping\n"); + skipfile(); +#endif + break; + case EXT_MACOSRESFORK: +#ifdef DUMP_MACOSX + (void)extractresourceufs(path); +#else + msg("MacOSX not supported in this version, skipping\n"); + skipfile(); +#endif + break; + case EXT_XATTR: + msg("EA/ACLs not supported in this version, skipping\n"); + skipfile(); + break; + default: + msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes); + skipfile(); + break; + } + } + return GOOD; +} + #ifdef DUMP_MACOSX int extractfinderinfoufs(char *name) @@ -1161,7 +1206,7 @@ extractresourceufs(char *name) (void) fchown(ofile, uid, gid); (void) fchmod(ofile, mode); (void) close(ofile); - (void) fsetflags(oFileRsrc, flags); + (void) lsetflags(oFileRsrc, flags); utimes(oFileRsrc, timep); return (GOOD); } @@ -1191,6 +1236,17 @@ skipfile(void) getfile(xtrnull, xtrnull); } +/* + * skip over any extended attributes. + */ +void +skipxattr(void) +{ + + while (spcl.c_flags & DR_EXTATTRIBUTES) + skipfile(); +} + /* * Extract a file from the tape. * When an allocated block is found it is passed to the fill function; @@ -1539,6 +1595,31 @@ cmpfiles(char *tapefile, char *diskfile, struct STAT *sbuf_disk) } #endif /* !COMPARE_ONTHEFLY */ +static void +compareattr(char *name) +{ + while (spcl.c_flags & DR_EXTATTRIBUTES) { + switch (spcl.c_extattributes) { + case EXT_MACOSFNDRINFO: + msg("MacOSX not supported for comparision in this version, skipping\n"); + skipfile(); + break; + case EXT_MACOSRESFORK: + msg("MacOSX not supported for comparision in this version, skipping\n"); + skipfile(); + break; + case EXT_XATTR: + msg("EA/ACLs not supported for comparision in this version, skipping\n"); + skipxattr(); + break; + default: + msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes); + skipfile(); + break; + } + } +} + #if !COMPARE_ONTHEFLY static char tmpfilename[MAXPATHLEN]; #endif @@ -1546,17 +1627,23 @@ static char tmpfilename[MAXPATHLEN]; void comparefile(char *name) { - unsigned int mode; + mode_t mode; + uid_t uid; + uid_t gid; + unsigned int flags; + unsigned long newflags; struct STAT sb; int r; #if !COMPARE_ONTHEFLY static char *tmpfile = NULL; struct STAT stemp; #endif - curfile.name = name; curfile.action = USING; mode = curfile.dip->di_mode; + flags = curfile.dip->di_flags; + uid = curfile.dip->di_uid; + gid = curfile.dip->di_gid; if ((mode & IFMT) == IFSOCK) { Vprintf(stdout, "skipped socket %s\n", name); @@ -1579,6 +1666,29 @@ comparefile(char *name) name, mode & 07777, sb.st_mode & 07777); do_compare_error; } + if (sb.st_uid != uid) { + fprintf(stderr, "%s: uid changed from %d to %d.\n", + name, uid, sb.st_uid); + do_compare_error; + } + if (sb.st_gid != gid) { + fprintf(stderr, "%s: gid changed from %d to %d.\n", + name, gid, sb.st_gid); + do_compare_error; + } +#ifdef __linux__ + if (lgetflags(name, &newflags) < 0) { + warn("%s: lgetflags failed", name); + do_compare_error; + } + else { + if (newflags != flags) { + fprintf(stderr, "%s: flags changed from 0x%08x to 0x%08lx.\n", + name, flags, newflags); + do_compare_error; + } + } +#endif if (spcl.c_flags & DR_METAONLY) { skipfile(); return; @@ -1594,6 +1704,7 @@ comparefile(char *name) case IFDIR: skipfile(); + compareattr(name); return; case IFLNK: { @@ -1629,6 +1740,7 @@ comparefile(char *name) do_compare_error; return; } + compareattr(name); return; } @@ -1653,6 +1765,7 @@ comparefile(char *name) do_compare_error; } skipfile(); + compareattr(name); return; case IFREG: @@ -1701,6 +1814,7 @@ comparefile(char *name) unlink(tmpfile); #endif #endif /* COMPARE_ONTHEFLY */ + compareattr(name); return; } /* NOTREACHED */ diff --git a/restore/utilities.c b/restore/utilities.c index e96dcf3..2e73aa8 100644 --- a/restore/utilities.c +++ b/restore/utilities.c @@ -37,7 +37,7 @@ #ifndef lint static const char rcsid[] = - "$Id: utilities.c,v 1.25 2004/12/14 14:07:58 stelian Exp $"; + "$Id: utilities.c,v 1.26 2004/12/15 11:00:01 stelian Exp $"; #endif /* not lint */ #include @@ -269,10 +269,10 @@ linkit(char *existing, char *new, int type) */ #ifdef sunos #else - if (fgetflags (existing, &s) != -1 && - fsetflags (existing, 0) != -1) { + if (lgetflags (existing, &s) != -1 && + lsetflags (existing, 0) != -1) { ret = link(existing, new); - fsetflags(existing, s); + lsetflags(existing, s); } #endif #endif @@ -724,9 +724,46 @@ CreateAppleDoubleFileRes(char *oFile, FndrFileInfo *finderinfo, mode_t mode, int (void)fchown(fdout, uid, gid); (void)fchmod(fdout, mode); close(fdout); - (void)fsetflags(oFile, flags); + (void)lsetflags(oFile, flags); utimes(oFile, timep); free(pp); return err; } #endif /* DUMP_MACOSX */ + +int +lgetflags(const char *path, unsigned long *flags) +{ + int err; + struct STAT sb; + + err = LSTAT(path, &sb); + if (err < 0) + return err; + + if (S_ISLNK(sb.st_mode) || S_ISFIFO(sb.st_mode)) { + // no way to get/set flags on a symlink + *flags = 0; + return 0; + } + else + return fgetflags(path, flags); +} + +int +lsetflags(const char *path, unsigned long flags) +{ + int err; + struct STAT sb; + + err = LSTAT(path, &sb); + if (err < 0) + return err; + + if (S_ISLNK(sb.st_mode) || S_ISFIFO(sb.st_mode)) { + // no way to get/set flags on a symlink + return 0; + } + else + return fsetflags(path, flags); +} -- 2.39.5