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