+#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);