]> git.wh0rd.org Git - dump.git/blob - restore/tape.c
Relicensed dump/restore under the revised BSD license, as per ftp://ftp.cs.berkeley...
[dump.git] / restore / tape.c
1 /*
2  *      Ported to Linux's Second Extended File System as part of the
3  *      dump and restore backup suit
4  *      Remy Card <card@Linux.EU.Org>, 1994-1997
5  *      Stelian Pop <stelian@popies.net>, 1999-2000
6  *      Stelian Pop <stelian@popies.net> - AlcĂ´ve <www.alcove.com>, 2000-2002
7  */
8
9 /*
10  * Copyright (c) 1983, 1993
11  *      The Regents of the University of California.  All rights reserved.
12  * (c) UNIX System Laboratories, Inc.
13  * All or some portions of this file are derived from material licensed
14  * to the University of California by American Telephone and Telegraph
15  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
16  * the permission of UNIX System Laboratories, Inc.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in the
25  *    documentation and/or other materials provided with the distribution.
26  * 3. Neither the name of the University nor the names of its contributors
27  *    may be used to endorse or promote products derived from this software
28  *    without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  */
42
43 #ifndef lint
44 static const char rcsid[] =
45         "$Id: tape.c,v 1.73 2003/03/30 15:40:40 stelian Exp $";
46 #endif /* not lint */
47
48 #include <config.h>
49 #include <compatlfs.h>
50 #include <errno.h>
51 #include <compaterr.h>
52 #include <system.h>
53 #include <setjmp.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58
59 #include <sys/param.h>
60 #include <sys/file.h>
61 #include <sys/mtio.h>
62 #include <sys/stat.h>
63
64 #ifdef  __linux__
65 #include <sys/time.h>
66 #include <time.h>
67 #ifdef HAVE_EXT2FS_EXT2_FS_H
68 #include <ext2fs/ext2_fs.h>
69 #else
70 #include <linux/ext2_fs.h>
71 #endif
72 #include <ext2fs/ext2fs.h>
73 #include <bsdcompat.h>
74 #else   /* __linux__ */
75 #include <ufs/ufs/dinode.h>
76 #endif  /* __linux__ */
77 #include <protocols/dumprestore.h>
78
79 #ifdef HAVE_ZLIB
80 #include <zlib.h>
81 #endif /* HAVE_ZLIB */
82
83 #ifdef HAVE_BZLIB
84 #include <bzlib.h>
85 #endif /* HAVE_BZLIB */
86
87 #include "restore.h"
88 #include "extern.h"
89 #include "pathnames.h"
90
91 #ifdef USE_QFA
92 int             noresyncmesg = 0;
93 #endif /* USE_QFA */
94 static long     fssize = MAXBSIZE;
95 static int      mt = -1;
96 int             pipein = 0;
97 static int      magtapein = 0;          /* input is from magtape */
98 static char     magtape[MAXPATHLEN];
99 static char     magtapeprefix[MAXPATHLEN];
100 static int      blkcnt;
101 static int      numtrec;
102 static char     *tapebuf;               /* input buffer for read */
103 static int      bufsize;                /* buffer size without prefix */
104 static char     *tbufptr = NULL;        /* active tape buffer */
105 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
106 static char     *comprbuf;              /* uncompress work buf */
107 static size_t   comprlen;               /* size including prefix */
108 #endif
109 static union    u_spcl endoftapemark;
110 static long     blksread;               /* blocks read since last header */
111 static long     tpblksread = 0;         /* TP_BSIZE blocks read */
112 static long     tapesread;
113 static sigjmp_buf       restart;
114 static int      gettingfile = 0;        /* restart has a valid frame */
115 char            *host = NULL;
116
117 static int      ofile;
118 static char     *map;
119 static char     lnkbuf[MAXPATHLEN + 1];
120 static int      pathlen;
121
122 int             oldinofmt;      /* old inode format conversion required */
123 int             Bcvt;           /* Swap Bytes (for CCI or sun) */
124 static int      Qcvt;           /* Swap quads (for sun) */
125
126 #define FLUSHTAPEBUF()  blkcnt = ntrec + 1
127
128 static void      accthdr __P((struct s_spcl *));
129 static int       checksum __P((int *));
130 static void      findinode __P((struct s_spcl *));
131 static void      findtapeblksize __P((void));
132 static int       gethead __P((struct s_spcl *));
133 static int       converthead __P((struct s_spcl *));
134 static void      converttapebuf __P((struct tapebuf *));
135 static void      readtape __P((char *));
136 static void      setdumpnum __P((void));
137 static u_int     swabi __P((u_int));
138 #if 0
139 static u_long    swabl __P((u_long));
140 #endif
141 static u_char   *swab64 __P((u_char *, int));
142 static u_char   *swab32 __P((u_char *, int));
143 static u_char   *swab16 __P((u_char *, int));
144 static void      terminateinput __P((void));
145 static void      xtrfile __P((char *, size_t));
146 static void      xtrlnkfile __P((char *, size_t));
147 static void      xtrlnkskip __P((char *, size_t));
148 static void      xtrmap __P((char *, size_t));
149 static void      xtrmapskip __P((char *, size_t));
150 static void      xtrskip __P((char *, size_t));
151 static void      setmagtapein __P((void));
152
153 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
154 static void     newcomprbuf __P((int));
155 static void     (*readtape_func) __P((char *));
156 static void     readtape_set __P((char *));
157 static void     readtape_uncompr __P((char *));
158 static void     readtape_comprfile __P((char *));
159 static void     readtape_comprtape __P((char *));
160 static char     *decompress_tapebuf __P((struct tapebuf *, int));
161 static void     msg_read_error __P((char *));
162 #endif
163 static int      read_a_block __P((int, char *, size_t, long *));
164 #define PREFIXSIZE      sizeof(struct tapebuf)
165
166 #define COMPARE_ONTHEFLY 1
167
168 #if COMPARE_ONTHEFLY
169 static int      ifile;          /* input file for compare */
170 static int      cmperror;       /* compare error */
171 static void     xtrcmpfile __P((char *, size_t));
172 static void     xtrcmpskip __P((char *, size_t));
173 #endif
174
175 static int readmapflag;
176 static int readingmaps;         /* set to 1 while reading the maps */
177
178 /*
179  * Set up an input source. This is called from main.c before setup() is.
180  */
181 void
182 setinput(char *source)
183 {
184         FLUSHTAPEBUF();
185         if (bflag)
186                 newtapebuf(ntrec);
187         else
188                 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
189         terminal = stdin;
190
191 #ifdef RRESTORE
192         if (strchr(source, ':')) {
193                 host = source;
194                 source = strchr(host, ':');
195                 *source++ = '\0';
196                 if (rmthost(host) == 0)
197                         exit(1);
198         } else
199 #endif
200         if (strcmp(source, "-") == 0) {
201                 /*
202                  * Since input is coming from a pipe we must establish
203                  * our own connection to the terminal.
204                  */
205                 terminal = fopen(_PATH_TTY, "r");
206                 if (terminal == NULL) {
207                         warn("cannot open %s", _PATH_TTY);
208                         terminal = fopen(_PATH_DEVNULL, "r");
209                         if (terminal == NULL)
210                                 err(1, "cannot open %s", _PATH_DEVNULL);
211                 }
212                 pipein++;
213         }
214         setuid(getuid());       /* no longer need or want root privileges */
215         if (Mflag) {
216                 strncpy(magtapeprefix, source, MAXPATHLEN);
217                 magtapeprefix[MAXPATHLEN-1] = '\0';
218                 snprintf(magtape, MAXPATHLEN, "%s%03d", source, 1);
219         }
220         else
221                 strncpy(magtape, source, MAXPATHLEN);
222         magtape[MAXPATHLEN - 1] = '\0';
223 }
224
225 void
226 newtapebuf(long size)
227 {
228         static int tapebufsize = -1;
229
230         ntrec = size;
231         bufsize = ntrec * TP_BSIZE;
232         if (size <= tapebufsize)
233                 return;
234         if (tapebuf != NULL)
235                 free(tapebuf);
236         tapebuf = malloc(size * TP_BSIZE + sizeof(struct tapebuf));
237         if (tapebuf == NULL)
238                 errx(1, "Cannot allocate space for tape buffer");
239         tapebufsize = size;
240 }
241
242 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
243 static void
244 newcomprbuf(int size)
245 {
246         size_t buf_size = (size+1) * TP_BSIZE + sizeof(struct tapebuf);
247         if (buf_size <= comprlen)
248                 return;
249         comprlen = buf_size;
250         if (comprbuf != NULL)
251                 free(comprbuf);
252         comprbuf = malloc(comprlen);
253         if (comprbuf == NULL)
254                 errx(1, "Cannot allocate space for decompress buffer");
255 }
256 #endif /* HAVE_ZLIB || HAVE_BZLIB */
257
258 /*
259  * Verify that the tape drive can be accessed and
260  * that it actually is a dump tape.
261  */
262 void
263 setup(void)
264 {
265         int i, j, *ip, bot_code;
266         struct STAT stbuf;
267         char *temptape;
268
269         Vprintf(stdout, "Verify tape and initialize maps\n");
270         if (Afile == NULL && bot_script) {
271                 msg("Launching %s\n", bot_script);
272                 bot_code = system_command(bot_script, magtape, 1);
273                 if (bot_code != 0 && bot_code != 1) {
274                         msg("Restore aborted by the beginning of tape script\n");
275                         exit(1);
276                 }
277         }
278
279         if (Afile)
280                 temptape = Afile;
281         else
282                 temptape = magtape;
283
284 #ifdef RRESTORE
285         if (!Afile && host)
286                 mt = rmtopen(temptape, O_RDONLY);
287         else
288 #endif
289         if (pipein)
290                 mt = 0;
291         else
292                 mt = OPEN(temptape, O_RDONLY, 0);
293         if (mt < 0)
294                 err(1, "%s", temptape);
295         if (!Afile) {
296                 volno = 1;
297                 setmagtapein();
298                 setdumpnum();
299         }
300 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
301         readtape_func = readtape_set;
302 #endif
303         FLUSHTAPEBUF();
304         findtapeblksize();
305         if (gethead(&spcl) == FAIL) {
306                 blkcnt--; /* push back this block */
307                 blksread--;
308                 tpblksread--;
309                 cvtflag++;
310                 if (gethead(&spcl) == FAIL)
311                         errx(1, "Tape is not a dump tape");
312                 fprintf(stderr, "Converting to new file system format.\n");
313         }
314
315         if (zflag) {
316                 fprintf(stderr, "Dump tape is compressed.\n");
317 #if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB)
318                 errx(1,"This restore version doesn't support decompression");
319 #endif /* !HAVE_ZLIB && !HAVE_BZLIB */
320         }
321         if (pipein) {
322                 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
323                 endoftapemark.s_spcl.c_type = TS_END;
324                 ip = (int *)&endoftapemark;
325                 j = sizeof(union u_spcl) / sizeof(int);
326                 i = 0;
327                 do
328                         i += *ip++;
329                 while (--j);
330                 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
331         }
332         if (vflag || command == 't' || command == 'C')
333                 printdumpinfo();
334 #ifdef USE_QFA
335         if (tapeposflag && (unsigned long)spcl.c_date != qfadumpdate)
336                 errx(1, "different QFA/dumpdates detected\n");
337 #endif
338         if (filesys[0] == '\0') {
339                 char *dirptr;
340                 strncpy(filesys, spcl.c_filesys, NAMELEN);
341                 filesys[NAMELEN - 1] = '\0';
342                 dirptr = strstr(filesys, " (dir");
343                 if (dirptr != NULL)
344                         *dirptr = '\0';
345         }
346         dumptime = spcl.c_ddate;
347         dumpdate = spcl.c_date;
348         if (STAT(".", &stbuf) < 0)
349                 err(1, "cannot stat .");
350         if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE )
351                 fssize = TP_BSIZE;
352         if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
353                 fssize = stbuf.st_blksize;
354         if (((fssize - 1) & fssize) != 0)
355                 errx(1, "bad block size %ld", fssize);
356         if (spcl.c_volume != 1)
357                 errx(1, "Tape is not volume 1 of the dump");
358         if (gethead(&spcl) == FAIL) {
359                 Dprintf(stdout, "header read failed at %ld blocks\n", (long)blksread);
360                 panic("no header after volume mark!\n");
361         }
362         readingmaps = 1;
363         findinode(&spcl);
364         if (spcl.c_type != TS_CLRI)
365                 errx(1, "Cannot find file removal list");
366         maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
367         map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
368         if (map == NULL)
369                 errx(1, "no memory for active inode map");
370         usedinomap = map;
371         curfile.action = USING;
372         getfile(xtrmap, xtrmapskip);
373         while (spcl.c_type == TS_ADDR) {
374                 /* Recompute maxino and the map */
375                 dump_ino_t oldmaxino = maxino;
376                 maxino += (spcl.c_count * TP_BSIZE * NBBY) + 1;
377                 resizemaps(oldmaxino, maxino);
378
379                 spcl.c_dinode.di_size = spcl.c_count * TP_BSIZE;
380                 getfile(xtrmap, xtrmapskip);
381         }
382         Dprintf(stdout, "maxino = %lu\n", (unsigned long)maxino);
383         if (spcl.c_type != TS_BITS)
384                 errx(1, "Cannot find file dump list");
385         map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
386         if (map == (char *)NULL)
387                 errx(1, "no memory for file dump list");
388         dumpmap = map;
389         curfile.action = USING;
390         getfile(xtrmap, xtrmapskip);
391         while (spcl.c_type == TS_ADDR) {
392                 spcl.c_dinode.di_size = spcl.c_count * TP_BSIZE;
393                 getfile(xtrmap, xtrmapskip);
394         }
395         /*
396          * If there may be whiteout entries on the tape, pretend that the
397          * whiteout inode exists, so that the whiteout entries can be
398          * extracted.
399          */
400         if (oldinofmt == 0)
401                 SETINO(WINO, dumpmap);
402         readingmaps = 0;
403         findinode(&spcl);
404 }
405
406 /*
407  * Prompt user to load a new dump volume.
408  * "Nextvol" is the next suggested volume to use.
409  * This suggested volume is enforced when doing full
410  * or incremental restores, but can be overridden by
411  * the user when only extracting a subset of the files.
412  */
413 void
414 getvol(long nextvol)
415 {
416         long newvol = 0, wantnext = 0, i;
417         long saved_blksread = 0, saved_tpblksread = 0;
418         union u_spcl tmpspcl;
419 #       define tmpbuf tmpspcl.s_spcl
420         char buf[TP_BSIZE];
421         int haderror = 0, bot_code = 1;
422
423         if (nextvol == 1) {
424                 tapesread = 0;
425                 gettingfile = 0;
426                 tpblksread = 0;
427                 blksread = 0;
428         }
429         if (pipein) {
430                 if (nextvol != 1)
431                         panic("Changing volumes on pipe input?\n");
432                 if (volno == 1)
433                         return;
434                 goto gethdr;
435         }
436         saved_blksread = blksread;
437         saved_tpblksread = tpblksread;
438 #if defined(USE_QFA) && defined(sunos)
439         if (createtapeposflag || tapeposflag) 
440                 close(fdsmtc);
441 #endif
442 again:
443         if (pipein)
444                 exit(1); /* pipes do not get a second chance */
445         if (aflag || curfile.action != SKIP) {
446                 newvol = nextvol;
447                 wantnext = 1;
448         } else {
449                 newvol = 0;
450                 wantnext = 0;
451         }
452         while (newvol <= 0) {
453                 if (tapesread == 0) {
454                         fprintf(stderr, "%s%s%s%s%s",
455                             "You have not read any volumes yet.\n",
456                             "Unless you know which volume your",
457                             " file(s) are on you should start\n",
458                             "with the last volume and work",
459                             " towards the first.\n");
460                 } else {
461                         fprintf(stderr, "You have read volumes");
462                         strcpy(buf, ": ");
463                         for (i = 1; i < 32; i++)
464                                 if (tapesread & (1 << i)) {
465                                         fprintf(stderr, "%s%ld", buf, (long)i);
466                                         strcpy(buf, ", ");
467                                 }
468                         fprintf(stderr, "\n");
469                 }
470                 do      {
471                         fprintf(stderr, "Specify next volume # (none if no more volumes): ");
472                         (void) fflush(stderr);
473                         (void) fgets(buf, TP_BSIZE, terminal);
474                 } while (!feof(terminal) && buf[0] == '\n');
475                 if (feof(terminal))
476                         exit(1);
477                 if (!strcmp(buf, "none\n")) {
478                         terminateinput();
479                         return;
480                 }
481                 newvol = atoi(buf);
482                 if (newvol <= 0) {
483                         fprintf(stderr,
484                             "Volume numbers are positive numerics\n");
485                 }
486         }
487         if (newvol == volno) {
488                 tapesread |= 1 << volno;
489 #if defined(USE_QFA) && defined(sunos)
490                 if (createtapeposflag || tapeposflag) {
491                         if (OpenSMTCmt(magtape) < 0) {
492                                 volno = -1;
493                                 haderror = 1;
494                                 goto again;
495                         }
496                 }
497 #endif
498                 return;
499         }
500         closemt();
501
502         /* 
503          * if using an archive file, reset its name so readtape()
504          * could properly use remote access.
505          */
506         Afile = NULL;
507
508         if (Mflag) {
509                 snprintf(magtape, MAXPATHLEN, "%s%03ld", magtapeprefix, newvol);
510                 magtape[MAXPATHLEN - 1] = '\0';
511         }
512         if (bot_script && !haderror) {
513                 msg("Launching %s\n", bot_script);
514                 bot_code = system_command(bot_script, magtape, newvol);
515                 if (bot_code != 0 && bot_code != 1) {
516                         msg("Restore aborted by the beginning of tape script\n");
517                         exit(1);
518                 }
519         }
520         if (haderror || (bot_code && !Mflag)) {
521                 haderror = 0;
522                 fprintf(stderr, "Mount volume %ld\n", (long)newvol);
523                 fprintf(stderr, "Enter ``none'' if there are no more volumes\n");
524                 fprintf(stderr, "otherwise enter volume name (default: %s) ", magtape);
525                 (void) fflush(stderr);
526                 (void) fgets(buf, TP_BSIZE, terminal);
527                 if (feof(terminal))
528                         exit(1);
529                 if (!strcmp(buf, "none\n")) {
530                         terminateinput();
531                         return;
532                 }
533                 if (buf[0] != '\n') {
534                         char *pos;
535                         (void) strncpy(magtape, buf, sizeof(magtape));
536                         magtape[sizeof(magtape) - 1] = '\0';
537                         if ((pos = strchr(magtape, '\n'))) 
538                                 magtape[pos - magtape] = '\0';
539                 }
540         }
541 #ifdef RRESTORE
542         if (host)
543                 mt = rmtopen(magtape, O_RDONLY);
544         else
545 #endif
546                 mt = OPEN(magtape, O_RDONLY, 0);
547
548         if (mt == -1) {
549                 fprintf(stderr, "Cannot open %s\n", magtape);
550                 volno = -1;
551                 haderror = 1;
552                 goto again;
553         }
554 gethdr:
555         setmagtapein();
556 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
557         readtape_func = readtape_set;
558 #endif
559         volno = newvol;
560         setdumpnum();
561         FLUSHTAPEBUF();
562         findtapeblksize();
563         if (gethead(&tmpbuf) == FAIL) {
564                 Dprintf(stdout, "header read failed at %ld blocks\n", (long)blksread);
565                 fprintf(stderr, "tape is not dump tape\n");
566                 volno = 0;
567                 haderror = 1;
568                 blksread = saved_blksread;
569                 tpblksread = saved_tpblksread;
570                 goto again;
571         }
572         if (tmpbuf.c_volume != volno) {
573                 fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
574                 volno = 0;
575                 haderror = 1;
576                 blksread = saved_blksread;
577                 tpblksread = saved_tpblksread;
578                 goto again;
579         }
580         if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
581                 fprintf(stderr, "Wrong dump date\n\tgot: %s",
582                         ctime4(&tmpbuf.c_date));
583                 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
584                 volno = 0;
585                 haderror = 1;
586                 blksread = saved_blksread;
587                 tpblksread = saved_tpblksread;
588                 goto again;
589         }
590         tapesread |= 1 << volno;
591         /*
592          * If continuing from the previous volume, skip over any
593          * blocks read already at the end of the previous volume.
594          *
595          * If coming to this volume at random, skip to the beginning
596          * of the next record.
597          */
598         if (zflag) {
599                 fprintf(stderr, "Dump tape is compressed.\n");
600 #if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB)
601                 errx(1,"This restore version doesn't support decompression");
602 #endif /* !HAVE_ZLIB && !HAVE_BZLIB */
603         }
604         Dprintf(stdout, "read %ld recs, tape starts with %ld\n",
605                 tpblksread - 1, (long)tmpbuf.c_firstrec);
606         if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
607                 if (!wantnext) {
608                         tpblksread = tmpbuf.c_firstrec + 1;
609                         for (i = tmpbuf.c_count; i > 0; i--)
610                                 readtape(buf);
611                 } else if (tmpbuf.c_firstrec > 0 &&
612                            tmpbuf.c_firstrec < tpblksread - 1) {
613                         /*
614                          * -1 since we've read the volume header
615                          */
616                         i = tpblksread - tmpbuf.c_firstrec - 1;
617                         Dprintf(stderr, "Skipping %ld duplicate record%s.\n",
618                                 (long)i, i > 1 ? "s" : "");
619                         while (--i >= 0)
620                                 readtape(buf);
621                 }
622         }
623         if (curfile.action == USING) {
624                 if (volno == 1)
625                         panic("active file into volume 1\n");
626                 return;
627         }
628         /*
629          * Skip up to the beginning of the next record
630          */
631         if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
632                 for (i = tmpbuf.c_count; i > 0; i--)
633                         readtape(buf);
634         (void) gethead(&spcl);
635         findinode(&spcl);
636         if (gettingfile) {
637                 gettingfile = 0;
638                 siglongjmp(restart, 1);
639         }
640 }
641
642 /*
643  * Handle unexpected EOF.
644  */
645 static void
646 terminateinput(void)
647 {
648
649         if (gettingfile && curfile.action == USING) {
650                 printf("Warning: %s %s\n",
651                     "End-of-input encountered while extracting", curfile.name);
652         }
653         curfile.name = "<name unknown>";
654         curfile.action = UNKNOWN;
655         curfile.dip = NULL;
656         curfile.ino = maxino;
657         if (gettingfile) {
658                 gettingfile = 0;
659                 siglongjmp(restart, 1);
660         }
661 }
662
663 /*
664  * handle multiple dumps per tape by skipping forward to the
665  * appropriate one.
666  */
667 static void
668 setdumpnum(void)
669 {
670         struct mtop tcom;
671
672         if (dumpnum == 1 || volno != 1)
673                 return;
674         if (pipein)
675                 errx(1, "Cannot have multiple dumps on pipe input");
676         tcom.mt_op = MTFSF;
677         tcom.mt_count = dumpnum - 1;
678 #ifdef RRESTORE
679         if (host)
680                 rmtioctl(MTFSF, dumpnum - 1);
681         else
682 #endif
683                 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
684                         warn("ioctl MTFSF");
685 }
686
687 void
688 printdumpinfo(void)
689 {
690         fprintf(stdout, "Dump   date: %s", ctime4(&spcl.c_date));
691         fprintf(stdout, "Dumped from: %s",
692             (spcl.c_ddate == 0) ? "the epoch\n" : ctime4(&spcl.c_ddate));
693         if (spcl.c_host[0] == '\0')
694                 return;
695         fprintf(stdout, "Level %d dump of %s on %s:%s\n",
696                 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
697         fprintf(stdout, "Label: %s\n", spcl.c_label);
698 }
699
700 void 
701 printvolinfo(void)
702 {
703         int i;
704
705         if (volinfo[1] == ROOTINO) {
706                 printf("Starting inode numbers by volume:\n");
707                 for (i = 1; i < (int)TP_NINOS && volinfo[i] != 0; ++i)
708                         printf("\tVolume %d: %lu\n", i, (unsigned long)volinfo[i]);
709         }
710 }
711
712 #ifdef sunos
713 struct timeval
714         time_t          tv_sec;         /* seconds */
715         suseconds_t     tv_usec;        /* and microseconds */
716 };
717 #endif
718
719 int
720 extractfile(struct entry *ep, int doremove)
721 {
722         unsigned int flags;
723         mode_t mode;
724         struct timeval timep[2];
725         char *name = myname(ep);
726
727         /* If removal is requested (-r mode) do remove it unless
728          * we are extracting a metadata only inode */
729         if (spcl.c_flags & DR_METAONLY) {
730                 Vprintf(stdout, "file %s is metadata only\n", name);
731         }
732         else {
733                 if (doremove) {
734                         removeleaf(ep);
735                         ep->e_flags &= ~REMOVED;
736                 }
737         }
738
739         curfile.name = name;
740         curfile.action = USING;
741 #if defined(__linux__) || defined(sunos)
742         timep[0].tv_sec = curfile.dip->di_atime.tv_sec;
743         timep[0].tv_usec = curfile.dip->di_atime.tv_usec;
744         timep[1].tv_sec = curfile.dip->di_mtime.tv_sec;
745         timep[1].tv_usec = curfile.dip->di_mtime.tv_usec;
746 #else   /* __linux__ || sunos */
747         timep[0].tv_sec = curfile.dip->di_atime;
748         timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
749         timep[1].tv_sec = curfile.dip->di_mtime;
750         timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
751 #endif  /* __linux__ */
752         mode = curfile.dip->di_mode;
753         flags = curfile.dip->di_flags;
754         switch (mode & IFMT) {
755
756         default:
757                 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
758                 skipfile();
759                 return (FAIL);
760
761         case IFSOCK:
762                 Vprintf(stdout, "skipped socket %s\n", name);
763                 skipfile();
764                 return (GOOD);
765
766         case IFDIR:
767                 if (mflag) {
768                         if (ep == NULL || ep->e_flags & EXTRACT)
769                                 panic("unextracted directory %s\n", name);
770                         skipfile();
771                         return (GOOD);
772                 }
773                 Vprintf(stdout, "extract file %s\n", name);
774                 return (genliteraldir(name, curfile.ino));
775
776         case IFLNK:
777         {
778 #ifdef HAVE_LCHOWN
779                 uid_t luid = curfile.dip->di_uid;
780                 gid_t lgid = curfile.dip->di_gid;
781 #endif
782                 if (! (spcl.c_flags & DR_METAONLY)) {
783                         lnkbuf[0] = '\0';
784                         pathlen = 0;
785                         getfile(xtrlnkfile, xtrlnkskip);
786                         if (pathlen == 0) {
787                                 Vprintf(stdout,
788                                     "%s: zero length symbolic link (ignored)\n", name);
789                                 return (GOOD);
790                         }
791                         if (linkit(lnkbuf, name, SYMLINK) == FAIL)
792                                 return (FAIL);
793                 }
794                 else
795                         skipfile();
796
797 #ifdef HAVE_LCHOWN
798                 (void) lchown(name, luid, lgid);
799 #endif
800                 return (GOOD);
801         }
802
803         case IFIFO:
804                 Vprintf(stdout, "extract fifo %s\n", name);
805                 if (Nflag) {
806                         skipfile();
807                         return (GOOD);
808                 }
809                 if (! (spcl.c_flags & DR_METAONLY)) {
810                         if (uflag && !Nflag)
811                                 (void)unlink(name);
812                         if (mkfifo(name, mode) < 0) {
813                                 warn("%s: cannot create fifo", name);
814                                 skipfile();
815                                 return (FAIL);
816                         }
817                 }
818                 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
819                 (void) chmod(name, mode);
820                 if (flags)
821 #ifdef  __linux__
822                         (void) fsetflags(name, flags);
823 #else
824                         (void) chflags(name, flags);
825 #endif
826                 skipfile();
827                 utimes(name, timep);
828                 return (GOOD);
829
830         case IFCHR:
831         case IFBLK:
832                 Vprintf(stdout, "extract special file %s\n", name);
833                 if (Nflag) {
834                         skipfile();
835                         return (GOOD);
836                 }
837                 if (! (spcl.c_flags & DR_METAONLY)) {
838                         if (uflag)
839                                 (void)unlink(name);
840                         if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
841                                 warn("%s: cannot create special file", name);
842                                 skipfile();
843                                 return (FAIL);
844                         }
845                 }
846                 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
847                 (void) chmod(name, mode);
848                 if (flags)
849 #ifdef  __linux__
850                         {
851                         warn("%s: fsetflags called on a special file", name);
852                         (void) fsetflags(name, flags);
853                         }
854 #else
855                         (void) chflags(name, flags);
856 #endif
857                 skipfile();
858                 utimes(name, timep);
859                 return (GOOD);
860
861         case IFREG:
862         {
863                 uid_t luid = curfile.dip->di_uid;
864                 gid_t lgid = curfile.dip->di_gid;
865
866                 Vprintf(stdout, "extract file %s\n", name);
867                 if (Nflag) {
868                         skipfile();
869                         return (GOOD);
870                 }
871                 if (! (spcl.c_flags & DR_METAONLY)) {
872                         if (uflag)
873                                 (void)unlink(name);
874                         if ((ofile = OPEN(name, O_WRONLY | O_CREAT | O_TRUNC,
875                             0666)) < 0) {
876                                 warn("%s: cannot create file", name);
877                                 skipfile();
878                                 return (FAIL);
879                         }
880                         getfile(xtrfile, xtrskip);
881                         (void) close(ofile);
882                 }
883                 else
884                         skipfile();
885                 (void) chown(name, luid, lgid);
886                 (void) chmod(name, mode);
887                 if (flags)
888 #ifdef  __linux__
889                         (void) fsetflags(name, flags);
890 #else
891                         (void) chflags(name, flags);
892 #endif
893                 utimes(name, timep);
894                 return (GOOD);
895         }
896         }
897         /* NOTREACHED */
898 }
899
900 /*
901  * skip over bit maps on the tape
902  */
903 void
904 skipmaps(void)
905 {
906
907         while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
908                 skipfile();
909 }
910
911 /*
912  * skip over a file on the tape
913  */
914 void
915 skipfile(void)
916 {
917
918         curfile.action = SKIP;
919         getfile(xtrnull, xtrnull);
920 }
921
922 /*
923  * Extract a file from the tape.
924  * When an allocated block is found it is passed to the fill function;
925  * when an unallocated block (hole) is found, a zeroed buffer is passed
926  * to the skip function.
927  */
928 void
929 getfile(void (*fill) __P((char *, size_t)), void (*skip) __P((char *, size_t)))
930 {
931         int i;
932         volatile int curblk = 0;
933         volatile quad_t size = spcl.c_dinode.di_size;
934         volatile int last_write_was_hole = 0;
935         quad_t origsize = size;
936         static char clearedbuf[MAXBSIZE];
937         char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
938         char junk[TP_BSIZE];
939
940         if (spcl.c_type == TS_END)
941                 panic("ran off end of tape\n");
942         if (spcl.c_magic != NFS_MAGIC)
943                 panic("not at beginning of a file\n");
944         if (!gettingfile && setjmp(restart) != 0)
945                 return;
946         gettingfile++;
947 loop:
948         for (i = 0; i < spcl.c_count; i++) {
949                 if (readmapflag || spcl.c_addr[i]) {
950                         readtape(&buf[curblk++][0]);
951                         if (curblk == fssize / TP_BSIZE) {
952                                 (*fill)((char *)buf, (size_t)(size > TP_BSIZE ?
953                                      fssize : (curblk - 1) * TP_BSIZE + size));
954                                 curblk = 0;
955                                 last_write_was_hole = 0;
956                         }
957                 } else {
958                         if (curblk > 0) {
959                                 (*fill)((char *)buf, (size_t)(size > TP_BSIZE ?
960                                      curblk * TP_BSIZE :
961                                      (curblk - 1) * TP_BSIZE + size));
962                                 curblk = 0;
963                         }
964                         (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
965                                 TP_BSIZE : size));
966                         last_write_was_hole = 1;
967                 }
968                 if ((size -= TP_BSIZE) <= 0) {
969                         for (i++; i < spcl.c_count; i++)
970                                 if (readmapflag || spcl.c_addr[i])
971                                         readtape(junk);
972                         break;
973                 }
974         }
975         if (gethead(&spcl) == GOOD && size > 0) {
976                 if (spcl.c_type == TS_ADDR)
977                         goto loop;
978                 Dprintf(stdout,
979                         "Missing address (header) block for %s at %ld blocks\n",
980                         curfile.name, (long)blksread);
981         }
982         if (curblk > 0) {
983                 (*fill)((char *)buf, (size_t)((curblk * TP_BSIZE) + size));
984                 last_write_was_hole = 0;
985         }
986         if (size > 0) {
987                 fprintf(stderr, "Missing blocks at the end of %s, assuming hole\n", curfile.name);
988                 while (size > 0) {
989                         size_t skp = size > TP_BSIZE ? TP_BSIZE : size;
990                         (*skip)(clearedbuf, skp);
991                         size -= skp;
992                 }
993                 last_write_was_hole = 1;
994         }
995         if (last_write_was_hole) {
996                 FTRUNCATE(ofile, origsize);
997         }
998         if (!readingmaps) 
999                 findinode(&spcl);
1000         gettingfile = 0;
1001 }
1002
1003 /*
1004  * Write out the next block of a file.
1005  */
1006 static void
1007 xtrfile(char *buf, size_t size)
1008 {
1009
1010         if (Nflag)
1011                 return;
1012         if (write(ofile, buf, (int) size) == -1)
1013                 err(1, "write error extracting inode %lu, name %s\nwrite",
1014                         (unsigned long)curfile.ino, curfile.name);
1015 }
1016
1017 /*
1018  * Skip over a hole in a file.
1019  */
1020 /* ARGSUSED */
1021 static void
1022 xtrskip(UNUSED(char *buf), size_t size)
1023 {
1024
1025         if (LSEEK(ofile, (OFF_T)size, SEEK_CUR) == -1)
1026                 err(1, "seek error extracting inode %lu, name %s\nlseek",
1027                         (unsigned long)curfile.ino, curfile.name);
1028 }
1029
1030 /*
1031  * Collect the next block of a symbolic link.
1032  */
1033 static void
1034 xtrlnkfile(char *buf, size_t size)
1035 {
1036
1037         pathlen += size;
1038         if (pathlen > MAXPATHLEN)
1039                 errx(1, "symbolic link name: %s->%s%s; too long %d",
1040                     curfile.name, lnkbuf, buf, pathlen);
1041         (void) strcat(lnkbuf, buf);
1042 }
1043
1044 /*
1045  * Skip over a hole in a symbolic link (should never happen).
1046  */
1047 /* ARGSUSED */
1048 static void
1049 xtrlnkskip(UNUSED(char *buf), UNUSED(size_t size))
1050 {
1051
1052         errx(1, "unallocated block in symbolic link %s", curfile.name);
1053 }
1054
1055 /*
1056  * Collect the next block of a bit map.
1057  */
1058 static void
1059 xtrmap(char *buf, size_t size)
1060 {
1061
1062         memmove(map, buf, size);
1063         map += size;
1064 }
1065
1066 /*
1067  * Skip over a hole in a bit map (should never happen).
1068  */
1069 /* ARGSUSED */
1070 static void
1071 xtrmapskip(UNUSED(char *buf), size_t size)
1072 {
1073
1074         panic("hole in map\n");
1075         map += size;
1076 }
1077
1078 /*
1079  * Noop, when an extraction function is not needed.
1080  */
1081 /* ARGSUSED */
1082 void
1083 xtrnull(UNUSED(char *buf), UNUSED(size_t size))
1084 {
1085
1086         return;
1087 }
1088
1089 #if COMPARE_ONTHEFLY
1090 /*
1091  * Compare the next block of a file.
1092  */
1093 static void
1094 xtrcmpfile(char *buf, size_t size)
1095 {
1096         static char cmpbuf[MAXBSIZE];
1097
1098         if (cmperror)
1099                 return;
1100         
1101         if (read(ifile, cmpbuf, size) != (ssize_t)size) {
1102                 fprintf(stderr, "%s: size has changed.\n", 
1103                         curfile.name);
1104                 cmperror = 1;
1105                 return;
1106         }
1107         
1108         if (memcmp(buf, cmpbuf, size) != 0) {
1109                 fprintf(stderr, "%s: tape and disk copies are different\n",
1110                         curfile.name);
1111                 cmperror = 1;
1112                 return;
1113         }
1114 }
1115
1116 /*
1117  * Skip over a hole in a file.
1118  */
1119 static void
1120 xtrcmpskip(UNUSED(char *buf), size_t size)
1121 {
1122         static char cmpbuf[MAXBSIZE];
1123         int i;
1124
1125         if (cmperror)
1126                 return;
1127         
1128         if (read(ifile, cmpbuf, size) != (ssize_t)size) {
1129                 fprintf(stderr, "%s: size has changed.\n", 
1130                         curfile.name);
1131                 cmperror = 1;
1132                 return;
1133         }
1134
1135         for (i = 0; i < (int)size; ++i)
1136                 if (cmpbuf[i] != '\0') {
1137                         fprintf(stderr, "%s: tape and disk copies are different\n",
1138                                 curfile.name);
1139                         cmperror = 1;
1140                         return;
1141                 }
1142 }
1143 #endif /* COMPARE_ONTHEFLY */
1144
1145 #if !COMPARE_ONTHEFLY
1146 static int
1147 do_cmpfiles(int fd_tape, int fd_disk, long size)
1148 {
1149         static char buf_tape[BUFSIZ];
1150         static char buf_disk[BUFSIZ];
1151         ssize_t n_tape;
1152         ssize_t n_disk;
1153
1154         while (size > 0) {
1155                 if ((n_tape = read(fd_tape, buf_tape, sizeof(buf_tape))) < 1) {
1156                         close(fd_tape), close(fd_disk);
1157                         panic("do_cmpfiles: unexpected EOF[1]");
1158                 }
1159                 if ((n_disk = read(fd_disk, buf_disk, sizeof(buf_tape))) < 1) {
1160                         close(fd_tape), close(fd_disk);
1161                         panic("do_cmpfiles: unexpected EOF[2]");
1162                 }
1163                 if (n_tape != n_disk) {
1164                         close(fd_tape), close(fd_disk);
1165                         panic("do_cmpfiles: sizes different!");
1166                 }
1167                 if (memcmp(buf_tape, buf_disk, (size_t)n_tape) != 0) return (1);
1168                 size -= n_tape;
1169         }
1170         return (0);
1171 }
1172
1173 /* for debugging compare problems */
1174 #undef COMPARE_FAIL_KEEP_FILE
1175
1176 static
1177 #ifdef COMPARE_FAIL_KEEP_FILE
1178 /* return true if tapefile should be unlinked after compare */
1179 int
1180 #else
1181 void
1182 #endif
1183 cmpfiles(char *tapefile, char *diskfile, struct STAT *sbuf_disk)
1184 {
1185         struct STAT sbuf_tape;
1186         int fd_tape, fd_disk;
1187
1188         if (STAT(tapefile, &sbuf_tape) != 0) {
1189                 panic("Can't lstat tmp file %s: %s\n", tapefile,
1190                       strerror(errno));
1191                 do_compare_error;
1192         }
1193
1194         if (sbuf_disk->st_size != sbuf_tape.st_size) {
1195                 fprintf(stderr,
1196                         "%s: size changed from %ld to %ld.\n",
1197                         diskfile, (long)sbuf_tape.st_size, (long)sbuf_disk->st_size);
1198                 do_compare_error;
1199 #ifdef COMPARE_FAIL_KEEP_FILE
1200                 return (0);
1201 #else
1202                 return;
1203 #endif
1204         }
1205
1206         if ((fd_tape = OPEN(tapefile, O_RDONLY)) < 0) {
1207                 panic("Can't open %s: %s\n", tapefile, strerror(errno));
1208                 do_compare_error;
1209         }
1210         if ((fd_disk = OPEN(diskfile, O_RDONLY)) < 0) {
1211                 close(fd_tape);
1212                 panic("Can't open %s: %s\n", diskfile, strerror(errno));
1213                 do_compare_error;
1214         }
1215
1216         if (do_cmpfiles(fd_tape, fd_disk, sbuf_tape.st_size)) {
1217                 fprintf(stderr, "%s: tape and disk copies are different\n",
1218                         diskfile);
1219                 close(fd_tape);
1220                 close(fd_disk);
1221                 do_compare_error;
1222 #ifdef COMPARE_FAIL_KEEP_FILE
1223                 /* rename the file to live in /tmp */
1224                 /* rename `tapefile' to /tmp/<basename of diskfile> */
1225                 {
1226                         char *p = strrchr(diskfile, '/');
1227                         char newname[MAXPATHLEN];
1228                         if (!p) {
1229                                 panic("can't find / in %s\n", diskfile);
1230                         }
1231                         snprintf(newname, sizeof(newname), "%s/debug/%s", tmpdir, p + 1);
1232                         if (rename(tapefile, newname)) {
1233                                 panic("rename from %s to %s failed: %s\n",
1234                                       tapefile, newname,
1235                                       strerror(errno));
1236                         } else {
1237                                 fprintf(stderr, "*** %s saved to %s\n",
1238                                         tapefile, newname);
1239                         }
1240                 }
1241                 
1242                 /* don't unlink the file (it's not there anymore */
1243                 /* anyway) */
1244                 return (0);
1245 #else
1246                 return;
1247 #endif
1248         }
1249         close(fd_tape);
1250         close(fd_disk);
1251 #ifdef COMPARE_FAIL_KEEP_FILE
1252         return (1);
1253 #endif
1254 }
1255 #endif /* !COMPARE_ONTHEFLY */
1256
1257 #if !COMPARE_ONTHEFLY
1258 static char tmpfilename[MAXPATHLEN];
1259 #endif
1260
1261 void
1262 comparefile(char *name)
1263 {
1264         unsigned int mode;
1265         struct STAT sb;
1266         int r;
1267 #if !COMPARE_ONTHEFLY
1268         static char *tmpfile = NULL;
1269         struct STAT stemp;
1270 #endif
1271
1272         curfile.name = name;
1273         curfile.action = USING;
1274         mode = curfile.dip->di_mode;
1275
1276         if ((mode & IFMT) == IFSOCK) {
1277                 Vprintf(stdout, "skipped socket %s\n", name);
1278                 skipfile();
1279                 return;
1280         }
1281
1282         if ((r = LSTAT(name, &sb)) != 0) {
1283                 warn("%s: does not exist (%d)", name, r);
1284                 do_compare_error;
1285                 skipfile();
1286                 return;
1287         }
1288
1289         Vprintf(stdout, "comparing %s (size: %ld, mode: 0%o)\n", name,
1290                 (long)sb.st_size, mode);
1291
1292         if (sb.st_mode != mode) {
1293                 fprintf(stderr, "%s: mode changed from 0%o to 0%o.\n",
1294                         name, mode & 07777, sb.st_mode & 07777);
1295                 do_compare_error;
1296         }
1297         if (spcl.c_flags & DR_METAONLY) {
1298                 skipfile();
1299                 return;
1300         }
1301         switch (mode & IFMT) {
1302         default:
1303                 skipfile();
1304                 return;
1305
1306         case IFSOCK:
1307                 skipfile();
1308                 return;
1309
1310         case IFDIR:
1311                 skipfile();
1312                 return;
1313
1314         case IFLNK: {
1315                 char lbuf[MAXPATHLEN + 1];
1316                 int lsize;
1317
1318                 if (!(sb.st_mode & S_IFLNK)) {
1319                         fprintf(stderr, "%s: is no longer a symbolic link\n",
1320                                 name);
1321                         do_compare_error;
1322                         return;
1323                 }
1324                 lnkbuf[0] = '\0';
1325                 pathlen = 0;
1326                 getfile(xtrlnkfile, xtrlnkskip);
1327                 if (pathlen == 0) {
1328                         fprintf(stderr,
1329                                 "%s: zero length symbolic link (ignored)\n",
1330                                 name);
1331                         do_compare_error;
1332                         return;
1333                 }
1334                 if ((lsize = readlink(name, lbuf, MAXPATHLEN)) < 0) {
1335                         panic("readlink of %s failed: %s", name,
1336                               strerror(errno));
1337                         do_compare_error;
1338                 }
1339                 lbuf[lsize] = 0;
1340                 if (strcmp(lbuf, lnkbuf) != 0) {
1341                         fprintf(stderr,
1342                                 "%s: symbolic link changed from %s to %s.\n",
1343                                 name, lnkbuf, lbuf);
1344                         do_compare_error;
1345                         return;
1346                 }
1347                 return;
1348         }
1349
1350         case IFCHR:
1351         case IFBLK:
1352                 if (!(sb.st_mode & (S_IFCHR|S_IFBLK))) {
1353                         fprintf(stderr, "%s: no longer a special file\n",
1354                                 name);
1355                         do_compare_error;
1356                         skipfile();
1357                         return;
1358                 }
1359
1360                 if (sb.st_rdev != (dev_t)curfile.dip->di_rdev) {
1361                         fprintf(stderr,
1362                                 "%s: device changed from %d,%d to %d,%d.\n",
1363                                 name,
1364                                 ((int)curfile.dip->di_rdev >> 8) & 0xff,
1365                                 (int)curfile.dip->di_rdev & 0xff,
1366                                 ((int)sb.st_rdev >> 8) & 0xff,
1367                                 (int)sb.st_rdev & 0xff);
1368                         do_compare_error;
1369                 }
1370                 skipfile();
1371                 return;
1372
1373         case IFREG:
1374 #if COMPARE_ONTHEFLY
1375                 if ((ifile = OPEN(name, O_RDONLY)) < 0) {
1376                         panic("Can't open %s: %s\n", name, strerror(errno));
1377                         skipfile();
1378                         do_compare_error;
1379                 }
1380                 else {
1381                         cmperror = 0;
1382                         getfile(xtrcmpfile, xtrcmpskip);
1383                         if (!cmperror) {
1384                                 char c;
1385                                 if (read(ifile, &c, 1) != 0) {
1386                                         fprintf(stderr, "%s: size has changed.\n", 
1387                                                 name);
1388                                         cmperror = 1;
1389                                 }
1390                         }
1391                         if (cmperror)
1392                                 do_compare_error;
1393                         close(ifile);
1394                 }
1395 #else
1396                 if (tmpfile == NULL) {
1397                         /* argument to mktemp() must not be in RO space: */
1398                         snprintf(tmpfilename, sizeof(tmpfilename), "%s/restoreCXXXXXX", tmpdir);
1399                         tmpfile = mktemp(&tmpfilename[0]);
1400                 }
1401                 if ((STAT(tmpfile, &stemp) == 0) && (unlink(tmpfile) != 0)) {
1402                         panic("cannot delete tmp file %s: %s\n",
1403                               tmpfile, strerror(errno));
1404                 }
1405                 if ((ofile = OPEN(tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
1406                         panic("cannot create file temp file %s: %s\n",
1407                               name, strerror(errno));
1408                 }
1409                 getfile(xtrfile, xtrskip);
1410                 (void) close(ofile);
1411 #ifdef COMPARE_FAIL_KEEP_FILE
1412                 if (cmpfiles(tmpfile, name, &sb))
1413                         unlink(tmpfile);
1414 #else
1415                 cmpfiles(tmpfile, name, &sb);
1416                 unlink(tmpfile);
1417 #endif
1418 #endif /* COMPARE_ONTHEFLY */
1419                 return;
1420         }
1421         /* NOTREACHED */
1422 }
1423
1424 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
1425 static void (*readtape_func)(char *) = readtape_set;
1426
1427 /*
1428  * Read TP_BSIZE blocks from the input.
1429  * Handle read errors, and end of media.
1430  * Decompress compressed blocks.
1431  */
1432 static void
1433 readtape(char *buf)
1434 {
1435         (*readtape_func)(buf);  /* call the actual processing routine */
1436 }
1437
1438 /*
1439  * Set function pointer for readtape() routine. zflag and magtapein must
1440  * be correctly set before the first call to readtape().
1441  */
1442 static void
1443 readtape_set(char *buf)
1444 {
1445         if (!zflag) 
1446                 readtape_func = readtape_uncompr;
1447         else {
1448                 newcomprbuf(ntrec);
1449                 if (magtapein)
1450                         readtape_func = readtape_comprtape;
1451                 else
1452                         readtape_func = readtape_comprfile;
1453         }
1454         readtape(buf);
1455 }
1456
1457 #endif /* HAVE_ZLIB || HAVE_BZLIB */
1458
1459 /*
1460  * This is the original readtape(), it's used for reading uncompressed input.
1461  * Read TP_BSIZE blocks from the input.
1462  * Handle read errors, and end of media.
1463  */
1464 static void
1465 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
1466 readtape_uncompr(char *buf)
1467 #else
1468 readtape(char *buf)
1469 #endif
1470 {
1471         ssize_t rd, newvol, i;
1472         int cnt, seek_failed;
1473
1474         if (blkcnt < numtrec) {
1475                 memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
1476                 blksread++;
1477                 tpblksread++;
1478                 return;
1479         }
1480         tbufptr = tapebuf;
1481         for (i = 0; i < ntrec; i++)
1482                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1483         if (numtrec == 0)
1484                 numtrec = ntrec;
1485         cnt = ntrec * TP_BSIZE;
1486         rd = 0;
1487 #ifdef USE_QFA
1488         if (createtapeposflag)
1489                 (void)GetTapePos(&curtapepos);
1490 #endif
1491 getmore:
1492 #ifdef RRESTORE
1493         if (!Afile && host)
1494                 i = rmtread(&tapebuf[rd], cnt);
1495         else
1496 #endif
1497                 i = read(mt, &tapebuf[rd], cnt);
1498
1499         /*
1500          * Check for mid-tape short read error.
1501          * If found, skip rest of buffer and start with the next.
1502          */
1503         if (!pipein && numtrec < ntrec && i > 0) {
1504                 Dprintf(stdout, "mid-media short read error.\n");
1505                 numtrec = ntrec;
1506         }
1507         /*
1508          * Handle partial block read.
1509          */
1510         if (pipein && i == 0 && rd > 0)
1511                 i = rd;
1512         else if (i > 0 && i != ntrec * TP_BSIZE) {
1513                 if (pipein) {
1514                         rd += i;
1515                         cnt -= i;
1516                         if (cnt > 0)
1517                                 goto getmore;
1518                         i = rd;
1519                 } else {
1520                         /*
1521                          * Short read. Process the blocks read.
1522                          */
1523                         if (i % TP_BSIZE != 0)
1524                                 Vprintf(stdout,
1525                                     "partial block read: %ld should be %ld\n",
1526                                     (long)i, ntrec * TP_BSIZE);
1527                         numtrec = i / TP_BSIZE;
1528                 }
1529         }
1530         /*
1531          * Handle read error.
1532          */
1533         if (i < 0) {
1534                 fprintf(stderr, "Tape read error while ");
1535                 switch (curfile.action) {
1536                 default:
1537                         fprintf(stderr, "trying to set up tape\n");
1538                         break;
1539                 case UNKNOWN:
1540                         fprintf(stderr, "trying to resynchronize\n");
1541                         break;
1542                 case USING:
1543                         fprintf(stderr, "restoring %s\n", curfile.name);
1544                         break;
1545                 case SKIP:
1546                         fprintf(stderr, "skipping over inode %lu\n",
1547                                 (unsigned long)curfile.ino);
1548                         break;
1549                 }
1550                 if (!yflag && !reply("continue"))
1551                         exit(1);
1552                 i = ntrec * TP_BSIZE;
1553                 memset(tapebuf, 0, (size_t)i);
1554 #ifdef RRESTORE
1555                 if (!Afile && host)
1556                         seek_failed = (rmtseek(i, 1) < 0);
1557                 else
1558 #endif
1559                         seek_failed = (LSEEK(mt, i, SEEK_CUR) == (OFF_T)-1);
1560
1561                 if (seek_failed) {
1562                         warn("continuation failed");
1563                         if (!yflag && !reply("assume end-of-tape and continue"))
1564                                 exit(1);
1565                         i = 0;
1566                 }
1567         }
1568         /*
1569          * Handle end of tape.
1570          */
1571         if (i == 0) {
1572                 Vprintf(stdout, "End-of-tape encountered\n");
1573                 if (!pipein) {
1574                         newvol = volno + 1;
1575                         volno = 0;
1576                         numtrec = 0;
1577                         getvol(newvol);
1578                         readtape(buf);
1579                         return;
1580                 }
1581                 if (rd % TP_BSIZE != 0)
1582                         panic("partial block read: %d should be %d\n",
1583                                 rd, ntrec * TP_BSIZE);
1584                 terminateinput();
1585                 memmove(&tapebuf[rd], &endoftapemark, TP_BSIZE);
1586         }
1587         blkcnt = 0;
1588         memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
1589         blksread++;
1590         tpblksread++;
1591 }
1592
1593 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
1594
1595 /*
1596  * Read a compressed format block from a file or pipe and uncompress it.
1597  * Attempt to handle read errors, and end of file. 
1598  */
1599 static void
1600 readtape_comprfile(char *buf)
1601 {
1602         long rl, size, i, ret;
1603         int newvol; 
1604         struct tapebuf *tpb;
1605
1606         if (blkcnt < numtrec) {
1607                 memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
1608                 blksread++;
1609                 tpblksread++;
1610                 return;
1611         }
1612         /* need to read the next block */
1613         tbufptr = tapebuf;
1614         for (i = 0; i < ntrec; i++)
1615                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1616         numtrec = ntrec;
1617         tpb = (struct tapebuf *) tapebuf;
1618
1619         /* read the block prefix */
1620         ret = read_a_block(mt, tapebuf, PREFIXSIZE, &rl);
1621         converttapebuf(tpb);
1622
1623         if (Vflag && (ret == 0 || rl < (int)PREFIXSIZE  ||  tpb->length == 0))
1624                 ret = 0;
1625         if (ret <= 0)
1626                 goto readerr;
1627
1628         /* read the data */
1629         size = tpb->length;
1630         if (size > bufsize)  {
1631                 /* something's wrong */
1632                 Vprintf(stdout, "Prefix size error, max size %d, got %ld\n",
1633                         bufsize, size);
1634                 size = bufsize;
1635                 tpb->length = bufsize;
1636         }
1637         ret = read_a_block(mt, tpb->buf, size, &rl);
1638         if (ret <= 0)
1639                 goto readerr;
1640
1641         tbufptr = decompress_tapebuf(tpb, rl + PREFIXSIZE);
1642         if (tbufptr == NULL) {
1643                 msg_read_error("File decompression error while");
1644                 if (!yflag && !reply("continue"))
1645                         exit(1);
1646                 memset(tapebuf, 0, bufsize);
1647                 tbufptr = tapebuf;
1648         }
1649
1650         blkcnt = 0;
1651         memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
1652         blksread++;
1653         tpblksread++;
1654         return;
1655
1656 readerr:
1657         /* Errors while reading from a file or pipe are catastrophic. Since
1658          * there are no block boundaries, it's impossible to bypass the
1659          * block in error and find the start of the next block.
1660          */
1661         if (ret == 0) {
1662                 /* It's possible to have multiple input files using -M
1663                  * and -f file1,file2...
1664                  */
1665                 Vprintf(stdout, "End-of-File encountered\n");
1666                 if (!pipein) {
1667                         newvol = volno + 1;
1668                         volno = 0;
1669                         numtrec = 0;
1670                         getvol(newvol);
1671                         readtape(buf);
1672                         return;
1673                 }
1674         }
1675         msg_read_error("Read error while");
1676         /* if (!yflag && !reply("continue")) */
1677                 exit(1);
1678 }
1679
1680 /*
1681  * Read compressed data from a tape and uncompress it.
1682  * Handle read errors, and end of media.
1683  * Since a tape consists of separate physical blocks, we try
1684  * to recover from errors by repositioning the tape to the next
1685  * block.
1686  */
1687 static void
1688 readtape_comprtape(char *buf)
1689 {
1690         long rl, size, i;
1691         int ret, newvol;
1692         struct tapebuf *tpb;
1693         struct mtop tcom;
1694
1695         if (blkcnt < numtrec) {
1696                 memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
1697                 blksread++;
1698                 tpblksread++;
1699                 return;
1700         }
1701         /* need to read the next block */
1702         tbufptr = tapebuf;
1703         for (i = 0; i < ntrec; i++)
1704                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1705         numtrec = ntrec;
1706         tpb = (struct tapebuf *) tapebuf;
1707
1708         /* read the block */
1709         size = bufsize + PREFIXSIZE;
1710         ret = read_a_block(mt, tapebuf, size, &rl);
1711         if (ret <= 0)
1712                 goto readerr;
1713
1714         converttapebuf(tpb);
1715         tbufptr = decompress_tapebuf(tpb, rl);
1716         if (tbufptr == NULL) {
1717                 msg_read_error("Tape decompression error while");
1718                 if (!yflag && !reply("continue"))
1719                         exit(1);
1720                 memset(tapebuf, 0, PREFIXSIZE + bufsize);
1721                 tbufptr = tapebuf;
1722         }
1723         goto moverecord;
1724
1725 readerr:
1726         /* Handle errors: EOT switches to the next volume, other errors
1727          * attempt to position the tape to the next block.
1728          */
1729         if (ret == 0) {
1730                 Vprintf(stdout, "End-of-tape encountered\n");
1731                 newvol = volno + 1;
1732                 volno = 0;
1733                 numtrec = 0;
1734                 getvol(newvol);
1735                 readtape(buf);
1736                 return;
1737         }
1738
1739         msg_read_error("Tape read error while");
1740         if (!yflag && !reply("continue"))
1741                 exit(1);
1742         memset(tapebuf, 0, PREFIXSIZE + bufsize);
1743         tbufptr = tapebuf;
1744
1745 #ifdef RRESTORE
1746         if (host)
1747                 rl = rmtioctl(MTFSR, 1);
1748         else
1749 #endif
1750         {
1751                 tcom.mt_op = MTFSR;
1752                 tcom.mt_count = 1;
1753                 rl = ioctl(mt, MTIOCTOP, &tcom);
1754         }
1755
1756         if (rl < 0) {
1757                 warn("continuation failed");
1758                 if (!yflag && !reply("assume end-of-tape and continue"))
1759                         exit(1);
1760                 ret = 0;         /* end of tape */
1761                 goto readerr;
1762         }
1763
1764 moverecord:
1765         blkcnt = 0;
1766         memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
1767         blksread++;
1768         tpblksread++;
1769 }
1770
1771 /*
1772  *  Decompress a struct tapebuf into a buffer. readsize is the size read
1773  *  from the tape/file and is used for error messages. Returns a pointer
1774  *  to the location of the uncompressed buffer or NULL on errors.
1775  *  Adjust numtrec and complain for a short block.
1776  */
1777 static char *
1778 decompress_tapebuf(struct tapebuf *tpbin, int readsize)
1779 {
1780         /* If zflag is on, all blocks have a struct tapebuf prefix */
1781         /* zflag gets set in setup() from the dump header          */
1782         int cresult, blocklen;        
1783         unsigned long worklen;
1784 #ifdef HAVE_BZLIB
1785         unsigned int worklen2;
1786 #endif
1787         char *output = NULL,*reason = NULL, *lengtherr = NULL;              
1788        
1789         /* build a length error message */
1790         blocklen = tpbin->length;
1791         if (readsize < blocklen + (int)PREFIXSIZE)
1792                 lengtherr = "short";
1793         else
1794                 if (readsize > blocklen + (int)PREFIXSIZE)
1795                         lengtherr = "long";
1796
1797         worklen = comprlen;
1798         cresult = 1;
1799         if (tpbin->compressed) {
1800                 /* uncompress whatever we read, if it fails, complain later */
1801                 if (tpbin->flags == COMPRESS_ZLIB) {
1802 #ifndef HAVE_ZLIB
1803                         errx(1,"This restore version doesn't support zlib decompression");
1804 #else
1805                         cresult = uncompress(comprbuf, &worklen, 
1806                                              tpbin->buf, blocklen);
1807                         output = comprbuf;
1808                         switch (cresult) {
1809                                 case Z_OK:
1810                                         break;
1811                                 case Z_MEM_ERROR:
1812                                         reason = "not enough memory";
1813                                         break;
1814                                 case Z_BUF_ERROR:
1815                                         reason = "buffer too small";
1816                                         break;
1817                                 case Z_DATA_ERROR:
1818                                         reason = "data error";
1819                                         break;
1820                                 default:
1821                                         reason = "unknown";
1822                         }
1823                         if (cresult == Z_OK)
1824                                 cresult = 1;
1825                         else
1826                                 cresult = 0;
1827 #endif /* HAVE_ZLIB */
1828                 }
1829                 if (tpbin->flags == COMPRESS_BZLIB) {
1830 #ifndef HAVE_BZLIB
1831                         errx(1,"This restore version doesn't support bzlib decompression");
1832 #else
1833                         worklen2 = worklen;
1834                         cresult = BZ2_bzBuffToBuffDecompress(
1835                                         comprbuf, &worklen2, 
1836                                         tpbin->buf, blocklen, 0, 0);
1837                         worklen = worklen2;
1838                         output = comprbuf;
1839                         switch (cresult) {
1840                                 case BZ_OK:
1841                                         break;
1842                                 case BZ_MEM_ERROR:
1843                                         reason = "not enough memory";
1844                                         break;
1845                                 case BZ_OUTBUFF_FULL:
1846                                         reason = "buffer too small";
1847                                         break;
1848                                 case BZ_DATA_ERROR:
1849                                 case BZ_DATA_ERROR_MAGIC:
1850                                 case BZ_UNEXPECTED_EOF:
1851                                         reason = "data error";
1852                                         break;
1853                                 default:
1854                                         reason = "unknown";
1855                         }
1856                         if (cresult == BZ_OK)
1857                                 cresult = 1;
1858                         else
1859                                 cresult = 0;
1860 #endif /* HAVE_BZLIB */
1861                 }
1862         }
1863         else {
1864                 output = tpbin->buf;
1865                 worklen = blocklen;
1866         }
1867         if (cresult) {
1868                 numtrec = worklen / TP_BSIZE;
1869                 if (worklen % TP_BSIZE != 0)
1870                         reason = "length mismatch";
1871         }
1872         if (reason) {
1873                 if (lengtherr)
1874                         fprintf(stderr, "%s compressed block: %d expected: %d\n",
1875                                 lengtherr, readsize, tpbin->length + PREFIXSIZE);
1876                 fprintf(stderr, "decompression error, block %ld: %s\n",
1877                         tpblksread+1, reason);
1878                 if (!cresult)
1879                         output = NULL;
1880         }
1881         return output;
1882 }
1883
1884 /*
1885  * Print an error message for a read error.
1886  * This was exteracted from the original readtape().
1887  */
1888 static void
1889 msg_read_error(char *m)
1890 {
1891         switch (curfile.action) {
1892                 default:
1893                         fprintf(stderr, "%s trying to set up tape\n", m);
1894                         break;
1895                 case UNKNOWN:
1896                         fprintf(stderr, "%s trying to resynchronize\n", m);
1897                         break;
1898                 case USING:
1899                         fprintf(stderr, "%s restoring %s\n", m, curfile.name);
1900                         break;
1901                 case SKIP:
1902                         fprintf(stderr, "%s skipping over inode %lu\n", m,
1903                                 (unsigned long)curfile.ino);
1904                         break;
1905         }
1906 }
1907 #endif /* HAVE_ZLIB || HAVE_BZLIB */
1908
1909 /*
1910  * Read the first block and get the blocksize from it. Test
1911  * for a compressed dump tape/file. setup() will make the final
1912  * determination by checking the compressed flag if gethead()
1913  * finds a valid header. The test here is necessary to offset the buffer
1914  * by the size of the compressed prefix. zflag is set here so that
1915  * readtape_set can set the correct function pointer for readtape().
1916  * Note that the first block of each tape/file is not compressed
1917  * and does not have a prefix.
1918  */ 
1919 static void
1920 findtapeblksize(void)
1921 {
1922         long i;
1923         size_t len;
1924         struct tapebuf *tpb = (struct tapebuf *) tapebuf;
1925         struct s_spcl spclpt;
1926
1927         for (i = 0; i < ntrec; i++)
1928                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1929         blkcnt = 0;
1930         tbufptr = tapebuf;
1931         /*
1932          * For a pipe or file, read in the first record. For a tape, read
1933          * the first block.
1934          */
1935         len = magtapein ? ntrec * TP_BSIZE : TP_BSIZE;
1936
1937         if (read_a_block(mt, tapebuf, len, &i) <= 0)
1938                 errx(1, "Tape read error on first record");
1939
1940         memcpy(&spclpt, tapebuf, TP_BSIZE);
1941         if (converthead(&spclpt) == FAIL) {
1942                 cvtflag++;
1943                 if (converthead(&spclpt) == FAIL) {
1944                         /* Special case for old compressed tapes with prefix */
1945                         if (magtapein && (i % TP_BSIZE != 0)) 
1946                                 goto oldformat;
1947                         errx(1, "Tape is not a dump tape");
1948                 }
1949                 fprintf(stderr, "Converting to new file system format.\n");
1950         }
1951         /*
1952          * If the input is from a file or a pipe, we read TP_BSIZE
1953          * bytes looking for a dump header. If the dump is compressed
1954          * we need to read in the rest of the block, as determined
1955          * by c_ntrec in the dump header. The first block of the
1956          * dump is not compressed and does not have a prefix.
1957          */
1958         if (!magtapein) {
1959                 if (spclpt.c_type == TS_TAPE
1960                     && spclpt.c_flags & DR_COMPRESSED) {
1961                         /* It's a compressed dump file, read in the */
1962                         /* rest of the block based on spclpt.c_ntrec. */
1963                         if (spclpt.c_ntrec > ntrec)
1964                                 errx(1, "Tape blocksize is too large, use "
1965                                      "\'-b %d\' ", spclpt.c_ntrec);
1966                         ntrec = spclpt.c_ntrec;
1967                         len = (ntrec - 1) * TP_BSIZE;
1968                         zflag = 1;   
1969                 }
1970                 else {
1971                         /* read in the rest of the block based on bufsize */
1972                         len = bufsize - TP_BSIZE;
1973                 }
1974                 if (read_a_block(mt, tapebuf+TP_BSIZE, len, &i) < 0
1975                     || (i != (long)len && i % TP_BSIZE != 0))
1976                         errx(1,"Error reading dump file header");
1977                 tbufptr = tapebuf;
1978                 numtrec = ntrec;
1979                 Vprintf(stdout, "Input block size is %ld\n", ntrec);
1980                 return;
1981         } /* if (!magtapein) */
1982
1983         /*
1984          * If the input is a tape, we tried to read ntrec * TP_BSIZE bytes.
1985          * If the value of ntrec is too large, we read less than
1986          * what we asked for; adjust the value of ntrec and test for 
1987          * a compressed dump tape.
1988          */
1989         if (i % TP_BSIZE != 0) {
1990 oldformat:
1991                 /* may be old format compressed dump tape with a prefix */
1992                 memcpy(&spclpt, tpb->buf, TP_BSIZE);
1993                 cvtflag = 0;
1994                 if (converthead(&spclpt) == FAIL) {
1995                         cvtflag++;
1996                         if (converthead(&spclpt) == FAIL)
1997                                 errx(1, "Tape is not a dump tape");
1998                         fprintf(stderr, "Converting to new file system format.\n");
1999                 }
2000                 if (i % TP_BSIZE == PREFIXSIZE
2001                     && tpb->compressed == 0
2002                     && spclpt.c_type == TS_TAPE
2003                     && spclpt.c_flags & DR_COMPRESSED) {
2004                         zflag = 1;
2005                         tbufptr = tpb->buf;
2006                         if (tpb->length > bufsize)
2007                                 errx(1, "Tape blocksize is too large, use "
2008                                         "\'-b %d\' ", tpb->length / TP_BSIZE);
2009                 }
2010                 else
2011                         errx(1, "Tape block size (%ld) is not a multiple of dump block size (%d)",
2012                                 i, TP_BSIZE);
2013         }
2014         ntrec = i / TP_BSIZE;
2015         if (spclpt.c_type == TS_TAPE) {
2016                 if (spclpt.c_flags & DR_COMPRESSED)
2017                         zflag = 1;
2018                 if (spclpt.c_ntrec > ntrec)
2019                         errx(1, "Tape blocksize is too large, use "
2020                                 "\'-b %d\' ", spclpt.c_ntrec);
2021         }
2022         numtrec = ntrec;
2023         Vprintf(stdout, "Tape block size is %ld\n", ntrec);
2024 }
2025
2026 /*
2027  * Read a block of data handling all of the messy details.
2028  */
2029 static int read_a_block(int fd, char *buf, size_t len, long *lengthread)
2030 {
2031         long i = 1, size;
2032
2033         size = len;
2034         while (size > 0) {
2035 #ifdef RRESTORE
2036                 if (!Afile && host)
2037                         i = rmtread(buf, size);
2038                 else
2039 #endif
2040                         i = read(fd, buf, size);                 
2041
2042                 if (i <= 0)
2043                         break; /* EOD or error */
2044                 size -= i;
2045                 if (magtapein)
2046                         break; /* block at a time for mt */
2047                 buf += i;
2048         }
2049         *lengthread = len - size;
2050         return i;
2051 }
2052
2053 void
2054 closemt(void)
2055 {
2056
2057         if (mt < 0)
2058                 return;
2059 #ifdef RRESTORE
2060         if (!Afile && host)
2061                 rmtclose();
2062         else
2063 #endif
2064                 (void) close(mt);
2065 }
2066
2067 static void
2068 setmagtapein(void) {
2069         struct mtget mt_stat;
2070         static int done = 0;
2071         if (done)
2072                 return;
2073         done = 1;
2074         if (!pipein) {
2075                 /* need to know if input is really from a tape */
2076 #ifdef RRESTORE
2077                 if (host)
2078                         magtapein = !lflag;
2079                 else
2080 #endif
2081                         magtapein = ioctl(mt, MTIOCGET, (char *)&mt_stat) == 0;
2082         }
2083
2084         Vprintf(stdout,"Input is from a %s %s\n",
2085                         host ? "remote" : "local",
2086                         magtapein ? "tape" :
2087                         Vflag ? "multi-volume (no tape)" : "file/pipe");
2088 }
2089
2090 /*
2091  * Read the next block from the tape.
2092  * Check to see if it is one of several vintage headers.
2093  * If it is an old style header, convert it to a new style header.
2094  * If it is not any valid header, return an error.
2095  */
2096 static int
2097 gethead(struct s_spcl *buf)
2098 {
2099         readtape((char *)buf);
2100         return converthead(buf);
2101 }
2102
2103 static int
2104 converthead(struct s_spcl *buf)
2105 {
2106         int32_t i;
2107         union {
2108                 quad_t  qval;
2109                 int32_t val[2];
2110         } qcvt;
2111         union u_ospcl {
2112                 char dummy[TP_BSIZE];
2113                 struct  s_ospcl {
2114                         int32_t c_type;
2115                         int32_t c_date;
2116                         int32_t c_ddate;
2117                         int32_t c_volume;
2118                         int32_t c_tapea;
2119                         u_int16_t c_inumber;
2120                         int32_t c_magic;
2121                         int32_t c_checksum;
2122                         struct odinode {
2123                                 u_int16_t odi_mode;
2124                                 u_int16_t odi_nlink;
2125                                 u_int16_t odi_uid;
2126                                 u_int16_t odi_gid;
2127                                 int32_t odi_size;
2128                                 int32_t odi_rdev;
2129                                 char    odi_addr[36];
2130                                 int32_t odi_atime;
2131                                 int32_t odi_mtime;
2132                                 int32_t odi_ctime;
2133                         } c_dinode;
2134                         int32_t c_count;
2135                         char    c_fill[256];
2136                 } s_ospcl;
2137         } u_ospcl;
2138
2139         if (!cvtflag) {
2140                 if (buf->c_magic != NFS_MAGIC) {
2141                         if (swabi(buf->c_magic) != NFS_MAGIC)
2142                                 return (FAIL);
2143                         if (!Bcvt) {
2144                                 Vprintf(stdout, "Note: Doing Byte swapping\n");
2145                                 Bcvt = 1;
2146                         }
2147                 }
2148                 if (checksum((int *)buf) == FAIL)
2149                         return (FAIL);
2150                 if (Bcvt)
2151                         swabst((u_char *)"8i4s31i528bi192b3i", (u_char *)buf);
2152                 goto good;
2153         }
2154         memcpy(&u_ospcl.s_ospcl, buf, TP_BSIZE);
2155         memset((char *)buf, 0, (long)TP_BSIZE);
2156         buf->c_type = u_ospcl.s_ospcl.c_type;
2157         buf->c_date = u_ospcl.s_ospcl.c_date;
2158         buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
2159         buf->c_volume = u_ospcl.s_ospcl.c_volume;
2160         buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
2161         buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
2162         buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
2163         buf->c_magic = u_ospcl.s_ospcl.c_magic;
2164         buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
2165         buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
2166         buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
2167         buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
2168         buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
2169         buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
2170 #if defined(__linux__) || defined(sunos)
2171         buf->c_dinode.di_atime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_atime;
2172         buf->c_dinode.di_mtime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime;
2173         buf->c_dinode.di_ctime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime;
2174 #else   /* __linux__ || sunos */
2175         buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
2176         buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
2177         buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
2178 #endif  /* __linux__ || sunos */
2179         buf->c_count = u_ospcl.s_ospcl.c_count;
2180         memmove(buf->c_addr, u_ospcl.s_ospcl.c_fill, (long)256);
2181         if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
2182             checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
2183                 return(FAIL);
2184         buf->c_magic = NFS_MAGIC;
2185
2186 good:
2187         if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
2188             (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
2189                 qcvt.qval = buf->c_dinode.di_size;
2190                 if (qcvt.val[0] || qcvt.val[1]) {
2191                         Vprintf(stdout, "Note: Doing Quad swapping\n");
2192                         Qcvt = 1;
2193                 }
2194         }
2195         if (Qcvt) {
2196                 qcvt.qval = buf->c_dinode.di_size;
2197                 i = qcvt.val[1];
2198                 qcvt.val[1] = qcvt.val[0];
2199                 qcvt.val[0] = i;
2200                 buf->c_dinode.di_size = qcvt.qval;
2201         }
2202         readmapflag = 0;
2203
2204         switch (buf->c_type) {
2205
2206         case TS_CLRI:
2207         case TS_BITS:
2208                 /*
2209                  * Have to patch up missing information in bit map headers
2210                  */
2211                 buf->c_inumber = 0;
2212                 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
2213                 if (buf->c_count > TP_NINDIR)
2214                         readmapflag = 1;
2215                 else 
2216                         for (i = 0; i < buf->c_count; i++)
2217                                 buf->c_addr[i]++;
2218                 break;
2219
2220         case TS_TAPE:
2221                 if ((buf->c_flags & DR_NEWINODEFMT) == 0)
2222                         oldinofmt = 1;
2223                 /* fall through */
2224         case TS_END:
2225                 buf->c_inumber = 0;
2226                 if (buf->c_flags & DR_INODEINFO) {
2227                         memcpy(volinfo, buf->c_inos, TP_NINOS * sizeof(dump_ino_t));
2228                         if (Bcvt)
2229                                 swabst((u_char *)"128i", (u_char *)volinfo);
2230                 }
2231                 break;
2232
2233         case TS_INODE:
2234         case TS_ADDR:
2235                 break;
2236
2237         default:
2238                 panic("gethead: unknown inode type %d\n", buf->c_type);
2239                 break;
2240         }
2241         /*
2242          * If we are restoring a filesystem with old format inodes,
2243          * copy the uid/gid to the new location.
2244          */
2245         if (oldinofmt) {
2246                 buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
2247                 buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
2248         }
2249         if (dflag)
2250                 accthdr(buf);
2251         return(GOOD);
2252 }
2253
2254 static void
2255 converttapebuf(struct tapebuf *tpb)
2256 {
2257         if (Bcvt) {
2258                 struct tb {
2259                         unsigned int    length:28;
2260                         unsigned int    flags:3;
2261                         unsigned int    compressed:1;
2262                 } tb;
2263                 swabst((u_char *)"i", (u_char *)tpb);
2264                 memcpy(&tb, tpb, 4);    
2265                 tpb->length = tb.length;
2266                 tpb->flags = tb.flags;
2267                 tpb->compressed = tb.compressed;
2268         }
2269 }
2270
2271 /*
2272  * Check that a header is where it belongs and predict the next header
2273  */
2274 static void
2275 accthdr(struct s_spcl *header)
2276 {
2277         static dump_ino_t previno = 0x7fffffff;
2278         static int prevtype;
2279         static long predict;
2280         long blks, i;
2281
2282         if (header->c_type == TS_TAPE) {
2283                 fprintf(stderr, "Volume header (%s inode format) ",
2284                     oldinofmt ? "old" : "new");
2285                 if (header->c_firstrec)
2286                         fprintf(stderr, "begins with record %d",
2287                                 header->c_firstrec);
2288                 fprintf(stderr, "\n");
2289                 previno = 0x7fffffff;
2290                 return;
2291         }
2292         if (previno == 0x7fffffff)
2293                 goto newcalc;
2294         switch (prevtype) {
2295         case TS_BITS:
2296                 fprintf(stderr, "Dumped inodes map header");
2297                 break;
2298         case TS_CLRI:
2299                 fprintf(stderr, "Used inodes map header");
2300                 break;
2301         case TS_INODE:
2302                 fprintf(stderr, "File header, ino %lu", (unsigned long)previno);
2303                 break;
2304         case TS_ADDR:
2305                 fprintf(stderr, "File continuation header, ino %ld", (long)previno);
2306                 break;
2307         case TS_END:
2308                 fprintf(stderr, "End of tape header");
2309                 break;
2310         }
2311         if (predict != blksread - 1)
2312                 fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
2313                         predict, blksread - 1);
2314         fprintf(stderr, "\n");
2315 newcalc:
2316         blks = 0;
2317         if (header->c_type != TS_END)
2318                 for (i = 0; i < header->c_count; i++)
2319                         if (readmapflag || header->c_addr[i] != 0)
2320                                 blks++;
2321         predict = blks;
2322         blksread = 0;
2323         prevtype = header->c_type;
2324         previno = header->c_inumber;
2325 }
2326
2327 /*
2328  * Find an inode header.
2329  * Complain if had to skip, and complain is set.
2330  */
2331 static void
2332 findinode(struct s_spcl *header)
2333 {
2334         static long skipcnt = 0;
2335         long i;
2336         char buf[TP_BSIZE];
2337
2338         curfile.name = "<name unknown>";
2339         curfile.action = UNKNOWN;
2340         curfile.dip = NULL;
2341         curfile.ino = 0;
2342         do {
2343                 if (header->c_magic != NFS_MAGIC) {
2344                         skipcnt++;
2345                         while (gethead(header) == FAIL ||
2346                             header->c_date != dumpdate)
2347                                 skipcnt++;
2348                 }
2349                 switch (header->c_type) {
2350
2351                 case TS_ADDR:
2352                         /*
2353                          * Skip up to the beginning of the next record
2354                          */
2355                         for (i = 0; i < header->c_count; i++)
2356                                 if (header->c_addr[i])
2357                                         readtape(buf);
2358                         while (gethead(header) == FAIL ||
2359                             header->c_date != dumpdate)
2360                                 skipcnt++;
2361                         break;
2362
2363                 case TS_INODE:
2364                         curfile.dip = &header->c_dinode;
2365                         curfile.ino = header->c_inumber;
2366                         break;
2367
2368                 case TS_END:
2369                         curfile.ino = maxino;
2370                         break;
2371
2372                 case TS_CLRI:
2373                         curfile.name = "<file removal list>";
2374                         break;
2375
2376                 case TS_BITS:
2377                         curfile.name = "<file dump list>";
2378                         break;
2379
2380                 case TS_TAPE:
2381                         panic("unexpected tape header\n");
2382                         /* NOTREACHED */
2383
2384                 default:
2385                         panic("unknown tape header type %d\n", spcl.c_type);
2386                         /* NOTREACHED */
2387
2388                 }
2389         } while (header->c_type == TS_ADDR);
2390         if (skipcnt > 0)
2391 #ifdef USE_QFA
2392                 if (!noresyncmesg)
2393 #endif
2394                         fprintf(stderr, "resync restore, skipped %ld blocks\n",
2395                                 skipcnt);
2396         skipcnt = 0;
2397 }
2398
2399 static int
2400 checksum(int *buf)
2401 {
2402         int i, j;
2403
2404         j = sizeof(union u_spcl) / sizeof(int);
2405         i = 0;
2406         if(!Bcvt) {
2407                 do
2408                         i += *buf++;
2409                 while (--j);
2410         } else {
2411                 /* What happens if we want to read restore tapes
2412                         for a 16bit int machine??? */
2413                 do
2414                         i += swabi(*buf++);
2415                 while (--j);
2416         }
2417
2418         if (i != CHECKSUM) {
2419                 fprintf(stderr, "Checksum error %o, inode %lu file %s\n", i,
2420                         (unsigned long)curfile.ino, curfile.name);
2421                 return(FAIL);
2422         }
2423         return(GOOD);
2424 }
2425
2426 #ifdef RRESTORE
2427 #ifdef __STDC__
2428 #include <stdarg.h>
2429 #else
2430 #include <varargs.h>
2431 #endif
2432
2433 void
2434 #ifdef __STDC__
2435 msg(const char *fmt, ...)
2436 #else
2437 msg(fmt, va_alist)
2438         char *fmt;
2439         va_dcl
2440 #endif
2441 {
2442         va_list ap;
2443 #ifdef __STDC__
2444         va_start(ap, fmt);
2445 #else
2446         va_start(ap);
2447 #endif
2448         (void)vfprintf(stderr, fmt, ap);
2449         va_end(ap);
2450 }
2451 #endif /* RRESTORE */
2452
2453 static u_char *
2454 swab16(u_char *sp, int n)
2455 {
2456         char c;
2457
2458         while (--n >= 0) {
2459                 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
2460                 sp += 2;
2461         }
2462         return (sp);
2463 }
2464
2465 static u_char *
2466 swab32(u_char *sp, int n)
2467 {
2468         char c;
2469
2470         while (--n >= 0) {
2471                 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
2472                 c = sp[1]; sp[1] = sp[2]; sp[2] = c;
2473                 sp += 4;
2474         }
2475         return (sp);
2476 }
2477
2478 static u_char *
2479 swab64(u_char *sp, int n)
2480 {
2481         char c;
2482
2483         while (--n >= 0) {
2484                 c = sp[0]; sp[0] = sp[7]; sp[7] = c;
2485                 c = sp[1]; sp[1] = sp[6]; sp[6] = c;
2486                 c = sp[2]; sp[2] = sp[5]; sp[5] = c;
2487                 c = sp[3]; sp[3] = sp[4]; sp[4] = c;
2488                 sp += 8;
2489         }
2490         return (sp);
2491 }
2492
2493 void
2494 swabst(u_char *cp, u_char *sp)
2495 {
2496         int n = 0;
2497
2498         while (*cp) {
2499                 switch (*cp) {
2500                 case '0': case '1': case '2': case '3': case '4':
2501                 case '5': case '6': case '7': case '8': case '9':
2502                         n = (n * 10) + (*cp++ - '0');
2503                         continue;
2504
2505                 case 's': case 'w': case 'h':
2506                         if (n == 0)
2507                                 n = 1;
2508                         sp = swab16(sp, n);
2509                         break;
2510
2511                 case 'i':
2512                         if (n == 0)
2513                                 n = 1;
2514                         sp = swab32(sp, n);
2515                         break;
2516
2517                 case 'l':
2518                         if (n == 0)
2519                                 n = 1;
2520                         sp = swab64(sp, n);
2521                         break;
2522
2523                 default: /* Any other character, like 'b' counts as byte. */
2524                         if (n == 0)
2525                                 n = 1;
2526                         sp += n;
2527                         break;
2528                 }
2529                 cp++;
2530                 n = 0;
2531         }
2532 }
2533
2534 static u_int
2535 swabi(u_int x)
2536 {
2537         swabst((u_char *)"i", (u_char *)&x);
2538         return (x);
2539 }
2540
2541 #if 0
2542 static u_long
2543 swabl(u_long x)
2544 {
2545         swabst((u_char *)"l", (u_char *)&x);
2546         return (x);
2547 }
2548 #endif
2549
2550 #ifdef USE_QFA
2551 /*
2552  * get the current position of the tape
2553  */
2554 int
2555 GetTapePos(long long *pos)
2556 {
2557         int err = 0;
2558
2559 #ifdef RDUMP
2560         if (host) {
2561                 *pos = (long long) rmtseek(0, SEEK_CUR);
2562                 err = *pos < 0;
2563         }
2564         else
2565 #endif
2566         {
2567         if (magtapein) {
2568                 long mtpos;
2569                 *pos = 0;
2570                 err = (ioctl(mt, MTIOCPOS, &mtpos) < 0);
2571                 *pos = (long long)mtpos;
2572         }
2573         else {
2574                 *pos = LSEEK(mt, 0, SEEK_CUR);
2575                 err = (*pos < 0);
2576         }
2577         }
2578         if (err) {
2579                 err = errno;
2580                 fprintf(stdout, "[%ld] error: %d (getting tapepos: %lld)\n", 
2581                         (unsigned long)getpid(), err, *pos);
2582                 return err;
2583         }
2584         return err;
2585 }
2586
2587 typedef struct mt_pos {
2588         short    mt_op;
2589         int      mt_count;
2590 } MTPosRec, *MTPosPtr;
2591
2592 /*
2593  * go to specified position on tape
2594  */
2595 int
2596 GotoTapePos(long long pos)
2597 {
2598         int err = 0;
2599
2600 #ifdef RDUMP
2601         if (host)
2602                 err = (rmtseek(pos, SEEK_SET) < 0);
2603         else
2604 #endif
2605         {
2606         if (magtapein) {
2607                 struct mt_pos buf;
2608                 buf.mt_op = MTSEEK;
2609                 buf.mt_count = (int) pos;
2610                 err = (ioctl(mt, MTIOCTOP, &buf) < 0);
2611         }
2612         else {
2613                 pos = LSEEK(mt, pos, SEEK_SET);
2614                 err = (pos < 0);
2615         }
2616         }
2617         if (err) {
2618                 err = errno;
2619                 fprintf(stdout, "[%ld] error: %d (setting tapepos: %lld)\n", 
2620                         (unsigned long)getpid(), err, pos);
2621                 return err;
2622         }
2623         return err;
2624 }
2625
2626 /*
2627  * read next data from tape to re-sync
2628  */
2629 void
2630 ReReadFromTape(void)
2631 {
2632         FLUSHTAPEBUF();
2633         noresyncmesg = 1;
2634         if (gethead(&spcl) == FAIL) {
2635 #ifdef DEBUG_QFA
2636                 fprintf(stdout, "DEBUG 1 gethead failed\n");
2637 #endif
2638         }
2639         findinode(&spcl);
2640         noresyncmesg = 0;
2641 }
2642
2643 void
2644 ReReadInodeFromTape(dump_ino_t theino)
2645 {
2646         long cntloop = 0;
2647
2648         FLUSHTAPEBUF();
2649         noresyncmesg = 1;
2650         do {
2651                 cntloop++;
2652                 gethead(&spcl);
2653         } while (!(spcl.c_inumber == theino && spcl.c_type == TS_INODE && spcl.c_date == dumpdate) && (cntloop < ntrec));
2654 #ifdef DEBUG_QFA
2655         fprintf(stderr, "%ld reads\n", cntloop);
2656         if (cntloop == ntrec) {
2657                 fprintf(stderr, "DEBUG: bufsize %d\n", bufsize);
2658                 fprintf(stderr, "DEBUG: ntrec %ld\n", ntrec);
2659         }
2660 #endif
2661         findinode(&spcl);
2662         noresyncmesg = 0;
2663 }
2664 #endif /* USE_QFA */
2665
2666 void
2667 RequestVol(long tnum)
2668 {
2669         FLUSHTAPEBUF();
2670         getvol(tnum);
2671 }