Made restore understand tapes with EA/ACLs.
-$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 ????????????)
==================================================================
entries. Thanks to Brian Ristuccia <bristuccia@starentnetworks.com>
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)
==================================================================
* Stelian Pop <stelian@popies.net>, 1999-2000
* Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 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 $
*/
/*
#define EXT_REGULAR 0
#define EXT_MACOSFNDRINFO 1
#define EXT_MACOSRESFORK 2
-#define EXT_ACL 3
+#define EXT_XATTR 3
/*
#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 <config.h>
};
#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));
{
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,
for (;;) {
curfile.name = "<directory file - name unknown>";
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);
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;
(void) chmod(cp, node.mode);
if (node.flags)
#ifdef __linux__
- (void) fsetflags(cp, node.flags);
+ (void) lsetflags(cp, node.flags);
#else
#ifdef sunos
#else
(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.
*/
*/
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)
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;
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);
}
/*
* Stelian Pop <stelian@popies.net>, 1999-2000
* Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 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 $
*/
/*-
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));
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 *));
int CreateAppleDoubleFileRes __P((char *, FndrFileInfo *, mode_t, int, struct timeval *, u_int32_t, u_int32_t));
#endif
-
-
+void skipxattr __P((void));
#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 <config.h>
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");
#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 <config.h>
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);
}
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
} 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
}
#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 <config.h>
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));
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:
{
#ifdef HAVE_LCHOWN
(void) lchown(name, luid, lgid);
#endif
+ extractattr(name);
return (GOOD);
}
(void) chmod(name, mode);
if (flags)
#ifdef __linux__
- (void) fsetflags(name, flags);
+ (void) lsetflags(name, flags);
#else
#ifdef sunos
{
#endif
#endif
skipfile();
+ extractattr(name);
utimes(name, timep);
return (GOOD);
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
#endif
#endif
skipfile();
+ extractattr(name);
utimes(name, timep);
return (GOOD);
(void) chmod(name, mode);
if (flags)
#ifdef __linux__
- (void) fsetflags(name, flags);
+ (void) lsetflags(name, flags);
#else
#ifdef sunos
{
(void) chflags(name, flags);
#endif
#endif
+ extractattr(name);
utimes(name, timep);
return (GOOD);
}
/* 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)
(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);
}
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;
}
#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
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);
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;
case IFDIR:
skipfile();
+ compareattr(name);
return;
case IFLNK: {
do_compare_error;
return;
}
+ compareattr(name);
return;
}
do_compare_error;
}
skipfile();
+ compareattr(name);
return;
case IFREG:
unlink(tmpfile);
#endif
#endif /* COMPARE_ONTHEFLY */
+ compareattr(name);
return;
}
/* NOTREACHED */
#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 <config.h>
*/
#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
(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);
+}