X-Git-Url: https://git.wh0rd.org/?p=dump.git;a=blobdiff_plain;f=restore%2Ftape.c;h=4710f889d1cdae269f1c3c586eb594cdc401c650;hp=553abbc8e99fef89f0d75fc27bdbd2a612451a3c;hb=2359fe7e917ea8a52c5d523c77d29bddf6f82fce;hpb=206f768c7a7a4bca1c4acc3c686d55578c0cb919 diff --git a/restore/tape.c b/restore/tape.c index 553abbc..4710f88 100644 --- a/restore/tape.c +++ b/restore/tape.c @@ -42,11 +42,12 @@ #ifndef lint static const char rcsid[] = - "$Id: tape.c,v 1.74 2003/03/31 09:42:59 stelian Exp $"; + "$Id: tape.c,v 1.100 2010/12/06 14:26:51 stelian Exp $"; #endif /* not lint */ #include #include +#include #include #include #include @@ -60,6 +61,8 @@ static const char rcsid[] = #include #include #include +#include +#include #ifdef __linux__ #include @@ -72,8 +75,18 @@ static const char rcsid[] = #include #include #else /* __linux__ */ +#ifdef sunos +#define quad_t int64_t +#include +#include +#include +#else #include +#endif #endif /* __linux__ */ +#ifdef DUMP_MACOSX +#include "darwin.h" +#endif #include #ifdef HAVE_ZLIB @@ -138,6 +151,10 @@ static int converthead __P((struct s_spcl *)); static void converttapebuf __P((struct tapebuf *)); static void readtape __P((char *)); static void setdumpnum __P((void)); +#ifdef DUMP_MACOSX +static void xtrfilefinderinfo __P((char *, size_t)); +#endif + static u_int swabi __P((u_int)); #if 0 static u_long swabl __P((u_long)); @@ -152,7 +169,10 @@ static void xtrlnkskip __P((char *, size_t)); 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)); @@ -179,12 +199,22 @@ static void xtrcmpskip __P((char *, size_t)); 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 + /* * Set up an input source. This is called from main.c before setup() is. */ void setinput(char *source) { + int i; + char *n; + FLUSHTAPEBUF(); if (bflag) newtapebuf(ntrec); @@ -193,12 +223,18 @@ setinput(char *source) terminal = stdin; #ifdef RRESTORE - if (strchr(source, ':')) { - host = source; - source = strchr(host, ':'); - *source++ = '\0'; - if (rmthost(host) == 0) - exit(1); + if ((n = strchr(source, ':'))) { + for (i = 0; i < (n - source); i++) { + if (source[i] == '/') + break; + } + if (source[i] != '/') { + host = source; + source = strchr(host, ':'); + *source++ = '\0'; + if (rmthost(host) == 0) + exit(1); + } } else #endif if (strcmp(source, "-") == 0) { @@ -312,6 +348,7 @@ setup(void) #endif FLUSHTAPEBUF(); findtapeblksize(); + cvtflag = 0; if (gethead(&spcl) == FAIL) { blkcnt--; /* push back this block */ blksread--; @@ -385,13 +422,19 @@ setup(void) dump_ino_t oldmaxino = maxino; maxino += (spcl.c_count * TP_BSIZE * NBBY) + 1; resizemaps(oldmaxino, maxino); + map = usedinomap; spcl.c_dinode.di_size = spcl.c_count * TP_BSIZE; getfile(xtrmap, xtrmapskip); } Dprintf(stdout, "maxino = %lu\n", (unsigned long)maxino); - if (spcl.c_type != TS_BITS) + if (spcl.c_type != TS_BITS) { + if (spcl.c_type == TS_END) { + msg("Cannot find file dump list, assuming empty tape\n"); + exit(0); + } errx(1, "Cannot find file dump list"); + } map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); if (map == (char *)NULL) errx(1, "no memory for file dump list"); @@ -433,7 +476,6 @@ getvol(long nextvol) if (nextvol == 1) { tapesread = 0; gettingfile = 0; - tpblksread = 0; blksread = 0; } if (pipein) { @@ -480,7 +522,8 @@ again: 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); @@ -504,7 +547,7 @@ again: goto again; } } -#endif +#endif /* USE_QFA */ return; } closemt(); @@ -529,11 +572,22 @@ again: } 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); - fprintf(stderr, "Enter ``none'' if there are no more volumes\n"); - fprintf(stderr, "otherwise enter volume name (default: %s) ", magtape); +#else + fprintf(stderr, "Mount tape volume %ld\n", (long)newvol); +#endif + fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); +#ifdef sunos + fprintf(stderr, "then enter volume name (default: %s) ", magtape); +#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")) { @@ -548,6 +602,15 @@ again: magtape[pos - magtape] = '\0'; } } +#if defined(USE_QFA) && defined(sunos) + if (createtapeposflag || tapeposflag) { + if (OpenSMTCmt(magtape) < 0) { + volno = -1; + haderror = 1; + goto again; + } + } +#endif /* USE_QFA */ #ifdef RRESTORE if (host) mt = rmtopen(magtape, O_RDONLY); @@ -589,7 +652,11 @@ gethdr: } if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) { fprintf(stderr, "Wrong dump date\n\tgot: %s", +#ifdef sunos + ctime(&tmpbuf.c_date)); +#else ctime4(&tmpbuf.c_date)); +#endif fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); volno = 0; haderror = 1; @@ -686,17 +753,33 @@ setdumpnum(void) tcom.mt_op = MTFSF; tcom.mt_count = dumpnum - 1; #ifdef RRESTORE - if (host) - rmtioctl(MTFSF, dumpnum - 1); - else + if (host) { + if (rmtioctl(MTFSF, dumpnum - 1) < 0) { + fprintf(stderr, "rmtioctl MTFSF: %s\n", strerror(errno)); + exit(1); + } + } else #endif - if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0) - warn("ioctl MTFSF"); + if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0) { + fprintf(stderr, "rmtioctl MTFSF: %s\n", strerror(errno)); + exit(1); + /* warn("ioctl MTFSF"); */ + } } void printdumpinfo(void) { +#ifdef sunos + Vprintf(stdout, "Dump date: %s", ctime(&spcl.c_date)); + Vprintf(stdout, "Dumped from: %s", + (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate)); + if (spcl.c_host[0] == '\0') + return; + Vprintf(stdout, "Level %d dump of %s on %s:%s\n", + spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); + Vprintf(stdout, "Label: %s\n", spcl.c_label); +#else fprintf(stdout, "Dump date: %s", ctime4(&spcl.c_date)); fprintf(stdout, "Dumped from: %s", (spcl.c_ddate == 0) ? "the epoch\n" : ctime4(&spcl.c_ddate)); @@ -705,6 +788,7 @@ printdumpinfo(void) fprintf(stdout, "Level %d dump of %s on %s:%s\n", spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); fprintf(stdout, "Label: %s\n", spcl.c_label); +#endif } void @@ -719,12 +803,6 @@ printvolinfo(void) } } -#ifdef sunos -struct timeval - time_t tv_sec; /* seconds */ - suseconds_t tv_usec; /* and microseconds */ -}; -#endif int extractfile(struct entry *ep, int doremove) @@ -769,19 +847,69 @@ extractfile(struct entry *ep, int doremove) 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: { @@ -805,69 +933,97 @@ extractfile(struct entry *ep, int doremove) 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 + { + warn("%s: cannot call chflags", name); + /* (void) chflags(name, flags); */ + } #else (void) chflags(name, flags); #endif - skipfile(); - utimes(name, timep); +#endif 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 + { + warn("%s: cannot call chflags on a special file", name); + /* (void) chflags(name, flags); */ + } +#else + { + warn("%s: chflags called on a special file", name); (void) chflags(name, flags); + } +#endif #endif - skipfile(); - utimes(name, timep); return (GOOD); - + } case IFREG: { uid_t luid = curfile.dip->di_uid; @@ -892,20 +1048,272 @@ extractfile(struct entry *ep, int doremove) } 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 + { + warn("%s: cannot call chflags", name); + /* (void) chflags(name, flags); */ + } #else (void) chflags(name, flags); #endif - utimes(name, timep); +#endif + 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) +{ + int err; + char oFileRsrc[MAXPATHLEN]; + int flags; + mode_t mode; + struct timeval timep[2]; + u_int32_t uid; + u_int32_t gid; + char path[MAXPATHLEN], fname[MAXPATHLEN]; + + curfile.name = name; + curfile.action = USING; + timep[0].tv_sec = curfile.dip->di_atime.tv_sec; + timep[0].tv_usec = curfile.dip->di_atime.tv_usec; + timep[1].tv_sec = curfile.dip->di_mtime.tv_sec; + timep[1].tv_usec = curfile.dip->di_mtime.tv_usec; + mode = curfile.dip->di_mode; + flags = curfile.dip->di_flags; + uid = curfile.dip->di_uid; + gid = curfile.dip->di_gid; + + switch (mode & IFMT) { + + default: + fprintf(stderr, "%s: (extr. finfoufs) unknown file mode 0%o\n", name, mode); + skipfile(); + return (FAIL); + + case IFDIR: + fprintf(stderr, "%s: (extr. finfoufs[IFDIR]) unknown file mode 0%o\n", name, mode); + skipfile(); + return (FAIL); + + case IFLNK: + skipfile(); + return (GOOD); + + case IFREG: + Vprintf(stdout, "extract finderinfo file %s\n", name); + if (Nflag) { + skipfile(); + return (GOOD); + } + getfile(xtrfilefinderinfo, xtrskip); + + GetPathFile(name, path, fname); + strcpy(oFileRsrc, path); + strcat(oFileRsrc, "._"); + strcat(oFileRsrc, fname); + + if ((err = CreateAppleDoubleFileRes(oFileRsrc, &gFndrInfo.fndrinfo, + mode, flags, timep, uid, gid)) != 0) { + fprintf(stderr, "%s: cannot create finderinfo: %s\n", + name, strerror(errno)); + skipfile(); + return (FAIL); + } return (GOOD); } + /* NOTREACHED */ +} + + +int +extractresourceufs(char *name) +{ + char oFileRsrc[MAXPATHLEN]; + int flags; + mode_t mode; + struct timeval timep[2]; + char path[MAXPATHLEN], fname[MAXPATHLEN]; + ASDHeaderPtr hp; + ASDEntryPtr ep; + u_long loff; + u_int32_t uid; + u_int32_t gid; + u_int64_t di_size; + char *p; + char buf[1024]; + + curfile.name = name; + curfile.action = USING; + timep[0].tv_sec = curfile.dip->di_atime.tv_sec; + timep[0].tv_usec = curfile.dip->di_atime.tv_usec; + timep[1].tv_sec = curfile.dip->di_mtime.tv_sec; + timep[1].tv_usec = curfile.dip->di_mtime.tv_usec; + mode = curfile.dip->di_mode; + flags = curfile.dip->di_flags; + uid = curfile.dip->di_uid; + gid = curfile.dip->di_gid; + di_size = curfile.dip->di_size; + + switch (mode & IFMT) { + + default: + fprintf(stderr, "%s: (extr. resufs) unknown file mode 0%o\n", name, mode); + skipfile(); + return (FAIL); + + case IFDIR: + fprintf(stderr, "%s: (extr. resufs [IFDIR]) unknown file mode 0%o\n", name, mode); + skipfile(); + return (FAIL); + + case IFLNK: + skipfile(); + return (GOOD); + + case IFREG: + Vprintf(stdout, "extract resource file %s\n", name); + if (Nflag) { + skipfile(); + return (GOOD); + } + + GetPathFile(name, path, fname); + strcpy(oFileRsrc, path); + strcat(oFileRsrc, "._"); + strcat(oFileRsrc, fname); + + if ((ofile = open(oFileRsrc, O_RDONLY, 0)) < 0) { + fprintf(stderr, "%s: cannot read finderinfo: %s\n", + name, strerror(errno)); + skipfile(); + return (FAIL); + } + read(ofile, buf, 70); + (void) close(ofile); + p = buf; + hp = (ASDHeaderPtr)p; + /* the header */ + hp->entries++; + p += sizeof(ASDHeader) - CORRECT; + ep = (ASDEntryPtr)p; + /* the finderinfo entry */ + ep->offset += sizeof(ASDEntry); + loff = ep->offset; + + p += sizeof(ASDEntry); + /* the finderinfo data */ + bcopy(p, p + sizeof(ASDEntry), INFOLEN); + ep = (ASDEntryPtr)p; + /* the new resourcefork entry */ + ep->entryID = EntryRSRCFork; + ep->offset = loff + INFOLEN; + ep->len = di_size; + /* write the new appledouble entries to the file */ + if ((ofile = open(oFileRsrc, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { + fprintf(stderr, "%s: cannot create resource file: %s\n", + name, strerror(errno)); + skipfile(); + return (FAIL); + } + write(ofile, buf, 70 + sizeof(ASDEntry)); + /* and add the resource data from tape */ + getfile(xtrfile, xtrskip); + + if (fchown(ofile, uid, gid) < 0) + warn("%s: fchown", name); + if (fchmod(ofile, mode) < 0) + warn("%s: fchmod", name); + (void) close(ofile); + 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 @@ -929,6 +1337,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; @@ -982,7 +1401,11 @@ loop: 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, @@ -1003,7 +1426,8 @@ loop: 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); @@ -1024,6 +1448,14 @@ xtrfile(char *buf, size_t size) (unsigned long)curfile.ino, curfile.name); } +#ifdef DUMP_MACOSX +static void +xtrfilefinderinfo(char *buf, size_t size) +{ + bcopy(buf, &gFndrInfo, size); +} +#endif /* DUMP_MACOSX */ + /* * Skip over a hole in a file. */ @@ -1045,10 +1477,13 @@ xtrlnkfile(char *buf, size_t size) { 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'; } /* @@ -1152,9 +1587,20 @@ xtrcmpskip(UNUSED(char *buf), size_t size) } #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]; @@ -1196,15 +1642,15 @@ cmpfiles(char *tapefile, char *diskfile, struct STAT *sbuf_disk) 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); @@ -1214,12 +1660,12 @@ cmpfiles(char *tapefile, char *diskfile, struct STAT *sbuf_disk) } 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; } @@ -1264,6 +1710,43 @@ cmpfiles(char *tapefile, char *diskfile, struct STAT *sbuf_disk) } #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 @@ -1271,17 +1754,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); @@ -1290,20 +1779,45 @@ comparefile(char *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; @@ -1319,6 +1833,7 @@ comparefile(char *name) case IFDIR: skipfile(); + compareattr(name); return; case IFLNK: { @@ -1342,7 +1857,7 @@ comparefile(char *name) 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; } @@ -1354,6 +1869,7 @@ comparefile(char *name) do_compare_error; return; } + compareattr(name); return; } @@ -1371,19 +1887,20 @@ comparefile(char *name) fprintf(stderr, "%s: device changed from %d,%d to %d,%d.\n", name, - ((int)curfile.dip->di_rdev >> 8) & 0xff, - (int)curfile.dip->di_rdev & 0xff, - ((int)sb.st_rdev >> 8) & 0xff, - (int)sb.st_rdev & 0xff); + major(curfile.dip->di_rdev), + minor(curfile.dip->di_rdev), + major(sb.st_rdev), + minor(sb.st_rdev)); 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; } @@ -1426,6 +1943,7 @@ comparefile(char *name) unlink(tmpfile); #endif #endif /* COMPARE_ONTHEFLY */ + compareattr(name); return; } /* NOTREACHED */ @@ -1791,9 +2309,6 @@ decompress_tapebuf(struct tapebuf *tpbin, int readsize) /* zflag gets set in setup() from the dump header */ int cresult, blocklen; unsigned long worklen; -#ifdef HAVE_BZLIB - unsigned int worklen2; -#endif char *output = NULL,*reason = NULL, *lengtherr = NULL; /* build a length error message */ @@ -1840,7 +2355,7 @@ decompress_tapebuf(struct tapebuf *tpbin, int readsize) #ifndef HAVE_BZLIB errx(1,"This restore version doesn't support bzlib decompression"); #else - worklen2 = worklen; + unsigned int worklen2 = worklen; cresult = BZ2_bzBuffToBuffDecompress( comprbuf, &worklen2, tpbin->buf, blocklen, 0, 0); @@ -1873,8 +2388,10 @@ decompress_tapebuf(struct tapebuf *tpbin, int readsize) #ifndef HAVE_LZO errx(1,"This restore version doesn't support lzo decompression"); #else + lzo_uint worklen2 = worklen; cresult = lzo1x_decompress(tpbin->buf, blocklen, - comprbuf, (lzo_uintp) &worklen,NULL); + comprbuf, &worklen2, NULL); + worklen = worklen2; output = comprbuf; switch (cresult) { case LZO_E_OK: @@ -1904,8 +2421,8 @@ decompress_tapebuf(struct tapebuf *tpbin, int readsize) } if (reason) { if (lengtherr) - fprintf(stderr, "%s compressed block: %d expected: %d\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) @@ -1971,6 +2488,7 @@ findtapeblksize(void) errx(1, "Tape read error on first record"); memcpy(&spclpt, tapebuf, TP_BSIZE); + cvtflag = 0; if (converthead(&spclpt) == FAIL) { cvtflag++; if (converthead(&spclpt) == FAIL) { @@ -2181,38 +2699,51 @@ converthead(struct s_spcl *buf) 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); - memset((char *)buf, 0, (long)TP_BSIZE); - buf->c_type = u_ospcl.s_ospcl.c_type; - buf->c_date = u_ospcl.s_ospcl.c_date; - buf->c_ddate = u_ospcl.s_ospcl.c_ddate; - buf->c_volume = u_ospcl.s_ospcl.c_volume; - buf->c_tapea = u_ospcl.s_ospcl.c_tapea; - buf->c_inumber = u_ospcl.s_ospcl.c_inumber; - buf->c_checksum = u_ospcl.s_ospcl.c_checksum; - buf->c_magic = u_ospcl.s_ospcl.c_magic; - buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode; - buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink; - buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid; - buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; - buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size; - buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev; + if (checksum((int *)(&u_ospcl.s_ospcl)) == FAIL) + return(FAIL); + if (u_ospcl.s_ospcl.c_magic == OFS_MAGIC) { + memset((char *)buf, 0, (long)TP_BSIZE); + buf->c_type = u_ospcl.s_ospcl.c_type; + buf->c_date = u_ospcl.s_ospcl.c_date; + buf->c_ddate = u_ospcl.s_ospcl.c_ddate; + buf->c_volume = u_ospcl.s_ospcl.c_volume; + buf->c_tapea = u_ospcl.s_ospcl.c_tapea; + buf->c_inumber = u_ospcl.s_ospcl.c_inumber; + buf->c_checksum = u_ospcl.s_ospcl.c_checksum; + buf->c_magic = u_ospcl.s_ospcl.c_magic; + buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode; + buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink; + buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid; + buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; + buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size; + buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev; #if defined(__linux__) || defined(sunos) - buf->c_dinode.di_atime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_atime; - buf->c_dinode.di_mtime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime; - buf->c_dinode.di_ctime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime; + buf->c_dinode.di_atime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_atime; + buf->c_dinode.di_mtime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime; + buf->c_dinode.di_ctime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime; #else /* __linux__ || sunos */ - buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime; - buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime; - buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime; + buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime; + buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime; + buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime; #endif /* __linux__ || sunos */ - buf->c_count = u_ospcl.s_ospcl.c_count; - memmove(buf->c_addr, u_ospcl.s_ospcl.c_fill, (long)256); - if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC || - checksum((int *)(&u_ospcl.s_ospcl)) == FAIL) + buf->c_count = u_ospcl.s_ospcl.c_count; + memmove(buf->c_addr, u_ospcl.s_ospcl.c_fill, (long)256); + } + else if (u_ospcl.s_ospcl.c_magic == FS_UFS2_MAGIC) { + buf->c_date = (int32_t)(*(int64_t *)&u_ospcl.dummy[896]); + buf->c_ddate = (int32_t)(*(int64_t *)&u_ospcl.dummy[904]); + buf->c_tapea = (int32_t)(*(int64_t *)&u_ospcl.dummy[912]); + buf->c_firstrec = (int32_t)(*(int64_t *)&u_ospcl.dummy[920]); + buf->c_ntrec = 0; + buf->c_extattributes = 0; + buf->c_flags |= DR_NEWINODEFMT; + ufs2flag = 1; + } + else return(FAIL); buf->c_magic = NFS_MAGIC; @@ -2580,7 +3111,132 @@ swabl(u_long x) } #endif +void +RequestVol(long tnum) +{ + FLUSHTAPEBUF(); + getvol(tnum); +} + #ifdef USE_QFA +#ifdef sunos +extern int fdsmtc; + +struct uscsi_cmd { + int uscsi_flags; /* read, write, etc. see below */ + short uscsi_status; /* resulting status */ + short uscsi_timeout; /* Command Timeout */ + caddr_t uscsi_cdb; /* cdb to send to target */ + caddr_t uscsi_bufaddr; /* i/o source/destination */ + u_int uscsi_buflen; /* size of i/o to take place */ + u_int uscsi_resid; /* resid from i/o operation */ + u_char uscsi_cdblen; /* # of valid cdb bytes */ + u_char uscsi_rqlen; /* size of uscsi_rqbuf */ + u_char uscsi_rqstatus; /* status of request sense cmd */ + u_char uscsi_rqresid; /* resid of request sense cmd */ + caddr_t uscsi_rqbuf; /* request sense buffer */ + void *uscsi_reserved_5; /* Reserved for Future Use */ +}; + +#define CDB_GROUP0 6 /* 6-byte cdb's */ +#define CDB_GROUP1 10 /* 10-byte cdb's */ +#define CDB_GROUP2 10 /* 10-byte cdb's */ +#define CDB_GROUP3 0 /* reserved */ +#define CDB_GROUP4 16 /* 16-byte cdb's */ +#define CDB_GROUP5 12 /* 12-byte cdb's */ +#define CDB_GROUP6 0 /* reserved */ +#define CDB_GROUP7 0 /* reserved */ + +#define USCSI_WRITE 0x00000 /* send data to device */ +#define USCSI_SILENT 0x00001 /* no error messages */ +#define USCSI_DIAGNOSE 0x00002 /* fail if any error occurs */ +#define USCSI_ISOLATE 0x00004 /* isolate from normal commands */ +#define USCSI_READ 0x00008 /* get data from device */ +#define USCSI_RESET 0x04000 /* Reset target */ +#define USCSI_RESET_ALL 0x08000 /* Reset all targets */ +#define USCSI_RQENABLE 0x10000 /* Enable Request Sense extensions */ + +#define USCSIIOC (0x04 << 8) +#define USCSICMD (USCSIIOC|201) /* user scsi command */ + +#define USCSI_TIMEOUT 30 +#define USCSI_SHORT_TIMEOUT 900 +#define USCSI_LONG_TIMEOUT 14000 + +#define B(s,i) ((unsigned char)((s) >> i)) +#define B1(s) ((unsigned char)(s)) + +#define MSB4(s,v) *(s)=B(v,24),(s)[1]=B(v,16), (s)[2]=B(v,8), (s)[3]=B1(v) + + +int +GetTapePos(long long *pos) +{ + int err = 0; + struct uscsi_cmd scmd; + char buf[512]; + char parm[512 * 8]; + long lpos; + + (void)memset((void *)buf, 0, sizeof(buf)); + (void)memset((void *)&scmd, 0, sizeof(scmd)); + scmd.uscsi_flags = USCSI_READ|USCSI_SILENT; + scmd.uscsi_timeout = USCSI_TIMEOUT; + scmd.uscsi_cdb = buf; + scmd.uscsi_cdblen = CDB_GROUP1; + buf[0] = 0x34; /* read position */ + buf[1] = 0; + (void)memset((void *)parm, 0, 512); + scmd.uscsi_bufaddr = parm; + scmd.uscsi_buflen = 56; + if (ioctl(fdsmtc, USCSICMD, &scmd) == -1) { + err = errno; + return err; + } + (void)memcpy(&lpos, &parm[4], sizeof(long)); + *pos = lpos; + return err; +} + +int +GotoTapePos(long long pos) +{ + int err = 0; + struct uscsi_cmd scmd; + char buf[512]; + char parm[512 * 8]; + long lpos = (long)pos; + + (void)memset((void *)buf, 0, sizeof(buf)); + (void)memset((void *)&scmd, 0, sizeof(scmd)); + scmd.uscsi_flags = USCSI_WRITE|USCSI_SILENT; + scmd.uscsi_timeout = 360; /* 5 Minutes */ + scmd.uscsi_cdb = buf; + scmd.uscsi_cdblen = CDB_GROUP1; + buf[0] = 0x2b; /* locate */ + buf[1] = 0; + MSB4(&buf[3], lpos); + (void)memset((void *)parm, 0, 512); + scmd.uscsi_bufaddr = NULL; + scmd.uscsi_buflen = 0; + if (ioctl(fdsmtc, USCSICMD, &scmd) == -1) { + err = errno; + return err; + } + return err; +} +#endif + +#define LSEEK_GET_TAPEPOS 10 +#define LSEEK_GO2_TAPEPOS 11 + +#ifdef __linux__ +typedef struct mt_pos { + short mt_op; + int mt_count; +} MTPosRec, *MTPosPtr; + + /* * get the current position of the tape */ @@ -2591,7 +3247,7 @@ GetTapePos(long long *pos) #ifdef RDUMP if (host) { - *pos = (long long) rmtseek(0, SEEK_CUR); + *pos = (long long) rmtseek((OFF_T)0, (int)LSEEK_GET_TAPEPOS); err = *pos < 0; } else @@ -2617,11 +3273,6 @@ GetTapePos(long long *pos) return err; } -typedef struct mt_pos { - short mt_op; - int mt_count; -} MTPosRec, *MTPosPtr; - /* * go to specified position on tape */ @@ -2632,7 +3283,7 @@ GotoTapePos(long long pos) #ifdef RDUMP if (host) - err = (rmtseek(pos, SEEK_SET) < 0); + err = (rmtseek((OFF_T)pos, (int)LSEEK_GO2_TAPEPOS) < 0); else #endif { @@ -2655,6 +3306,7 @@ GotoTapePos(long long pos) } return err; } +#endif /* __linux__ */ /* * read next data from tape to re-sync @@ -2676,29 +3328,45 @@ ReReadFromTape(void) void ReReadInodeFromTape(dump_ino_t theino) { - long cntloop = 0; + long cntloop = 0; FLUSHTAPEBUF(); noresyncmesg = 1; do { cntloop++; gethead(&spcl); - } while (!(spcl.c_inumber == theino && spcl.c_type == TS_INODE && spcl.c_date == dumpdate) && (cntloop < ntrec)); + } while (!(spcl.c_inumber == theino && spcl.c_type == TS_INODE && spcl.c_date == dumpdate)); + + tpblksread = spcl.c_tapea + spcl.c_volume; #ifdef DEBUG_QFA - fprintf(stderr, "%ld reads\n", cntloop); - if (cntloop == ntrec) { - fprintf(stderr, "DEBUG: bufsize %d\n", bufsize); - fprintf(stderr, "DEBUG: ntrec %ld\n", ntrec); - } + fprintf(stderr, "DEBUG: %ld reads\n", cntloop); + fprintf(stderr, "DEBUG: bufsize %ld\n", bufsize); + fprintf(stderr, "DEBUG: ntrec %ld\n", ntrec); + fprintf(stderr, "DEBUG: tapea %d\n", spcl.c_tapea); + fprintf(stderr, "DEBUG: tpblksread %ld\n", tpblksread); #endif findinode(&spcl); noresyncmesg = 0; } -#endif /* USE_QFA */ -void -RequestVol(long tnum) +#ifdef sunos +int +OpenSMTCmt(char *themagtape) { - FLUSHTAPEBUF(); - getvol(tnum); + if (GetSCSIIDFromPath(themagtape, &scsiid)) { + fprintf(stderr, "can't get SCSI-ID for %s\n", themagtape); + return -1; + } + if (scsiid < 0) { + fprintf(stderr, "can't get SCSI-ID for %s\n", themagtape); + return -1; + } + sprintf(smtcpath, "/dev/rsmtc%ld,0", scsiid); + if ((fdsmtc = open(smtcpath, O_RDWR)) == -1) { + fprintf(stderr, "can't open smtc device: %s, %d\n", smtcpath, errno); + return -1; + } + return 0; } +#endif /* sunos */ +#endif /* USE_QFA */