#ifndef lint
static const char rcsid[] =
- "$Id: tape.c,v 1.81 2004/05/25 10:39:31 stelian Exp $";
+ "$Id: tape.c,v 1.99 2010/06/11 11:19:17 stelian Exp $";
#endif /* not lint */
#include <config.h>
#include <sys/file.h>
#include <sys/mtio.h>
#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#ifdef __linux__
#include <sys/time.h>
static void xtrmap __P((char *, size_t));
static void xtrmapskip __P((char *, size_t));
static void xtrskip __P((char *, size_t));
+static void xtrxattr __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));
static int readmapflag;
static int readingmaps; /* set to 1 while reading the maps */
+static char xattrbuf[XATTR_MAXSIZE];
+static int xattrlen;
+
#ifdef DUMP_MACOSX
static DumpFinderInfo gFndrInfo;
#endif
#endif
FLUSHTAPEBUF();
findtapeblksize();
+ cvtflag = 0;
if (gethead(&spcl) == FAIL) {
blkcnt--; /* push back this block */
blksread--;
if (nextvol == 1) {
tapesread = 0;
gettingfile = 0;
- tpblksread = 0;
blksread = 0;
}
if (pipein) {
do {
fprintf(stderr, "Specify next volume # (none if no more volumes): ");
(void) fflush(stderr);
- (void) fgets(buf, TP_BSIZE, terminal);
+ if (!fgets(buf, TP_BSIZE, terminal))
+ break;
} while (!feof(terminal) && buf[0] == '\n');
if (feof(terminal))
exit(1);
}
if (haderror || (bot_code && !Mflag)) {
haderror = 0;
+ if (compare_errors)
+ fprintf(stderr, "%d compare errors so far\n", compare_errors);
#ifdef sunos
fprintf(stderr, "Mount volume %ld\n", (long)newvol);
#else
fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
#endif
(void) fflush(stderr);
- (void) fgets(buf, TP_BSIZE, terminal);
+ if (fgets(buf, TP_BSIZE, terminal))
+ exit(1);
if (feof(terminal))
exit(1);
if (!strcmp(buf, "none\n")) {
return (FAIL);
case IFSOCK:
- Vprintf(stdout, "skipped socket %s\n", name);
+ {
+ uid_t luid = curfile.dip->di_uid;
+ gid_t lgid = curfile.dip->di_gid;
+
+ Vprintf(stdout, "extract socket %s\n", name);
skipfile();
+ if (Nflag)
+ return (GOOD);
+ if (! (spcl.c_flags & DR_METAONLY)) {
+ int sk;
+ struct sockaddr_un addr;
+
+ if (uflag)
+ (void)unlink(name);
+
+ if ((sk = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
+ warn("%s: cannot create socket", name);
+ return (FAIL);
+ }
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, name);
+ if (bind(sk, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
+ warn("%s: cannot create socket", name);
+ return (FAIL);
+ }
+ close(sk);
+ }
+ if (chown(name, luid, lgid) < 0)
+ warn("%s: chown", name);
+ if (chmod(name, mode) < 0)
+ warn("%s: chmod", name);
+ extractattr(name);
+ utimes(name, timep);
+ if (flags)
+#ifdef __linux__
+ (void) lsetflags(name, flags);
+#else
+#ifdef sunos
+ {
+ warn("%s: cannot call chflags", name);
+ /* (void) chflags(name, flags); */
+ }
+#else
+ (void) chflags(name, flags);
+#endif
+#endif
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:
{
skipfile();
#ifdef HAVE_LCHOWN
- (void) lchown(name, luid, lgid);
+ if (lchown(name, luid, lgid) < 0)
+ warn("%s: lchown", name);
#endif
+ extractattr(name);
return (GOOD);
}
case IFIFO:
+ {
+ uid_t luid = curfile.dip->di_uid;
+ gid_t lgid = curfile.dip->di_gid;
+
Vprintf(stdout, "extract fifo %s\n", name);
- if (Nflag) {
- skipfile();
+ skipfile();
+ if (Nflag)
return (GOOD);
- }
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);
+ if (chown(name, luid, lgid) < 0)
+ warn("%s: chown", name);
+ if (chmod(name, mode) < 0)
+ warn("%s: chmod", name);
+ extractattr(name);
+ utimes(name, timep);
if (flags)
#ifdef __linux__
- (void) fsetflags(name, flags);
+ (void) lsetflags(name, flags);
#else
#ifdef sunos
{
(void) chflags(name, flags);
#endif
#endif
- skipfile();
- utimes(name, timep);
return (GOOD);
-
+ }
case IFCHR:
case IFBLK:
+ {
+ uid_t luid = curfile.dip->di_uid;
+ gid_t lgid = curfile.dip->di_gid;
+ int lrdev = (int)curfile.dip->di_rdev;
+
Vprintf(stdout, "extract special file %s\n", name);
- if (Nflag) {
- skipfile();
+ skipfile();
+ if (Nflag)
return (GOOD);
- }
if (! (spcl.c_flags & DR_METAONLY)) {
if (uflag)
(void)unlink(name);
- if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
+ if (mknod(name, mode, lrdev) < 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);
+ if (chown(name, luid, lgid) < 0)
+ warn("%s: chown", name);
+ if (chmod(name, mode) < 0)
+ warn("%s: chmod", name);
+ extractattr(name);
+ utimes(name, timep);
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();
- utimes(name, timep);
return (GOOD);
-
+ }
case IFREG:
{
uid_t luid = curfile.dip->di_uid;
}
else
skipfile();
- (void) chown(name, luid, lgid);
- (void) chmod(name, mode);
+ if (chown(name, luid, lgid) < 0)
+ warn("%s: chown", name);
+ if (chmod(name, mode) < 0)
+ warn("%s: chmod", name);
+ extractattr(name);
+ utimes(name, timep);
if (flags)
#ifdef __linux__
- (void) fsetflags(name, flags);
+ (void) lsetflags(name, flags);
#else
#ifdef sunos
{
(void) chflags(name, flags);
#endif
#endif
- 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: {
+ char xattr[XATTR_MAXSIZE];
+
+ if (readxattr(xattr) == GOOD) {
+ xattr_extract(path, xattr);
+ break;
+ }
+ }
+ default:
+ msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes);
+ skipfile();
+ break;
+ }
+ }
+ return GOOD;
+}
+
#ifdef DUMP_MACOSX
int
extractfinderinfoufs(char *name)
u_int32_t uid;
u_int32_t gid;
char path[MAXPATHLEN], fname[MAXPATHLEN];
- int toto;
curfile.name = name;
curfile.action = USING;
/* and add the resource data from tape */
getfile(xtrfile, xtrskip);
- (void) fchown(ofile, uid, gid);
- (void) fchmod(ofile, mode);
+ if (fchown(ofile, uid, gid) < 0)
+ warn("%s: fchown", name);
+ if (fchmod(ofile, mode) < 0)
+ warn("%s: fchmod", name);
(void) close(ofile);
- (void) fsetflags(oFileRsrc, flags);
utimes(oFileRsrc, timep);
+ (void) lsetflags(oFileRsrc, flags);
return (GOOD);
}
/* NOTREACHED */
}
#endif /* DUMP_MACOSX */
+int
+readxattr(char *buffer)
+{
+ if (dflag)
+ msg("reading EA data for inode %lu\n", curfile.ino);
+
+ curfile.name = "EA block";
+ if (curfile.dip->di_size > XATTR_MAXSIZE) {
+ fprintf(stderr, "EA size too big (%ld)", (long)curfile.dip->di_size);
+ skipfile();
+ return (FAIL);
+ }
+
+ memset(xattrbuf, 0, XATTR_MAXSIZE);
+ xattrlen = 0;
+
+ /*
+ * ugly hack: cope with invalid spcl.c_addr[] records written by
+ * old versions of dump.
+ */
+ readmapflag = 1;
+
+ getfile(xtrxattr, xtrnull);
+
+ readmapflag = 0;
+
+ memcpy(buffer, xattrbuf, XATTR_MAXSIZE);
+
+ return (GOOD);
+}
+
/*
* skip over bit maps on the tape
*/
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;
break;
}
}
- if (gethead(&spcl) == GOOD && size > 0) {
+ while (gethead(&spcl) != GOOD) {
+ fprintf(stderr, "Incorrect block for %s at %ld blocks\n",
+ curfile.name, (long)blksread);
+ }
+ if (size > 0) {
if (spcl.c_type == TS_ADDR)
goto loop;
Dprintf(stdout,
last_write_was_hole = 1;
}
if (last_write_was_hole) {
- FTRUNCATE(ofile, origsize);
+ if (FTRUNCATE(ofile, origsize) < 0)
+ warn("%s: ftruncate", curfile.name);
}
if (!readingmaps)
findinode(&spcl);
static void
xtrfilefinderinfo(char *buf, size_t size)
{
- if (Nflag)
- return;
bcopy(buf, &gFndrInfo, size);
}
#endif /* DUMP_MACOSX */
{
pathlen += size;
- if (pathlen > MAXPATHLEN)
+ if (pathlen > MAXPATHLEN) {
+ buf[size - 1] = '\0';
errx(1, "symbolic link name: %s->%s%s; too long %d",
curfile.name, lnkbuf, buf, pathlen);
+ }
(void) strcat(lnkbuf, buf);
+ lnkbuf[pathlen] = '\0';
}
/*
}
#endif /* COMPARE_ONTHEFLY */
+static void
+xtrxattr(char *buf, size_t size)
+{
+ if (xattrlen + size > XATTR_MAXSIZE) {
+ fprintf(stderr, "EA size too big (%ld)", (long)xattrlen + size);
+ return;
+ }
+ memcpy(xattrbuf + xattrlen, buf, size);
+ xattrlen += size;
+}
+
#if !COMPARE_ONTHEFLY
static int
-do_cmpfiles(int fd_tape, int fd_disk, long size)
+do_cmpfiles(int fd_tape, int fd_disk, OFF_T size)
{
static char buf_tape[BUFSIZ];
static char buf_disk[BUFSIZ];
int fd_tape, fd_disk;
if (STAT(tapefile, &sbuf_tape) != 0) {
- panic("Can't lstat tmp file %s: %s\n", tapefile,
+ panic("can't lstat tmp file %s: %s\n", tapefile,
strerror(errno));
do_compare_error;
}
if (sbuf_disk->st_size != sbuf_tape.st_size) {
fprintf(stderr,
- "%s: size changed from %ld to %ld.\n",
- diskfile, (long)sbuf_tape.st_size, (long)sbuf_disk->st_size);
+ "%s: size changed from %lld to %lld.\n",
+ diskfile, (long long)sbuf_tape.st_size, (long long)sbuf_disk->st_size);
do_compare_error;
#ifdef COMPARE_FAIL_KEEP_FILE
return (0);
}
if ((fd_tape = OPEN(tapefile, O_RDONLY)) < 0) {
- panic("Can't open %s: %s\n", tapefile, strerror(errno));
+ panic("can't open %s: %s\n", tapefile, strerror(errno));
do_compare_error;
}
if ((fd_disk = OPEN(diskfile, O_RDONLY)) < 0) {
close(fd_tape);
- panic("Can't open %s: %s\n", diskfile, strerror(errno));
+ panic("can't open %s: %s\n", diskfile, strerror(errno));
do_compare_error;
}
}
#endif /* !COMPARE_ONTHEFLY */
+static void
+compareattr(char *name)
+{
+ int xattr_done = 0;
+
+ 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: {
+ char xattr[XATTR_MAXSIZE];
+
+ if (readxattr(xattr) == GOOD) {
+ if (xattr_compare(name, xattr) == FAIL)
+ do_compare_error;
+ xattr_done = 1;
+ }
+ else
+ do_compare_error;
+ break;
+ }
+ default:
+ msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes);
+ skipfile();
+ break;
+ }
+ }
+ if (!xattr_done && xattr_compare(name, NULL) == FAIL)
+ do_compare_error;
+}
+
#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);
}
if ((r = LSTAT(name, &sb)) != 0) {
- warn("%s: does not exist (%d)", name, r);
+ warn("unable to stat %s", name);
do_compare_error;
skipfile();
return;
}
- Vprintf(stdout, "comparing %s (size: %ld, mode: 0%o)\n", name,
- (long)sb.st_size, mode);
+ Vprintf(stdout, "comparing %s (size: %lld, mode: 0%o)\n", name,
+ (long long)sb.st_size, mode);
if (sb.st_mode != mode) {
fprintf(stderr, "%s: mode changed from 0%o to 0%o.\n",
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) {
+ if (flags != 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: {
return;
}
if ((lsize = readlink(name, lbuf, MAXPATHLEN)) < 0) {
- panic("readlink of %s failed: %s", name,
+ panic("readlink of %s failed: %s\n", name,
strerror(errno));
do_compare_error;
}
do_compare_error;
return;
}
+ compareattr(name);
return;
}
do_compare_error;
}
skipfile();
+ compareattr(name);
return;
case IFREG:
#if COMPARE_ONTHEFLY
if ((ifile = OPEN(name, O_RDONLY)) < 0) {
- panic("Can't open %s: %s\n", name, strerror(errno));
+ warn("can't open %s", name);
skipfile();
do_compare_error;
}
unlink(tmpfile);
#endif
#endif /* COMPARE_ONTHEFLY */
+ compareattr(name);
return;
}
/* NOTREACHED */
}
if (reason) {
if (lengtherr)
- fprintf(stderr, "%s compressed block: %d expected: %u\n",
- lengtherr, readsize, tpbin->length + PREFIXSIZE);
+ fprintf(stderr, "%s compressed block: %d expected: %lu\n",
+ lengtherr, readsize, (unsigned long)tpbin->length + PREFIXSIZE);
fprintf(stderr, "decompression error, block %ld: %s\n",
tpblksread+1, reason);
if (!cresult)
errx(1, "Tape read error on first record");
memcpy(&spclpt, tapebuf, TP_BSIZE);
+ cvtflag = 0;
if (converthead(&spclpt) == FAIL) {
cvtflag++;
if (converthead(&spclpt) == FAIL) {
if (checksum((int *)buf) == FAIL)
return (FAIL);
if (Bcvt)
- swabst((u_char *)"8i4s31i528bi192b3i", (u_char *)buf);
+ swabst((u_char *)"8i4s1l29i528bi192b4i", (u_char *)buf);
goto good;
}
memcpy(&u_ospcl.s_ospcl, buf, TP_BSIZE);