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