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