X-Git-Url: https://git.wh0rd.org/?p=dump.git;a=blobdiff_plain;f=restore%2Ftape.c;h=bd411b945bf298467144dee8d1a297d160ee102c;hp=b6d27f7a691060a9656337bcab4c1e6ca6da353c;hb=e17af4c1a919e1d1456d6079682b63c7df947a7f;hpb=fe0e02857a1ff7db4bf8cb28780de7ecf2f24234 diff --git a/restore/tape.c b/restore/tape.c index b6d27f7..bd411b9 100644 --- a/restore/tape.c +++ b/restore/tape.c @@ -23,11 +23,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -46,11 +42,12 @@ #ifndef lint static const char rcsid[] = - "$Id: tape.c,v 1.58 2002/02/04 11:18:46 stelian Exp $"; + "$Id: tape.c,v 1.101 2011/05/05 16:05:40 stelian Exp $"; #endif /* not lint */ #include #include +#include #include #include #include @@ -64,6 +61,8 @@ static const char rcsid[] = #include #include #include +#include +#include #ifdef __linux__ #include @@ -76,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 @@ -88,6 +97,10 @@ static const char rcsid[] = #include #endif /* HAVE_BZLIB */ +#ifdef HAVE_LZO +#include +#endif /* HAVE_LZO */ + #include "restore.h" #include "extern.h" #include "pathnames.h" @@ -106,7 +119,7 @@ static int numtrec; static char *tapebuf; /* input buffer for read */ static int bufsize; /* buffer size without prefix */ static char *tbufptr = NULL; /* active tape buffer */ -#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO) static char *comprbuf; /* uncompress work buf */ static size_t comprlen; /* size including prefix */ #endif @@ -134,8 +147,14 @@ static int checksum __P((int *)); static void findinode __P((struct s_spcl *)); static void findtapeblksize __P((void)); static int gethead __P((struct s_spcl *)); +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)); @@ -150,9 +169,12 @@ 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) +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO) static void newcomprbuf __P((int)); static void (*readtape_func) __P((char *)); static void readtape_set __P((char *)); @@ -175,6 +197,14 @@ static void xtrcmpskip __P((char *, size_t)); #endif 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. @@ -182,6 +212,9 @@ static int readmapflag; void setinput(char *source) { + int i; + char *n; + FLUSHTAPEBUF(); if (bflag) newtapebuf(ntrec); @@ -190,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) { @@ -240,7 +279,7 @@ newtapebuf(long size) tapebufsize = size; } -#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO) static void newcomprbuf(int size) { @@ -254,7 +293,7 @@ newcomprbuf(int size) if (comprbuf == NULL) errx(1, "Cannot allocate space for decompress buffer"); } -#endif /* HAVE_ZLIB || HAVE_BZLIB */ +#endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */ /* * Verify that the tape drive can be accessed and @@ -283,8 +322,8 @@ setup(void) temptape = magtape; #ifdef RRESTORE - if (host) - mt = rmtopen(temptape, 0); + if (!Afile && host) + mt = rmtopen(temptape, O_RDONLY); else #endif if (pipein) @@ -292,17 +331,24 @@ setup(void) else mt = OPEN(temptape, O_RDONLY, 0); if (mt < 0) - err(1, "%s", magtape); + err(1, "%s", temptape); if (!Afile) { volno = 1; setmagtapein(); setdumpnum(); } -#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO) readtape_func = readtape_set; +#if defined(HAVE_LZO) + if (lzo_init() != LZO_E_OK) { + msg("internal error - lzo_init failed \n"); + exit(1); + } +#endif #endif FLUSHTAPEBUF(); findtapeblksize(); + cvtflag = 0; if (gethead(&spcl) == FAIL) { blkcnt--; /* push back this block */ blksread--; @@ -315,7 +361,7 @@ setup(void) if (zflag) { fprintf(stderr, "Dump tape is compressed.\n"); -#if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB) +#if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB) && !defined(HAVE_LZO) errx(1,"This restore version doesn't support decompression"); #endif /* !HAVE_ZLIB && !HAVE_BZLIB */ } @@ -333,7 +379,7 @@ setup(void) if (vflag || command == 't' || command == 'C') printdumpinfo(); #ifdef USE_QFA - if (tapeposflag && spcl.c_date != qfadumpdate) + if (tapeposflag && (unsigned long)spcl.c_date != qfadumpdate) errx(1, "different QFA/dumpdates detected\n"); #endif if (filesys[0] == '\0') { @@ -360,26 +406,45 @@ setup(void) Dprintf(stdout, "header read failed at %ld blocks\n", (long)blksread); panic("no header after volume mark!\n"); } + readingmaps = 1; findinode(&spcl); if (spcl.c_type != TS_CLRI) errx(1, "Cannot find file removal list"); maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; - Dprintf(stdout, "maxino = %ld\n", (long)maxino); map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); if (map == NULL) errx(1, "no memory for active inode map"); usedinomap = map; curfile.action = USING; getfile(xtrmap, xtrmapskip); - findinode(&spcl); - if (spcl.c_type != TS_BITS) + while (spcl.c_type == TS_ADDR) { + /* Recompute maxino and the map */ + 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_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"); dumpmap = map; curfile.action = USING; getfile(xtrmap, xtrmapskip); + while (spcl.c_type == TS_ADDR) { + spcl.c_dinode.di_size = spcl.c_count * TP_BSIZE; + getfile(xtrmap, xtrmapskip); + } /* * If there may be whiteout entries on the tape, pretend that the * whiteout inode exists, so that the whiteout entries can be @@ -387,6 +452,7 @@ setup(void) */ if (oldinofmt == 0) SETINO(WINO, dumpmap); + readingmaps = 0; findinode(&spcl); } @@ -410,6 +476,7 @@ getvol(long nextvol) if (nextvol == 1) { tapesread = 0; gettingfile = 0; + blksread = 0; } if (pipein) { if (nextvol != 1) @@ -455,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); @@ -479,10 +547,17 @@ again: goto again; } } -#endif +#endif /* USE_QFA */ return; } closemt(); + + /* + * if using an archive file, reset its name so readtape() + * could properly use remote access. + */ + Afile = NULL; + if (Mflag) { snprintf(magtape, MAXPATHLEN, "%s%03ld", magtapeprefix, newvol); magtape[MAXPATHLEN - 1] = '\0'; @@ -497,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")) { @@ -516,9 +602,18 @@ 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, 0); + mt = rmtopen(magtape, O_RDONLY); else #endif mt = OPEN(magtape, O_RDONLY, 0); @@ -531,7 +626,7 @@ again: } gethdr: setmagtapein(); -#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO) readtape_func = readtape_set; #endif volno = newvol; @@ -557,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; @@ -566,8 +665,6 @@ gethdr: goto again; } tapesread |= 1 << volno; - blksread = saved_blksread; - tpblksread = saved_tpblksread; /* * If continuing from the previous volume, skip over any * blocks read already at the end of the previous volume. @@ -577,15 +674,15 @@ gethdr: */ if (zflag) { fprintf(stderr, "Dump tape is compressed.\n"); -#if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB) +#if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB) && !defined(HAVE_LZO) errx(1,"This restore version doesn't support decompression"); #endif /* !HAVE_ZLIB && !HAVE_BZLIB */ } Dprintf(stdout, "read %ld recs, tape starts with %ld\n", - tpblksread, (long)tmpbuf.c_firstrec); + tpblksread - 1, (long)tmpbuf.c_firstrec); if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) { if (!wantnext) { - tpblksread = tmpbuf.c_firstrec; + tpblksread = tmpbuf.c_firstrec + 1; for (i = tmpbuf.c_count; i > 0; i--) readtape(buf); } else if (tmpbuf.c_firstrec > 0 && @@ -656,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)); @@ -675,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 @@ -684,25 +798,31 @@ printvolinfo(void) if (volinfo[1] == ROOTINO) { printf("Starting inode numbers by volume:\n"); - for (i = 1; i < TP_NINOS && volinfo[i] != 0; ++i) + for (i = 1; i < (int)TP_NINOS && volinfo[i] != 0; ++i) printf("\tVolume %d: %lu\n", i, (unsigned long)volinfo[i]); } } -#ifdef sunos -struct timeval - time_t tv_sec; /* seconds */ - suseconds_t tv_usec; /* and microseconds */ -}; -#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; @@ -727,20 +847,69 @@ extractfile(char *name) 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) { - ep = lookupname(name); 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: { @@ -748,105 +917,403 @@ 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); + 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); + return (FAIL); + } } - 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); + skipfile(); + if (Nflag) + return (GOOD); + if (! (spcl.c_flags & DR_METAONLY)) { + if (uflag) + (void)unlink(name); + if (mknod(name, mode, lrdev) < 0) { + warn("%s: cannot create special file", name); + return (FAIL); + } + } + 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: 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 + 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 (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 ((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) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); - (void) chmod(name, mode); + else + skipfile(); + 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: fsetflags called on a special file", name); - (void) fsetflags(name, flags); + warn("%s: cannot call chflags", name); + /* (void) chflags(name, flags); */ } #else (void) chflags(name, flags); #endif +#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(); - utimes(name, timep); return (GOOD); case IFREG: - Vprintf(stdout, "extract file %s\n", name); + Vprintf(stdout, "extract finderinfo 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); + 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); } - (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid); - (void) fchmod(ofile, mode); - if (flags) -#ifdef __linux__ - (void) setflags(ofile, flags); -#else - (void) fchflags(ofile, flags); -#endif + 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(name, timep); + 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 @@ -870,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; @@ -923,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, @@ -944,9 +1426,11 @@ loop: last_write_was_hole = 1; } if (last_write_was_hole) { - FTRUNCATE(ofile, origsize); + if (FTRUNCATE(ofile, origsize) < 0) + warn("%s: ftruncate", curfile.name); } - findinode(&spcl); + if (!readingmaps) + findinode(&spcl); gettingfile = 0; } @@ -964,15 +1448,23 @@ 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. */ /* ARGSUSED */ static void -xtrskip(char *buf, size_t size) +xtrskip(UNUSED(char *buf), size_t size) { - if (LSEEK(ofile, (off_t)size, SEEK_CUR) == -1) + if (LSEEK(ofile, (OFF_T)size, SEEK_CUR) == -1) err(1, "seek error extracting inode %lu, name %s\nlseek", (unsigned long)curfile.ino, curfile.name); } @@ -985,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'; } /* @@ -996,7 +1491,7 @@ xtrlnkfile(char *buf, size_t size) */ /* ARGSUSED */ static void -xtrlnkskip(char *buf, size_t size) +xtrlnkskip(UNUSED(char *buf), UNUSED(size_t size)) { errx(1, "unallocated block in symbolic link %s", curfile.name); @@ -1018,7 +1513,7 @@ xtrmap(char *buf, size_t size) */ /* ARGSUSED */ static void -xtrmapskip(char *buf, size_t size) +xtrmapskip(UNUSED(char *buf), size_t size) { panic("hole in map\n"); @@ -1030,7 +1525,7 @@ xtrmapskip(char *buf, size_t size) */ /* ARGSUSED */ void -xtrnull(char *buf, size_t size) +xtrnull(UNUSED(char *buf), UNUSED(size_t size)) { return; @@ -1048,7 +1543,7 @@ xtrcmpfile(char *buf, size_t size) if (cmperror) return; - if (read(ifile, cmpbuf, size) != size) { + if (read(ifile, cmpbuf, size) != (ssize_t)size) { fprintf(stderr, "%s: size has changed.\n", curfile.name); cmperror = 1; @@ -1067,7 +1562,7 @@ xtrcmpfile(char *buf, size_t size) * Skip over a hole in a file. */ static void -xtrcmpskip(char *buf, size_t size) +xtrcmpskip(UNUSED(char *buf), size_t size) { static char cmpbuf[MAXBSIZE]; int i; @@ -1075,14 +1570,14 @@ xtrcmpskip(char *buf, size_t size) if (cmperror) return; - if (read(ifile, cmpbuf, size) != size) { + if (read(ifile, cmpbuf, size) != (ssize_t)size) { fprintf(stderr, "%s: size has changed.\n", curfile.name); cmperror = 1; return; } - for (i = 0; i < size; ++i) + for (i = 0; i < (int)size; ++i) if (cmpbuf[i] != '\0') { fprintf(stderr, "%s: tape and disk copies are different\n", curfile.name); @@ -1092,9 +1587,20 @@ xtrcmpskip(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]; @@ -1136,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); @@ -1154,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; } @@ -1204,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 @@ -1211,33 +1754,74 @@ static char tmpfilename[MAXPATHLEN]; void comparefile(char *name) { - 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); + skipfile(); + return; + } 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; } - curfile.name = name; - curfile.action = USING; - mode = curfile.dip->di_mode; - - 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; + } switch (mode & IFMT) { default: skipfile(); @@ -1249,6 +1833,7 @@ comparefile(char *name) case IFDIR: skipfile(); + compareattr(name); return; case IFLNK: { @@ -1272,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; } @@ -1284,6 +1869,7 @@ comparefile(char *name) do_compare_error; return; } + compareattr(name); return; } @@ -1297,23 +1883,24 @@ comparefile(char *name) return; } - if (sb.st_rdev != (int)curfile.dip->di_rdev) { + if (sb.st_rdev != (dev_t)curfile.dip->di_rdev) { 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; } @@ -1356,12 +1943,13 @@ comparefile(char *name) unlink(tmpfile); #endif #endif /* COMPARE_ONTHEFLY */ + compareattr(name); return; } /* NOTREACHED */ } -#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO) static void (*readtape_func)(char *) = readtape_set; /* @@ -1394,7 +1982,7 @@ readtape_set(char *buf) readtape(buf); } -#endif /* HAVE_ZLIB || HAVE_BZLIB */ +#endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */ /* * This is the original readtape(), it's used for reading uncompressed input. @@ -1402,7 +1990,7 @@ readtape_set(char *buf) * Handle read errors, and end of media. */ static void -#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO) readtape_uncompr(char *buf) #else readtape(char *buf) @@ -1430,7 +2018,7 @@ readtape(char *buf) #endif getmore: #ifdef RRESTORE - if (host) + if (!Afile && host) i = rmtread(&tapebuf[rd], cnt); else #endif @@ -1492,11 +2080,11 @@ getmore: i = ntrec * TP_BSIZE; memset(tapebuf, 0, (size_t)i); #ifdef RRESTORE - if (host) + if (!Afile && host) seek_failed = (rmtseek(i, 1) < 0); else #endif - seek_failed = (LSEEK(mt, i, SEEK_CUR) == (off_t)-1); + seek_failed = (LSEEK(mt, i, SEEK_CUR) == (OFF_T)-1); if (seek_failed) { warn("continuation failed"); @@ -1530,7 +2118,7 @@ getmore: tpblksread++; } -#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO) /* * Read a compressed format block from a file or pipe and uncompress it. @@ -1555,11 +2143,16 @@ readtape_comprfile(char *buf) ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; numtrec = ntrec; tpb = (struct tapebuf *) tapebuf; +#ifdef USE_QFA + if (createtapeposflag) + (void)GetTapePos(&curtapepos); +#endif /* read the block prefix */ ret = read_a_block(mt, tapebuf, PREFIXSIZE, &rl); + converttapebuf(tpb); - if (Vflag && (ret == 0 || rl < PREFIXSIZE || tpb->length == 0)) + if (Vflag && (ret == 0 || rl < (int)PREFIXSIZE || tpb->length == 0)) ret = 0; if (ret <= 0) goto readerr; @@ -1643,6 +2236,10 @@ readtape_comprtape(char *buf) ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; numtrec = ntrec; tpb = (struct tapebuf *) tapebuf; +#ifdef USE_QFA + if (createtapeposflag) + (void)GetTapePos(&curtapepos); +#endif /* read the block */ size = bufsize + PREFIXSIZE; @@ -1650,6 +2247,7 @@ readtape_comprtape(char *buf) if (ret <= 0) goto readerr; + converttapebuf(tpb); tbufptr = decompress_tapebuf(tpb, rl); if (tbufptr == NULL) { msg_read_error("Tape decompression error while"); @@ -1719,17 +2317,14 @@ 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 */ blocklen = tpbin->length; - if (readsize < blocklen + PREFIXSIZE) + if (readsize < blocklen + (int)PREFIXSIZE) lengtherr = "short"; else - if (readsize > blocklen + PREFIXSIZE) + if (readsize > blocklen + (int)PREFIXSIZE) lengtherr = "long"; worklen = comprlen; @@ -1768,7 +2363,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); @@ -1797,6 +2392,31 @@ decompress_tapebuf(struct tapebuf *tpbin, int readsize) cresult = 0; #endif /* HAVE_BZLIB */ } + if (tpbin->flags == COMPRESS_LZO) { +#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, &worklen2, NULL); + worklen = worklen2; + output = comprbuf; + switch (cresult) { + case LZO_E_OK: + break; + case LZO_E_ERROR: + case LZO_E_EOF_NOT_FOUND: + reason = "data error"; + break; + default: + reason = "unknown"; + } + if (cresult == LZO_E_OK) + cresult = 1; + else + cresult = 0; +#endif /* HAVE_LZO */ + } } else { output = tpbin->buf; @@ -1809,8 +2429,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) @@ -1842,7 +2462,7 @@ msg_read_error(char *m) break; } } -#endif /* HAVE_ZLIB || HAVE_BZLIB */ +#endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */ /* * Read the first block and get the blocksize from it. Test @@ -1860,7 +2480,7 @@ findtapeblksize(void) long i; size_t len; struct tapebuf *tpb = (struct tapebuf *) tapebuf; - struct s_spcl *spclpt = (struct s_spcl *) tapebuf; + struct s_spcl spclpt; for (i = 0; i < ntrec; i++) ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; @@ -1875,6 +2495,18 @@ findtapeblksize(void) if (read_a_block(mt, tapebuf, len, &i) <= 0) errx(1, "Tape read error on first record"); + memcpy(&spclpt, tapebuf, TP_BSIZE); + cvtflag = 0; + if (converthead(&spclpt) == FAIL) { + cvtflag++; + if (converthead(&spclpt) == FAIL) { + /* Special case for old compressed tapes with prefix */ + if (magtapein && (i % TP_BSIZE != 0)) + goto oldformat; + errx(1, "Tape is not a dump tape"); + } + fprintf(stderr, "Converting to new file system format.\n"); + } /* * If the input is from a file or a pipe, we read TP_BSIZE * bytes looking for a dump header. If the dump is compressed @@ -1883,14 +2515,14 @@ findtapeblksize(void) * dump is not compressed and does not have a prefix. */ if (!magtapein) { - if (spclpt->c_type == TS_TAPE - && spclpt->c_flags & DR_COMPRESSED) { + if (spclpt.c_type == TS_TAPE + && spclpt.c_flags & DR_COMPRESSED) { /* It's a compressed dump file, read in the */ - /* rest of the block based on spclpt->c_ntrec. */ - if (spclpt->c_ntrec > ntrec) + /* rest of the block based on spclpt.c_ntrec. */ + if (spclpt.c_ntrec > ntrec) errx(1, "Tape blocksize is too large, use " - "\'-b %d\' ", spclpt->c_ntrec); - ntrec = spclpt->c_ntrec; + "\'-b %d\' ", spclpt.c_ntrec); + ntrec = spclpt.c_ntrec; len = (ntrec - 1) * TP_BSIZE; zflag = 1; } @@ -1899,7 +2531,7 @@ findtapeblksize(void) len = bufsize - TP_BSIZE; } if (read_a_block(mt, tapebuf+TP_BSIZE, len, &i) < 0 - || (i != len && i % TP_BSIZE != 0)) + || (i != (long)len && i % TP_BSIZE != 0)) errx(1,"Error reading dump file header"); tbufptr = tapebuf; numtrec = ntrec; @@ -1913,14 +2545,21 @@ findtapeblksize(void) * what we asked for; adjust the value of ntrec and test for * a compressed dump tape. */ - if (i % TP_BSIZE != 0) { +oldformat: /* may be old format compressed dump tape with a prefix */ - spclpt = (struct s_spcl *) tpb->buf; + memcpy(&spclpt, tpb->buf, TP_BSIZE); + cvtflag = 0; + if (converthead(&spclpt) == FAIL) { + cvtflag++; + if (converthead(&spclpt) == FAIL) + errx(1, "Tape is not a dump tape"); + fprintf(stderr, "Converting to new file system format.\n"); + } if (i % TP_BSIZE == PREFIXSIZE && tpb->compressed == 0 - && spclpt->c_type == TS_TAPE - && spclpt->c_flags & DR_COMPRESSED) { + && spclpt.c_type == TS_TAPE + && spclpt.c_flags & DR_COMPRESSED) { zflag = 1; tbufptr = tpb->buf; if (tpb->length > bufsize) @@ -1932,12 +2571,12 @@ findtapeblksize(void) i, TP_BSIZE); } ntrec = i / TP_BSIZE; - if (spclpt->c_type == TS_TAPE) { - if (spclpt->c_flags & DR_COMPRESSED) + if (spclpt.c_type == TS_TAPE) { + if (spclpt.c_flags & DR_COMPRESSED) zflag = 1; - if (spclpt->c_ntrec > ntrec) + if (spclpt.c_ntrec > ntrec) errx(1, "Tape blocksize is too large, use " - "\'-b %d\' ", spclpt->c_ntrec); + "\'-b %d\' ", spclpt.c_ntrec); } numtrec = ntrec; Vprintf(stdout, "Tape block size is %ld\n", ntrec); @@ -1953,7 +2592,7 @@ static int read_a_block(int fd, char *buf, size_t len, long *lengthread) size = len; while (size > 0) { #ifdef RRESTORE - if (host) + if (!Afile && host) i = rmtread(buf, size); else #endif @@ -1977,7 +2616,7 @@ closemt(void) if (mt < 0) return; #ifdef RRESTORE - if (host) + if (!Afile && host) rmtclose(); else #endif @@ -2001,7 +2640,8 @@ setmagtapein(void) { magtapein = ioctl(mt, MTIOCGET, (char *)&mt_stat) == 0; } - Vprintf(stdout,"Input is from %s\n", + Vprintf(stdout,"Input is from a %s %s\n", + host ? "remote" : "local", magtapein ? "tape" : Vflag ? "multi-volume (no tape)" : "file/pipe"); } @@ -2014,6 +2654,13 @@ setmagtapein(void) { */ static int gethead(struct s_spcl *buf) +{ + readtape((char *)buf); + return converthead(buf); +} + +static int +converthead(struct s_spcl *buf) { int32_t i; union { @@ -2049,7 +2696,6 @@ gethead(struct s_spcl *buf) } u_ospcl; if (!cvtflag) { - readtape((char *)buf); if (buf->c_magic != NFS_MAGIC) { if (swabi(buf->c_magic) != NFS_MAGIC) return (FAIL); @@ -2061,38 +2707,51 @@ gethead(struct s_spcl *buf) if (checksum((int *)buf) == FAIL) return (FAIL); if (Bcvt) - swabst((u_char *)"8i4s31i528bi192b2i", (u_char *)buf); + swabst((u_char *)"8i4s1l29i528bi192b4i", (u_char *)buf); goto good; } - readtape((char *)(&u_ospcl.s_ospcl)); - 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; + memcpy(&u_ospcl.s_ospcl, buf, TP_BSIZE); + 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; @@ -2164,6 +2823,23 @@ good: return(GOOD); } +static void +converttapebuf(struct tapebuf *tpb) +{ + if (Bcvt) { + struct tb { + unsigned int length:28; + unsigned int flags:3; + unsigned int compressed:1; + } tb; + swabst((u_char *)"i", (u_char *)tpb); + memcpy(&tb, tpb, 4); + tpb->length = tb.length; + tpb->flags = tb.flags; + tpb->compressed = tb.compressed; + } +} + /* * Check that a header is where it belongs and predict the next header */ @@ -2443,7 +3119,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 */ @@ -2454,7 +3255,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 @@ -2480,11 +3281,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 */ @@ -2495,7 +3291,7 @@ GotoTapePos(long long pos) #ifdef RDUMP if (host) - err = (rmtseek((long)pos, SEEK_SET) < 0); + err = (rmtseek((OFF_T)pos, (int)LSEEK_GO2_TAPEPOS) < 0); else #endif { @@ -2518,6 +3314,7 @@ GotoTapePos(long long pos) } return err; } +#endif /* __linux__ */ /* * read next data from tape to re-sync @@ -2539,30 +3336,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 < 32)); + } 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 == 32) { - fprintf(stderr, "DEBUG: bufsize %d\n", bufsize); - fprintf(stderr, "DEBUG: ntrec %ld\n", ntrec); - fprintf(stderr, "DEBUG: %ld reads\n", cntloop); - } + 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 */