+ {
+ 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 */
+ }
+ }
+ 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: %u\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 || HAVE_LZO */
+
+/*
+ * 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;
+
+ 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");
+
+ 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
+ * 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 != (long)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) */