+ cmpfiles(tmpfile, name, &sb);
+ unlink(tmpfile);
+#endif
+#endif /* COMPARE_ONTHEFLY */
+ compareattr(name);
+ return;
+ }
+ /* NOTREACHED */
+}
+
+#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
+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(char *buf)
+{
+ (*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 || HAVE_LZO */
+
+/*
+ * 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) || defined(HAVE_LZO)
+readtape_uncompr(char *buf)
+#else
+readtape(char *buf)
+#endif
+{
+ ssize_t rd, newvol, i;
+ int cnt, seek_failed;
+
+ if (blkcnt < numtrec) {
+ 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 (!Afile && host)
+ i = rmtread(&tapebuf[rd], cnt);
+ 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");
+ numtrec = ntrec;
+ }
+ /*
+ * Handle partial block read.
+ */
+ if (pipein && i == 0 && rd > 0)
+ i = rd;
+ else if (i > 0 && i != ntrec * TP_BSIZE) {
+ if (pipein) {
+ rd += i;
+ cnt -= i;
+ if (cnt > 0)
+ goto getmore;
+ i = rd;
+ } else {
+ /*
+ * Short read. Process the blocks read.
+ */
+ if (i % TP_BSIZE != 0)
+ Vprintf(stdout,
+ "partial block read: %ld should be %ld\n",
+ (long)i, ntrec * TP_BSIZE);
+ numtrec = i / TP_BSIZE;
+ }
+ }
+ /*
+ * Handle read error.
+ */
+ if (i < 0) {
+ fprintf(stderr, "Tape read error while ");
+ switch (curfile.action) {
+ default:
+ fprintf(stderr, "trying to set up tape\n");
+ break;
+ case UNKNOWN:
+ fprintf(stderr, "trying to resynchronize\n");
+ break;
+ case USING:
+ fprintf(stderr, "restoring %s\n", curfile.name);
+ break;
+ case SKIP:
+ fprintf(stderr, "skipping over inode %lu\n",
+ (unsigned long)curfile.ino);
+ break;
+ }
+ if (!yflag && !reply("continue"))
+ exit(1);
+ i = ntrec * TP_BSIZE;
+ memset(tapebuf, 0, (size_t)i);
+#ifdef RRESTORE
+ if (!Afile && host)
+ seek_failed = (rmtseek(i, 1) < 0);
+ else
+#endif
+ seek_failed = (LSEEK(mt, i, SEEK_CUR) == (OFF_T)-1);
+
+ if (seek_failed) {
+ 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");
+ if (!pipein) {
+ newvol = volno + 1;
+ volno = 0;
+ numtrec = 0;
+ getvol(newvol);
+ readtape(buf);
+ return;
+ }
+ if (rd % TP_BSIZE != 0)
+ panic("partial block read: %d should be %d\n",
+ rd, ntrec * TP_BSIZE);
+ terminateinput();
+ memmove(&tapebuf[rd], &endoftapemark, TP_BSIZE);
+ }
+ blkcnt = 0;
+ memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
+ blksread++;
+ tpblksread++;
+}
+
+#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
+
+/*
+ * Read a compressed format block from a file or pipe and uncompress it.
+ * Attempt to handle read errors, and end of file.
+ */
+static void
+readtape_comprfile(char *buf)
+{
+ 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);
+ converttapebuf(tpb);
+
+ if (Vflag && (ret == 0 || rl < (int)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;
+
+ converttapebuf(tpb);
+ 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)
+ rl = rmtioctl(MTFSR, 1);
+ else
+#endif
+ {
+ tcom.mt_op = MTFSR;
+ tcom.mt_count = 1;
+ rl = ioctl(mt, MTIOCTOP, &tcom);
+ }
+
+ 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;
+ char *output = NULL,*reason = NULL, *lengtherr = NULL;
+
+ /* build a length error message */
+ blocklen = tpbin->length;
+ if (readsize < blocklen + (int)PREFIXSIZE)
+ lengtherr = "short";
+ else
+ if (readsize > blocklen + (int)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
+ unsigned int 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 */
+ }
+ 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 */
+ }