X-Git-Url: https://git.wh0rd.org/?p=dump.git;a=blobdiff_plain;f=restore%2Ftape.c;h=1b6b1d9d52578436d8fd6c1cfa6baf712359fe11;hp=4ac6a25d68c70aaaadc412fc6ecad3e35dc4f778;hb=ff9e45da1a0be7807fb18401ca7e5ee28d0e1007;hpb=b45f51d61e911ac8a040bef1efda6afd82261e03 diff --git a/restore/tape.c b/restore/tape.c index 4ac6a25..1b6b1d9 100644 --- a/restore/tape.c +++ b/restore/tape.c @@ -2,8 +2,8 @@ * Ported to Linux's Second Extended File System as part of the * dump and restore backup suit * Remy Card , 1994-1997 - * Stelian Pop , 1999 - * + * Stelian Pop , 1999-2000 + * Stelian Pop - AlcĂ´ve , 2000-2002 */ /* @@ -45,13 +45,21 @@ */ #ifndef lint -#if 0 -static char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95"; -#endif static const char rcsid[] = - "$Id: tape.c,v 1.2 1999/10/11 12:53:24 stelian Exp $"; + "$Id: tape.c,v 1.61 2002/05/06 08:45:41 stelian Exp $"; #endif /* not lint */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -59,42 +67,56 @@ static const char rcsid[] = #ifdef __linux__ #include +#include +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else #include +#endif +#include #include #else /* __linux__ */ #include #endif /* __linux__ */ #include -#include -#include -#include -#include -#include -#include +#ifdef HAVE_ZLIB +#include +#endif /* HAVE_ZLIB */ -#ifdef __linux__ -#include -#endif +#ifdef HAVE_BZLIB +#include +#endif /* HAVE_BZLIB */ #include "restore.h" #include "extern.h" #include "pathnames.h" +#ifdef USE_QFA +int noresyncmesg = 0; +#endif /* USE_QFA */ static long fssize = MAXBSIZE; static int mt = -1; -static int pipein = 0; -static char *magtape; +int pipein = 0; +static int magtapein = 0; /* input is from magtape */ +static char magtape[MAXPATHLEN]; +static char magtapeprefix[MAXPATHLEN]; static int blkcnt; static int numtrec; -static char *tapebuf; +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) +static char *comprbuf; /* uncompress work buf */ +static size_t comprlen; /* size including prefix */ +#endif static union u_spcl endoftapemark; static long blksread; /* blocks read since last header */ static long tpblksread = 0; /* TP_BSIZE blocks read */ static long tapesread; -static jmp_buf restart; +static sigjmp_buf restart; static int gettingfile = 0; /* restart has a valid frame */ -static char *host = NULL; +char *host = NULL; static int ofile; static char *map; @@ -114,25 +136,52 @@ static void findtapeblksize __P((void)); static int gethead __P((struct s_spcl *)); static void readtape __P((char *)); static void setdumpnum __P((void)); +static u_int swabi __P((u_int)); +#if 0 static u_long swabl __P((u_long)); -static u_char *swablong __P((u_char *, int)); -static u_char *swabshort __P((u_char *, int)); +#endif +static u_char *swab64 __P((u_char *, int)); +static u_char *swab32 __P((u_char *, int)); +static u_char *swab16 __P((u_char *, int)); static void terminateinput __P((void)); -static void xtrfile __P((char *, long)); -static void xtrlnkfile __P((char *, long)); -static void xtrlnkskip __P((char *, long)); -static void xtrmap __P((char *, long)); -static void xtrmapskip __P((char *, long)); -static void xtrskip __P((char *, long)); +static void xtrfile __P((char *, size_t)); +static void xtrlnkfile __P((char *, size_t)); +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 setmagtapein __P((void)); + +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) +static void newcomprbuf __P((int)); +static void (*readtape_func) __P((char *)); +static void readtape_set __P((char *)); +static void readtape_uncompr __P((char *)); +static void readtape_comprfile __P((char *)); +static void readtape_comprtape __P((char *)); +static char *decompress_tapebuf __P((struct tapebuf *, int)); +static void msg_read_error __P((char *)); +#endif +static int read_a_block __P((int, char *, size_t, long *)); +#define PREFIXSIZE sizeof(struct tapebuf) + +#define COMPARE_ONTHEFLY 1 + +#if COMPARE_ONTHEFLY +static int ifile; /* input file for compare */ +static int cmperror; /* compare error */ +static void xtrcmpfile __P((char *, size_t)); +static void xtrcmpskip __P((char *, size_t)); +#endif static int readmapflag; +static int readingmaps; /* set to 1 while reading the maps */ /* - * Set up an input source + * Set up an input source. This is called from main.c before setup() is. */ void -setinput(source) - char *source; +setinput(char *source) { FLUSHTAPEBUF(); if (bflag) @@ -147,7 +196,7 @@ setinput(source) source = strchr(host, ':'); *source++ = '\0'; if (rmthost(host) == 0) - done(1); + exit(1); } else #endif if (strcmp(source, "-") == 0) { @@ -157,84 +206,120 @@ setinput(source) */ terminal = fopen(_PATH_TTY, "r"); if (terminal == NULL) { - (void)fprintf(stderr, "cannot open %s: %s\n", - _PATH_TTY, strerror(errno)); + warn("cannot open %s", _PATH_TTY); terminal = fopen(_PATH_DEVNULL, "r"); - if (terminal == NULL) { - (void)fprintf(stderr, "cannot open %s: %s\n", - _PATH_DEVNULL, strerror(errno)); - done(1); - } + if (terminal == NULL) + err(1, "cannot open %s", _PATH_DEVNULL); } pipein++; } setuid(getuid()); /* no longer need or want root privileges */ - magtape = strdup(source); - if (magtape == NULL) { - fprintf(stderr, "Cannot allocate space for magtape buffer\n"); - done(1); + if (Mflag) { + strncpy(magtapeprefix, source, MAXPATHLEN); + magtapeprefix[MAXPATHLEN-1] = '\0'; + snprintf(magtape, MAXPATHLEN, "%s%03d", source, 1); } + else + strncpy(magtape, source, MAXPATHLEN); + magtape[MAXPATHLEN - 1] = '\0'; } void -newtapebuf(size) - long size; +newtapebuf(long size) { - static tapebufsize = -1; + static int tapebufsize = -1; ntrec = size; + bufsize = ntrec * TP_BSIZE; if (size <= tapebufsize) return; if (tapebuf != NULL) free(tapebuf); - tapebuf = malloc(size * TP_BSIZE); - if (tapebuf == NULL) { - fprintf(stderr, "Cannot allocate space for tape buffer\n"); - done(1); - } + tapebuf = malloc(size * TP_BSIZE + sizeof(struct tapebuf)); + if (tapebuf == NULL) + errx(1, "Cannot allocate space for tape buffer"); tapebufsize = size; } +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) +static void +newcomprbuf(int size) +{ + size_t buf_size = (size+1) * TP_BSIZE + sizeof(struct tapebuf); + if (buf_size <= comprlen) + return; + comprlen = buf_size; + if (comprbuf != NULL) + free(comprbuf); + comprbuf = malloc(comprlen); + if (comprbuf == NULL) + errx(1, "Cannot allocate space for decompress buffer"); +} +#endif /* HAVE_ZLIB || HAVE_BZLIB */ + /* * Verify that the tape drive can be accessed and * that it actually is a dump tape. */ void -setup() +setup(void) { - int i, j, *ip; - struct stat stbuf; + int i, j, *ip, bot_code; + struct STAT stbuf; + char *temptape; + + Vprintf(stdout, "Verify tape and initialize maps\n"); + if (Afile == NULL && bot_script) { + msg("Launching %s\n", bot_script); + bot_code = system_command(bot_script, magtape, 1); + if (bot_code != 0 && bot_code != 1) { + msg("Restore aborted by the beginning of tape script\n"); + exit(1); + } + } + + if (Afile) + temptape = Afile; + else + temptape = magtape; - vprintf(stdout, "Verify tape and initialize maps\n"); #ifdef RRESTORE if (host) - mt = rmtopen(magtape, 0); + mt = rmtopen(temptape, 0); else #endif if (pipein) mt = 0; else - mt = open(magtape, O_RDONLY, 0); - if (mt < 0) { - fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); - done(1); - } - volno = 1; - setdumpnum(); + mt = OPEN(temptape, O_RDONLY, 0); + if (mt < 0) + err(1, "%s", magtape); + if (!Afile) { + volno = 1; + setmagtapein(); + setdumpnum(); + } +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) + readtape_func = readtape_set; +#endif FLUSHTAPEBUF(); - if (!pipein && !bflag) - findtapeblksize(); + findtapeblksize(); if (gethead(&spcl) == FAIL) { blkcnt--; /* push back this block */ blksread--; tpblksread--; cvtflag++; - if (gethead(&spcl) == FAIL) { - fprintf(stderr, "Tape is not a dump tape\n"); - done(1); - } + if (gethead(&spcl) == FAIL) + errx(1, "Tape is not a dump tape"); fprintf(stderr, "Converting to new file system format.\n"); } + + if (zflag) { + fprintf(stderr, "Dump tape is compressed.\n"); +#if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB) + errx(1,"This restore version doesn't support decompression"); +#endif /* !HAVE_ZLIB && !HAVE_BZLIB */ + } if (pipein) { endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC; endoftapemark.s_spcl.c_type = TS_END; @@ -248,54 +333,73 @@ setup() } if (vflag || command == 't' || command == 'C') printdumpinfo(); - if (filesys == NULL) { - filesys = spcl.c_filesys; +#ifdef USE_QFA + if (tapeposflag && spcl.c_date != qfadumpdate) + errx(1, "different QFA/dumpdates detected\n"); +#endif + if (filesys[0] == '\0') { + char *dirptr; + strncpy(filesys, spcl.c_filesys, NAMELEN); + filesys[NAMELEN - 1] = '\0'; + dirptr = strstr(filesys, " (dir"); + if (dirptr != NULL) + *dirptr = '\0'; } dumptime = spcl.c_ddate; dumpdate = spcl.c_date; - if (stat(".", &stbuf) < 0) { - fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); - done(1); - } + if (STAT(".", &stbuf) < 0) + err(1, "cannot stat ."); if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) fssize = TP_BSIZE; if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) fssize = stbuf.st_blksize; - if (((fssize - 1) & fssize) != 0) { - fprintf(stderr, "bad block size %ld\n", fssize); - done(1); - } - if (spcl.c_volume != 1) { - fprintf(stderr, "Tape is not volume 1 of the dump\n"); - done(1); - } + if (((fssize - 1) & fssize) != 0) + errx(1, "bad block size %ld", fssize); + if (spcl.c_volume != 1) + errx(1, "Tape is not volume 1 of the dump"); if (gethead(&spcl) == FAIL) { - dprintf(stdout, "header read failed at %ld blocks\n", blksread); + 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) { - fprintf(stderr, "Cannot find file removal list\n"); - done(1); - } + 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", maxino); map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); if (map == NULL) - panic("no memory for active inode map\n"); + errx(1, "no memory for active inode map"); usedinomap = map; curfile.action = USING; getfile(xtrmap, xtrmapskip); - if (spcl.c_type != TS_BITS) { - fprintf(stderr, "Cannot find file dump list\n"); - done(1); - } + while (spcl.c_type == TS_ADDR) { + /* Recompute maxino and the map */ + char *oldmap = usedinomap; + dump_ino_t oldmaxino = maxino; + maxino += (spcl.c_count * TP_BSIZE * NBBY) + 1; + map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); + if (map == NULL) + errx(1, "no memory for active inode map"); + usedinomap = map; + memcpy(usedinomap, oldmap, howmany(oldmaxino, NBBY)); + free(oldmap); + + 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) + errx(1, "Cannot find file dump list"); map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); if (map == (char *)NULL) - panic("no memory for file dump list\n"); + 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 @@ -303,6 +407,8 @@ setup() */ if (oldinofmt == 0) SETINO(WINO, dumpmap); + readingmaps = 0; + findinode(&spcl); } /* @@ -313,17 +419,20 @@ setup() * the user when only extracting a subset of the files. */ void -getvol(nextvol) - long nextvol; +getvol(long nextvol) { - long newvol=0, savecnt=0, wantnext=0, i; + long newvol = 0, wantnext = 0, i; + long saved_blksread = 0, saved_tpblksread = 0; union u_spcl tmpspcl; # define tmpbuf tmpspcl.s_spcl char buf[TP_BSIZE]; + int haderror = 0, bot_code = 1; if (nextvol == 1) { tapesread = 0; gettingfile = 0; + tpblksread = 0; + blksread = 0; } if (pipein) { if (nextvol != 1) @@ -332,11 +441,16 @@ getvol(nextvol) return; goto gethdr; } - savecnt = blksread; + saved_blksread = blksread; + saved_tpblksread = tpblksread; +#if defined(USE_QFA) && defined(sunos) + if (createtapeposflag || tapeposflag) + close(fdsmtc); +#endif again: if (pipein) - done(1); /* pipes do not get a second chance */ - if (command == 'R' || command == 'r' || curfile.action != SKIP) { + exit(1); /* pipes do not get a second chance */ + if (aflag || curfile.action != SKIP) { newvol = nextvol; wantnext = 1; } else { @@ -346,7 +460,7 @@ again: while (newvol <= 0) { if (tapesread == 0) { fprintf(stderr, "%s%s%s%s%s", - "You have not read any tapes yet.\n", + "You have not read any volumes yet.\n", "Unless you know which volume your", " file(s) are on you should start\n", "with the last volume and work", @@ -356,18 +470,22 @@ again: strcpy(buf, ": "); for (i = 1; i < 32; i++) if (tapesread & (1 << i)) { - fprintf(stderr, "%s%ld", buf, i); + fprintf(stderr, "%s%ld", buf, (long)i); strcpy(buf, ", "); } fprintf(stderr, "\n"); } do { - fprintf(stderr, "Specify next volume #: "); + fprintf(stderr, "Specify next volume # (none if no more volumes): "); (void) fflush(stderr); - (void) fgets(buf, BUFSIZ, terminal); + (void) fgets(buf, TP_BSIZE, terminal); } while (!feof(terminal) && buf[0] == '\n'); if (feof(terminal)) - done(1); + exit(1); + if (!strcmp(buf, "none\n")) { + terminateinput(); + return; + } newvol = atoi(buf); if (newvol <= 0) { fprintf(stderr, @@ -376,66 +494,101 @@ again: } if (newvol == volno) { tapesread |= 1 << volno; +#if defined(USE_QFA) && defined(sunos) + if (createtapeposflag || tapeposflag) { + if (OpenSMTCmt(magtape) < 0) { + volno = -1; + haderror = 1; + goto again; + } + } +#endif return; } closemt(); - fprintf(stderr, "Mount tape volume %ld\n", newvol); - fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); - fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); - (void) fflush(stderr); - (void) fgets(buf, BUFSIZ, terminal); - if (feof(terminal)) - done(1); - if (!strcmp(buf, "none\n")) { - terminateinput(); - return; + if (Mflag) { + snprintf(magtape, MAXPATHLEN, "%s%03ld", magtapeprefix, newvol); + magtape[MAXPATHLEN - 1] = '\0'; + } + if (bot_script && !haderror) { + msg("Launching %s\n", bot_script); + bot_code = system_command(bot_script, magtape, newvol); + if (bot_code != 0 && bot_code != 1) { + msg("Restore aborted by the beginning of tape script\n"); + exit(1); + } } - if (buf[0] != '\n') { - (void) strcpy(magtape, buf); - magtape[strlen(magtape) - 1] = '\0'; + if (haderror || (bot_code && !Mflag)) { + haderror = 0; + 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); + (void) fflush(stderr); + (void) fgets(buf, TP_BSIZE, terminal); + if (feof(terminal)) + exit(1); + if (!strcmp(buf, "none\n")) { + terminateinput(); + return; + } + if (buf[0] != '\n') { + char *pos; + (void) strncpy(magtape, buf, sizeof(magtape)); + magtape[sizeof(magtape) - 1] = '\0'; + if ((pos = strchr(magtape, '\n'))) + magtape[pos - magtape] = '\0'; + } } #ifdef RRESTORE if (host) mt = rmtopen(magtape, 0); else #endif - mt = open(magtape, O_RDONLY, 0); + mt = OPEN(magtape, O_RDONLY, 0); if (mt == -1) { fprintf(stderr, "Cannot open %s\n", magtape); volno = -1; + haderror = 1; goto again; } gethdr: + setmagtapein(); +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) + readtape_func = readtape_set; +#endif volno = newvol; setdumpnum(); FLUSHTAPEBUF(); + findtapeblksize(); if (gethead(&tmpbuf) == FAIL) { - dprintf(stdout, "header read failed at %ld blocks\n", blksread); + Dprintf(stdout, "header read failed at %ld blocks\n", (long)blksread); fprintf(stderr, "tape is not dump tape\n"); volno = 0; + haderror = 1; + blksread = saved_blksread; + tpblksread = saved_tpblksread; goto again; } if (tmpbuf.c_volume != volno) { fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume); volno = 0; + haderror = 1; + blksread = saved_blksread; + tpblksread = saved_tpblksread; goto again; } if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) { -#ifdef __linux__ fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime4(&tmpbuf.c_date)); - fprintf(stderr, "\twanted: %s", ctime4(&dumpdate)); -#else - fprintf(stderr, "Wrong dump date\n\tgot: %s", - ctime(&tmpbuf.c_date)); fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); -#endif volno = 0; + haderror = 1; + blksread = saved_blksread; + tpblksread = saved_tpblksread; goto again; } tapesread |= 1 << volno; - blksread = savecnt; /* * If continuing from the previous volume, skip over any * blocks read already at the end of the previous volume. @@ -443,11 +596,17 @@ gethdr: * If coming to this volume at random, skip to the beginning * of the next record. */ - dprintf(stdout, "read %ld recs, tape starts with %d\n", - tpblksread, tmpbuf.c_firstrec); + if (zflag) { + fprintf(stderr, "Dump tape is compressed.\n"); +#if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB) + 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 - 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 && @@ -456,8 +615,8 @@ gethdr: * -1 since we've read the volume header */ i = tpblksread - tmpbuf.c_firstrec - 1; - dprintf(stderr, "Skipping %ld duplicate record%s.\n", - i, i > 1 ? "s" : ""); + Dprintf(stderr, "Skipping %ld duplicate record%s.\n", + (long)i, i > 1 ? "s" : ""); while (--i >= 0) readtape(buf); } @@ -477,7 +636,7 @@ gethdr: findinode(&spcl); if (gettingfile) { gettingfile = 0; - longjmp(restart, 1); + siglongjmp(restart, 1); } } @@ -485,7 +644,7 @@ gethdr: * Handle unexpected EOF. */ static void -terminateinput() +terminateinput(void) { if (gettingfile && curfile.action == USING) { @@ -498,7 +657,7 @@ terminateinput() curfile.ino = maxino; if (gettingfile) { gettingfile = 0; - longjmp(restart, 1); + siglongjmp(restart, 1); } } @@ -507,16 +666,14 @@ terminateinput() * appropriate one. */ static void -setdumpnum() +setdumpnum(void) { struct mtop tcom; if (dumpnum == 1 || volno != 1) return; - if (pipein) { - fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); - done(1); - } + if (pipein) + errx(1, "Cannot have multiple dumps on pipe input"); tcom.mt_op = MTFSF; tcom.mt_count = dumpnum - 1; #ifdef RRESTORE @@ -525,50 +682,69 @@ setdumpnum() else #endif if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0) - fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); + warn("ioctl MTFSF"); } void -printdumpinfo() +printdumpinfo(void) { -#ifdef __linux__ 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)); -#else - fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date)); - fprintf(stdout, "Dumped from: %s", - (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate)); -#endif if (spcl.c_host[0] == '\0') return; - fprintf(stderr, "Level %d dump of %s on %s:%s\n", + fprintf(stdout, "Level %d dump of %s on %s:%s\n", spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); - fprintf(stderr, "Label: %s\n", spcl.c_label); + fprintf(stdout, "Label: %s\n", spcl.c_label); } +void +printvolinfo(void) +{ + int i; + + if (volinfo[1] == ROOTINO) { + printf("Starting inode numbers by volume:\n"); + for (i = 1; i < 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(name) - char *name; +extractfile(struct entry *ep, int doremove) { - int flags; + unsigned int flags; mode_t mode; struct timeval timep[2]; - struct entry *ep; -#ifdef __linux__ - int err; - uid_t uid; - gid_t gid; -#endif + 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; -#ifdef __linux__ +#if defined(__linux__) || defined(sunos) 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; -#else /* __linux__ */ +#else /* __linux__ || sunos */ timep[0].tv_sec = curfile.dip->di_atime; timep[0].tv_usec = curfile.dip->di_atimensec / 1000; timep[1].tv_sec = curfile.dip->di_mtime; @@ -584,63 +760,69 @@ extractfile(name) return (FAIL); case IFSOCK: - vprintf(stdout, "skipped socket %s\n", name); + Vprintf(stdout, "skipped socket %s\n", name); skipfile(); return (GOOD); case IFDIR: 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); + Vprintf(stdout, "extract file %s\n", name); return (genliteraldir(name, curfile.ino)); case IFLNK: - lnkbuf[0] = '\0'; - pathlen = 0; -#ifdef __linux__ - uid = curfile.dip->di_uid; - gid = curfile.dip->di_gid; + { +#ifdef HAVE_LCHOWN + uid_t luid = curfile.dip->di_uid; + gid_t lgid = curfile.dip->di_gid; #endif - 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); } -#ifdef __linux__ - err = linkit(lnkbuf, name, SYMLINK); - if (err == GOOD) - (void) chown(name, uid, gid); - return (err); -#else - return (linkit(lnkbuf, name, SYMLINK)); + else + skipfile(); + +#ifdef HAVE_LCHOWN + (void) lchown(name, luid, lgid); #endif + return (GOOD); + } case IFIFO: - vprintf(stdout, "extract fifo %s\n", name); + Vprintf(stdout, "extract fifo %s\n", name); if (Nflag) { skipfile(); return (GOOD); } - if (uflag && !Nflag) - (void)unlink(name); - if (mkfifo(name, mode) < 0) { - fprintf(stderr, "%s: cannot create fifo: %s\n", - name, strerror(errno)); - skipfile(); - return (FAIL); + 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 (flags) #ifdef __linux__ - (void) fsetflags(name, flags); + (void) fsetflags(name, flags); #else - (void) chflags(name, flags); + (void) chflags(name, flags); #endif skipfile(); utimes(name, timep); @@ -648,57 +830,71 @@ extractfile(name) case IFCHR: case IFBLK: - vprintf(stdout, "extract special file %s\n", name); + Vprintf(stdout, "extract special file %s\n", name); if (Nflag) { skipfile(); return (GOOD); } - if (uflag) - (void)unlink(name); - if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { - fprintf(stderr, "%s: cannot create special file: %s\n", - name, strerror(errno)); - skipfile(); - return (FAIL); + if (! (spcl.c_flags & DR_METAONLY)) { + 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); + } } (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); (void) chmod(name, mode); + if (flags) #ifdef __linux__ - (void) fsetflags(name, flags); + { + warn("%s: fsetflags called on a special file", name); + (void) fsetflags(name, flags); + } #else - (void) chflags(name, flags); + (void) chflags(name, flags); #endif skipfile(); utimes(name, timep); return (GOOD); case IFREG: - vprintf(stdout, "extract file %s\n", name); + { + 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 ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, - 0666)) < 0) { - fprintf(stderr, "%s: cannot create file: %s\n", - name, strerror(errno)); - 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) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid); - (void) fchmod(ofile, mode); + else + skipfile(); + (void) chown(name, luid, lgid); + (void) chmod(name, mode); + if (flags) #ifdef __linux__ - (void) fsetflags(ofile, flags); + (void) fsetflags(name, flags); #else - (void) fchflags(ofile, flags); + (void) chflags(name, flags); #endif - getfile(xtrfile, xtrskip); - (void) close(ofile); utimes(name, timep); return (GOOD); } + } /* NOTREACHED */ } @@ -706,7 +902,7 @@ extractfile(name) * skip over bit maps on the tape */ void -skipmaps() +skipmaps(void) { while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) @@ -717,7 +913,7 @@ skipmaps() * skip over a file on the tape */ void -skipfile() +skipfile(void) { curfile.action = SKIP; @@ -731,15 +927,13 @@ skipfile() * to the skip function. */ void -getfile(fill, skip) - void (*fill) __P((char *, long)); - void (*skip) __P((char *, long)); +getfile(void (*fill) __P((char *, size_t)), void (*skip) __P((char *, size_t))) { - register int i; - int curblk = 0; - quad_t size = spcl.c_dinode.di_size; - int last_write_was_hole = 0; - long origsize = size; + int i; + volatile int curblk = 0; + volatile quad_t size = spcl.c_dinode.di_size; + volatile int last_write_was_hole = 0; + quad_t origsize = size; static char clearedbuf[MAXBSIZE]; char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; char junk[TP_BSIZE]; @@ -756,14 +950,14 @@ loop: if (readmapflag || spcl.c_addr[i]) { readtape(&buf[curblk++][0]); if (curblk == fssize / TP_BSIZE) { - (*fill)((char *)buf, (long)(size > TP_BSIZE ? + (*fill)((char *)buf, (size_t)(size > TP_BSIZE ? fssize : (curblk - 1) * TP_BSIZE + size)); curblk = 0; last_write_was_hole = 0; } } else { if (curblk > 0) { - (*fill)((char *)buf, (long)(size > TP_BSIZE ? + (*fill)((char *)buf, (size_t)(size > TP_BSIZE ? curblk * TP_BSIZE : (curblk - 1) * TP_BSIZE + size)); curblk = 0; @@ -782,18 +976,28 @@ loop: if (gethead(&spcl) == GOOD && size > 0) { if (spcl.c_type == TS_ADDR) goto loop; - dprintf(stdout, + Dprintf(stdout, "Missing address (header) block for %s at %ld blocks\n", - curfile.name, blksread); + curfile.name, (long)blksread); } if (curblk > 0) { - (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size)); + (*fill)((char *)buf, (size_t)((curblk * TP_BSIZE) + size)); last_write_was_hole = 0; } + if (size > 0) { + fprintf(stderr, "Missing blocks at the end of %s, assuming hole\n", curfile.name); + while (size > 0) { + size_t skp = size > TP_BSIZE ? TP_BSIZE : size; + (*skip)(clearedbuf, skp); + size -= skp; + } + last_write_was_hole = 1; + } if (last_write_was_hole) { - ftruncate(ofile, origsize); + FTRUNCATE(ofile, origsize); } - findinode(&spcl); + if (!readingmaps) + findinode(&spcl); gettingfile = 0; } @@ -801,19 +1005,14 @@ loop: * Write out the next block of a file. */ static void -xtrfile(buf, size) - char *buf; - long size; +xtrfile(char *buf, size_t size) { if (Nflag) return; - if (write(ofile, buf, (int) size) == -1) { - fprintf(stderr, - "write error extracting inode %ld, name %s\nwrite: %s\n", - curfile.ino, curfile.name, strerror(errno)); - done(1); - } + if (write(ofile, buf, (int) size) == -1) + err(1, "write error extracting inode %lu, name %s\nwrite", + (unsigned long)curfile.ino, curfile.name); } /* @@ -821,34 +1020,25 @@ xtrfile(buf, size) */ /* ARGSUSED */ static void -xtrskip(buf, size) - char *buf; - long size; +xtrskip(char *buf, size_t size) { - if (lseek(ofile, size, SEEK_CUR) == -1) { - fprintf(stderr, - "seek error extracting inode %ld, name %s\nlseek: %s\n", - curfile.ino, curfile.name, strerror(errno)); - done(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); } /* * Collect the next block of a symbolic link. */ static void -xtrlnkfile(buf, size) - char *buf; - long size; +xtrlnkfile(char *buf, size_t size) { pathlen += size; - if (pathlen > MAXPATHLEN) { - fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", + if (pathlen > MAXPATHLEN) + errx(1, "symbolic link name: %s->%s%s; too long %d", curfile.name, lnkbuf, buf, pathlen); - done(1); - } (void) strcat(lnkbuf, buf); } @@ -857,23 +1047,17 @@ xtrlnkfile(buf, size) */ /* ARGSUSED */ static void -xtrlnkskip(buf, size) - char *buf; - long size; +xtrlnkskip(char *buf, size_t size) { - fprintf(stderr, "unallocated block in symbolic link %s\n", - curfile.name); - done(1); + errx(1, "unallocated block in symbolic link %s", curfile.name); } /* * Collect the next block of a bit map. */ static void -xtrmap(buf, size) - char *buf; - long size; +xtrmap(char *buf, size_t size) { memmove(map, buf, size); @@ -885,9 +1069,7 @@ xtrmap(buf, size) */ /* ARGSUSED */ static void -xtrmapskip(buf, size) - char *buf; - long size; +xtrmapskip(char *buf, size_t size) { panic("hole in map\n"); @@ -899,31 +1081,83 @@ xtrmapskip(buf, size) */ /* ARGSUSED */ void -xtrnull(buf, size) - char *buf; - long size; +xtrnull(char *buf, size_t size) { return; } -int +#if COMPARE_ONTHEFLY +/* + * Compare the next block of a file. + */ +static void +xtrcmpfile(char *buf, size_t size) +{ + static char cmpbuf[MAXBSIZE]; + + if (cmperror) + return; + + if (read(ifile, cmpbuf, size) != size) { + fprintf(stderr, "%s: size has changed.\n", + curfile.name); + cmperror = 1; + return; + } + + if (memcmp(buf, cmpbuf, size) != 0) { + fprintf(stderr, "%s: tape and disk copies are different\n", + curfile.name); + cmperror = 1; + return; + } +} + +/* + * Skip over a hole in a file. + */ +static void +xtrcmpskip(char *buf, size_t size) +{ + static char cmpbuf[MAXBSIZE]; + int i; + + if (cmperror) + return; + + if (read(ifile, cmpbuf, size) != size) { + fprintf(stderr, "%s: size has changed.\n", + curfile.name); + cmperror = 1; + return; + } + + for (i = 0; i < size; ++i) + if (cmpbuf[i] != '\0') { + fprintf(stderr, "%s: tape and disk copies are different\n", + curfile.name); + cmperror = 1; + return; + } +} +#endif /* COMPARE_ONTHEFLY */ + +#if !COMPARE_ONTHEFLY +static int do_cmpfiles(int fd_tape, int fd_disk, long size) { -#ifndef BUFSIZE -#define BUFSIZE 1024 -#endif static char buf_tape[BUFSIZ]; static char buf_disk[BUFSIZ]; - int n_tape; - int n_disk; + ssize_t n_tape; + ssize_t n_disk; while (size > 0) { - if ((n_tape = read(fd_tape, buf_tape, BUFSIZE)) < 1) { + if ((n_tape = read(fd_tape, buf_tape, sizeof(buf_tape))) < 1) { close(fd_tape), close(fd_disk); panic("do_cmpfiles: unexpected EOF[1]"); } - if ((n_disk = read(fd_disk, buf_disk, BUFSIZE)) < 1) { + if ((n_disk = read(fd_disk, buf_disk, sizeof(buf_tape))) < 1) { close(fd_tape), close(fd_disk); panic("do_cmpfiles: unexpected EOF[2]"); } @@ -931,7 +1165,7 @@ do_cmpfiles(int fd_tape, int fd_disk, long size) close(fd_tape), close(fd_disk); panic("do_cmpfiles: sizes different!"); } - if (memcmp(buf_tape, buf_disk, n_tape) != 0) return (1); + if (memcmp(buf_tape, buf_disk, (size_t)n_tape) != 0) return (1); size -= n_tape; } return (0); @@ -940,26 +1174,29 @@ do_cmpfiles(int fd_tape, int fd_disk, long size) /* for debugging compare problems */ #undef COMPARE_FAIL_KEEP_FILE +static #ifdef COMPARE_FAIL_KEEP_FILE /* return true if tapefile should be unlinked after compare */ int #else void #endif -cmpfiles(char *tapefile, char *diskfile, struct stat *sbuf_disk) +cmpfiles(char *tapefile, char *diskfile, struct STAT *sbuf_disk) { - struct stat sbuf_tape; + struct STAT sbuf_tape; int fd_tape, fd_disk; - if (stat(tapefile, &sbuf_tape) != 0) { + if (STAT(tapefile, &sbuf_tape) != 0) { 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, sbuf_tape.st_size, sbuf_disk->st_size); + diskfile, (long)sbuf_tape.st_size, (long)sbuf_disk->st_size); + do_compare_error; #ifdef COMPARE_FAIL_KEEP_FILE return (0); #else @@ -967,12 +1204,14 @@ cmpfiles(char *tapefile, char *diskfile, struct stat *sbuf_disk) #endif } - if ((fd_tape = open(tapefile, O_RDONLY)) < 0) { + if ((fd_tape = OPEN(tapefile, O_RDONLY)) < 0) { panic("Can't open %s: %s\n", tapefile, strerror(errno)); + do_compare_error; } - if ((fd_disk = open(diskfile, O_RDONLY)) < 0) { + if ((fd_disk = OPEN(diskfile, O_RDONLY)) < 0) { close(fd_tape); panic("Can't open %s: %s\n", diskfile, strerror(errno)); + do_compare_error; } if (do_cmpfiles(fd_tape, fd_disk, sbuf_tape.st_size)) { @@ -980,6 +1219,7 @@ cmpfiles(char *tapefile, char *diskfile, struct stat *sbuf_disk) diskfile); close(fd_tape); close(fd_disk); + do_compare_error; #ifdef COMPARE_FAIL_KEEP_FILE /* rename the file to live in /tmp */ /* rename `tapefile' to /tmp/ */ @@ -989,7 +1229,7 @@ cmpfiles(char *tapefile, char *diskfile, struct stat *sbuf_disk) if (!p) { panic("can't find / in %s\n", diskfile); } - sprintf(newname, "%s/debug/%s", tmpdir, p + 1); + snprintf(newname, sizeof(newname), "%s/debug/%s", tmpdir, p + 1); if (rename(tapefile, newname)) { panic("rename from %s to %s failed: %s\n", tapefile, newname, @@ -1013,20 +1253,26 @@ cmpfiles(char *tapefile, char *diskfile, struct stat *sbuf_disk) return (1); #endif } +#endif /* !COMPARE_ONTHEFLY */ -static char tmpfilename[128]; +#if !COMPARE_ONTHEFLY +static char tmpfilename[MAXPATHLEN]; +#endif void -comparefile(name) - char *name; +comparefile(char *name) { - static char *tmpfile = NULL; int mode; - struct stat sb, stemp; + struct STAT sb; int r; +#if !COMPARE_ONTHEFLY + static char *tmpfile = NULL; + struct STAT stemp; +#endif - if ((r = lstat(name, &sb)) != 0) { - fprintf(stderr, "%s: does not exist (%d, %d).\n", name, r, errno); + if ((r = LSTAT(name, &sb)) != 0) { + warn("%s: does not exist (%d)", name, r); + do_compare_error; skipfile(); return; } @@ -1035,12 +1281,17 @@ comparefile(name) curfile.action = USING; mode = curfile.dip->di_mode; - vprintf(stdout, "comparing %s (size: %ld, mode: 0%o)\n", name, - sb.st_size, mode); + Vprintf(stdout, "comparing %s (size: %ld, mode: 0%o)\n", name, + (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 (spcl.c_flags & DR_METAONLY) { + skipfile(); + return; } switch (mode & IFMT) { default: @@ -1062,6 +1313,7 @@ comparefile(name) if (!(sb.st_mode & S_IFLNK)) { fprintf(stderr, "%s: is no longer a symbolic link\n", name); + do_compare_error; return; } lnkbuf[0] = '\0'; @@ -1071,17 +1323,20 @@ comparefile(name) fprintf(stderr, "%s: zero length symbolic link (ignored)\n", name); + do_compare_error; return; } if ((lsize = readlink(name, lbuf, MAXPATHLEN)) < 0) { panic("readlink of %s failed: %s", name, strerror(errno)); + do_compare_error; } lbuf[lsize] = 0; if (strcmp(lbuf, lnkbuf) != 0) { fprintf(stderr, "%s: symbolic link changed from %s to %s.\n", name, lnkbuf, lbuf); + do_compare_error; return; } return; @@ -1092,6 +1347,7 @@ comparefile(name) if (!(sb.st_mode & (S_IFCHR|S_IFBLK))) { fprintf(stderr, "%s: no longer a special file\n", name); + do_compare_error; skipfile(); return; } @@ -1100,25 +1356,48 @@ comparefile(name) fprintf(stderr, "%s: device changed from %d,%d to %d,%d.\n", name, - ((int)curfile.dip->di_rdev >> 8) & 0xf, - (int)curfile.dip->di_rdev & 0xf, - ((int)sb.st_rdev >> 8) & 0xf, - (int)sb.st_rdev & 0xf); + ((int)curfile.dip->di_rdev >> 8) & 0xff, + (int)curfile.dip->di_rdev & 0xff, + ((int)sb.st_rdev >> 8) & 0xff, + (int)sb.st_rdev & 0xff); + do_compare_error; } skipfile(); return; case IFREG: +#if COMPARE_ONTHEFLY + if ((ifile = OPEN(name, O_RDONLY)) < 0) { + panic("Can't open %s: %s\n", name, strerror(errno)); + skipfile(); + do_compare_error; + } + else { + cmperror = 0; + getfile(xtrcmpfile, xtrcmpskip); + if (!cmperror) { + char c; + if (read(ifile, &c, 1) != 0) { + fprintf(stderr, "%s: size has changed.\n", + name); + cmperror = 1; + } + } + if (cmperror) + do_compare_error; + close(ifile); + } +#else if (tmpfile == NULL) { /* argument to mktemp() must not be in RO space: */ - sprintf(tmpfilename, "%s/restoreCXXXXXX", tmpdir); + snprintf(tmpfilename, sizeof(tmpfilename), "%s/restoreCXXXXXX", tmpdir); tmpfile = mktemp(&tmpfilename[0]); } - if ((stat(tmpfile, &stemp) == 0) && (unlink(tmpfile) != 0)) { + if ((STAT(tmpfile, &stemp) == 0) && (unlink(tmpfile) != 0)) { panic("cannot delete tmp file %s: %s\n", tmpfile, strerror(errno)); } - if ((ofile = creat(tmpfile, 0600)) < 0) { + if ((ofile = OPEN(tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { panic("cannot create file temp file %s: %s\n", name, strerror(errno)); } @@ -1131,34 +1410,79 @@ comparefile(name) cmpfiles(tmpfile, name, &sb); unlink(tmpfile); #endif +#endif /* COMPARE_ONTHEFLY */ return; } /* NOTREACHED */ } +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) +static void (*readtape_func)(char *) = readtape_set; + /* * Read TP_BSIZE blocks from the input. * Handle read errors, and end of media. + * Decompress compressed blocks. */ static void -readtape(buf) - char *buf; +readtape(char *buf) { - long rd, newvol, i; + (*readtape_func)(buf); /* call the actual processing routine */ +} + +/* + * Set function pointer for readtape() routine. zflag and magtapein must + * be correctly set before the first call to readtape(). + */ +static void +readtape_set(char *buf) +{ + if (!zflag) + readtape_func = readtape_uncompr; + else { + newcomprbuf(ntrec); + if (magtapein) + readtape_func = readtape_comprtape; + else + readtape_func = readtape_comprfile; + } + readtape(buf); +} + +#endif /* HAVE_ZLIB || HAVE_BZLIB */ + +/* + * This is the original readtape(), it's used for reading uncompressed input. + * Read TP_BSIZE blocks from the input. + * Handle read errors, and end of media. + */ +static void +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) +readtape_uncompr(char *buf) +#else +readtape(char *buf) +#endif +{ + ssize_t rd, newvol, i; int cnt, seek_failed; if (blkcnt < numtrec) { - memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); + memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE); blksread++; tpblksread++; return; } + tbufptr = tapebuf; for (i = 0; i < ntrec; i++) ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; if (numtrec == 0) numtrec = ntrec; cnt = ntrec * TP_BSIZE; rd = 0; +#ifdef USE_QFA + if (createtapeposflag) + (void)GetTapePos(&curtapepos); +#endif getmore: #ifdef RRESTORE if (host) @@ -1166,12 +1490,13 @@ getmore: else #endif i = read(mt, &tapebuf[rd], cnt); + /* * Check for mid-tape short read error. * If found, skip rest of buffer and start with the next. */ if (!pipein && numtrec < ntrec && i > 0) { - dprintf(stdout, "mid-media short read error.\n"); + Dprintf(stdout, "mid-media short read error.\n"); numtrec = ntrec; } /* @@ -1191,9 +1516,9 @@ getmore: * Short read. Process the blocks read. */ if (i % TP_BSIZE != 0) - vprintf(stdout, + Vprintf(stdout, "partial block read: %ld should be %ld\n", - i, ntrec * TP_BSIZE); + (long)i, ntrec * TP_BSIZE); numtrec = i / TP_BSIZE; } } @@ -1213,32 +1538,33 @@ getmore: fprintf(stderr, "restoring %s\n", curfile.name); break; case SKIP: - fprintf(stderr, "skipping over inode %ld\n", - curfile.ino); + fprintf(stderr, "skipping over inode %lu\n", + (unsigned long)curfile.ino); break; } if (!yflag && !reply("continue")) - done(1); + exit(1); i = ntrec * TP_BSIZE; - memset(tapebuf, 0, i); + memset(tapebuf, 0, (size_t)i); #ifdef RRESTORE if (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) { - fprintf(stderr, - "continuation failed: %s\n", strerror(errno)); - done(1); + warn("continuation failed"); + if (!yflag && !reply("assume end-of-tape and continue")) + exit(1); + i = 0; } } /* * Handle end of tape. */ if (i == 0) { - vprintf(stdout, "End-of-tape encountered\n"); + Vprintf(stdout, "End-of-tape encountered\n"); if (!pipein) { newvol = volno + 1; volno = 0; @@ -1251,45 +1577,456 @@ getmore: panic("partial block read: %d should be %d\n", rd, ntrec * TP_BSIZE); terminateinput(); - memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); + memmove(&tapebuf[rd], &endoftapemark, TP_BSIZE); } blkcnt = 0; - memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); + memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE); blksread++; tpblksread++; } +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) + +/* + * Read a compressed format block from a file or pipe and uncompress it. + * Attempt to handle read errors, and end of file. + */ static void -findtapeblksize() +readtape_comprfile(char *buf) { - register long i; + long rl, size, i, ret; + int newvol; + struct tapebuf *tpb; + if (blkcnt < numtrec) { + memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE); + blksread++; + tpblksread++; + return; + } + /* need to read the next block */ + tbufptr = tapebuf; for (i = 0; i < ntrec; i++) ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; + numtrec = ntrec; + tpb = (struct tapebuf *) tapebuf; + + /* read the block prefix */ + ret = read_a_block(mt, tapebuf, PREFIXSIZE, &rl); + + if (Vflag && (ret == 0 || rl < PREFIXSIZE || tpb->length == 0)) + ret = 0; + if (ret <= 0) + goto readerr; + + /* read the data */ + size = tpb->length; + if (size > bufsize) { + /* something's wrong */ + Vprintf(stdout, "Prefix size error, max size %d, got %ld\n", + bufsize, size); + size = bufsize; + tpb->length = bufsize; + } + ret = read_a_block(mt, tpb->buf, size, &rl); + if (ret <= 0) + goto readerr; + + tbufptr = decompress_tapebuf(tpb, rl + PREFIXSIZE); + if (tbufptr == NULL) { + msg_read_error("File decompression error while"); + if (!yflag && !reply("continue")) + exit(1); + memset(tapebuf, 0, bufsize); + tbufptr = tapebuf; + } + blkcnt = 0; + memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE); + blksread++; + tpblksread++; + return; + +readerr: + /* Errors while reading from a file or pipe are catastrophic. Since + * there are no block boundaries, it's impossible to bypass the + * block in error and find the start of the next block. + */ + if (ret == 0) { + /* It's possible to have multiple input files using -M + * and -f file1,file2... + */ + Vprintf(stdout, "End-of-File encountered\n"); + if (!pipein) { + newvol = volno + 1; + volno = 0; + numtrec = 0; + getvol(newvol); + readtape(buf); + return; + } + } + msg_read_error("Read error while"); + /* if (!yflag && !reply("continue")) */ + exit(1); +} + +/* + * Read compressed data from a tape and uncompress it. + * Handle read errors, and end of media. + * Since a tape consists of separate physical blocks, we try + * to recover from errors by repositioning the tape to the next + * block. + */ +static void +readtape_comprtape(char *buf) +{ + long rl, size, i; + int ret, newvol; + struct tapebuf *tpb; + struct mtop tcom; + + if (blkcnt < numtrec) { + memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE); + blksread++; + tpblksread++; + return; + } + /* need to read the next block */ + tbufptr = tapebuf; + for (i = 0; i < ntrec; i++) + ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; + numtrec = ntrec; + tpb = (struct tapebuf *) tapebuf; + + /* read the block */ + size = bufsize + PREFIXSIZE; + ret = read_a_block(mt, tapebuf, size, &rl); + if (ret <= 0) + goto readerr; + + tbufptr = decompress_tapebuf(tpb, rl); + if (tbufptr == NULL) { + msg_read_error("Tape decompression error while"); + if (!yflag && !reply("continue")) + exit(1); + memset(tapebuf, 0, PREFIXSIZE + bufsize); + tbufptr = tapebuf; + } + goto moverecord; + +readerr: + /* Handle errors: EOT switches to the next volume, other errors + * attempt to position the tape to the next block. + */ + if (ret == 0) { + Vprintf(stdout, "End-of-tape encountered\n"); + newvol = volno + 1; + volno = 0; + numtrec = 0; + getvol(newvol); + readtape(buf); + return; + } + + msg_read_error("Tape read error while"); + if (!yflag && !reply("continue")) + exit(1); + memset(tapebuf, 0, PREFIXSIZE + bufsize); + tbufptr = tapebuf; + #ifdef RRESTORE if (host) - i = rmtread(tapebuf, ntrec * TP_BSIZE); + rl = rmtioctl(MTFSR, 1); else #endif - i = read(mt, tapebuf, ntrec * TP_BSIZE); + { + tcom.mt_op = MTFSR; + tcom.mt_count = 1; + rl = ioctl(mt, MTIOCTOP, &tcom); + } - if (i <= 0) { - fprintf(stderr, "tape read error: %s\n", strerror(errno)); - done(1); + if (rl < 0) { + warn("continuation failed"); + if (!yflag && !reply("assume end-of-tape and continue")) + exit(1); + ret = 0; /* end of tape */ + goto readerr; } + +moverecord: + blkcnt = 0; + memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE); + blksread++; + tpblksread++; +} + +/* + * Decompress a struct tapebuf into a buffer. readsize is the size read + * from the tape/file and is used for error messages. Returns a pointer + * to the location of the uncompressed buffer or NULL on errors. + * Adjust numtrec and complain for a short block. + */ +static char * +decompress_tapebuf(struct tapebuf *tpbin, int readsize) +{ + /* If zflag is on, all blocks have a struct tapebuf prefix */ + /* 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) + lengtherr = "short"; + else + if (readsize > blocklen + PREFIXSIZE) + lengtherr = "long"; + + worklen = comprlen; + cresult = 1; + if (tpbin->compressed) { + /* uncompress whatever we read, if it fails, complain later */ + if (tpbin->flags == COMPRESS_ZLIB) { +#ifndef HAVE_ZLIB + errx(1,"This restore version doesn't support zlib decompression"); +#else + cresult = uncompress(comprbuf, &worklen, + tpbin->buf, blocklen); + output = comprbuf; + switch (cresult) { + case Z_OK: + break; + case Z_MEM_ERROR: + reason = "not enough memory"; + break; + case Z_BUF_ERROR: + reason = "buffer too small"; + break; + case Z_DATA_ERROR: + reason = "data error"; + break; + default: + reason = "unknown"; + } + if (cresult == Z_OK) + cresult = 1; + else + cresult = 0; +#endif /* HAVE_ZLIB */ + } + if (tpbin->flags == COMPRESS_BZLIB) { +#ifndef HAVE_BZLIB + errx(1,"This restore version doesn't support bzlib decompression"); +#else + worklen2 = worklen; + cresult = BZ2_bzBuffToBuffDecompress( + comprbuf, &worklen2, + tpbin->buf, blocklen, 0, 0); + worklen = worklen2; + output = comprbuf; + switch (cresult) { + case BZ_OK: + break; + case BZ_MEM_ERROR: + reason = "not enough memory"; + break; + case BZ_OUTBUFF_FULL: + reason = "buffer too small"; + break; + case BZ_DATA_ERROR: + case BZ_DATA_ERROR_MAGIC: + case BZ_UNEXPECTED_EOF: + reason = "data error"; + break; + default: + reason = "unknown"; + } + if (cresult == BZ_OK) + cresult = 1; + else + cresult = 0; +#endif /* HAVE_BZLIB */ + } + } + else { + output = tpbin->buf; + worklen = blocklen; + } + if (cresult) { + numtrec = worklen / TP_BSIZE; + if (worklen % TP_BSIZE != 0) + reason = "length mismatch"; + } + if (reason) { + if (lengtherr) + fprintf(stderr, "%s compressed block: %d expected: %d\n", + lengtherr, readsize, tpbin->length + PREFIXSIZE); + fprintf(stderr, "decompression error, block %ld: %s\n", + tpblksread+1, reason); + if (!cresult) + output = NULL; + } + return output; +} + +/* + * Print an error message for a read error. + * This was exteracted from the original readtape(). + */ +static void +msg_read_error(char *m) +{ + switch (curfile.action) { + default: + fprintf(stderr, "%s trying to set up tape\n", m); + break; + case UNKNOWN: + fprintf(stderr, "%s trying to resynchronize\n", m); + break; + case USING: + fprintf(stderr, "%s restoring %s\n", m, curfile.name); + break; + case SKIP: + fprintf(stderr, "%s skipping over inode %lu\n", m, + (unsigned long)curfile.ino); + break; + } +} +#endif /* HAVE_ZLIB || HAVE_BZLIB */ + +/* + * Read the first block and get the blocksize from it. Test + * for a compressed dump tape/file. setup() will make the final + * determination by checking the compressed flag if gethead() + * finds a valid header. The test here is necessary to offset the buffer + * by the size of the compressed prefix. zflag is set here so that + * readtape_set can set the correct function pointer for readtape(). + * Note that the first block of each tape/file is not compressed + * and does not have a prefix. + */ +static void +findtapeblksize(void) +{ + long i; + size_t len; + struct tapebuf *tpb = (struct tapebuf *) tapebuf; + struct s_spcl *spclpt = (struct s_spcl *) tapebuf; + + for (i = 0; i < ntrec; i++) + ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; + blkcnt = 0; + tbufptr = tapebuf; + /* + * For a pipe or file, read in the first record. For a tape, read + * the first block. + */ + len = magtapein ? ntrec * TP_BSIZE : TP_BSIZE; + + if (read_a_block(mt, tapebuf, len, &i) <= 0) + errx(1, "Tape read error on first record"); + + /* + * 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 + * we need to read in the rest of the block, as determined + * by c_ntrec in the dump header. The first block of the + * dump is not compressed and does not have a prefix. + */ + if (!magtapein) { + 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) + errx(1, "Tape blocksize is too large, use " + "\'-b %d\' ", spclpt->c_ntrec); + ntrec = spclpt->c_ntrec; + len = (ntrec - 1) * TP_BSIZE; + zflag = 1; + } + else { + /* read in the rest of the block based on bufsize */ + len = bufsize - TP_BSIZE; + } + if (read_a_block(mt, tapebuf+TP_BSIZE, len, &i) < 0 + || (i != len && i % TP_BSIZE != 0)) + errx(1,"Error reading dump file header"); + tbufptr = tapebuf; + numtrec = ntrec; + Vprintf(stdout, "Input block size is %ld\n", ntrec); + return; + } /* if (!magtapein) */ + + /* + * If the input is a tape, we tried to read ntrec * TP_BSIZE bytes. + * If the value of ntrec is too large, we read less than + * what we asked for; adjust the value of ntrec and test for + * a compressed dump tape. + */ + if (i % TP_BSIZE != 0) { - fprintf(stderr, "Tape block size (%ld) %s (%d)\n", - i, "is not a multiple of dump block size", TP_BSIZE); - done(1); + /* may be old format compressed dump tape with a prefix */ + spclpt = (struct s_spcl *) tpb->buf; + if (i % TP_BSIZE == PREFIXSIZE + && tpb->compressed == 0 + && spclpt->c_type == TS_TAPE + && spclpt->c_flags & DR_COMPRESSED) { + zflag = 1; + tbufptr = tpb->buf; + if (tpb->length > bufsize) + errx(1, "Tape blocksize is too large, use " + "\'-b %d\' ", tpb->length / TP_BSIZE); + } + else + errx(1, "Tape block size (%ld) is not a multiple of dump block size (%d)", + i, TP_BSIZE); } ntrec = i / TP_BSIZE; + if (spclpt->c_type == TS_TAPE) { + if (spclpt->c_flags & DR_COMPRESSED) + zflag = 1; + if (spclpt->c_ntrec > ntrec) + errx(1, "Tape blocksize is too large, use " + "\'-b %d\' ", spclpt->c_ntrec); + } numtrec = ntrec; - vprintf(stdout, "Tape block size is %ld\n", ntrec); + Vprintf(stdout, "Tape block size is %ld\n", ntrec); +} + +/* + * Read a block of data handling all of the messy details. + */ +static int read_a_block(int fd, char *buf, size_t len, long *lengthread) +{ + long i = 1, size; + + size = len; + while (size > 0) { +#ifdef RRESTORE + if (host) + i = rmtread(buf, size); + else +#endif + i = read(fd, buf, size); + + if (i <= 0) + break; /* EOD or error */ + size -= i; + if (magtapein) + break; /* block at a time for mt */ + buf += i; + } + *lengthread = len - size; + return i; } void -closemt() +closemt(void) { if (mt < 0) @@ -1302,6 +2039,28 @@ closemt() (void) close(mt); } +static void +setmagtapein(void) { + struct mtget mt_stat; + static int done = 0; + if (done) + return; + done = 1; + if (!pipein) { + /* need to know if input is really from a tape */ +#ifdef RRESTORE + if (host) + magtapein = !lflag; + else +#endif + magtapein = ioctl(mt, MTIOCGET, (char *)&mt_stat) == 0; + } + + Vprintf(stdout,"Input is from %s\n", + magtapein ? "tape" : + Vflag ? "multi-volume (no tape)" : "file/pipe"); +} + /* * Read the next block from the tape. * Check to see if it is one of several vintage headers. @@ -1309,10 +2068,9 @@ closemt() * If it is not any valid header, return an error. */ static int -gethead(buf) - struct s_spcl *buf; +gethead(struct s_spcl *buf) { - long i; + int32_t i; union { quad_t qval; int32_t val[2]; @@ -1325,14 +2083,14 @@ gethead(buf) int32_t c_ddate; int32_t c_volume; int32_t c_tapea; - u_short c_inumber; + u_int16_t c_inumber; int32_t c_magic; int32_t c_checksum; struct odinode { - unsigned short odi_mode; - u_short odi_nlink; - u_short odi_uid; - u_short odi_gid; + u_int16_t odi_mode; + u_int16_t odi_nlink; + u_int16_t odi_uid; + u_int16_t odi_gid; int32_t odi_size; int32_t odi_rdev; char odi_addr[36]; @@ -1341,31 +2099,28 @@ gethead(buf) int32_t odi_ctime; } c_dinode; int32_t c_count; - char c_addr[256]; + char c_fill[256]; } s_ospcl; } u_ospcl; if (!cvtflag) { readtape((char *)buf); if (buf->c_magic != NFS_MAGIC) { - if (swabl(buf->c_magic) != NFS_MAGIC) + if (swabi(buf->c_magic) != NFS_MAGIC) return (FAIL); if (!Bcvt) { - vprintf(stdout, "Note: Doing Byte swapping\n"); + Vprintf(stdout, "Note: Doing Byte swapping\n"); Bcvt = 1; } } if (checksum((int *)buf) == FAIL) return (FAIL); - if (Bcvt) { - swabst((u_char *)"8l4s31l", (u_char *)buf); - swabst((u_char *)"l",(u_char *) &buf->c_level); - swabst((u_char *)"2l",(u_char *) &buf->c_flags); - } + if (Bcvt) + swabst((u_char *)"8i4s31i528bi192b2i", (u_char *)buf); goto good; } readtape((char *)(&u_ospcl.s_ospcl)); - memset(buf, 0, (long)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; @@ -1380,17 +2135,17 @@ gethead(buf) 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; -#ifdef __linux__ +#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; -#else /* __linux__ */ +#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; -#endif /* __linux__ */ +#endif /* __linux__ || sunos */ buf->c_count = u_ospcl.s_ospcl.c_count; - memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256); + 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) return(FAIL); @@ -1401,7 +2156,7 @@ good: (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) { qcvt.qval = buf->c_dinode.di_size; if (qcvt.val[0] || qcvt.val[1]) { - printf("Note: Doing Quad swapping\n"); + Vprintf(stdout, "Note: Doing Quad swapping\n"); Qcvt = 1; } } @@ -1436,6 +2191,11 @@ good: /* fall through */ case TS_END: buf->c_inumber = 0; + if (buf->c_flags & DR_INODEINFO) { + memcpy(volinfo, buf->c_inos, TP_NINOS * sizeof(dump_ino_t)); + if (Bcvt) + swabst((u_char *)"128i", (u_char *)volinfo); + } break; case TS_INODE: @@ -1463,10 +2223,9 @@ good: * Check that a header is where it belongs and predict the next header */ static void -accthdr(header) - struct s_spcl *header; +accthdr(struct s_spcl *header) { - static ino_t previno = 0x7fffffff; + static dump_ino_t previno = 0x7fffffff; static int prevtype; static long predict; long blks, i; @@ -1491,10 +2250,10 @@ accthdr(header) fprintf(stderr, "Used inodes map header"); break; case TS_INODE: - fprintf(stderr, "File header, ino %ld", previno); + fprintf(stderr, "File header, ino %lu", (unsigned long)previno); break; case TS_ADDR: - fprintf(stderr, "File continuation header, ino %ld", previno); + fprintf(stderr, "File continuation header, ino %ld", (long)previno); break; case TS_END: fprintf(stderr, "End of tape header"); @@ -1521,8 +2280,7 @@ newcalc: * Complain if had to skip, and complain is set. */ static void -findinode(header) - struct s_spcl *header; +findinode(struct s_spcl *header) { static long skipcnt = 0; long i; @@ -1581,16 +2339,18 @@ findinode(header) } } while (header->c_type == TS_ADDR); if (skipcnt > 0) - fprintf(stderr, "resync restore, skipped %ld blocks\n", - skipcnt); +#ifdef USE_QFA + if (!noresyncmesg) +#endif + fprintf(stderr, "resync restore, skipped %ld blocks\n", + skipcnt); skipcnt = 0; } static int -checksum(buf) - register int *buf; +checksum(int *buf) { - register int i, j; + int i, j; j = sizeof(union u_spcl) / sizeof(int); i = 0; @@ -1602,27 +2362,27 @@ checksum(buf) /* What happens if we want to read restore tapes for a 16bit int machine??? */ do - i += swabl(*buf++); + i += swabi(*buf++); while (--j); } if (i != CHECKSUM) { - fprintf(stderr, "Checksum error %o, inode %ld file %s\n", i, - curfile.ino, curfile.name); + fprintf(stderr, "Checksum error %o, inode %lu file %s\n", i, + (unsigned long)curfile.ino, curfile.name); return(FAIL); } return(GOOD); } #ifdef RRESTORE -#if __STDC__ +#ifdef __STDC__ #include #else #include #endif void -#if __STDC__ +#ifdef __STDC__ msg(const char *fmt, ...) #else msg(fmt, va_alist) @@ -1631,7 +2391,7 @@ msg(fmt, va_alist) #endif { va_list ap; -#if __STDC__ +#ifdef __STDC__ va_start(ap, fmt); #else va_start(ap); @@ -1642,9 +2402,7 @@ msg(fmt, va_alist) #endif /* RRESTORE */ static u_char * -swabshort(sp, n) - register u_char *sp; - register int n; +swab16(u_char *sp, int n) { char c; @@ -1656,23 +2414,35 @@ swabshort(sp, n) } static u_char * -swablong(sp, n) - register u_char *sp; - register int n; +swab32(u_char *sp, int n) { char c; while (--n >= 0) { c = sp[0]; sp[0] = sp[3]; sp[3] = c; - c = sp[2]; sp[2] = sp[1]; sp[1] = c; + c = sp[1]; sp[1] = sp[2]; sp[2] = c; sp += 4; } return (sp); } +static u_char * +swab64(u_char *sp, int n) +{ + char c; + + while (--n >= 0) { + c = sp[0]; sp[0] = sp[7]; sp[7] = c; + c = sp[1]; sp[1] = sp[6]; sp[6] = c; + c = sp[2]; sp[2] = sp[5]; sp[5] = c; + c = sp[3]; sp[3] = sp[4]; sp[4] = c; + sp += 8; + } + return (sp); +} + void -swabst(cp, sp) - register u_char *cp, *sp; +swabst(u_char *cp, u_char *sp) { int n = 0; @@ -1686,13 +2456,19 @@ swabst(cp, sp) case 's': case 'w': case 'h': if (n == 0) n = 1; - sp = swabshort(sp, n); + sp = swab16(sp, n); + break; + + case 'i': + if (n == 0) + n = 1; + sp = swab32(sp, n); break; case 'l': if (n == 0) n = 1; - sp = swablong(sp, n); + sp = swab64(sp, n); break; default: /* Any other character, like 'b' counts as byte. */ @@ -1706,10 +2482,142 @@ swabst(cp, sp) } } +static u_int +swabi(u_int x) +{ + swabst((u_char *)"i", (u_char *)&x); + return (x); +} + +#if 0 static u_long -swabl(x) - u_long x; +swabl(u_long x) { swabst((u_char *)"l", (u_char *)&x); return (x); } +#endif + +#ifdef USE_QFA +/* + * get the current position of the tape + */ +int +GetTapePos(long long *pos) +{ + int err = 0; + +#ifdef RDUMP + if (host) { + *pos = (long long) rmtseek(0, SEEK_CUR); + err = *pos < 0; + } + else +#endif + { + if (magtapein) { + long mtpos; + *pos = 0; + err = (ioctl(mt, MTIOCPOS, &mtpos) < 0); + *pos = (long long)mtpos; + } + else { + *pos = LSEEK(mt, 0, SEEK_CUR); + err = (*pos < 0); + } + } + if (err) { + err = errno; + fprintf(stdout, "[%ld] error: %d (getting tapepos: %lld)\n", + (unsigned long)getpid(), err, *pos); + return err; + } + return err; +} + +typedef struct mt_pos { + short mt_op; + int mt_count; +} MTPosRec, *MTPosPtr; + +/* + * go to specified position on tape + */ +int +GotoTapePos(long long pos) +{ + int err = 0; + +#ifdef RDUMP + if (host) + err = (rmtseek((long)pos, SEEK_SET) < 0); + else +#endif + { + if (magtapein) { + struct mt_pos buf; + buf.mt_op = MTSEEK; + buf.mt_count = (int) pos; + err = (ioctl(mt, MTIOCTOP, &buf) < 0); + } + else { + pos = LSEEK(mt, pos, SEEK_SET); + err = (pos < 0); + } + } + if (err) { + err = errno; + fprintf(stdout, "[%ld] error: %d (setting tapepos: %lld)\n", + (unsigned long)getpid(), err, pos); + return err; + } + return err; +} + +/* + * read next data from tape to re-sync + */ +void +ReReadFromTape(void) +{ + FLUSHTAPEBUF(); + noresyncmesg = 1; + if (gethead(&spcl) == FAIL) { +#ifdef DEBUG_QFA + fprintf(stdout, "DEBUG 1 gethead failed\n"); +#endif + } + findinode(&spcl); + noresyncmesg = 0; +} + +void +ReReadInodeFromTape(dump_ino_t theino) +{ + 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)); +#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); + } +#endif + findinode(&spcl); + noresyncmesg = 0; +} +#endif /* USE_QFA */ + +void +RequestVol(long tnum) +{ + FLUSHTAPEBUF(); + getvol(tnum); +}