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