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