Imported Upstream version 0.4b43
[debian/dump] / 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.99 2010/06/11 11:19:17 stelian Exp $";
46 #endif /* not lint */
47
48 #include <config.h>
49 #include <compatlfs.h>
50 #include <sys/types.h>
51 #include <errno.h>
52 #include <compaterr.h>
53 #include <system.h>
54 #include <setjmp.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <unistd.h>
59
60 #include <sys/param.h>
61 #include <sys/file.h>
62 #include <sys/mtio.h>
63 #include <sys/stat.h>
64 #include <sys/socket.h>
65 #include <sys/un.h>
66
67 #ifdef  __linux__
68 #include <sys/time.h>
69 #include <time.h>
70 #ifdef HAVE_EXT2FS_EXT2_FS_H
71 #include <ext2fs/ext2_fs.h>
72 #else
73 #include <linux/ext2_fs.h>
74 #endif
75 #include <ext2fs/ext2fs.h>
76 #include <bsdcompat.h>
77 #else   /* __linux__ */
78 #ifdef sunos
79 #define quad_t int64_t
80 #include <sys/time.h>
81 #include <sys/fcntl.h>
82 #include <bsdcompat.h>
83 #else
84 #include <ufs/ufs/dinode.h>
85 #endif
86 #endif  /* __linux__ */
87 #ifdef DUMP_MACOSX
88 #include "darwin.h"
89 #endif
90 #include <protocols/dumprestore.h>
91
92 #ifdef HAVE_ZLIB
93 #include <zlib.h>
94 #endif /* HAVE_ZLIB */
95
96 #ifdef HAVE_BZLIB
97 #include <bzlib.h>
98 #endif /* HAVE_BZLIB */
99
100 #ifdef HAVE_LZO
101 #include <minilzo.h>
102 #endif /* HAVE_LZO */
103
104 #include "restore.h"
105 #include "extern.h"
106 #include "pathnames.h"
107
108 #ifdef USE_QFA
109 int             noresyncmesg = 0;
110 #endif /* USE_QFA */
111 static long     fssize = MAXBSIZE;
112 static int      mt = -1;
113 int             pipein = 0;
114 static int      magtapein = 0;          /* input is from magtape */
115 static char     magtape[MAXPATHLEN];
116 static char     magtapeprefix[MAXPATHLEN];
117 static int      blkcnt;
118 static int      numtrec;
119 static char     *tapebuf;               /* input buffer for read */
120 static int      bufsize;                /* buffer size without prefix */
121 static char     *tbufptr = NULL;        /* active tape buffer */
122 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
123 static char     *comprbuf;              /* uncompress work buf */
124 static size_t   comprlen;               /* size including prefix */
125 #endif
126 static union    u_spcl endoftapemark;
127 static long     blksread;               /* blocks read since last header */
128 static long     tpblksread = 0;         /* TP_BSIZE blocks read */
129 static long     tapesread;
130 static sigjmp_buf       restart;
131 static int      gettingfile = 0;        /* restart has a valid frame */
132 char            *host = NULL;
133
134 static int      ofile;
135 static char     *map;
136 static char     lnkbuf[MAXPATHLEN + 1];
137 static int      pathlen;
138
139 int             oldinofmt;      /* old inode format conversion required */
140 int             Bcvt;           /* Swap Bytes (for CCI or sun) */
141 static int      Qcvt;           /* Swap quads (for sun) */
142
143 #define FLUSHTAPEBUF()  blkcnt = ntrec + 1
144
145 static void      accthdr __P((struct s_spcl *));
146 static int       checksum __P((int *));
147 static void      findinode __P((struct s_spcl *));
148 static void      findtapeblksize __P((void));
149 static int       gethead __P((struct s_spcl *));
150 static int       converthead __P((struct s_spcl *));
151 static void      converttapebuf __P((struct tapebuf *));
152 static void      readtape __P((char *));
153 static void      setdumpnum __P((void));
154 #ifdef DUMP_MACOSX
155 static void      xtrfilefinderinfo __P((char *, size_t));
156 #endif
157
158 static u_int     swabi __P((u_int));
159 #if 0
160 static u_long    swabl __P((u_long));
161 #endif
162 static u_char   *swab64 __P((u_char *, int));
163 static u_char   *swab32 __P((u_char *, int));
164 static u_char   *swab16 __P((u_char *, int));
165 static void      terminateinput __P((void));
166 static void      xtrfile __P((char *, size_t));
167 static void      xtrlnkfile __P((char *, size_t));
168 static void      xtrlnkskip __P((char *, size_t));
169 static void      xtrmap __P((char *, size_t));
170 static void      xtrmapskip __P((char *, size_t));
171 static void      xtrskip __P((char *, size_t));
172 static void      xtrxattr __P((char *, size_t));
173 static void      setmagtapein __P((void));
174 static int       extractattr __P((char *));
175 static void      compareattr __P((char *));
176
177 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
178 static void     newcomprbuf __P((int));
179 static void     (*readtape_func) __P((char *));
180 static void     readtape_set __P((char *));
181 static void     readtape_uncompr __P((char *));
182 static void     readtape_comprfile __P((char *));
183 static void     readtape_comprtape __P((char *));
184 static char     *decompress_tapebuf __P((struct tapebuf *, int));
185 static void     msg_read_error __P((char *));
186 #endif
187 static int      read_a_block __P((int, char *, size_t, long *));
188 #define PREFIXSIZE      sizeof(struct tapebuf)
189
190 #define COMPARE_ONTHEFLY 1
191
192 #if COMPARE_ONTHEFLY
193 static int      ifile;          /* input file for compare */
194 static int      cmperror;       /* compare error */
195 static void     xtrcmpfile __P((char *, size_t));
196 static void     xtrcmpskip __P((char *, size_t));
197 #endif
198
199 static int readmapflag;
200 static int readingmaps;         /* set to 1 while reading the maps */
201
202 static char xattrbuf[XATTR_MAXSIZE];
203 static int xattrlen;
204
205 #ifdef DUMP_MACOSX
206 static DumpFinderInfo   gFndrInfo;
207 #endif
208
209 /*
210  * Set up an input source. This is called from main.c before setup() is.
211  */
212 void
213 setinput(char *source)
214 {
215         int i;
216         char *n;
217
218         FLUSHTAPEBUF();
219         if (bflag)
220                 newtapebuf(ntrec);
221         else
222                 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
223         terminal = stdin;
224
225 #ifdef RRESTORE
226         if ((n = strchr(source, ':'))) {
227                 for (i = 0; i < (n - source); i++) {
228                         if (source[i] == '/')
229                                 break;
230                 }
231                 if (source[i] != '/') {
232                         host = source;
233                         source = strchr(host, ':');
234                         *source++ = '\0';
235                         if (rmthost(host) == 0)
236                                 exit(1);
237                 }
238         } else
239 #endif
240         if (strcmp(source, "-") == 0) {
241                 /*
242                  * Since input is coming from a pipe we must establish
243                  * our own connection to the terminal.
244                  */
245                 terminal = fopen(_PATH_TTY, "r");
246                 if (terminal == NULL) {
247                         warn("cannot open %s", _PATH_TTY);
248                         terminal = fopen(_PATH_DEVNULL, "r");
249                         if (terminal == NULL)
250                                 err(1, "cannot open %s", _PATH_DEVNULL);
251                 }
252                 pipein++;
253         }
254         setuid(getuid());       /* no longer need or want root privileges */
255         if (Mflag) {
256                 strncpy(magtapeprefix, source, MAXPATHLEN);
257                 magtapeprefix[MAXPATHLEN-1] = '\0';
258                 snprintf(magtape, MAXPATHLEN, "%s%03d", source, 1);
259         }
260         else
261                 strncpy(magtape, source, MAXPATHLEN);
262         magtape[MAXPATHLEN - 1] = '\0';
263 }
264
265 void
266 newtapebuf(long size)
267 {
268         static int tapebufsize = -1;
269
270         ntrec = size;
271         bufsize = ntrec * TP_BSIZE;
272         if (size <= tapebufsize)
273                 return;
274         if (tapebuf != NULL)
275                 free(tapebuf);
276         tapebuf = malloc(size * TP_BSIZE + sizeof(struct tapebuf));
277         if (tapebuf == NULL)
278                 errx(1, "Cannot allocate space for tape buffer");
279         tapebufsize = size;
280 }
281
282 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
283 static void
284 newcomprbuf(int size)
285 {
286         size_t buf_size = (size+1) * TP_BSIZE + sizeof(struct tapebuf);
287         if (buf_size <= comprlen)
288                 return;
289         comprlen = buf_size;
290         if (comprbuf != NULL)
291                 free(comprbuf);
292         comprbuf = malloc(comprlen);
293         if (comprbuf == NULL)
294                 errx(1, "Cannot allocate space for decompress buffer");
295 }
296 #endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */
297
298 /*
299  * Verify that the tape drive can be accessed and
300  * that it actually is a dump tape.
301  */
302 void
303 setup(void)
304 {
305         int i, j, *ip, bot_code;
306         struct STAT stbuf;
307         char *temptape;
308
309         Vprintf(stdout, "Verify tape and initialize maps\n");
310         if (Afile == NULL && bot_script) {
311                 msg("Launching %s\n", bot_script);
312                 bot_code = system_command(bot_script, magtape, 1);
313                 if (bot_code != 0 && bot_code != 1) {
314                         msg("Restore aborted by the beginning of tape script\n");
315                         exit(1);
316                 }
317         }
318
319         if (Afile)
320                 temptape = Afile;
321         else
322                 temptape = magtape;
323
324 #ifdef RRESTORE
325         if (!Afile && host)
326                 mt = rmtopen(temptape, O_RDONLY);
327         else
328 #endif
329         if (pipein)
330                 mt = 0;
331         else
332                 mt = OPEN(temptape, O_RDONLY, 0);
333         if (mt < 0)
334                 err(1, "%s", temptape);
335         if (!Afile) {
336                 volno = 1;
337                 setmagtapein();
338                 setdumpnum();
339         }
340 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
341         readtape_func = readtape_set;
342 #if defined(HAVE_LZO)
343         if (lzo_init() != LZO_E_OK) {
344           msg("internal error - lzo_init failed \n");
345           exit(1);
346         }
347 #endif
348 #endif
349         FLUSHTAPEBUF();
350         findtapeblksize();
351         cvtflag = 0;
352         if (gethead(&spcl) == FAIL) {
353                 blkcnt--; /* push back this block */
354                 blksread--;
355                 tpblksread--;
356                 cvtflag++;
357                 if (gethead(&spcl) == FAIL)
358                         errx(1, "Tape is not a dump tape");
359                 fprintf(stderr, "Converting to new file system format.\n");
360         }
361
362         if (zflag) {
363                 fprintf(stderr, "Dump tape is compressed.\n");
364 #if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB) && !defined(HAVE_LZO)
365                 errx(1,"This restore version doesn't support decompression");
366 #endif /* !HAVE_ZLIB && !HAVE_BZLIB */
367         }
368         if (pipein) {
369                 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
370                 endoftapemark.s_spcl.c_type = TS_END;
371                 ip = (int *)&endoftapemark;
372                 j = sizeof(union u_spcl) / sizeof(int);
373                 i = 0;
374                 do
375                         i += *ip++;
376                 while (--j);
377                 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
378         }
379         if (vflag || command == 't' || command == 'C')
380                 printdumpinfo();
381 #ifdef USE_QFA
382         if (tapeposflag && (unsigned long)spcl.c_date != qfadumpdate)
383                 errx(1, "different QFA/dumpdates detected\n");
384 #endif
385         if (filesys[0] == '\0') {
386                 char *dirptr;
387                 strncpy(filesys, spcl.c_filesys, NAMELEN);
388                 filesys[NAMELEN - 1] = '\0';
389                 dirptr = strstr(filesys, " (dir");
390                 if (dirptr != NULL)
391                         *dirptr = '\0';
392         }
393         dumptime = spcl.c_ddate;
394         dumpdate = spcl.c_date;
395         if (STAT(".", &stbuf) < 0)
396                 err(1, "cannot stat .");
397         if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE )
398                 fssize = TP_BSIZE;
399         if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
400                 fssize = stbuf.st_blksize;
401         if (((fssize - 1) & fssize) != 0)
402                 errx(1, "bad block size %ld", fssize);
403         if (spcl.c_volume != 1)
404                 errx(1, "Tape is not volume 1 of the dump");
405         if (gethead(&spcl) == FAIL) {
406                 Dprintf(stdout, "header read failed at %ld blocks\n", (long)blksread);
407                 panic("no header after volume mark!\n");
408         }
409         readingmaps = 1;
410         findinode(&spcl);
411         if (spcl.c_type != TS_CLRI)
412                 errx(1, "Cannot find file removal list");
413         maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
414         map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
415         if (map == NULL)
416                 errx(1, "no memory for active inode map");
417         usedinomap = map;
418         curfile.action = USING;
419         getfile(xtrmap, xtrmapskip);
420         while (spcl.c_type == TS_ADDR) {
421                 /* Recompute maxino and the map */
422                 dump_ino_t oldmaxino = maxino;
423                 maxino += (spcl.c_count * TP_BSIZE * NBBY) + 1;
424                 resizemaps(oldmaxino, maxino);
425                 map = usedinomap;
426
427                 spcl.c_dinode.di_size = spcl.c_count * TP_BSIZE;
428                 getfile(xtrmap, xtrmapskip);
429         }
430         Dprintf(stdout, "maxino = %lu\n", (unsigned long)maxino);
431         if (spcl.c_type != TS_BITS) {
432                 if (spcl.c_type == TS_END) {
433                         msg("Cannot find file dump list, assuming empty tape\n");
434                         exit(0);
435                 }
436                 errx(1, "Cannot find file dump list");
437         }
438         map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
439         if (map == (char *)NULL)
440                 errx(1, "no memory for file dump list");
441         dumpmap = map;
442         curfile.action = USING;
443         getfile(xtrmap, xtrmapskip);
444         while (spcl.c_type == TS_ADDR) {
445                 spcl.c_dinode.di_size = spcl.c_count * TP_BSIZE;
446                 getfile(xtrmap, xtrmapskip);
447         }
448         /*
449          * If there may be whiteout entries on the tape, pretend that the
450          * whiteout inode exists, so that the whiteout entries can be
451          * extracted.
452          */
453         if (oldinofmt == 0)
454                 SETINO(WINO, dumpmap);
455         readingmaps = 0;
456         findinode(&spcl);
457 }
458
459 /*
460  * Prompt user to load a new dump volume.
461  * "Nextvol" is the next suggested volume to use.
462  * This suggested volume is enforced when doing full
463  * or incremental restores, but can be overridden by
464  * the user when only extracting a subset of the files.
465  */
466 void
467 getvol(long nextvol)
468 {
469         long newvol = 0, wantnext = 0, i;
470         long saved_blksread = 0, saved_tpblksread = 0;
471         union u_spcl tmpspcl;
472 #       define tmpbuf tmpspcl.s_spcl
473         char buf[TP_BSIZE];
474         int haderror = 0, bot_code = 1;
475
476         if (nextvol == 1) {
477                 tapesread = 0;
478                 gettingfile = 0;
479                 blksread = 0;
480         }
481         if (pipein) {
482                 if (nextvol != 1)
483                         panic("Changing volumes on pipe input?\n");
484                 if (volno == 1)
485                         return;
486                 goto gethdr;
487         }
488         saved_blksread = blksread;
489         saved_tpblksread = tpblksread;
490 #if defined(USE_QFA) && defined(sunos)
491         if (createtapeposflag || tapeposflag) 
492                 close(fdsmtc);
493 #endif
494 again:
495         if (pipein)
496                 exit(1); /* pipes do not get a second chance */
497         if (aflag || curfile.action != SKIP) {
498                 newvol = nextvol;
499                 wantnext = 1;
500         } else {
501                 newvol = 0;
502                 wantnext = 0;
503         }
504         while (newvol <= 0) {
505                 if (tapesread == 0) {
506                         fprintf(stderr, "%s%s%s%s%s",
507                             "You have not read any volumes yet.\n",
508                             "Unless you know which volume your",
509                             " file(s) are on you should start\n",
510                             "with the last volume and work",
511                             " towards the first.\n");
512                 } else {
513                         fprintf(stderr, "You have read volumes");
514                         strcpy(buf, ": ");
515                         for (i = 1; i < 32; i++)
516                                 if (tapesread & (1 << i)) {
517                                         fprintf(stderr, "%s%ld", buf, (long)i);
518                                         strcpy(buf, ", ");
519                                 }
520                         fprintf(stderr, "\n");
521                 }
522                 do      {
523                         fprintf(stderr, "Specify next volume # (none if no more volumes): ");
524                         (void) fflush(stderr);
525                         if (!fgets(buf, TP_BSIZE, terminal))
526                                 break;
527                 } while (!feof(terminal) && buf[0] == '\n');
528                 if (feof(terminal))
529                         exit(1);
530                 if (!strcmp(buf, "none\n")) {
531                         terminateinput();
532                         return;
533                 }
534                 newvol = atoi(buf);
535                 if (newvol <= 0) {
536                         fprintf(stderr,
537                             "Volume numbers are positive numerics\n");
538                 }
539         }
540         if (newvol == volno) {
541                 tapesread |= 1 << volno;
542 #if defined(USE_QFA) && defined(sunos)
543                 if (createtapeposflag || tapeposflag) {
544                         if (OpenSMTCmt(magtape) < 0) {
545                                 volno = -1;
546                                 haderror = 1;
547                                 goto again;
548                         }
549                 }
550 #endif  /* USE_QFA */
551                 return;
552         }
553         closemt();
554
555         /* 
556          * if using an archive file, reset its name so readtape()
557          * could properly use remote access.
558          */
559         Afile = NULL;
560
561         if (Mflag) {
562                 snprintf(magtape, MAXPATHLEN, "%s%03ld", magtapeprefix, newvol);
563                 magtape[MAXPATHLEN - 1] = '\0';
564         }
565         if (bot_script && !haderror) {
566                 msg("Launching %s\n", bot_script);
567                 bot_code = system_command(bot_script, magtape, newvol);
568                 if (bot_code != 0 && bot_code != 1) {
569                         msg("Restore aborted by the beginning of tape script\n");
570                         exit(1);
571                 }
572         }
573         if (haderror || (bot_code && !Mflag)) {
574                 haderror = 0;
575                 if (compare_errors)
576                         fprintf(stderr, "%d compare errors so far\n", compare_errors);
577 #ifdef sunos
578                 fprintf(stderr, "Mount volume %ld\n", (long)newvol);
579 #else
580                 fprintf(stderr, "Mount tape volume %ld\n", (long)newvol);
581 #endif
582                 fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
583 #ifdef sunos
584                 fprintf(stderr, "then enter volume name (default: %s) ", magtape);
585 #else
586                 fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
587 #endif
588                 (void) fflush(stderr);
589                 if (fgets(buf, TP_BSIZE, terminal))
590                         exit(1);
591                 if (feof(terminal))
592                         exit(1);
593                 if (!strcmp(buf, "none\n")) {
594                         terminateinput();
595                         return;
596                 }
597                 if (buf[0] != '\n') {
598                         char *pos;
599                         (void) strncpy(magtape, buf, sizeof(magtape));
600                         magtape[sizeof(magtape) - 1] = '\0';
601                         if ((pos = strchr(magtape, '\n'))) 
602                                 magtape[pos - magtape] = '\0';
603                 }
604         }
605 #if defined(USE_QFA) && defined(sunos)
606         if (createtapeposflag || tapeposflag) {
607                 if (OpenSMTCmt(magtape) < 0) {
608                         volno = -1;
609                         haderror = 1;
610                         goto again;
611                 }
612         }
613 #endif  /* USE_QFA */
614 #ifdef RRESTORE
615         if (host)
616                 mt = rmtopen(magtape, O_RDONLY);
617         else
618 #endif
619                 mt = OPEN(magtape, O_RDONLY, 0);
620
621         if (mt == -1) {
622                 fprintf(stderr, "Cannot open %s\n", magtape);
623                 volno = -1;
624                 haderror = 1;
625                 goto again;
626         }
627 gethdr:
628         setmagtapein();
629 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
630         readtape_func = readtape_set;
631 #endif
632         volno = newvol;
633         setdumpnum();
634         FLUSHTAPEBUF();
635         findtapeblksize();
636         if (gethead(&tmpbuf) == FAIL) {
637                 Dprintf(stdout, "header read failed at %ld blocks\n", (long)blksread);
638                 fprintf(stderr, "tape is not dump tape\n");
639                 volno = 0;
640                 haderror = 1;
641                 blksread = saved_blksread;
642                 tpblksread = saved_tpblksread;
643                 goto again;
644         }
645         if (tmpbuf.c_volume != volno) {
646                 fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
647                 volno = 0;
648                 haderror = 1;
649                 blksread = saved_blksread;
650                 tpblksread = saved_tpblksread;
651                 goto again;
652         }
653         if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
654                 fprintf(stderr, "Wrong dump date\n\tgot: %s",
655 #ifdef sunos
656                         ctime(&tmpbuf.c_date));
657 #else
658                         ctime4(&tmpbuf.c_date));
659 #endif
660                 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
661                 volno = 0;
662                 haderror = 1;
663                 blksread = saved_blksread;
664                 tpblksread = saved_tpblksread;
665                 goto again;
666         }
667         tapesread |= 1 << volno;
668         /*
669          * If continuing from the previous volume, skip over any
670          * blocks read already at the end of the previous volume.
671          *
672          * If coming to this volume at random, skip to the beginning
673          * of the next record.
674          */
675         if (zflag) {
676                 fprintf(stderr, "Dump tape is compressed.\n");
677 #if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB) && !defined(HAVE_LZO)
678                 errx(1,"This restore version doesn't support decompression");
679 #endif /* !HAVE_ZLIB && !HAVE_BZLIB */
680         }
681         Dprintf(stdout, "read %ld recs, tape starts with %ld\n",
682                 tpblksread - 1, (long)tmpbuf.c_firstrec);
683         if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
684                 if (!wantnext) {
685                         tpblksread = tmpbuf.c_firstrec + 1;
686                         for (i = tmpbuf.c_count; i > 0; i--)
687                                 readtape(buf);
688                 } else if (tmpbuf.c_firstrec > 0 &&
689                            tmpbuf.c_firstrec < tpblksread - 1) {
690                         /*
691                          * -1 since we've read the volume header
692                          */
693                         i = tpblksread - tmpbuf.c_firstrec - 1;
694                         Dprintf(stderr, "Skipping %ld duplicate record%s.\n",
695                                 (long)i, i > 1 ? "s" : "");
696                         while (--i >= 0)
697                                 readtape(buf);
698                 }
699         }
700         if (curfile.action == USING) {
701                 if (volno == 1)
702                         panic("active file into volume 1\n");
703                 return;
704         }
705         /*
706          * Skip up to the beginning of the next record
707          */
708         if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
709                 for (i = tmpbuf.c_count; i > 0; i--)
710                         readtape(buf);
711         (void) gethead(&spcl);
712         findinode(&spcl);
713         if (gettingfile) {
714                 gettingfile = 0;
715                 siglongjmp(restart, 1);
716         }
717 }
718
719 /*
720  * Handle unexpected EOF.
721  */
722 static void
723 terminateinput(void)
724 {
725
726         if (gettingfile && curfile.action == USING) {
727                 printf("Warning: %s %s\n",
728                     "End-of-input encountered while extracting", curfile.name);
729         }
730         curfile.name = "<name unknown>";
731         curfile.action = UNKNOWN;
732         curfile.dip = NULL;
733         curfile.ino = maxino;
734         if (gettingfile) {
735                 gettingfile = 0;
736                 siglongjmp(restart, 1);
737         }
738 }
739
740 /*
741  * handle multiple dumps per tape by skipping forward to the
742  * appropriate one.
743  */
744 static void
745 setdumpnum(void)
746 {
747         struct mtop tcom;
748
749         if (dumpnum == 1 || volno != 1)
750                 return;
751         if (pipein)
752                 errx(1, "Cannot have multiple dumps on pipe input");
753         tcom.mt_op = MTFSF;
754         tcom.mt_count = dumpnum - 1;
755 #ifdef RRESTORE
756         if (host) {
757                 if (rmtioctl(MTFSF, dumpnum - 1) < 0) {
758                         fprintf(stderr, "rmtioctl MTFSF: %s\n", strerror(errno));
759             exit(1);
760                 }
761         } else
762 #endif
763                 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0) {
764                         fprintf(stderr, "rmtioctl MTFSF: %s\n", strerror(errno));
765                         exit(1);
766                         /* warn("ioctl MTFSF"); */
767                 }
768 }
769
770 void
771 printdumpinfo(void)
772 {
773 #ifdef sunos
774         Vprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
775         Vprintf(stdout, "Dumped from: %s",
776             (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
777         if (spcl.c_host[0] == '\0')
778                 return;
779         Vprintf(stdout, "Level %d dump of %s on %s:%s\n",
780                 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
781         Vprintf(stdout, "Label: %s\n", spcl.c_label);
782 #else
783         fprintf(stdout, "Dump   date: %s", ctime4(&spcl.c_date));
784         fprintf(stdout, "Dumped from: %s",
785             (spcl.c_ddate == 0) ? "the epoch\n" : ctime4(&spcl.c_ddate));
786         if (spcl.c_host[0] == '\0')
787                 return;
788         fprintf(stdout, "Level %d dump of %s on %s:%s\n",
789                 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
790         fprintf(stdout, "Label: %s\n", spcl.c_label);
791 #endif
792 }
793
794 void 
795 printvolinfo(void)
796 {
797         int i;
798
799         if (volinfo[1] == ROOTINO) {
800                 printf("Starting inode numbers by volume:\n");
801                 for (i = 1; i < (int)TP_NINOS && volinfo[i] != 0; ++i)
802                         printf("\tVolume %d: %lu\n", i, (unsigned long)volinfo[i]);
803         }
804 }
805
806
807 int
808 extractfile(struct entry *ep, int doremove)
809 {
810         unsigned int flags;
811         mode_t mode;
812         struct timeval timep[2];
813         char *name = myname(ep);
814
815         /* If removal is requested (-r mode) do remove it unless
816          * we are extracting a metadata only inode */
817         if (spcl.c_flags & DR_METAONLY) {
818                 Vprintf(stdout, "file %s is metadata only\n", name);
819         }
820         else {
821                 if (doremove) {
822                         removeleaf(ep);
823                         ep->e_flags &= ~REMOVED;
824                 }
825         }
826
827         curfile.name = name;
828         curfile.action = USING;
829 #if defined(__linux__) || defined(sunos)
830         timep[0].tv_sec = curfile.dip->di_atime.tv_sec;
831         timep[0].tv_usec = curfile.dip->di_atime.tv_usec;
832         timep[1].tv_sec = curfile.dip->di_mtime.tv_sec;
833         timep[1].tv_usec = curfile.dip->di_mtime.tv_usec;
834 #else   /* __linux__ || sunos */
835         timep[0].tv_sec = curfile.dip->di_atime;
836         timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
837         timep[1].tv_sec = curfile.dip->di_mtime;
838         timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
839 #endif  /* __linux__ */
840         mode = curfile.dip->di_mode;
841         flags = curfile.dip->di_flags;
842         switch (mode & IFMT) {
843
844         default:
845                 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
846                 skipfile();
847                 return (FAIL);
848
849         case IFSOCK:
850         {
851                 uid_t luid = curfile.dip->di_uid;
852                 gid_t lgid = curfile.dip->di_gid;
853
854                 Vprintf(stdout, "extract socket %s\n", name);
855                 skipfile();
856                 if (Nflag)
857                         return (GOOD);
858                 if (! (spcl.c_flags & DR_METAONLY)) {
859                         int sk;
860                         struct sockaddr_un addr;
861
862                         if (uflag)
863                                 (void)unlink(name);
864
865                         if ((sk = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
866                                 warn("%s: cannot create socket", name);
867                                 return (FAIL);
868                         }
869                         addr.sun_family = AF_UNIX;
870                         strcpy(addr.sun_path, name);
871                         if (bind(sk, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
872                                 warn("%s: cannot create socket", name);
873                                 return (FAIL);
874                         }
875                         close(sk);
876                 }
877                 if (chown(name, luid, lgid) < 0)
878                         warn("%s: chown", name);
879                 if (chmod(name, mode) < 0)
880                         warn("%s: chmod", name);
881                 extractattr(name);
882                 utimes(name, timep);
883                 if (flags)
884 #ifdef  __linux__
885                         (void) lsetflags(name, flags);
886 #else
887 #ifdef sunos
888                         {
889                         warn("%s: cannot call chflags", name);
890                         /* (void) chflags(name, flags); */
891                         }
892 #else
893                         (void) chflags(name, flags);
894 #endif
895 #endif
896                 return (GOOD);
897         }
898
899         case IFDIR:
900         {
901                 int ret;
902                 if (mflag) {
903                         if (ep == NULL || ep->e_flags & EXTRACT)
904                                 panic("unextracted directory %s\n", name);
905                         skipfile();
906                         return (GOOD);
907                 }
908                 Vprintf(stdout, "extract dir %s\n", name);
909                 ret = genliteraldir(name, curfile.ino);
910                 extractattr(name);
911                 return ret;
912         }
913
914         case IFLNK:
915         {
916 #ifdef HAVE_LCHOWN
917                 uid_t luid = curfile.dip->di_uid;
918                 gid_t lgid = curfile.dip->di_gid;
919 #endif
920                 if (! (spcl.c_flags & DR_METAONLY)) {
921                         lnkbuf[0] = '\0';
922                         pathlen = 0;
923                         getfile(xtrlnkfile, xtrlnkskip);
924                         if (pathlen == 0) {
925                                 Vprintf(stdout,
926                                     "%s: zero length symbolic link (ignored)\n", name);
927                                 return (GOOD);
928                         }
929                         if (linkit(lnkbuf, name, SYMLINK) == FAIL)
930                                 return (FAIL);
931                 }
932                 else
933                         skipfile();
934
935 #ifdef HAVE_LCHOWN
936                 if (lchown(name, luid, lgid) < 0)
937                         warn("%s: lchown", name);
938 #endif
939                 extractattr(name);
940                 return (GOOD);
941         }
942
943         case IFIFO:
944         {
945                 uid_t luid = curfile.dip->di_uid;
946                 gid_t lgid = curfile.dip->di_gid;
947
948                 Vprintf(stdout, "extract fifo %s\n", name);
949                 skipfile();
950                 if (Nflag)
951                         return (GOOD);
952                 if (! (spcl.c_flags & DR_METAONLY)) {
953                         if (uflag && !Nflag)
954                                 (void)unlink(name);
955                         if (mkfifo(name, mode) < 0) {
956                                 warn("%s: cannot create fifo", name);
957                                 return (FAIL);
958                         }
959                 }
960                 if (chown(name, luid, lgid) < 0)
961                         warn("%s: chown", name);
962                 if (chmod(name, mode) < 0)
963                         warn("%s: chmod", name);
964                 extractattr(name);
965                 utimes(name, timep);
966                 if (flags)
967 #ifdef  __linux__
968                         (void) lsetflags(name, flags);
969 #else
970 #ifdef sunos
971                         {
972                         warn("%s: cannot call chflags", name);
973                         /* (void) chflags(name, flags); */
974                         }
975 #else
976                         (void) chflags(name, flags);
977 #endif
978 #endif
979                 return (GOOD);
980         }
981         case IFCHR:
982         case IFBLK:
983         {
984                 uid_t luid = curfile.dip->di_uid;
985                 gid_t lgid = curfile.dip->di_gid;
986                 int lrdev = (int)curfile.dip->di_rdev;
987
988                 Vprintf(stdout, "extract special file %s\n", name);
989                 skipfile();
990                 if (Nflag)
991                         return (GOOD);
992                 if (! (spcl.c_flags & DR_METAONLY)) {
993                         if (uflag)
994                                 (void)unlink(name);
995                         if (mknod(name, mode, lrdev) < 0) {
996                                 warn("%s: cannot create special file", name);
997                                 return (FAIL);
998                         }
999                 }
1000                 if (chown(name, luid, lgid) < 0)
1001                         warn("%s: chown", name);
1002                 if (chmod(name, mode) < 0)
1003                         warn("%s: chmod", name);
1004                 extractattr(name);
1005                 utimes(name, timep);
1006                 if (flags)
1007 #ifdef  __linux__
1008                         {
1009                         warn("%s: lsetflags called on a special file", name);
1010                         (void) lsetflags(name, flags);
1011                         }
1012 #else
1013 #ifdef sunos
1014                         {
1015                         warn("%s: cannot call chflags on a special file", name);
1016                         /* (void) chflags(name, flags); */
1017                         }
1018 #else
1019                         {
1020                         warn("%s: chflags called on a special file", name);
1021                         (void) chflags(name, flags);
1022                         }
1023 #endif
1024 #endif
1025                 return (GOOD);
1026         }
1027         case IFREG:
1028         {
1029                 uid_t luid = curfile.dip->di_uid;
1030                 gid_t lgid = curfile.dip->di_gid;
1031
1032                 Vprintf(stdout, "extract file %s\n", name);
1033                 if (Nflag) {
1034                         skipfile();
1035                         return (GOOD);
1036                 }
1037                 if (! (spcl.c_flags & DR_METAONLY)) {
1038                         if (uflag)
1039                                 (void)unlink(name);
1040                         if ((ofile = OPEN(name, O_WRONLY | O_CREAT | O_TRUNC,
1041                             0666)) < 0) {
1042                                 warn("%s: cannot create file", name);
1043                                 skipfile();
1044                                 return (FAIL);
1045                         }
1046                         getfile(xtrfile, xtrskip);
1047                         (void) close(ofile);
1048                 }
1049                 else
1050                         skipfile();
1051                 if (chown(name, luid, lgid) < 0)
1052                         warn("%s: chown", name);
1053                 if (chmod(name, mode) < 0)
1054                         warn("%s: chmod", name);
1055                 extractattr(name);
1056                 utimes(name, timep);
1057                 if (flags)
1058 #ifdef  __linux__
1059                         (void) lsetflags(name, flags);
1060 #else
1061 #ifdef sunos
1062                         {
1063                         warn("%s: cannot call chflags", name);
1064                         /* (void) chflags(name, flags); */
1065                         }
1066 #else
1067                         (void) chflags(name, flags);
1068 #endif
1069 #endif
1070                 return (GOOD);
1071         }
1072         }
1073         /* NOTREACHED */
1074 }
1075
1076 static int
1077 extractattr(char *path)
1078 {
1079         while (spcl.c_flags & DR_EXTATTRIBUTES) {
1080                 switch (spcl.c_extattributes) {
1081                 case EXT_MACOSFNDRINFO:
1082 #ifdef DUMP_MACOSX
1083                         (void)extractfinderinfoufs(path);
1084 #else
1085                         msg("MacOSX not supported in this version, skipping\n");
1086                         skipfile();
1087 #endif
1088                         break;
1089                 case EXT_MACOSRESFORK:
1090 #ifdef DUMP_MACOSX
1091                         (void)extractresourceufs(path);
1092 #else
1093                         msg("MacOSX not supported in this version, skipping\n");
1094                         skipfile();
1095 #endif
1096                         break;
1097                 case EXT_XATTR: {
1098                         char xattr[XATTR_MAXSIZE];
1099                         
1100                         if (readxattr(xattr) == GOOD) {
1101                                 xattr_extract(path, xattr);
1102                                 break;
1103                         }
1104                 }
1105                 default:
1106                         msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes);
1107                         skipfile();
1108                         break;
1109                 }
1110         }
1111         return GOOD;
1112 }
1113
1114 #ifdef DUMP_MACOSX
1115 int
1116 extractfinderinfoufs(char *name)
1117 {
1118         int err;
1119         char                    oFileRsrc[MAXPATHLEN];
1120         int flags;
1121         mode_t mode;
1122         struct timeval timep[2];
1123         u_int32_t       uid;
1124         u_int32_t       gid;
1125         char    path[MAXPATHLEN], fname[MAXPATHLEN];
1126
1127         curfile.name = name;
1128         curfile.action = USING;
1129         timep[0].tv_sec = curfile.dip->di_atime.tv_sec;
1130         timep[0].tv_usec = curfile.dip->di_atime.tv_usec;
1131         timep[1].tv_sec = curfile.dip->di_mtime.tv_sec;
1132         timep[1].tv_usec = curfile.dip->di_mtime.tv_usec;
1133         mode = curfile.dip->di_mode;
1134         flags = curfile.dip->di_flags;
1135         uid = curfile.dip->di_uid;
1136         gid =  curfile.dip->di_gid;
1137
1138         switch (mode & IFMT) {
1139
1140         default:
1141                 fprintf(stderr, "%s: (extr. finfoufs) unknown file mode 0%o\n", name, mode);
1142                 skipfile();
1143                 return (FAIL);
1144
1145         case IFDIR:
1146                 fprintf(stderr, "%s: (extr. finfoufs[IFDIR]) unknown file mode 0%o\n", name, mode);
1147                 skipfile();
1148                 return (FAIL);
1149
1150         case IFLNK:
1151                 skipfile();
1152                 return (GOOD);
1153
1154         case IFREG:
1155                 Vprintf(stdout, "extract finderinfo file %s\n", name);
1156                 if (Nflag) {
1157                         skipfile();
1158                         return (GOOD);
1159                 }
1160                 getfile(xtrfilefinderinfo, xtrskip);
1161
1162                 GetPathFile(name, path, fname);
1163                 strcpy(oFileRsrc, path);
1164                 strcat(oFileRsrc, "._");
1165                 strcat(oFileRsrc, fname);
1166
1167                 if ((err = CreateAppleDoubleFileRes(oFileRsrc, &gFndrInfo.fndrinfo,
1168                                 mode, flags, timep, uid, gid)) != 0) {
1169                         fprintf(stderr, "%s: cannot create finderinfo: %s\n",
1170                         name, strerror(errno));
1171                         skipfile();
1172                         return (FAIL);
1173                 }
1174                 return (GOOD);
1175         }
1176         /* NOTREACHED */
1177 }
1178
1179
1180 int
1181 extractresourceufs(char *name)
1182 {
1183         char                    oFileRsrc[MAXPATHLEN];
1184         int flags;
1185         mode_t mode;
1186         struct timeval timep[2];
1187         char    path[MAXPATHLEN], fname[MAXPATHLEN];
1188         ASDHeaderPtr    hp;
1189         ASDEntryPtr     ep;
1190         u_long  loff;
1191          u_int32_t      uid;
1192         u_int32_t       gid;
1193         u_int64_t       di_size;
1194         char            *p;
1195         char            buf[1024];
1196
1197         curfile.name = name;
1198         curfile.action = USING;
1199         timep[0].tv_sec = curfile.dip->di_atime.tv_sec;
1200         timep[0].tv_usec = curfile.dip->di_atime.tv_usec;
1201         timep[1].tv_sec = curfile.dip->di_mtime.tv_sec;
1202         timep[1].tv_usec = curfile.dip->di_mtime.tv_usec;
1203         mode = curfile.dip->di_mode;
1204         flags = curfile.dip->di_flags;
1205         uid = curfile.dip->di_uid;
1206         gid =  curfile.dip->di_gid;
1207         di_size = curfile.dip->di_size;
1208
1209         switch (mode & IFMT) {
1210
1211         default:
1212                 fprintf(stderr, "%s: (extr. resufs) unknown file mode 0%o\n", name, mode);
1213                 skipfile();
1214                 return (FAIL);
1215
1216         case IFDIR:
1217                 fprintf(stderr, "%s: (extr. resufs [IFDIR]) unknown file mode 0%o\n", name, mode);
1218                 skipfile();
1219                 return (FAIL);
1220
1221         case IFLNK:
1222                 skipfile();
1223                 return (GOOD);
1224
1225         case IFREG:
1226                 Vprintf(stdout, "extract resource file %s\n", name);
1227                 if (Nflag) {
1228                         skipfile();
1229                         return (GOOD);
1230                 }
1231
1232                 GetPathFile(name, path, fname);
1233                 strcpy(oFileRsrc, path);
1234                 strcat(oFileRsrc, "._");
1235                 strcat(oFileRsrc, fname);
1236
1237                 if ((ofile = open(oFileRsrc, O_RDONLY, 0)) < 0) {
1238                         fprintf(stderr, "%s: cannot read finderinfo: %s\n",
1239                             name, strerror(errno));
1240                         skipfile();
1241                         return (FAIL);
1242                 }
1243                 read(ofile, buf, 70);
1244                 (void) close(ofile);
1245                 p = buf;
1246                 hp = (ASDHeaderPtr)p;
1247                 /* the header */
1248                 hp->entries++;
1249                 p += sizeof(ASDHeader) - CORRECT;
1250                 ep = (ASDEntryPtr)p;
1251                 /* the finderinfo entry */
1252                 ep->offset += sizeof(ASDEntry);
1253                 loff = ep->offset;
1254
1255                 p += sizeof(ASDEntry);
1256                 /* the finderinfo data */
1257                 bcopy(p, p + sizeof(ASDEntry), INFOLEN);
1258                 ep = (ASDEntryPtr)p;
1259                 /* the new resourcefork entry */
1260                 ep->entryID = EntryRSRCFork;
1261                 ep->offset = loff + INFOLEN;
1262                 ep->len = di_size;
1263                 /* write the new appledouble entries to the file */
1264                 if ((ofile = open(oFileRsrc, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
1265                         fprintf(stderr, "%s: cannot create resource file: %s\n",
1266                             name, strerror(errno));
1267                         skipfile();
1268                         return (FAIL);
1269                 }
1270                 write(ofile, buf, 70 + sizeof(ASDEntry));
1271                 /* and add the resource data from tape */
1272                 getfile(xtrfile, xtrskip);
1273
1274                 if (fchown(ofile, uid, gid) < 0)
1275                         warn("%s: fchown", name);
1276                 if (fchmod(ofile, mode) < 0)
1277                         warn("%s: fchmod", name);
1278                 (void) close(ofile);
1279                 utimes(oFileRsrc, timep);
1280                 (void) lsetflags(oFileRsrc, flags);
1281                 return (GOOD);
1282         }
1283         /* NOTREACHED */
1284 }
1285 #endif /* DUMP_MACOSX */
1286
1287 int
1288 readxattr(char *buffer)
1289 {
1290         if (dflag)
1291                 msg("reading EA data for inode %lu\n", curfile.ino);
1292
1293         curfile.name = "EA block";
1294         if (curfile.dip->di_size > XATTR_MAXSIZE) {
1295                 fprintf(stderr, "EA size too big (%ld)", (long)curfile.dip->di_size);
1296                 skipfile();
1297                 return (FAIL);
1298         }
1299
1300         memset(xattrbuf, 0, XATTR_MAXSIZE);
1301         xattrlen = 0;
1302
1303         /*
1304          * ugly hack: cope with invalid spcl.c_addr[] records written by
1305          * old versions of dump.
1306          */
1307         readmapflag = 1;
1308
1309         getfile(xtrxattr, xtrnull);
1310
1311         readmapflag = 0;
1312
1313         memcpy(buffer, xattrbuf, XATTR_MAXSIZE);
1314
1315         return (GOOD);
1316 }
1317
1318 /*
1319  * skip over bit maps on the tape
1320  */
1321 void
1322 skipmaps(void)
1323 {
1324
1325         while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
1326                 skipfile();
1327 }
1328
1329 /*
1330  * skip over a file on the tape
1331  */
1332 void
1333 skipfile(void)
1334 {
1335
1336         curfile.action = SKIP;
1337         getfile(xtrnull, xtrnull);
1338 }
1339
1340 /*
1341  * skip over any extended attributes.
1342  */
1343 void
1344 skipxattr(void)
1345 {
1346
1347         while (spcl.c_flags & DR_EXTATTRIBUTES)
1348                 skipfile();
1349 }
1350
1351 /*
1352  * Extract a file from the tape.
1353  * When an allocated block is found it is passed to the fill function;
1354  * when an unallocated block (hole) is found, a zeroed buffer is passed
1355  * to the skip function.
1356  */
1357 void
1358 getfile(void (*fill) __P((char *, size_t)), void (*skip) __P((char *, size_t)))
1359 {
1360         int i;
1361         volatile int curblk = 0;
1362         volatile quad_t size = spcl.c_dinode.di_size;
1363         volatile int last_write_was_hole = 0;
1364         quad_t origsize = size;
1365         static char clearedbuf[MAXBSIZE];
1366         char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
1367         char junk[TP_BSIZE];
1368
1369         if (spcl.c_type == TS_END)
1370                 panic("ran off end of tape\n");
1371         if (spcl.c_magic != NFS_MAGIC)
1372                 panic("not at beginning of a file\n");
1373         if (!gettingfile && setjmp(restart) != 0)
1374                 return;
1375         gettingfile++;
1376 loop:
1377         for (i = 0; i < spcl.c_count; i++) {
1378                 if (readmapflag || spcl.c_addr[i]) {
1379                         readtape(&buf[curblk++][0]);
1380                         if (curblk == fssize / TP_BSIZE) {
1381                                 (*fill)((char *)buf, (size_t)(size > TP_BSIZE ?
1382                                      fssize : (curblk - 1) * TP_BSIZE + size));
1383                                 curblk = 0;
1384                                 last_write_was_hole = 0;
1385                         }
1386                 } else {
1387                         if (curblk > 0) {
1388                                 (*fill)((char *)buf, (size_t)(size > TP_BSIZE ?
1389                                      curblk * TP_BSIZE :
1390                                      (curblk - 1) * TP_BSIZE + size));
1391                                 curblk = 0;
1392                         }
1393                         (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
1394                                 TP_BSIZE : size));
1395                         last_write_was_hole = 1;
1396                 }
1397                 if ((size -= TP_BSIZE) <= 0) {
1398                         for (i++; i < spcl.c_count; i++)
1399                                 if (readmapflag || spcl.c_addr[i])
1400                                         readtape(junk);
1401                         break;
1402                 }
1403         }
1404         while (gethead(&spcl) != GOOD) {
1405                 fprintf(stderr, "Incorrect block for %s at %ld blocks\n",
1406                         curfile.name, (long)blksread);
1407         }
1408         if (size > 0) {
1409                 if (spcl.c_type == TS_ADDR)
1410                         goto loop;
1411                 Dprintf(stdout,
1412                         "Missing address (header) block for %s at %ld blocks\n",
1413                         curfile.name, (long)blksread);
1414         }
1415         if (curblk > 0) {
1416                 (*fill)((char *)buf, (size_t)((curblk * TP_BSIZE) + size));
1417                 last_write_was_hole = 0;
1418         }
1419         if (size > 0) {
1420                 fprintf(stderr, "Missing blocks at the end of %s, assuming hole\n", curfile.name);
1421                 while (size > 0) {
1422                         size_t skp = size > TP_BSIZE ? TP_BSIZE : size;
1423                         (*skip)(clearedbuf, skp);
1424                         size -= skp;
1425                 }
1426                 last_write_was_hole = 1;
1427         }
1428         if (last_write_was_hole) {
1429                 if (FTRUNCATE(ofile, origsize) < 0)
1430                         warn("%s: ftruncate", curfile.name);
1431         }
1432         if (!readingmaps) 
1433                 findinode(&spcl);
1434         gettingfile = 0;
1435 }
1436
1437 /*
1438  * Write out the next block of a file.
1439  */
1440 static void
1441 xtrfile(char *buf, size_t size)
1442 {
1443
1444         if (Nflag)
1445                 return;
1446         if (write(ofile, buf, (int) size) == -1)
1447                 err(1, "write error extracting inode %lu, name %s\nwrite",
1448                         (unsigned long)curfile.ino, curfile.name);
1449 }
1450
1451 #ifdef DUMP_MACOSX
1452 static void
1453 xtrfilefinderinfo(char *buf, size_t size)
1454 {
1455         bcopy(buf, &gFndrInfo, size);
1456 }
1457 #endif /* DUMP_MACOSX */
1458
1459 /*
1460  * Skip over a hole in a file.
1461  */
1462 /* ARGSUSED */
1463 static void
1464 xtrskip(UNUSED(char *buf), size_t size)
1465 {
1466
1467         if (LSEEK(ofile, (OFF_T)size, SEEK_CUR) == -1)
1468                 err(1, "seek error extracting inode %lu, name %s\nlseek",
1469                         (unsigned long)curfile.ino, curfile.name);
1470 }
1471
1472 /*
1473  * Collect the next block of a symbolic link.
1474  */
1475 static void
1476 xtrlnkfile(char *buf, size_t size)
1477 {
1478
1479         pathlen += size;
1480         if (pathlen > MAXPATHLEN) {
1481                 buf[size - 1] = '\0';
1482                 errx(1, "symbolic link name: %s->%s%s; too long %d",
1483                     curfile.name, lnkbuf, buf, pathlen);
1484         }
1485         (void) strcat(lnkbuf, buf);
1486         lnkbuf[pathlen] = '\0';
1487 }
1488
1489 /*
1490  * Skip over a hole in a symbolic link (should never happen).
1491  */
1492 /* ARGSUSED */
1493 static void
1494 xtrlnkskip(UNUSED(char *buf), UNUSED(size_t size))
1495 {
1496
1497         errx(1, "unallocated block in symbolic link %s", curfile.name);
1498 }
1499
1500 /*
1501  * Collect the next block of a bit map.
1502  */
1503 static void
1504 xtrmap(char *buf, size_t size)
1505 {
1506
1507         memmove(map, buf, size);
1508         map += size;
1509 }
1510
1511 /*
1512  * Skip over a hole in a bit map (should never happen).
1513  */
1514 /* ARGSUSED */
1515 static void
1516 xtrmapskip(UNUSED(char *buf), size_t size)
1517 {
1518
1519         panic("hole in map\n");
1520         map += size;
1521 }
1522
1523 /*
1524  * Noop, when an extraction function is not needed.
1525  */
1526 /* ARGSUSED */
1527 void
1528 xtrnull(UNUSED(char *buf), UNUSED(size_t size))
1529 {
1530
1531         return;
1532 }
1533
1534 #if COMPARE_ONTHEFLY
1535 /*
1536  * Compare the next block of a file.
1537  */
1538 static void
1539 xtrcmpfile(char *buf, size_t size)
1540 {
1541         static char cmpbuf[MAXBSIZE];
1542
1543         if (cmperror)
1544                 return;
1545         
1546         if (read(ifile, cmpbuf, size) != (ssize_t)size) {
1547                 fprintf(stderr, "%s: size has changed.\n", 
1548                         curfile.name);
1549                 cmperror = 1;
1550                 return;
1551         }
1552         
1553         if (memcmp(buf, cmpbuf, size) != 0) {
1554                 fprintf(stderr, "%s: tape and disk copies are different\n",
1555                         curfile.name);
1556                 cmperror = 1;
1557                 return;
1558         }
1559 }
1560
1561 /*
1562  * Skip over a hole in a file.
1563  */
1564 static void
1565 xtrcmpskip(UNUSED(char *buf), size_t size)
1566 {
1567         static char cmpbuf[MAXBSIZE];
1568         int i;
1569
1570         if (cmperror)
1571                 return;
1572         
1573         if (read(ifile, cmpbuf, size) != (ssize_t)size) {
1574                 fprintf(stderr, "%s: size has changed.\n", 
1575                         curfile.name);
1576                 cmperror = 1;
1577                 return;
1578         }
1579
1580         for (i = 0; i < (int)size; ++i)
1581                 if (cmpbuf[i] != '\0') {
1582                         fprintf(stderr, "%s: tape and disk copies are different\n",
1583                                 curfile.name);
1584                         cmperror = 1;
1585                         return;
1586                 }
1587 }
1588 #endif /* COMPARE_ONTHEFLY */
1589
1590 static void
1591 xtrxattr(char *buf, size_t size)
1592 {
1593         if (xattrlen + size > XATTR_MAXSIZE) {
1594                 fprintf(stderr, "EA size too big (%ld)", (long)xattrlen + size);
1595                 return;
1596         }
1597         memcpy(xattrbuf + xattrlen, buf, size);
1598         xattrlen += size;
1599 }
1600
1601 #if !COMPARE_ONTHEFLY
1602 static int
1603 do_cmpfiles(int fd_tape, int fd_disk, OFF_T size)
1604 {
1605         static char buf_tape[BUFSIZ];
1606         static char buf_disk[BUFSIZ];
1607         ssize_t n_tape;
1608         ssize_t n_disk;
1609
1610         while (size > 0) {
1611                 if ((n_tape = read(fd_tape, buf_tape, sizeof(buf_tape))) < 1) {
1612                         close(fd_tape), close(fd_disk);
1613                         panic("do_cmpfiles: unexpected EOF[1]");
1614                 }
1615                 if ((n_disk = read(fd_disk, buf_disk, sizeof(buf_tape))) < 1) {
1616                         close(fd_tape), close(fd_disk);
1617                         panic("do_cmpfiles: unexpected EOF[2]");
1618                 }
1619                 if (n_tape != n_disk) {
1620                         close(fd_tape), close(fd_disk);
1621                         panic("do_cmpfiles: sizes different!");
1622                 }
1623                 if (memcmp(buf_tape, buf_disk, (size_t)n_tape) != 0) return (1);
1624                 size -= n_tape;
1625         }
1626         return (0);
1627 }
1628
1629 /* for debugging compare problems */
1630 #undef COMPARE_FAIL_KEEP_FILE
1631
1632 static
1633 #ifdef COMPARE_FAIL_KEEP_FILE
1634 /* return true if tapefile should be unlinked after compare */
1635 int
1636 #else
1637 void
1638 #endif
1639 cmpfiles(char *tapefile, char *diskfile, struct STAT *sbuf_disk)
1640 {
1641         struct STAT sbuf_tape;
1642         int fd_tape, fd_disk;
1643
1644         if (STAT(tapefile, &sbuf_tape) != 0) {
1645                 panic("can't lstat tmp file %s: %s\n", tapefile,
1646                       strerror(errno));
1647                 do_compare_error;
1648         }
1649
1650         if (sbuf_disk->st_size != sbuf_tape.st_size) {
1651                 fprintf(stderr,
1652                         "%s: size changed from %lld to %lld.\n",
1653                         diskfile, (long long)sbuf_tape.st_size, (long long)sbuf_disk->st_size);
1654                 do_compare_error;
1655 #ifdef COMPARE_FAIL_KEEP_FILE
1656                 return (0);
1657 #else
1658                 return;
1659 #endif
1660         }
1661
1662         if ((fd_tape = OPEN(tapefile, O_RDONLY)) < 0) {
1663                 panic("can't open %s: %s\n", tapefile, strerror(errno));
1664                 do_compare_error;
1665         }
1666         if ((fd_disk = OPEN(diskfile, O_RDONLY)) < 0) {
1667                 close(fd_tape);
1668                 panic("can't open %s: %s\n", diskfile, strerror(errno));
1669                 do_compare_error;
1670         }
1671
1672         if (do_cmpfiles(fd_tape, fd_disk, sbuf_tape.st_size)) {
1673                 fprintf(stderr, "%s: tape and disk copies are different\n",
1674                         diskfile);
1675                 close(fd_tape);
1676                 close(fd_disk);
1677                 do_compare_error;
1678 #ifdef COMPARE_FAIL_KEEP_FILE
1679                 /* rename the file to live in /tmp */
1680                 /* rename `tapefile' to /tmp/<basename of diskfile> */
1681                 {
1682                         char *p = strrchr(diskfile, '/');
1683                         char newname[MAXPATHLEN];
1684                         if (!p) {
1685                                 panic("can't find / in %s\n", diskfile);
1686                         }
1687                         snprintf(newname, sizeof(newname), "%s/debug/%s", tmpdir, p + 1);
1688                         if (rename(tapefile, newname)) {
1689                                 panic("rename from %s to %s failed: %s\n",
1690                                       tapefile, newname,
1691                                       strerror(errno));
1692                         } else {
1693                                 fprintf(stderr, "*** %s saved to %s\n",
1694                                         tapefile, newname);
1695                         }
1696                 }
1697                 
1698                 /* don't unlink the file (it's not there anymore */
1699                 /* anyway) */
1700                 return (0);
1701 #else
1702                 return;
1703 #endif
1704         }
1705         close(fd_tape);
1706         close(fd_disk);
1707 #ifdef COMPARE_FAIL_KEEP_FILE
1708         return (1);
1709 #endif
1710 }
1711 #endif /* !COMPARE_ONTHEFLY */
1712
1713 static void
1714 compareattr(char *name)
1715 {
1716         int xattr_done = 0;
1717         
1718         while (spcl.c_flags & DR_EXTATTRIBUTES) {
1719                 switch (spcl.c_extattributes) {
1720                 case EXT_MACOSFNDRINFO:
1721                         msg("MacOSX not supported for comparision in this version, skipping\n");
1722                         skipfile();
1723                         break;
1724                 case EXT_MACOSRESFORK:
1725                         msg("MacOSX not supported for comparision in this version, skipping\n");
1726                         skipfile();
1727                         break;
1728                 case EXT_XATTR: {
1729                         char xattr[XATTR_MAXSIZE];
1730
1731                         if (readxattr(xattr) == GOOD) {
1732                                 if (xattr_compare(name, xattr) == FAIL)
1733                                         do_compare_error;
1734                                 xattr_done = 1;
1735                         }
1736                         else
1737                                 do_compare_error;
1738                         break;
1739                 }
1740                 default:
1741                         msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes);
1742                         skipfile();
1743                         break;
1744                 }
1745         }
1746         if (!xattr_done && xattr_compare(name, NULL) == FAIL)
1747                 do_compare_error;
1748 }
1749
1750 #if !COMPARE_ONTHEFLY
1751 static char tmpfilename[MAXPATHLEN];
1752 #endif
1753
1754 void
1755 comparefile(char *name)
1756 {
1757         mode_t mode;
1758         uid_t uid;
1759         uid_t gid;
1760         unsigned int flags;
1761         unsigned long newflags;
1762         struct STAT sb;
1763         int r;
1764 #if !COMPARE_ONTHEFLY
1765         static char *tmpfile = NULL;
1766         struct STAT stemp;
1767 #endif
1768         curfile.name = name;
1769         curfile.action = USING;
1770         mode = curfile.dip->di_mode;
1771         flags = curfile.dip->di_flags;
1772         uid = curfile.dip->di_uid;
1773         gid =  curfile.dip->di_gid;
1774
1775         if ((mode & IFMT) == IFSOCK) {
1776                 Vprintf(stdout, "skipped socket %s\n", name);
1777                 skipfile();
1778                 return;
1779         }
1780
1781         if ((r = LSTAT(name, &sb)) != 0) {
1782                 warn("unable to stat %s", name);
1783                 do_compare_error;
1784                 skipfile();
1785                 return;
1786         }
1787
1788         Vprintf(stdout, "comparing %s (size: %lld, mode: 0%o)\n", name,
1789                 (long long)sb.st_size, mode);
1790
1791         if (sb.st_mode != mode) {
1792                 fprintf(stderr, "%s: mode changed from 0%o to 0%o.\n",
1793                         name, mode & 07777, sb.st_mode & 07777);
1794                 do_compare_error;
1795         }
1796         if (sb.st_uid != uid) {
1797                 fprintf(stderr, "%s: uid changed from %d to %d.\n",
1798                         name, uid, sb.st_uid);
1799                 do_compare_error;
1800         }
1801         if (sb.st_gid != gid) {
1802                 fprintf(stderr, "%s: gid changed from %d to %d.\n",
1803                         name, gid, sb.st_gid);
1804                 do_compare_error;
1805         }
1806 #ifdef  __linux__
1807         if (lgetflags(name, &newflags) < 0) {
1808                 if (flags != 0) {
1809                         warn("%s: lgetflags failed", name);
1810                         do_compare_error;
1811                 }
1812         }
1813         else {
1814                 if (newflags != flags) {
1815                         fprintf(stderr, "%s: flags changed from 0x%08x to 0x%08lx.\n",
1816                                 name, flags, newflags);
1817                         do_compare_error;
1818                 }
1819         }
1820 #endif
1821         if (spcl.c_flags & DR_METAONLY) {
1822                 skipfile();
1823                 return;
1824         }
1825         switch (mode & IFMT) {
1826         default:
1827                 skipfile();
1828                 return;
1829
1830         case IFSOCK:
1831                 skipfile();
1832                 return;
1833
1834         case IFDIR:
1835                 skipfile();
1836                 compareattr(name);
1837                 return;
1838
1839         case IFLNK: {
1840                 char lbuf[MAXPATHLEN + 1];
1841                 int lsize;
1842
1843                 if (!(sb.st_mode & S_IFLNK)) {
1844                         fprintf(stderr, "%s: is no longer a symbolic link\n",
1845                                 name);
1846                         do_compare_error;
1847                         return;
1848                 }
1849                 lnkbuf[0] = '\0';
1850                 pathlen = 0;
1851                 getfile(xtrlnkfile, xtrlnkskip);
1852                 if (pathlen == 0) {
1853                         fprintf(stderr,
1854                                 "%s: zero length symbolic link (ignored)\n",
1855                                 name);
1856                         do_compare_error;
1857                         return;
1858                 }
1859                 if ((lsize = readlink(name, lbuf, MAXPATHLEN)) < 0) {
1860                         panic("readlink of %s failed: %s\n", name,
1861                               strerror(errno));
1862                         do_compare_error;
1863                 }
1864                 lbuf[lsize] = 0;
1865                 if (strcmp(lbuf, lnkbuf) != 0) {
1866                         fprintf(stderr,
1867                                 "%s: symbolic link changed from %s to %s.\n",
1868                                 name, lnkbuf, lbuf);
1869                         do_compare_error;
1870                         return;
1871                 }
1872                 compareattr(name);
1873                 return;
1874         }
1875
1876         case IFCHR:
1877         case IFBLK:
1878                 if (!(sb.st_mode & (S_IFCHR|S_IFBLK))) {
1879                         fprintf(stderr, "%s: no longer a special file\n",
1880                                 name);
1881                         do_compare_error;
1882                         skipfile();
1883                         return;
1884                 }
1885
1886                 if (sb.st_rdev != (dev_t)curfile.dip->di_rdev) {
1887                         fprintf(stderr,
1888                                 "%s: device changed from %d,%d to %d,%d.\n",
1889                                 name,
1890                                 major(curfile.dip->di_rdev),
1891                                 minor(curfile.dip->di_rdev),
1892                                 major(sb.st_rdev),
1893                                 minor(sb.st_rdev));
1894                         do_compare_error;
1895                 }
1896                 skipfile();
1897                 compareattr(name);
1898                 return;
1899
1900         case IFREG:
1901 #if COMPARE_ONTHEFLY
1902                 if ((ifile = OPEN(name, O_RDONLY)) < 0) {
1903                         warn("can't open %s", name);
1904                         skipfile();
1905                         do_compare_error;
1906                 }
1907                 else {
1908                         cmperror = 0;
1909                         getfile(xtrcmpfile, xtrcmpskip);
1910                         if (!cmperror) {
1911                                 char c;
1912                                 if (read(ifile, &c, 1) != 0) {
1913                                         fprintf(stderr, "%s: size has changed.\n", 
1914                                                 name);
1915                                         cmperror = 1;
1916                                 }
1917                         }
1918                         if (cmperror)
1919                                 do_compare_error;
1920                         close(ifile);
1921                 }
1922 #else
1923                 if (tmpfile == NULL) {
1924                         /* argument to mktemp() must not be in RO space: */
1925                         snprintf(tmpfilename, sizeof(tmpfilename), "%s/restoreCXXXXXX", tmpdir);
1926                         tmpfile = mktemp(&tmpfilename[0]);
1927                 }
1928                 if ((STAT(tmpfile, &stemp) == 0) && (unlink(tmpfile) != 0)) {
1929                         panic("cannot delete tmp file %s: %s\n",
1930                               tmpfile, strerror(errno));
1931                 }
1932                 if ((ofile = OPEN(tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
1933                         panic("cannot create file temp file %s: %s\n",
1934                               name, strerror(errno));
1935                 }
1936                 getfile(xtrfile, xtrskip);
1937                 (void) close(ofile);
1938 #ifdef COMPARE_FAIL_KEEP_FILE
1939                 if (cmpfiles(tmpfile, name, &sb))
1940                         unlink(tmpfile);
1941 #else
1942                 cmpfiles(tmpfile, name, &sb);
1943                 unlink(tmpfile);
1944 #endif
1945 #endif /* COMPARE_ONTHEFLY */
1946                 compareattr(name);
1947                 return;
1948         }
1949         /* NOTREACHED */
1950 }
1951
1952 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
1953 static void (*readtape_func)(char *) = readtape_set;
1954
1955 /*
1956  * Read TP_BSIZE blocks from the input.
1957  * Handle read errors, and end of media.
1958  * Decompress compressed blocks.
1959  */
1960 static void
1961 readtape(char *buf)
1962 {
1963         (*readtape_func)(buf);  /* call the actual processing routine */
1964 }
1965
1966 /*
1967  * Set function pointer for readtape() routine. zflag and magtapein must
1968  * be correctly set before the first call to readtape().
1969  */
1970 static void
1971 readtape_set(char *buf)
1972 {
1973         if (!zflag) 
1974                 readtape_func = readtape_uncompr;
1975         else {
1976                 newcomprbuf(ntrec);
1977                 if (magtapein)
1978                         readtape_func = readtape_comprtape;
1979                 else
1980                         readtape_func = readtape_comprfile;
1981         }
1982         readtape(buf);
1983 }
1984
1985 #endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */
1986
1987 /*
1988  * This is the original readtape(), it's used for reading uncompressed input.
1989  * Read TP_BSIZE blocks from the input.
1990  * Handle read errors, and end of media.
1991  */
1992 static void
1993 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
1994 readtape_uncompr(char *buf)
1995 #else
1996 readtape(char *buf)
1997 #endif
1998 {
1999         ssize_t rd, newvol, i;
2000         int cnt, seek_failed;
2001
2002         if (blkcnt < numtrec) {
2003                 memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
2004                 blksread++;
2005                 tpblksread++;
2006                 return;
2007         }
2008         tbufptr = tapebuf;
2009         for (i = 0; i < ntrec; i++)
2010                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
2011         if (numtrec == 0)
2012                 numtrec = ntrec;
2013         cnt = ntrec * TP_BSIZE;
2014         rd = 0;
2015 #ifdef USE_QFA
2016         if (createtapeposflag)
2017                 (void)GetTapePos(&curtapepos);
2018 #endif
2019 getmore:
2020 #ifdef RRESTORE
2021         if (!Afile && host)
2022                 i = rmtread(&tapebuf[rd], cnt);
2023         else
2024 #endif
2025                 i = read(mt, &tapebuf[rd], cnt);
2026
2027         /*
2028          * Check for mid-tape short read error.
2029          * If found, skip rest of buffer and start with the next.
2030          */
2031         if (!pipein && numtrec < ntrec && i > 0) {
2032                 Dprintf(stdout, "mid-media short read error.\n");
2033                 numtrec = ntrec;
2034         }
2035         /*
2036          * Handle partial block read.
2037          */
2038         if (pipein && i == 0 && rd > 0)
2039                 i = rd;
2040         else if (i > 0 && i != ntrec * TP_BSIZE) {
2041                 if (pipein) {
2042                         rd += i;
2043                         cnt -= i;
2044                         if (cnt > 0)
2045                                 goto getmore;
2046                         i = rd;
2047                 } else {
2048                         /*
2049                          * Short read. Process the blocks read.
2050                          */
2051                         if (i % TP_BSIZE != 0)
2052                                 Vprintf(stdout,
2053                                     "partial block read: %ld should be %ld\n",
2054                                     (long)i, ntrec * TP_BSIZE);
2055                         numtrec = i / TP_BSIZE;
2056                 }
2057         }
2058         /*
2059          * Handle read error.
2060          */
2061         if (i < 0) {
2062                 fprintf(stderr, "Tape read error while ");
2063                 switch (curfile.action) {
2064                 default:
2065                         fprintf(stderr, "trying to set up tape\n");
2066                         break;
2067                 case UNKNOWN:
2068                         fprintf(stderr, "trying to resynchronize\n");
2069                         break;
2070                 case USING:
2071                         fprintf(stderr, "restoring %s\n", curfile.name);
2072                         break;
2073                 case SKIP:
2074                         fprintf(stderr, "skipping over inode %lu\n",
2075                                 (unsigned long)curfile.ino);
2076                         break;
2077                 }
2078                 if (!yflag && !reply("continue"))
2079                         exit(1);
2080                 i = ntrec * TP_BSIZE;
2081                 memset(tapebuf, 0, (size_t)i);
2082 #ifdef RRESTORE
2083                 if (!Afile && host)
2084                         seek_failed = (rmtseek(i, 1) < 0);
2085                 else
2086 #endif
2087                         seek_failed = (LSEEK(mt, i, SEEK_CUR) == (OFF_T)-1);
2088
2089                 if (seek_failed) {
2090                         warn("continuation failed");
2091                         if (!yflag && !reply("assume end-of-tape and continue"))
2092                                 exit(1);
2093                         i = 0;
2094                 }
2095         }
2096         /*
2097          * Handle end of tape.
2098          */
2099         if (i == 0) {
2100                 Vprintf(stdout, "End-of-tape encountered\n");
2101                 if (!pipein) {
2102                         newvol = volno + 1;
2103                         volno = 0;
2104                         numtrec = 0;
2105                         getvol(newvol);
2106                         readtape(buf);
2107                         return;
2108                 }
2109                 if (rd % TP_BSIZE != 0)
2110                         panic("partial block read: %d should be %d\n",
2111                                 rd, ntrec * TP_BSIZE);
2112                 terminateinput();
2113                 memmove(&tapebuf[rd], &endoftapemark, TP_BSIZE);
2114         }
2115         blkcnt = 0;
2116         memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
2117         blksread++;
2118         tpblksread++;
2119 }
2120
2121 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
2122
2123 /*
2124  * Read a compressed format block from a file or pipe and uncompress it.
2125  * Attempt to handle read errors, and end of file. 
2126  */
2127 static void
2128 readtape_comprfile(char *buf)
2129 {
2130         long rl, size, i, ret;
2131         int newvol; 
2132         struct tapebuf *tpb;
2133
2134         if (blkcnt < numtrec) {
2135                 memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
2136                 blksread++;
2137                 tpblksread++;
2138                 return;
2139         }
2140         /* need to read the next block */
2141         tbufptr = tapebuf;
2142         for (i = 0; i < ntrec; i++)
2143                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
2144         numtrec = ntrec;
2145         tpb = (struct tapebuf *) tapebuf;
2146
2147         /* read the block prefix */
2148         ret = read_a_block(mt, tapebuf, PREFIXSIZE, &rl);
2149         converttapebuf(tpb);
2150
2151         if (Vflag && (ret == 0 || rl < (int)PREFIXSIZE  ||  tpb->length == 0))
2152                 ret = 0;
2153         if (ret <= 0)
2154                 goto readerr;
2155
2156         /* read the data */
2157         size = tpb->length;
2158         if (size > bufsize)  {
2159                 /* something's wrong */
2160                 Vprintf(stdout, "Prefix size error, max size %d, got %ld\n",
2161                         bufsize, size);
2162                 size = bufsize;
2163                 tpb->length = bufsize;
2164         }
2165         ret = read_a_block(mt, tpb->buf, size, &rl);
2166         if (ret <= 0)
2167                 goto readerr;
2168
2169         tbufptr = decompress_tapebuf(tpb, rl + PREFIXSIZE);
2170         if (tbufptr == NULL) {
2171                 msg_read_error("File decompression error while");
2172                 if (!yflag && !reply("continue"))
2173                         exit(1);
2174                 memset(tapebuf, 0, bufsize);
2175                 tbufptr = tapebuf;
2176         }
2177
2178         blkcnt = 0;
2179         memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
2180         blksread++;
2181         tpblksread++;
2182         return;
2183
2184 readerr:
2185         /* Errors while reading from a file or pipe are catastrophic. Since
2186          * there are no block boundaries, it's impossible to bypass the
2187          * block in error and find the start of the next block.
2188          */
2189         if (ret == 0) {
2190                 /* It's possible to have multiple input files using -M
2191                  * and -f file1,file2...
2192                  */
2193                 Vprintf(stdout, "End-of-File encountered\n");
2194                 if (!pipein) {
2195                         newvol = volno + 1;
2196                         volno = 0;
2197                         numtrec = 0;
2198                         getvol(newvol);
2199                         readtape(buf);
2200                         return;
2201                 }
2202         }
2203         msg_read_error("Read error while");
2204         /* if (!yflag && !reply("continue")) */
2205                 exit(1);
2206 }
2207
2208 /*
2209  * Read compressed data from a tape and uncompress it.
2210  * Handle read errors, and end of media.
2211  * Since a tape consists of separate physical blocks, we try
2212  * to recover from errors by repositioning the tape to the next
2213  * block.
2214  */
2215 static void
2216 readtape_comprtape(char *buf)
2217 {
2218         long rl, size, i;
2219         int ret, newvol;
2220         struct tapebuf *tpb;
2221         struct mtop tcom;
2222
2223         if (blkcnt < numtrec) {
2224                 memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
2225                 blksread++;
2226                 tpblksread++;
2227                 return;
2228         }
2229         /* need to read the next block */
2230         tbufptr = tapebuf;
2231         for (i = 0; i < ntrec; i++)
2232                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
2233         numtrec = ntrec;
2234         tpb = (struct tapebuf *) tapebuf;
2235
2236         /* read the block */
2237         size = bufsize + PREFIXSIZE;
2238         ret = read_a_block(mt, tapebuf, size, &rl);
2239         if (ret <= 0)
2240                 goto readerr;
2241
2242         converttapebuf(tpb);
2243         tbufptr = decompress_tapebuf(tpb, rl);
2244         if (tbufptr == NULL) {
2245                 msg_read_error("Tape decompression error while");
2246                 if (!yflag && !reply("continue"))
2247                         exit(1);
2248                 memset(tapebuf, 0, PREFIXSIZE + bufsize);
2249                 tbufptr = tapebuf;
2250         }
2251         goto moverecord;
2252
2253 readerr:
2254         /* Handle errors: EOT switches to the next volume, other errors
2255          * attempt to position the tape to the next block.
2256          */
2257         if (ret == 0) {
2258                 Vprintf(stdout, "End-of-tape encountered\n");
2259                 newvol = volno + 1;
2260                 volno = 0;
2261                 numtrec = 0;
2262                 getvol(newvol);
2263                 readtape(buf);
2264                 return;
2265         }
2266
2267         msg_read_error("Tape read error while");
2268         if (!yflag && !reply("continue"))
2269                 exit(1);
2270         memset(tapebuf, 0, PREFIXSIZE + bufsize);
2271         tbufptr = tapebuf;
2272
2273 #ifdef RRESTORE
2274         if (host)
2275                 rl = rmtioctl(MTFSR, 1);
2276         else
2277 #endif
2278         {
2279                 tcom.mt_op = MTFSR;
2280                 tcom.mt_count = 1;
2281                 rl = ioctl(mt, MTIOCTOP, &tcom);
2282         }
2283
2284         if (rl < 0) {
2285                 warn("continuation failed");
2286                 if (!yflag && !reply("assume end-of-tape and continue"))
2287                         exit(1);
2288                 ret = 0;         /* end of tape */
2289                 goto readerr;
2290         }
2291
2292 moverecord:
2293         blkcnt = 0;
2294         memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
2295         blksread++;
2296         tpblksread++;
2297 }
2298
2299 /*
2300  *  Decompress a struct tapebuf into a buffer. readsize is the size read
2301  *  from the tape/file and is used for error messages. Returns a pointer
2302  *  to the location of the uncompressed buffer or NULL on errors.
2303  *  Adjust numtrec and complain for a short block.
2304  */
2305 static char *
2306 decompress_tapebuf(struct tapebuf *tpbin, int readsize)
2307 {
2308         /* If zflag is on, all blocks have a struct tapebuf prefix */
2309         /* zflag gets set in setup() from the dump header          */
2310         int cresult, blocklen;        
2311         unsigned long worklen;
2312         char *output = NULL,*reason = NULL, *lengtherr = NULL;              
2313        
2314         /* build a length error message */
2315         blocklen = tpbin->length;
2316         if (readsize < blocklen + (int)PREFIXSIZE)
2317                 lengtherr = "short";
2318         else
2319                 if (readsize > blocklen + (int)PREFIXSIZE)
2320                         lengtherr = "long";
2321
2322         worklen = comprlen;
2323         cresult = 1;
2324         if (tpbin->compressed) {
2325                 /* uncompress whatever we read, if it fails, complain later */
2326                 if (tpbin->flags == COMPRESS_ZLIB) {
2327 #ifndef HAVE_ZLIB
2328                         errx(1,"This restore version doesn't support zlib decompression");
2329 #else
2330                         cresult = uncompress(comprbuf, &worklen, 
2331                                              tpbin->buf, blocklen);
2332                         output = comprbuf;
2333                         switch (cresult) {
2334                                 case Z_OK:
2335                                         break;
2336                                 case Z_MEM_ERROR:
2337                                         reason = "not enough memory";
2338                                         break;
2339                                 case Z_BUF_ERROR:
2340                                         reason = "buffer too small";
2341                                         break;
2342                                 case Z_DATA_ERROR:
2343                                         reason = "data error";
2344                                         break;
2345                                 default:
2346                                         reason = "unknown";
2347                         }
2348                         if (cresult == Z_OK)
2349                                 cresult = 1;
2350                         else
2351                                 cresult = 0;
2352 #endif /* HAVE_ZLIB */
2353                 }
2354                 if (tpbin->flags == COMPRESS_BZLIB) {
2355 #ifndef HAVE_BZLIB
2356                         errx(1,"This restore version doesn't support bzlib decompression");
2357 #else
2358                         unsigned int worklen2 = worklen;
2359                         cresult = BZ2_bzBuffToBuffDecompress(
2360                                         comprbuf, &worklen2, 
2361                                         tpbin->buf, blocklen, 0, 0);
2362                         worklen = worklen2;
2363                         output = comprbuf;
2364                         switch (cresult) {
2365                                 case BZ_OK:
2366                                         break;
2367                                 case BZ_MEM_ERROR:
2368                                         reason = "not enough memory";
2369                                         break;
2370                                 case BZ_OUTBUFF_FULL:
2371                                         reason = "buffer too small";
2372                                         break;
2373                                 case BZ_DATA_ERROR:
2374                                 case BZ_DATA_ERROR_MAGIC:
2375                                 case BZ_UNEXPECTED_EOF:
2376                                         reason = "data error";
2377                                         break;
2378                                 default:
2379                                         reason = "unknown";
2380                         }
2381                         if (cresult == BZ_OK)
2382                                 cresult = 1;
2383                         else
2384                                 cresult = 0;
2385 #endif /* HAVE_BZLIB */
2386                 }
2387                 if (tpbin->flags == COMPRESS_LZO) {
2388 #ifndef HAVE_LZO
2389                         errx(1,"This restore version doesn't support lzo decompression");
2390 #else
2391                         lzo_uint worklen2 = worklen;
2392                         cresult = lzo1x_decompress(tpbin->buf, blocklen,
2393                                                    comprbuf, &worklen2, NULL);
2394                         worklen = worklen2;
2395                         output = comprbuf;
2396                         switch (cresult) {
2397                                 case LZO_E_OK:
2398                                         break;
2399                                 case LZO_E_ERROR:
2400                                 case LZO_E_EOF_NOT_FOUND:
2401                                         reason = "data error";
2402                                         break;
2403                                 default:
2404                                         reason = "unknown";
2405                         }
2406                         if (cresult == LZO_E_OK)
2407                                 cresult = 1;
2408                         else
2409                                 cresult = 0;
2410 #endif /* HAVE_LZO */
2411                 }
2412         }
2413         else {
2414                 output = tpbin->buf;
2415                 worklen = blocklen;
2416         }
2417         if (cresult) {
2418                 numtrec = worklen / TP_BSIZE;
2419                 if (worklen % TP_BSIZE != 0)
2420                         reason = "length mismatch";
2421         }
2422         if (reason) {
2423                 if (lengtherr)
2424                         fprintf(stderr, "%s compressed block: %d expected: %lu\n",
2425                                 lengtherr, readsize, (unsigned long)tpbin->length + PREFIXSIZE);
2426                 fprintf(stderr, "decompression error, block %ld: %s\n",
2427                         tpblksread+1, reason);
2428                 if (!cresult)
2429                         output = NULL;
2430         }
2431         return output;
2432 }
2433
2434 /*
2435  * Print an error message for a read error.
2436  * This was exteracted from the original readtape().
2437  */
2438 static void
2439 msg_read_error(char *m)
2440 {
2441         switch (curfile.action) {
2442                 default:
2443                         fprintf(stderr, "%s trying to set up tape\n", m);
2444                         break;
2445                 case UNKNOWN:
2446                         fprintf(stderr, "%s trying to resynchronize\n", m);
2447                         break;
2448                 case USING:
2449                         fprintf(stderr, "%s restoring %s\n", m, curfile.name);
2450                         break;
2451                 case SKIP:
2452                         fprintf(stderr, "%s skipping over inode %lu\n", m,
2453                                 (unsigned long)curfile.ino);
2454                         break;
2455         }
2456 }
2457 #endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */
2458
2459 /*
2460  * Read the first block and get the blocksize from it. Test
2461  * for a compressed dump tape/file. setup() will make the final
2462  * determination by checking the compressed flag if gethead()
2463  * finds a valid header. The test here is necessary to offset the buffer
2464  * by the size of the compressed prefix. zflag is set here so that
2465  * readtape_set can set the correct function pointer for readtape().
2466  * Note that the first block of each tape/file is not compressed
2467  * and does not have a prefix.
2468  */ 
2469 static void
2470 findtapeblksize(void)
2471 {
2472         long i;
2473         size_t len;
2474         struct tapebuf *tpb = (struct tapebuf *) tapebuf;
2475         struct s_spcl spclpt;
2476
2477         for (i = 0; i < ntrec; i++)
2478                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
2479         blkcnt = 0;
2480         tbufptr = tapebuf;
2481         /*
2482          * For a pipe or file, read in the first record. For a tape, read
2483          * the first block.
2484          */
2485         len = magtapein ? ntrec * TP_BSIZE : TP_BSIZE;
2486
2487         if (read_a_block(mt, tapebuf, len, &i) <= 0)
2488                 errx(1, "Tape read error on first record");
2489
2490         memcpy(&spclpt, tapebuf, TP_BSIZE);
2491         cvtflag = 0;
2492         if (converthead(&spclpt) == FAIL) {
2493                 cvtflag++;
2494                 if (converthead(&spclpt) == FAIL) {
2495                         /* Special case for old compressed tapes with prefix */
2496                         if (magtapein && (i % TP_BSIZE != 0)) 
2497                                 goto oldformat;
2498                         errx(1, "Tape is not a dump tape");
2499                 }
2500                 fprintf(stderr, "Converting to new file system format.\n");
2501         }
2502         /*
2503          * If the input is from a file or a pipe, we read TP_BSIZE
2504          * bytes looking for a dump header. If the dump is compressed
2505          * we need to read in the rest of the block, as determined
2506          * by c_ntrec in the dump header. The first block of the
2507          * dump is not compressed and does not have a prefix.
2508          */
2509         if (!magtapein) {
2510                 if (spclpt.c_type == TS_TAPE
2511                     && spclpt.c_flags & DR_COMPRESSED) {
2512                         /* It's a compressed dump file, read in the */
2513                         /* rest of the block based on spclpt.c_ntrec. */
2514                         if (spclpt.c_ntrec > ntrec)
2515                                 errx(1, "Tape blocksize is too large, use "
2516                                      "\'-b %d\' ", spclpt.c_ntrec);
2517                         ntrec = spclpt.c_ntrec;
2518                         len = (ntrec - 1) * TP_BSIZE;
2519                         zflag = 1;   
2520                 }
2521                 else {
2522                         /* read in the rest of the block based on bufsize */
2523                         len = bufsize - TP_BSIZE;
2524                 }
2525                 if (read_a_block(mt, tapebuf+TP_BSIZE, len, &i) < 0
2526                     || (i != (long)len && i % TP_BSIZE != 0))
2527                         errx(1,"Error reading dump file header");
2528                 tbufptr = tapebuf;
2529                 numtrec = ntrec;
2530                 Vprintf(stdout, "Input block size is %ld\n", ntrec);
2531                 return;
2532         } /* if (!magtapein) */
2533
2534         /*
2535          * If the input is a tape, we tried to read ntrec * TP_BSIZE bytes.
2536          * If the value of ntrec is too large, we read less than
2537          * what we asked for; adjust the value of ntrec and test for 
2538          * a compressed dump tape.
2539          */
2540         if (i % TP_BSIZE != 0) {
2541 oldformat:
2542                 /* may be old format compressed dump tape with a prefix */
2543                 memcpy(&spclpt, tpb->buf, TP_BSIZE);
2544                 cvtflag = 0;
2545                 if (converthead(&spclpt) == FAIL) {
2546                         cvtflag++;
2547                         if (converthead(&spclpt) == FAIL)
2548                                 errx(1, "Tape is not a dump tape");
2549                         fprintf(stderr, "Converting to new file system format.\n");
2550                 }
2551                 if (i % TP_BSIZE == PREFIXSIZE
2552                     && tpb->compressed == 0
2553                     && spclpt.c_type == TS_TAPE
2554                     && spclpt.c_flags & DR_COMPRESSED) {
2555                         zflag = 1;
2556                         tbufptr = tpb->buf;
2557                         if (tpb->length > bufsize)
2558                                 errx(1, "Tape blocksize is too large, use "
2559                                         "\'-b %d\' ", tpb->length / TP_BSIZE);
2560                 }
2561                 else
2562                         errx(1, "Tape block size (%ld) is not a multiple of dump block size (%d)",
2563                                 i, TP_BSIZE);
2564         }
2565         ntrec = i / TP_BSIZE;
2566         if (spclpt.c_type == TS_TAPE) {
2567                 if (spclpt.c_flags & DR_COMPRESSED)
2568                         zflag = 1;
2569                 if (spclpt.c_ntrec > ntrec)
2570                         errx(1, "Tape blocksize is too large, use "
2571                                 "\'-b %d\' ", spclpt.c_ntrec);
2572         }
2573         numtrec = ntrec;
2574         Vprintf(stdout, "Tape block size is %ld\n", ntrec);
2575 }
2576
2577 /*
2578  * Read a block of data handling all of the messy details.
2579  */
2580 static int read_a_block(int fd, char *buf, size_t len, long *lengthread)
2581 {
2582         long i = 1, size;
2583
2584         size = len;
2585         while (size > 0) {
2586 #ifdef RRESTORE
2587                 if (!Afile && host)
2588                         i = rmtread(buf, size);
2589                 else
2590 #endif
2591                         i = read(fd, buf, size);                 
2592
2593                 if (i <= 0)
2594                         break; /* EOD or error */
2595                 size -= i;
2596                 if (magtapein)
2597                         break; /* block at a time for mt */
2598                 buf += i;
2599         }
2600         *lengthread = len - size;
2601         return i;
2602 }
2603
2604 void
2605 closemt(void)
2606 {
2607
2608         if (mt < 0)
2609                 return;
2610 #ifdef RRESTORE
2611         if (!Afile && host)
2612                 rmtclose();
2613         else
2614 #endif
2615                 (void) close(mt);
2616 }
2617
2618 static void
2619 setmagtapein(void) {
2620         struct mtget mt_stat;
2621         static int done = 0;
2622         if (done)
2623                 return;
2624         done = 1;
2625         if (!pipein) {
2626                 /* need to know if input is really from a tape */
2627 #ifdef RRESTORE
2628                 if (host)
2629                         magtapein = !lflag;
2630                 else
2631 #endif
2632                         magtapein = ioctl(mt, MTIOCGET, (char *)&mt_stat) == 0;
2633         }
2634
2635         Vprintf(stdout,"Input is from a %s %s\n",
2636                         host ? "remote" : "local",
2637                         magtapein ? "tape" :
2638                         Vflag ? "multi-volume (no tape)" : "file/pipe");
2639 }
2640
2641 /*
2642  * Read the next block from the tape.
2643  * Check to see if it is one of several vintage headers.
2644  * If it is an old style header, convert it to a new style header.
2645  * If it is not any valid header, return an error.
2646  */
2647 static int
2648 gethead(struct s_spcl *buf)
2649 {
2650         readtape((char *)buf);
2651         return converthead(buf);
2652 }
2653
2654 static int
2655 converthead(struct s_spcl *buf)
2656 {
2657         int32_t i;
2658         union {
2659                 quad_t  qval;
2660                 int32_t val[2];
2661         } qcvt;
2662         union u_ospcl {
2663                 char dummy[TP_BSIZE];
2664                 struct  s_ospcl {
2665                         int32_t c_type;
2666                         int32_t c_date;
2667                         int32_t c_ddate;
2668                         int32_t c_volume;
2669                         int32_t c_tapea;
2670                         u_int16_t c_inumber;
2671                         int32_t c_magic;
2672                         int32_t c_checksum;
2673                         struct odinode {
2674                                 u_int16_t odi_mode;
2675                                 u_int16_t odi_nlink;
2676                                 u_int16_t odi_uid;
2677                                 u_int16_t odi_gid;
2678                                 int32_t odi_size;
2679                                 int32_t odi_rdev;
2680                                 char    odi_addr[36];
2681                                 int32_t odi_atime;
2682                                 int32_t odi_mtime;
2683                                 int32_t odi_ctime;
2684                         } c_dinode;
2685                         int32_t c_count;
2686                         char    c_fill[256];
2687                 } s_ospcl;
2688         } u_ospcl;
2689
2690         if (!cvtflag) {
2691                 if (buf->c_magic != NFS_MAGIC) {
2692                         if (swabi(buf->c_magic) != NFS_MAGIC)
2693                                 return (FAIL);
2694                         if (!Bcvt) {
2695                                 Vprintf(stdout, "Note: Doing Byte swapping\n");
2696                                 Bcvt = 1;
2697                         }
2698                 }
2699                 if (checksum((int *)buf) == FAIL)
2700                         return (FAIL);
2701                 if (Bcvt)
2702                         swabst((u_char *)"8i4s1l29i528bi192b4i", (u_char *)buf);
2703                 goto good;
2704         }
2705         memcpy(&u_ospcl.s_ospcl, buf, TP_BSIZE);
2706         if (checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
2707                 return(FAIL);
2708         if (u_ospcl.s_ospcl.c_magic == OFS_MAGIC) {
2709                 memset((char *)buf, 0, (long)TP_BSIZE);
2710                 buf->c_type = u_ospcl.s_ospcl.c_type;
2711                 buf->c_date = u_ospcl.s_ospcl.c_date;
2712                 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
2713                 buf->c_volume = u_ospcl.s_ospcl.c_volume;
2714                 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
2715                 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
2716                 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
2717                 buf->c_magic = u_ospcl.s_ospcl.c_magic;
2718                 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
2719                 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
2720                 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
2721                 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
2722                 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
2723                 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
2724 #if defined(__linux__) || defined(sunos)
2725                 buf->c_dinode.di_atime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_atime;
2726                 buf->c_dinode.di_mtime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime;
2727                 buf->c_dinode.di_ctime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime;
2728 #else   /* __linux__ || sunos */
2729                 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
2730                 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
2731                 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
2732 #endif  /* __linux__ || sunos */
2733                 buf->c_count = u_ospcl.s_ospcl.c_count;
2734                 memmove(buf->c_addr, u_ospcl.s_ospcl.c_fill, (long)256);
2735         }
2736         else if (u_ospcl.s_ospcl.c_magic == FS_UFS2_MAGIC) {
2737                 buf->c_date = (int32_t)(*(int64_t *)&u_ospcl.dummy[896]);
2738                 buf->c_ddate = (int32_t)(*(int64_t *)&u_ospcl.dummy[904]);
2739                 buf->c_tapea = (int32_t)(*(int64_t *)&u_ospcl.dummy[912]);
2740                 buf->c_firstrec = (int32_t)(*(int64_t *)&u_ospcl.dummy[920]);
2741                 buf->c_ntrec = 0;
2742                 buf->c_extattributes = 0;
2743                 buf->c_flags |= DR_NEWINODEFMT;
2744                 ufs2flag = 1;
2745         }
2746         else
2747                 return(FAIL);
2748         buf->c_magic = NFS_MAGIC;
2749
2750 good:
2751         if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
2752             (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
2753                 qcvt.qval = buf->c_dinode.di_size;
2754                 if (qcvt.val[0] || qcvt.val[1]) {
2755                         Vprintf(stdout, "Note: Doing Quad swapping\n");
2756                         Qcvt = 1;
2757                 }
2758         }
2759         if (Qcvt) {
2760                 qcvt.qval = buf->c_dinode.di_size;
2761                 i = qcvt.val[1];
2762                 qcvt.val[1] = qcvt.val[0];
2763                 qcvt.val[0] = i;
2764                 buf->c_dinode.di_size = qcvt.qval;
2765         }
2766         readmapflag = 0;
2767
2768         switch (buf->c_type) {
2769
2770         case TS_CLRI:
2771         case TS_BITS:
2772                 /*
2773                  * Have to patch up missing information in bit map headers
2774                  */
2775                 buf->c_inumber = 0;
2776                 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
2777                 if (buf->c_count > TP_NINDIR)
2778                         readmapflag = 1;
2779                 else 
2780                         for (i = 0; i < buf->c_count; i++)
2781                                 buf->c_addr[i]++;
2782                 break;
2783
2784         case TS_TAPE:
2785                 if ((buf->c_flags & DR_NEWINODEFMT) == 0)
2786                         oldinofmt = 1;
2787                 /* fall through */
2788         case TS_END:
2789                 buf->c_inumber = 0;
2790                 if (buf->c_flags & DR_INODEINFO) {
2791                         memcpy(volinfo, buf->c_inos, TP_NINOS * sizeof(dump_ino_t));
2792                         if (Bcvt)
2793                                 swabst((u_char *)"128i", (u_char *)volinfo);
2794                 }
2795                 break;
2796
2797         case TS_INODE:
2798         case TS_ADDR:
2799                 break;
2800
2801         default:
2802                 panic("gethead: unknown inode type %d\n", buf->c_type);
2803                 break;
2804         }
2805         /*
2806          * If we are restoring a filesystem with old format inodes,
2807          * copy the uid/gid to the new location.
2808          */
2809         if (oldinofmt) {
2810                 buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
2811                 buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
2812         }
2813         if (dflag)
2814                 accthdr(buf);
2815         return(GOOD);
2816 }
2817
2818 static void
2819 converttapebuf(struct tapebuf *tpb)
2820 {
2821         if (Bcvt) {
2822                 struct tb {
2823                         unsigned int    length:28;
2824                         unsigned int    flags:3;
2825                         unsigned int    compressed:1;
2826                 } tb;
2827                 swabst((u_char *)"i", (u_char *)tpb);
2828                 memcpy(&tb, tpb, 4);    
2829                 tpb->length = tb.length;
2830                 tpb->flags = tb.flags;
2831                 tpb->compressed = tb.compressed;
2832         }
2833 }
2834
2835 /*
2836  * Check that a header is where it belongs and predict the next header
2837  */
2838 static void
2839 accthdr(struct s_spcl *header)
2840 {
2841         static dump_ino_t previno = 0x7fffffff;
2842         static int prevtype;
2843         static long predict;
2844         long blks, i;
2845
2846         if (header->c_type == TS_TAPE) {
2847                 fprintf(stderr, "Volume header (%s inode format) ",
2848                     oldinofmt ? "old" : "new");
2849                 if (header->c_firstrec)
2850                         fprintf(stderr, "begins with record %d",
2851                                 header->c_firstrec);
2852                 fprintf(stderr, "\n");
2853                 previno = 0x7fffffff;
2854                 return;
2855         }
2856         if (previno == 0x7fffffff)
2857                 goto newcalc;
2858         switch (prevtype) {
2859         case TS_BITS:
2860                 fprintf(stderr, "Dumped inodes map header");
2861                 break;
2862         case TS_CLRI:
2863                 fprintf(stderr, "Used inodes map header");
2864                 break;
2865         case TS_INODE:
2866                 fprintf(stderr, "File header, ino %lu", (unsigned long)previno);
2867                 break;
2868         case TS_ADDR:
2869                 fprintf(stderr, "File continuation header, ino %ld", (long)previno);
2870                 break;
2871         case TS_END:
2872                 fprintf(stderr, "End of tape header");
2873                 break;
2874         }
2875         if (predict != blksread - 1)
2876                 fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
2877                         predict, blksread - 1);
2878         fprintf(stderr, "\n");
2879 newcalc:
2880         blks = 0;
2881         if (header->c_type != TS_END)
2882                 for (i = 0; i < header->c_count; i++)
2883                         if (readmapflag || header->c_addr[i] != 0)
2884                                 blks++;
2885         predict = blks;
2886         blksread = 0;
2887         prevtype = header->c_type;
2888         previno = header->c_inumber;
2889 }
2890
2891 /*
2892  * Find an inode header.
2893  * Complain if had to skip, and complain is set.
2894  */
2895 static void
2896 findinode(struct s_spcl *header)
2897 {
2898         static long skipcnt = 0;
2899         long i;
2900         char buf[TP_BSIZE];
2901
2902         curfile.name = "<name unknown>";
2903         curfile.action = UNKNOWN;
2904         curfile.dip = NULL;
2905         curfile.ino = 0;
2906         do {
2907                 if (header->c_magic != NFS_MAGIC) {
2908                         skipcnt++;
2909                         while (gethead(header) == FAIL ||
2910                             header->c_date != dumpdate)
2911                                 skipcnt++;
2912                 }
2913                 switch (header->c_type) {
2914
2915                 case TS_ADDR:
2916                         /*
2917                          * Skip up to the beginning of the next record
2918                          */
2919                         for (i = 0; i < header->c_count; i++)
2920                                 if (header->c_addr[i])
2921                                         readtape(buf);
2922                         while (gethead(header) == FAIL ||
2923                             header->c_date != dumpdate)
2924                                 skipcnt++;
2925                         break;
2926
2927                 case TS_INODE:
2928                         curfile.dip = &header->c_dinode;
2929                         curfile.ino = header->c_inumber;
2930                         break;
2931
2932                 case TS_END:
2933                         curfile.ino = maxino;
2934                         break;
2935
2936                 case TS_CLRI:
2937                         curfile.name = "<file removal list>";
2938                         break;
2939
2940                 case TS_BITS:
2941                         curfile.name = "<file dump list>";
2942                         break;
2943
2944                 case TS_TAPE:
2945                         panic("unexpected tape header\n");
2946                         /* NOTREACHED */
2947
2948                 default:
2949                         panic("unknown tape header type %d\n", spcl.c_type);
2950                         /* NOTREACHED */
2951
2952                 }
2953         } while (header->c_type == TS_ADDR);
2954         if (skipcnt > 0)
2955 #ifdef USE_QFA
2956                 if (!noresyncmesg)
2957 #endif
2958                         fprintf(stderr, "resync restore, skipped %ld blocks\n",
2959                                 skipcnt);
2960         skipcnt = 0;
2961 }
2962
2963 static int
2964 checksum(int *buf)
2965 {
2966         int i, j;
2967
2968         j = sizeof(union u_spcl) / sizeof(int);
2969         i = 0;
2970         if(!Bcvt) {
2971                 do
2972                         i += *buf++;
2973                 while (--j);
2974         } else {
2975                 /* What happens if we want to read restore tapes
2976                         for a 16bit int machine??? */
2977                 do
2978                         i += swabi(*buf++);
2979                 while (--j);
2980         }
2981
2982         if (i != CHECKSUM) {
2983                 fprintf(stderr, "Checksum error %o, inode %lu file %s\n", i,
2984                         (unsigned long)curfile.ino, curfile.name);
2985                 return(FAIL);
2986         }
2987         return(GOOD);
2988 }
2989
2990 #ifdef RRESTORE
2991 #ifdef __STDC__
2992 #include <stdarg.h>
2993 #else
2994 #include <varargs.h>
2995 #endif
2996
2997 void
2998 #ifdef __STDC__
2999 msg(const char *fmt, ...)
3000 #else
3001 msg(fmt, va_alist)
3002         char *fmt;
3003         va_dcl
3004 #endif
3005 {
3006         va_list ap;
3007 #ifdef __STDC__
3008         va_start(ap, fmt);
3009 #else
3010         va_start(ap);
3011 #endif
3012         (void)vfprintf(stderr, fmt, ap);
3013         va_end(ap);
3014 }
3015 #endif /* RRESTORE */
3016
3017 static u_char *
3018 swab16(u_char *sp, int n)
3019 {
3020         char c;
3021
3022         while (--n >= 0) {
3023                 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
3024                 sp += 2;
3025         }
3026         return (sp);
3027 }
3028
3029 static u_char *
3030 swab32(u_char *sp, int n)
3031 {
3032         char c;
3033
3034         while (--n >= 0) {
3035                 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
3036                 c = sp[1]; sp[1] = sp[2]; sp[2] = c;
3037                 sp += 4;
3038         }
3039         return (sp);
3040 }
3041
3042 static u_char *
3043 swab64(u_char *sp, int n)
3044 {
3045         char c;
3046
3047         while (--n >= 0) {
3048                 c = sp[0]; sp[0] = sp[7]; sp[7] = c;
3049                 c = sp[1]; sp[1] = sp[6]; sp[6] = c;
3050                 c = sp[2]; sp[2] = sp[5]; sp[5] = c;
3051                 c = sp[3]; sp[3] = sp[4]; sp[4] = c;
3052                 sp += 8;
3053         }
3054         return (sp);
3055 }
3056
3057 void
3058 swabst(u_char *cp, u_char *sp)
3059 {
3060         int n = 0;
3061
3062         while (*cp) {
3063                 switch (*cp) {
3064                 case '0': case '1': case '2': case '3': case '4':
3065                 case '5': case '6': case '7': case '8': case '9':
3066                         n = (n * 10) + (*cp++ - '0');
3067                         continue;
3068
3069                 case 's': case 'w': case 'h':
3070                         if (n == 0)
3071                                 n = 1;
3072                         sp = swab16(sp, n);
3073                         break;
3074
3075                 case 'i':
3076                         if (n == 0)
3077                                 n = 1;
3078                         sp = swab32(sp, n);
3079                         break;
3080
3081                 case 'l':
3082                         if (n == 0)
3083                                 n = 1;
3084                         sp = swab64(sp, n);
3085                         break;
3086
3087                 default: /* Any other character, like 'b' counts as byte. */
3088                         if (n == 0)
3089                                 n = 1;
3090                         sp += n;
3091                         break;
3092                 }
3093                 cp++;
3094                 n = 0;
3095         }
3096 }
3097
3098 static u_int
3099 swabi(u_int x)
3100 {
3101         swabst((u_char *)"i", (u_char *)&x);
3102         return (x);
3103 }
3104
3105 #if 0
3106 static u_long
3107 swabl(u_long x)
3108 {
3109         swabst((u_char *)"l", (u_char *)&x);
3110         return (x);
3111 }
3112 #endif
3113
3114 void
3115 RequestVol(long tnum)
3116 {
3117         FLUSHTAPEBUF();
3118         getvol(tnum);
3119 }
3120
3121 #ifdef USE_QFA
3122 #ifdef sunos
3123 extern int fdsmtc;
3124
3125 struct uscsi_cmd {
3126         int     uscsi_flags;            /* read, write, etc. see below */
3127         short   uscsi_status;           /* resulting status  */
3128         short   uscsi_timeout;          /* Command Timeout */
3129         caddr_t uscsi_cdb;              /* cdb to send to target */
3130         caddr_t uscsi_bufaddr;          /* i/o source/destination */
3131         u_int   uscsi_buflen;           /* size of i/o to take place */
3132         u_int   uscsi_resid;            /* resid from i/o operation */
3133         u_char  uscsi_cdblen;           /* # of valid cdb bytes */
3134         u_char  uscsi_rqlen;            /* size of uscsi_rqbuf */
3135         u_char  uscsi_rqstatus;         /* status of request sense cmd */
3136         u_char  uscsi_rqresid;          /* resid of request sense cmd */
3137         caddr_t uscsi_rqbuf;            /* request sense buffer */
3138         void   *uscsi_reserved_5;       /* Reserved for Future Use */
3139 };
3140
3141 #define CDB_GROUP0      6       /*  6-byte cdb's */
3142 #define CDB_GROUP1      10      /* 10-byte cdb's */
3143 #define CDB_GROUP2      10      /* 10-byte cdb's */
3144 #define CDB_GROUP3      0       /* reserved */
3145 #define CDB_GROUP4      16      /* 16-byte cdb's */
3146 #define CDB_GROUP5      12      /* 12-byte cdb's */
3147 #define CDB_GROUP6      0       /* reserved */
3148 #define CDB_GROUP7      0       /* reserved */
3149
3150 #define USCSI_WRITE     0x00000 /* send data to device */
3151 #define USCSI_SILENT    0x00001 /* no error messages */
3152 #define USCSI_DIAGNOSE  0x00002 /* fail if any error occurs */
3153 #define USCSI_ISOLATE   0x00004 /* isolate from normal commands */
3154 #define USCSI_READ      0x00008 /* get data from device */
3155 #define USCSI_RESET     0x04000 /* Reset target */
3156 #define USCSI_RESET_ALL 0x08000 /* Reset all targets */
3157 #define USCSI_RQENABLE  0x10000 /* Enable Request Sense extensions */
3158
3159 #define USCSIIOC        (0x04 << 8)
3160 #define USCSICMD        (USCSIIOC|201)  /* user scsi command */
3161
3162 #define USCSI_TIMEOUT   30
3163 #define USCSI_SHORT_TIMEOUT     900
3164 #define USCSI_LONG_TIMEOUT      14000
3165
3166 #define B(s,i) ((unsigned char)((s) >> i))
3167 #define B1(s)                           ((unsigned char)(s))
3168
3169 #define MSB4(s,v) *(s)=B(v,24),(s)[1]=B(v,16), (s)[2]=B(v,8), (s)[3]=B1(v)
3170
3171
3172 int
3173 GetTapePos(long long *pos)
3174 {
3175         int                                     err = 0;
3176         struct uscsi_cmd        scmd;
3177         char                            buf[512];
3178         char                            parm[512 * 8];
3179         long                            lpos;
3180
3181         (void)memset((void *)buf, 0, sizeof(buf));
3182         (void)memset((void *)&scmd, 0, sizeof(scmd));
3183         scmd.uscsi_flags = USCSI_READ|USCSI_SILENT;
3184         scmd.uscsi_timeout = USCSI_TIMEOUT;
3185         scmd.uscsi_cdb = buf;
3186         scmd.uscsi_cdblen = CDB_GROUP1;
3187         buf[0] = 0x34;  /* read position */
3188         buf[1] = 0;
3189         (void)memset((void *)parm, 0, 512);
3190         scmd.uscsi_bufaddr = parm;
3191         scmd.uscsi_buflen = 56;
3192         if (ioctl(fdsmtc, USCSICMD, &scmd) == -1) {
3193                 err = errno;
3194                 return err;
3195         }
3196         (void)memcpy(&lpos, &parm[4], sizeof(long));
3197         *pos = lpos;
3198         return err;
3199 }
3200
3201 int
3202 GotoTapePos(long long pos)
3203 {
3204         int                                     err = 0;
3205         struct uscsi_cmd        scmd;
3206         char                            buf[512];
3207         char                            parm[512 * 8];
3208         long                            lpos = (long)pos;
3209
3210         (void)memset((void *)buf, 0, sizeof(buf));
3211         (void)memset((void *)&scmd, 0, sizeof(scmd));
3212         scmd.uscsi_flags = USCSI_WRITE|USCSI_SILENT;
3213         scmd.uscsi_timeout = 360;       /* 5 Minutes */
3214         scmd.uscsi_cdb = buf;
3215         scmd.uscsi_cdblen = CDB_GROUP1;
3216         buf[0] = 0x2b;  /* locate */
3217         buf[1] = 0;
3218         MSB4(&buf[3], lpos);
3219         (void)memset((void *)parm, 0, 512);
3220         scmd.uscsi_bufaddr = NULL;
3221         scmd.uscsi_buflen = 0;
3222         if (ioctl(fdsmtc, USCSICMD, &scmd) == -1) {
3223                 err = errno;
3224                 return err;
3225         }
3226         return err;
3227 }
3228 #endif
3229
3230 #define LSEEK_GET_TAPEPOS       10
3231 #define LSEEK_GO2_TAPEPOS       11
3232
3233 #ifdef  __linux__
3234 typedef struct mt_pos {
3235         short    mt_op;
3236         int      mt_count;
3237 } MTPosRec, *MTPosPtr;
3238
3239
3240 /*
3241  * get the current position of the tape
3242  */
3243 int
3244 GetTapePos(long long *pos)
3245 {
3246         int err = 0;
3247
3248 #ifdef RDUMP
3249         if (host) {
3250                 *pos = (long long) rmtseek((OFF_T)0, (int)LSEEK_GET_TAPEPOS);
3251                 err = *pos < 0;
3252         }
3253         else
3254 #endif
3255         {
3256         if (magtapein) {
3257                 long mtpos;
3258                 *pos = 0;
3259                 err = (ioctl(mt, MTIOCPOS, &mtpos) < 0);
3260                 *pos = (long long)mtpos;
3261         }
3262         else {
3263                 *pos = LSEEK(mt, 0, SEEK_CUR);
3264                 err = (*pos < 0);
3265         }
3266         }
3267         if (err) {
3268                 err = errno;
3269                 fprintf(stdout, "[%ld] error: %d (getting tapepos: %lld)\n", 
3270                         (unsigned long)getpid(), err, *pos);
3271                 return err;
3272         }
3273         return err;
3274 }
3275
3276 /*
3277  * go to specified position on tape
3278  */
3279 int
3280 GotoTapePos(long long pos)
3281 {
3282         int err = 0;
3283
3284 #ifdef RDUMP
3285         if (host)
3286                 err = (rmtseek((OFF_T)pos, (int)LSEEK_GO2_TAPEPOS) < 0);
3287         else
3288 #endif
3289         {
3290         if (magtapein) {
3291                 struct mt_pos buf;
3292                 buf.mt_op = MTSEEK;
3293                 buf.mt_count = (int) pos;
3294                 err = (ioctl(mt, MTIOCTOP, &buf) < 0);
3295         }
3296         else {
3297                 pos = LSEEK(mt, pos, SEEK_SET);
3298                 err = (pos < 0);
3299         }
3300         }
3301         if (err) {
3302                 err = errno;
3303                 fprintf(stdout, "[%ld] error: %d (setting tapepos: %lld)\n", 
3304                         (unsigned long)getpid(), err, pos);
3305                 return err;
3306         }
3307         return err;
3308 }
3309 #endif /* __linux__ */
3310
3311 /*
3312  * read next data from tape to re-sync
3313  */
3314 void
3315 ReReadFromTape(void)
3316 {
3317         FLUSHTAPEBUF();
3318         noresyncmesg = 1;
3319         if (gethead(&spcl) == FAIL) {
3320 #ifdef DEBUG_QFA
3321                 fprintf(stdout, "DEBUG 1 gethead failed\n");
3322 #endif
3323         }
3324         findinode(&spcl);
3325         noresyncmesg = 0;
3326 }
3327
3328 void
3329 ReReadInodeFromTape(dump_ino_t theino)
3330 {
3331         long    cntloop = 0;
3332
3333         FLUSHTAPEBUF();
3334         noresyncmesg = 1;
3335         do {
3336                 cntloop++;
3337                 gethead(&spcl);
3338         } while (!(spcl.c_inumber == theino && spcl.c_type == TS_INODE && spcl.c_date == dumpdate));
3339 #ifdef DEBUG_QFA
3340         fprintf(stderr, "DEBUG: %ld reads\n", cntloop);
3341         fprintf(stderr, "DEBUG: bufsize %ld\n", bufsize);
3342         fprintf(stderr, "DEBUG: ntrec %ld\n", ntrec);
3343         fprintf(stderr, "DEBUG: %ld reads\n", cntloop);
3344 #endif
3345         findinode(&spcl);
3346         noresyncmesg = 0;
3347 }
3348
3349 #ifdef sunos
3350 int
3351 OpenSMTCmt(char *themagtape)
3352 {
3353         if (GetSCSIIDFromPath(themagtape, &scsiid)) {
3354                 fprintf(stderr, "can't get SCSI-ID for %s\n", themagtape);
3355                 return -1;
3356         }
3357         if (scsiid < 0) {
3358                 fprintf(stderr, "can't get SCSI-ID for %s\n", themagtape);
3359                 return -1;
3360         }
3361         sprintf(smtcpath, "/dev/rsmtc%ld,0", scsiid);
3362         if ((fdsmtc = open(smtcpath, O_RDWR)) == -1) {
3363                 fprintf(stderr, "can't open smtc device: %s, %d\n", smtcpath, errno);
3364                 return -1;
3365         }
3366         return 0;
3367 }
3368 #endif /* sunos */
3369 #endif /* USE_QFA */