tape.c revision 1.65 1 /* $NetBSD: tape.c,v 1.65 2011/08/06 20:46:42 dholland Exp $ */
2
3 /*
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95";
41 #else
42 __RCSID("$NetBSD: tape.c,v 1.65 2011/08/06 20:46:42 dholland Exp $");
43 #endif
44 #endif /* not lint */
45
46 #include <sys/param.h>
47 #include <sys/file.h>
48 #include <sys/ioctl.h>
49 #include <sys/mtio.h>
50 #include <sys/stat.h>
51
52 #include <ufs/ufs/dinode.h>
53 #include <protocols/dumprestore.h>
54
55 #include <err.h>
56 #include <errno.h>
57 #include <paths.h>
58 #include <setjmp.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <time.h>
63 #include <unistd.h>
64
65 #include <md5.h>
66 #include <rmd160.h>
67 #include <sha1.h>
68
69 #include "restore.h"
70 #include "extern.h"
71
72 static u_int32_t fssize = MAXBSIZE;
73 static int mt = -1;
74 static int pipein = 0;
75 static char magtape[BUFSIZ];
76 static int blkcnt;
77 static int numtrec;
78 static char *tapebuf;
79 static union u_spcl endoftapemark;
80 static int blksread; /* blocks read since last header */
81 static int tpblksread = 0; /* TP_BSIZE blocks read */
82 static int tapesread;
83 static jmp_buf restart;
84 static int gettingfile = 0; /* restart has a valid frame */
85 #ifdef RRESTORE
86 static const char *host = NULL;
87 #endif
88
89 static int ofile;
90 static char lnkbuf[MAXPATHLEN + 1];
91 static int pathlen;
92
93 int oldinofmt; /* old inode format conversion required */
94 int Bcvt; /* Swap Bytes (for CCI or sun) */
95
96 const struct digest_desc *ddesc;
97
98 static union digest_context {
99 MD5_CTX dc_MD5;
100 SHA1_CTX dc_SHA1;
101 RMD160_CTX dc_RMD160;
102 } dcontext;
103
104 /*
105 * 32 for md5; 40 for sha1 and rmd160
106 * plus a null terminator.
107 */
108 #define DIGEST_BUFFER_SIZE (40 + 1)
109
110 #define FLUSHTAPEBUF() blkcnt = ntrec + 1
111
112 union u_ospcl {
113 char dummy[TP_BSIZE];
114 struct s_ospcl {
115 int32_t c_type;
116 int32_t c_date;
117 int32_t c_ddate;
118 int32_t c_volume;
119 int32_t c_tapea;
120 u_int16_t c_inumber;
121 int32_t c_magic;
122 int32_t c_checksum;
123 struct odinode {
124 unsigned short odi_mode;
125 u_int16_t odi_nlink;
126 u_int16_t odi_uid;
127 u_int16_t odi_gid;
128 int32_t odi_size;
129 int32_t odi_rdev;
130 char odi_addr[36];
131 int32_t odi_atime;
132 int32_t odi_mtime;
133 int32_t odi_ctime;
134 } c_odinode;
135 int32_t c_count;
136 char c_addr[256];
137 } s_ospcl;
138 };
139
140 static void accthdr(struct s_spcl *);
141 static int checksum(int *);
142 static void findinode(struct s_spcl *);
143 static void findtapeblksize(void);
144 static void getbitmap(char **);
145 static int gethead(struct s_spcl *);
146 static void readtape(char *);
147 static void setdumpnum(void);
148 static void terminateinput(void);
149 static void xtrfile(char *, long);
150 static void xtrlnkfile(char *, long);
151 static void xtrlnkskip(char *, long);
152 static void xtrskip(char *, long);
153 static void swap_header(struct s_spcl *);
154 static void swap_old_header(struct s_ospcl *);
155
156 ////////////////////////////////////////////////////////////
157 // thunks for type correctness
158
159 #define WRAP(alg) \
160 static void \
161 do_##alg##Init(void *ctx) \
162 { \
163 alg##Init(ctx); \
164 } \
165 \
166 static void \
167 do_##alg##Update(union digest_context *ctx, \
168 const void *buf, unsigned len) \
169 { \
170 alg##Update(&ctx->dc_##alg, buf, len); \
171 } \
172 \
173 static char * \
174 do_##alg##End(void *ctx, char *str) \
175 { \
176 return alg##End(ctx, str); \
177 }
178
179 WRAP(MD5);
180 WRAP(SHA1);
181 WRAP(RMD160);
182
183 static const struct digest_desc digest_descs[] = {
184 { "MD5",
185 do_MD5Init,
186 do_MD5Update,
187 do_MD5End, },
188 { "SHA1",
189 do_SHA1Init,
190 do_SHA1Update,
191 do_SHA1End, },
192 { "RMD160",
193 do_RMD160Init,
194 do_RMD160Update,
195 do_RMD160End, },
196 { .dd_name = NULL },
197 };
198
199 ////////////////////////////////////////////////////////////
200
201 const struct digest_desc *
202 digest_lookup(const char *name)
203 {
204 const struct digest_desc *dd;
205
206 for (dd = digest_descs; dd->dd_name != NULL; dd++)
207 if (strcasecmp(dd->dd_name, name) == 0)
208 return (dd);
209
210 return (NULL);
211 }
212
213 /*
214 * Set up an input source
215 */
216 void
217 setinput(const char *source)
218 {
219 char *cp;
220 FLUSHTAPEBUF();
221 if (bflag)
222 newtapebuf(ntrec);
223 else
224 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
225 terminal = stdin;
226
227 #ifdef RRESTORE
228 if ((cp = strchr(source, ':')) != NULL) {
229 host = source;
230 /* Ok, because const strings don't have : */
231 *cp++ = '\0';
232 source = cp;
233 if (rmthost(host) == 0)
234 exit(1);
235 } else
236 #endif
237 if (strcmp(source, "-") == 0) {
238 /*
239 * Since input is coming from a pipe we must establish
240 * our own connection to the terminal.
241 */
242 terminal = fopen(_PATH_TTY, "r");
243 if (terminal == NULL) {
244 (void)fprintf(stderr, "cannot open %s: %s\n",
245 _PATH_TTY, strerror(errno));
246 terminal = fopen(_PATH_DEVNULL, "r");
247 if (terminal == NULL) {
248 (void)fprintf(stderr, "cannot open %s: %s\n",
249 _PATH_DEVNULL, strerror(errno));
250 exit(1);
251 }
252 }
253 pipein++;
254 }
255 (void) strcpy(magtape, source);
256 }
257
258 void
259 newtapebuf(long size)
260 {
261 static int tapebufsize = -1;
262
263 ntrec = size;
264 if (size <= tapebufsize)
265 return;
266 if (tapebuf != NULL)
267 free(tapebuf);
268 tapebuf = malloc(size * TP_BSIZE);
269 if (tapebuf == NULL) {
270 fprintf(stderr, "Cannot allocate space for tape buffer\n");
271 exit(1);
272 }
273 tapebufsize = size;
274 }
275
276 /*
277 * Verify that the tape drive can be accessed and
278 * that it actually is a dump tape.
279 */
280 void
281 setup(void)
282 {
283 int i, j, *ip;
284 struct stat stbuf;
285
286 vprintf(stdout, "Verify tape and initialize maps\n");
287 #ifdef RRESTORE
288 if (host)
289 mt = rmtopen(magtape, 0, 0);
290 else
291 #endif
292 if (pipein)
293 mt = 0;
294 else
295 mt = open(magtape, O_RDONLY, 0);
296 if (mt < 0) {
297 fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
298 exit(1);
299 }
300 volno = 1;
301 setdumpnum();
302 FLUSHTAPEBUF();
303 if (!pipein && !bflag)
304 findtapeblksize();
305 if (gethead(&spcl) == FAIL) {
306 blkcnt--; /* push back this block */
307 blksread--;
308 tpblksread--;
309 cvtflag++;
310 if (gethead(&spcl) == FAIL) {
311 fprintf(stderr, "Tape is not a dump tape\n");
312 exit(1);
313 }
314 fprintf(stderr, "Converting to new file system format.\n");
315 }
316 if (pipein) {
317 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC :
318 FS_UFS2_MAGIC;
319 endoftapemark.s_spcl.c_type = TS_END;
320 ip = (int *)&endoftapemark;
321 j = sizeof(union u_spcl) / sizeof(int);
322 i = 0;
323 do
324 i += *ip++;
325 while (--j);
326 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
327 }
328 if (vflag || command == 't')
329 printdumpinfo();
330 dumptime = spcl.c_ddate;
331 dumpdate = spcl.c_date;
332 if (stat(".", &stbuf) < 0) {
333 fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
334 exit(1);
335 }
336 if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
337 fssize = stbuf.st_blksize;
338 if (((fssize - 1) & fssize) != 0) {
339 fprintf(stderr, "bad block size %d\n", fssize);
340 exit(1);
341 }
342 if (spcl.c_volume != 1) {
343 fprintf(stderr, "Tape is not volume 1 of the dump\n");
344 exit(1);
345 }
346 if (gethead(&spcl) == FAIL) {
347 dprintf(stdout, "header read failed at %d blocks\n", blksread);
348 panic("no header after volume mark!\n");
349 }
350 findinode(&spcl);
351 if (spcl.c_type != TS_CLRI) {
352 fprintf(stderr, "Cannot find file removal list\n");
353 exit(1);
354 }
355 getbitmap(&usedinomap);
356 getbitmap(&dumpmap);
357 /*
358 * If there may be whiteout entries on the tape, pretend that the
359 * whiteout inode exists, so that the whiteout entries can be
360 * extracted.
361 */
362 if (oldinofmt == 0)
363 SETINO(WINO, dumpmap);
364 }
365
366 /*
367 * Prompt user to load a new dump volume.
368 * "Nextvol" is the next suggested volume to use.
369 * This suggested volume is enforced when doing full
370 * or incremental restores, but can be overrridden by
371 * the user when only extracting a subset of the files.
372 */
373 void
374 getvol(int nextvol)
375 {
376 int newvol, savecnt, wantnext, i;
377 union u_spcl tmpspcl;
378 # define tmpbuf tmpspcl.s_spcl
379 char buf[TP_BSIZE];
380
381 newvol = savecnt = wantnext = 0;
382 if (nextvol == 1) {
383 tapesread = 0;
384 gettingfile = 0;
385 }
386 if (pipein) {
387 if (nextvol != 1)
388 panic("Changing volumes on pipe input?\n");
389 if (volno == 1)
390 return;
391 goto gethdr;
392 }
393 savecnt = blksread;
394 again:
395 if (pipein)
396 exit(1); /* pipes do not get a second chance */
397 if (command == 'R' || command == 'r' || curfile.action != SKIP) {
398 newvol = nextvol;
399 wantnext = 1;
400 } else {
401 newvol = 0;
402 wantnext = 0;
403 }
404 while (newvol <= 0) {
405 if (tapesread == 0) {
406 fprintf(stderr, "%s%s%s%s%s",
407 "You have not read any tapes yet.\n",
408 "Unless you know which volume your",
409 " file(s) are on you should start\n",
410 "with the last volume and work",
411 " towards the first.\n");
412 fprintf(stderr,
413 "(Use 1 for the first volume/tape, etc.)\n");
414 } else {
415 fprintf(stderr, "You have read volumes");
416 strcpy(buf, ": ");
417 for (i = 1; i < 32; i++)
418 if (tapesread & (1 << i)) {
419 fprintf(stderr, "%s%d", buf, i);
420 strcpy(buf, ", ");
421 }
422 fprintf(stderr, "\n");
423 }
424 do {
425 fprintf(stderr, "Specify next volume #: ");
426 (void) fflush(stderr);
427 (void) fgets(buf, BUFSIZ, terminal);
428 } while (!feof(terminal) && buf[0] == '\n');
429 if (feof(terminal))
430 exit(1);
431 newvol = atoi(buf);
432 if (newvol <= 0) {
433 fprintf(stderr,
434 "Volume numbers are positive numerics\n");
435 }
436 }
437 if (newvol == volno) {
438 tapesread |= 1 << volno;
439 return;
440 }
441 closemt();
442 fprintf(stderr, "Mount tape volume %d\n", newvol);
443 fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
444 fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
445 (void) fflush(stderr);
446 (void) fgets(buf, BUFSIZ, terminal);
447 if (feof(terminal))
448 exit(1);
449 if (!strcmp(buf, "none\n")) {
450 terminateinput();
451 return;
452 }
453 if (buf[0] != '\n') {
454 (void) strcpy(magtape, buf);
455 magtape[strlen(magtape) - 1] = '\0';
456 }
457 #ifdef RRESTORE
458 if (host)
459 mt = rmtopen(magtape, 0, 0);
460 else
461 #endif
462 mt = open(magtape, O_RDONLY, 0);
463
464 if (mt == -1) {
465 fprintf(stderr, "Cannot open %s\n", magtape);
466 volno = -1;
467 goto again;
468 }
469 gethdr:
470 volno = newvol;
471 setdumpnum();
472 FLUSHTAPEBUF();
473 if (gethead(&tmpbuf) == FAIL) {
474 dprintf(stdout, "header read failed at %d blocks\n", blksread);
475 fprintf(stderr, "tape is not dump tape\n");
476 volno = 0;
477 goto again;
478 }
479 if (tmpbuf.c_volume != volno) {
480 fprintf(stderr,
481 "Volume mismatch: expecting %d, tape header claims it is %d\n",
482 volno, tmpbuf.c_volume);
483 volno = 0;
484 goto again;
485 }
486 if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
487 time_t ttime = tmpbuf.c_date;
488 fprintf(stderr, "Wrong dump date\n\tgot: %s",
489 ctime(&ttime));
490 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
491 volno = 0;
492 goto again;
493 }
494 tapesread |= 1 << volno;
495 blksread = savecnt;
496 /*
497 * If continuing from the previous volume, skip over any
498 * blocks read already at the end of the previous volume.
499 *
500 * If coming to this volume at random, skip to the beginning
501 * of the next record.
502 */
503 dprintf(stdout, "read %ld recs, tape starts with %ld\n",
504 (long)tpblksread, (long)tmpbuf.c_firstrec);
505 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
506 if (!wantnext) {
507 tpblksread = tmpbuf.c_firstrec;
508 for (i = tmpbuf.c_count; i > 0; i--)
509 readtape(buf);
510 } else if (tmpbuf.c_firstrec > 0 &&
511 tmpbuf.c_firstrec < tpblksread - 1) {
512 /*
513 * -1 since we've read the volume header
514 */
515 i = tpblksread - tmpbuf.c_firstrec - 1;
516 dprintf(stderr, "Skipping %d duplicate record%s.\n",
517 i, i > 1 ? "s" : "");
518 while (--i >= 0)
519 readtape(buf);
520 }
521 }
522 if (curfile.action == USING) {
523 if (volno == 1)
524 panic("active file into volume 1\n");
525 return;
526 }
527 /*
528 * Skip up to the beginning of the next record
529 */
530 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
531 for (i = tmpbuf.c_count; i > 0; i--)
532 readtape(buf);
533 (void) gethead(&spcl);
534 findinode(&spcl);
535 if (gettingfile) {
536 gettingfile = 0;
537 longjmp(restart, 1);
538 }
539 }
540
541 /*
542 * Handle unexpected EOF.
543 */
544 static void
545 terminateinput(void)
546 {
547
548 if (gettingfile && curfile.action == USING) {
549 printf("Warning: %s %s\n",
550 "End-of-input encountered while extracting", curfile.name);
551 }
552 curfile.name = "<name unknown>";
553 curfile.action = UNKNOWN;
554 curfile.mode = 0;
555 curfile.ino = maxino;
556 if (gettingfile) {
557 gettingfile = 0;
558 longjmp(restart, 1);
559 }
560 }
561
562 /*
563 * handle multiple dumps per tape by skipping forward to the
564 * appropriate one.
565 */
566 static void
567 setdumpnum(void)
568 {
569 struct mtop tcom;
570
571 if (dumpnum == 1 || volno != 1)
572 return;
573 if (pipein) {
574 fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
575 exit(1);
576 }
577 tcom.mt_op = MTFSF;
578 tcom.mt_count = dumpnum - 1;
579 #ifdef RRESTORE
580 if (host)
581 rmtioctl(MTFSF, dumpnum - 1);
582 else
583 #endif
584 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
585 fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
586 }
587
588 void
589 printdumpinfo(void)
590 {
591 time_t ttime;
592
593 ttime = spcl.c_date;
594 fprintf(stdout, "Dump date: %s", ctime(&ttime));
595 ttime = spcl.c_ddate;
596 fprintf(stdout, "Dumped from: %s",
597 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&ttime));
598 fprintf(stderr, "Level %d dump of %s on %s:%s\n",
599 spcl.c_level, spcl.c_filesys,
600 *spcl.c_host? spcl.c_host: "[unknown]", spcl.c_dev);
601 fprintf(stderr, "Label: %s\n", spcl.c_label);
602
603 if (Mtreefile) {
604 ttime = spcl.c_date;
605 fprintf(Mtreefile, "#Dump date: %s", ctime(&ttime));
606 ttime = spcl.c_ddate;
607 fprintf(Mtreefile, "#Dumped from: %s",
608 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&ttime));
609 fprintf(Mtreefile, "#Level %d dump of %s on %s:%s\n",
610 spcl.c_level, spcl.c_filesys,
611 *spcl.c_host? spcl.c_host: "[unknown]", spcl.c_dev);
612 fprintf(Mtreefile, "#Label: %s\n", spcl.c_label);
613 fprintf(Mtreefile, "/set uname=root gname=wheel\n");
614 if (ferror(Mtreefile))
615 err(1, "error writing to mtree file");
616 }
617 }
618
619 int
620 extractfile(char *name)
621 {
622 char dbuffer[DIGEST_BUFFER_SIZE];
623 int flags;
624 uid_t uid;
625 gid_t gid;
626 mode_t mode;
627 struct timeval mtimep[2], ctimep[2];
628 struct entry *ep;
629 int setbirth;
630
631 curfile.name = name;
632 curfile.action = USING;
633 mtimep[0].tv_sec = curfile.atime_sec;
634 mtimep[0].tv_usec = curfile.atime_nsec / 1000;
635 mtimep[1].tv_sec = curfile.mtime_sec;
636 mtimep[1].tv_usec = curfile.mtime_nsec / 1000;
637
638 setbirth = curfile.birthtime_sec != 0;
639
640 if (setbirth) {
641 ctimep[0].tv_sec = curfile.atime_sec;
642 ctimep[0].tv_usec = curfile.atime_nsec / 1000;
643 ctimep[1].tv_sec = curfile.birthtime_sec;
644 ctimep[1].tv_usec = curfile.birthtime_nsec / 1000;
645 }
646 uid = curfile.uid;
647 gid = curfile.gid;
648 mode = curfile.mode;
649 flags = curfile.file_flags;
650 switch (mode & IFMT) {
651
652 default:
653 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
654 skipfile();
655 return (FAIL);
656
657 case IFSOCK:
658 vprintf(stdout, "skipped socket %s\n", name);
659 skipfile();
660 return (GOOD);
661
662 case IFDIR:
663 if (mflag) {
664 ep = lookupname(name);
665 if (ep == NULL || ep->e_flags & EXTRACT)
666 panic("unextracted directory %s\n", name);
667 skipfile();
668 return (GOOD);
669 }
670 vprintf(stdout, "extract file %s\n", name);
671 return (genliteraldir(name, curfile.ino));
672
673 case IFLNK:
674 lnkbuf[0] = '\0';
675 pathlen = 0;
676 getfile(xtrlnkfile, xtrlnkskip);
677 if (pathlen == 0) {
678 vprintf(stdout,
679 "%s: zero length symbolic link (ignored)\n", name);
680 return (GOOD);
681 }
682 if (uflag)
683 (void) unlink(name);
684 if (linkit(lnkbuf, name, SYMLINK) == GOOD) {
685 if (setbirth)
686 (void) lutimes(name, ctimep);
687 (void) lutimes(name, mtimep);
688 (void) lchown(name, uid, gid);
689 (void) lchmod(name, mode);
690 if (Mtreefile) {
691 writemtree(name, "link",
692 uid, gid, mode, flags);
693 } else
694 (void) lchflags(name, flags);
695 return (GOOD);
696 }
697 return (FAIL);
698
699 case IFCHR:
700 case IFBLK:
701 vprintf(stdout, "extract special file %s\n", name);
702 if (Nflag) {
703 skipfile();
704 return (GOOD);
705 }
706 if (uflag)
707 (void) unlink(name);
708 if (mknod(name, (mode & (IFCHR | IFBLK)) | 0600,
709 (int)curfile.rdev) < 0) {
710 fprintf(stderr, "%s: cannot create special file: %s\n",
711 name, strerror(errno));
712 skipfile();
713 return (FAIL);
714 }
715 skipfile();
716 if (setbirth)
717 (void) utimes(name, ctimep);
718 (void) utimes(name, mtimep);
719 (void) chown(name, uid, gid);
720 (void) chmod(name, mode);
721 if (Mtreefile) {
722 writemtree(name,
723 ((mode & (S_IFBLK | IFCHR)) == IFBLK) ?
724 "block" : "char",
725 uid, gid, mode, flags);
726 } else
727 (void) chflags(name, flags);
728 return (GOOD);
729
730 case IFIFO:
731 vprintf(stdout, "extract fifo %s\n", name);
732 if (Nflag) {
733 skipfile();
734 return (GOOD);
735 }
736 if (uflag)
737 (void) unlink(name);
738 if (mkfifo(name, 0600) < 0) {
739 fprintf(stderr, "%s: cannot create fifo: %s\n",
740 name, strerror(errno));
741 skipfile();
742 return (FAIL);
743 }
744 skipfile();
745 if (setbirth)
746 (void) utimes(name, ctimep);
747 (void) utimes(name, mtimep);
748 (void) chown(name, uid, gid);
749 (void) chmod(name, mode);
750 if (Mtreefile) {
751 writemtree(name, "fifo",
752 uid, gid, mode, flags);
753 } else
754 (void) chflags(name, flags);
755 return (GOOD);
756
757 case IFREG:
758 vprintf(stdout, "extract file %s\n", name);
759 if (uflag)
760 (void) unlink(name);
761 if (!Nflag && (ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
762 0600)) < 0) {
763 fprintf(stderr, "%s: cannot create file: %s\n",
764 name, strerror(errno));
765 skipfile();
766 return (FAIL);
767 }
768 if (Dflag)
769 (*ddesc->dd_init)(&dcontext);
770 getfile(xtrfile, xtrskip);
771 if (Dflag) {
772 (*ddesc->dd_end)(&dcontext, dbuffer);
773 for (ep = lookupname(name); ep != NULL;
774 ep = ep->e_links)
775 fprintf(stdout, "%s (%s) = %s\n",
776 ddesc->dd_name, myname(ep),
777 dbuffer);
778 }
779 if (Nflag)
780 return (GOOD);
781 if (setbirth)
782 (void) futimes(ofile, ctimep);
783 (void) futimes(ofile, mtimep);
784 (void) fchown(ofile, uid, gid);
785 (void) fchmod(ofile, mode);
786 if (Mtreefile) {
787 writemtree(name, "file",
788 uid, gid, mode, flags);
789 } else
790 (void) fchflags(ofile, flags);
791 (void) close(ofile);
792 return (GOOD);
793 }
794 /* NOTREACHED */
795 }
796
797 /*
798 * skip over bit maps on the tape
799 */
800 void
801 skipmaps(void)
802 {
803
804 while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
805 skipfile();
806 }
807
808 /*
809 * skip over a file on the tape
810 */
811 void
812 skipfile(void)
813 {
814
815 curfile.action = SKIP;
816 getfile(xtrnull, xtrnull);
817 }
818
819 /*
820 * Extract a bitmap from the tape.
821 * The first bitmap sets maxino;
822 * other bitmaps must be of same size.
823 */
824 void
825 getbitmap(char **map)
826 {
827 int i;
828 size_t volatile size = spcl.c_size;
829 size_t volatile mapsize = size;
830 char *mapptr;
831
832 curfile.action = USING;
833 if (spcl.c_type == TS_END)
834 panic("ran off end of tape\n");
835 if (spcl.c_magic != FS_UFS2_MAGIC)
836 panic("not at beginning of a file\n");
837 if (!gettingfile && setjmp(restart) != 0)
838 return;
839 gettingfile++;
840 mapptr = *map = malloc(size);
841 loop:
842 if (*map == NULL)
843 panic("no memory for %s\n", curfile.name);
844 for (i = 0; i < spcl.c_count && size >= TP_BSIZE; i++) {
845 readtape(mapptr);
846 mapptr += TP_BSIZE;
847 size -= TP_BSIZE;
848 }
849 if (size != 0 || i != spcl.c_count)
850 panic("%s: inconsistent map size\n", curfile.name);
851 if (gethead(&spcl) == GOOD && spcl.c_type == TS_ADDR) {
852 size = spcl.c_count * TP_BSIZE;
853 *map = realloc(*map, mapsize + size);
854 mapptr = *map + mapsize;
855 mapsize += size;
856 goto loop;
857 }
858 if (maxino == 0)
859 maxino = mapsize * NBBY + 1;
860 else if (maxino != mapsize * NBBY + 1)
861 panic("%s: map size changed\n", curfile.name);
862 findinode(&spcl);
863 gettingfile = 0;
864 }
865
866 /*
867 * Extract a file from the tape.
868 * When an allocated block is found it is passed to the fill function;
869 * when an unallocated block (hole) is found, a zeroed buffer is passed
870 * to the skip function.
871 */
872 void
873 getfile(void (*fill)(char *buf, long size),
874 void (*skip)(char *buf, long size))
875 {
876 int i;
877 int volatile curblk;
878 quad_t volatile size;
879 static char clearedbuf[MAXBSIZE];
880 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
881 char junk[TP_BSIZE];
882
883 curblk = 0;
884 size = spcl.c_size;
885
886 if (spcl.c_type == TS_END)
887 panic("ran off end of tape\n");
888 if (spcl.c_magic != FS_UFS2_MAGIC)
889 panic("not at beginning of a file\n");
890 if (!gettingfile && setjmp(restart) != 0)
891 return;
892 gettingfile++;
893 loop:
894 for (i = 0; i < spcl.c_count; i++) {
895 if (spcl.c_addr[i]) {
896 readtape(&buf[curblk++][0]);
897 if ((uint32_t)curblk == fssize / TP_BSIZE) {
898 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
899 fssize : (curblk - 1) * TP_BSIZE + size));
900 curblk = 0;
901 }
902 } else {
903 if (curblk > 0) {
904 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
905 curblk * TP_BSIZE :
906 (curblk - 1) * TP_BSIZE + size));
907 curblk = 0;
908 }
909 (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
910 TP_BSIZE : size));
911 }
912 if ((size -= TP_BSIZE) <= 0) {
913 for (i++; i < spcl.c_count; i++)
914 if (spcl.c_addr[i])
915 readtape(junk);
916 break;
917 }
918 }
919 if (gethead(&spcl) == GOOD && size > 0) {
920 if (spcl.c_type == TS_ADDR)
921 goto loop;
922 dprintf(stdout,
923 "Missing address (header) block for %s at %d blocks\n",
924 curfile.name, blksread);
925 }
926 if (curblk > 0)
927 (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
928 /* Skip over Linux extended attributes. */
929 if (spcl.c_type == TS_INODE && (spcl.c_flags & DR_EXTATTRIBUTES)) {
930 for (i = 0; i < spcl.c_count; i++)
931 readtape(junk);
932 (void)gethead(&spcl);
933 }
934 findinode(&spcl);
935 gettingfile = 0;
936 }
937
938 /*
939 * Write out the next block of a file.
940 */
941 static void
942 xtrfile(char *buf, long size)
943 {
944
945 if (Dflag)
946 (*ddesc->dd_update)(&dcontext, buf, size);
947 if (Nflag)
948 return;
949 if (write(ofile, buf, (int) size) == -1) {
950 fprintf(stderr,
951 "write error extracting inode %llu, name %s\nwrite: %s\n",
952 (unsigned long long)curfile.ino, curfile.name,
953 strerror(errno));
954 exit(1);
955 }
956 }
957
958 /*
959 * Skip over a hole in a file.
960 */
961 /* ARGSUSED */
962 static void
963 xtrskip(char *buf, long size)
964 {
965
966 if (Dflag)
967 (*ddesc->dd_update)(&dcontext, buf, size);
968 if (Nflag)
969 return;
970 if (lseek(ofile, size, SEEK_CUR) == -1) {
971 fprintf(stderr,
972 "seek error extracting inode %llu, name %s\nlseek: %s\n",
973 (unsigned long long)curfile.ino, curfile.name,
974 strerror(errno));
975 exit(1);
976 }
977 }
978
979 /*
980 * Collect the next block of a symbolic link.
981 */
982 static void
983 xtrlnkfile(char *buf, long size)
984 {
985
986 pathlen += size;
987 if (pathlen > MAXPATHLEN) {
988 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
989 curfile.name, lnkbuf, buf, pathlen);
990 exit(1);
991 }
992 (void) strcat(lnkbuf, buf);
993 }
994
995 /*
996 * Skip over a hole in a symbolic link (should never happen).
997 */
998 /* ARGSUSED */
999 static void
1000 xtrlnkskip(char *buf __unused, long size __unused)
1001 {
1002
1003 fprintf(stderr, "unallocated block in symbolic link %s\n",
1004 curfile.name);
1005 exit(1);
1006 }
1007
1008 /*
1009 * Noop, when an extraction function is not needed.
1010 */
1011 /* ARGSUSED */
1012 void
1013 xtrnull(char *buf __unused, long size __unused)
1014 {
1015
1016 return;
1017 }
1018
1019 /*
1020 * Read TP_BSIZE blocks from the input.
1021 * Handle read errors, and end of media.
1022 */
1023 static void
1024 readtape(char *buf)
1025 {
1026 int rd, newvol, i;
1027 int cnt, seek_failed;
1028
1029 if (blkcnt < numtrec) {
1030 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
1031 blksread++;
1032 tpblksread++;
1033 return;
1034 }
1035 for (i = 0; i < ntrec; i++)
1036 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1037 if (numtrec == 0)
1038 numtrec = ntrec;
1039 cnt = ntrec * TP_BSIZE;
1040 rd = 0;
1041 getmore:
1042 #ifdef RRESTORE
1043 if (host)
1044 i = rmtread(&tapebuf[rd], cnt);
1045 else
1046 #endif
1047 i = read(mt, &tapebuf[rd], cnt);
1048 /*
1049 * Check for mid-tape short read error.
1050 * If found, skip rest of buffer and start with the next.
1051 */
1052 if (!pipein && numtrec < ntrec && i > 0) {
1053 dprintf(stdout, "mid-media short read error.\n");
1054 numtrec = ntrec;
1055 }
1056 /*
1057 * Handle partial block read.
1058 */
1059 if (pipein && i == 0 && rd > 0)
1060 i = rd;
1061 else if (i > 0 && i != ntrec * TP_BSIZE) {
1062 if (pipein) {
1063 rd += i;
1064 cnt -= i;
1065 if (cnt > 0)
1066 goto getmore;
1067 i = rd;
1068 } else {
1069 /*
1070 * Short read. Process the blocks read.
1071 */
1072 if (i % TP_BSIZE != 0)
1073 vprintf(stdout,
1074 "partial block read: %d should be %d\n",
1075 i, ntrec * TP_BSIZE);
1076 numtrec = i / TP_BSIZE;
1077 }
1078 }
1079 /*
1080 * Handle read error.
1081 */
1082 if (i < 0) {
1083 fprintf(stderr, "Tape read error while ");
1084 switch (curfile.action) {
1085 default:
1086 fprintf(stderr, "trying to set up tape\n");
1087 break;
1088 case UNKNOWN:
1089 fprintf(stderr, "trying to resynchronize\n");
1090 break;
1091 case USING:
1092 fprintf(stderr, "restoring %s\n", curfile.name);
1093 break;
1094 case SKIP:
1095 fprintf(stderr, "skipping over inode %llu\n",
1096 (unsigned long long)curfile.ino);
1097 break;
1098 }
1099 if (!yflag && !reply("continue"))
1100 exit(1);
1101 i = ntrec * TP_BSIZE;
1102 memset(tapebuf, 0, i);
1103 #ifdef RRESTORE
1104 if (host)
1105 seek_failed = (rmtseek(i, 1) < 0);
1106 else
1107 #endif
1108 seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
1109
1110 if (seek_failed) {
1111 fprintf(stderr,
1112 "continuation failed: %s\n", strerror(errno));
1113 exit(1);
1114 }
1115 }
1116 /*
1117 * Handle end of tape.
1118 */
1119 if (i == 0) {
1120 vprintf(stdout, "End-of-tape encountered\n");
1121 if (!pipein) {
1122 newvol = volno + 1;
1123 volno = 0;
1124 numtrec = 0;
1125 getvol(newvol);
1126 readtape(buf);
1127 return;
1128 }
1129 if (rd % TP_BSIZE != 0)
1130 panic("partial block read: %d should be %d\n",
1131 rd, ntrec * TP_BSIZE);
1132 terminateinput();
1133 memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
1134 }
1135 blkcnt = 0;
1136 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
1137 blksread++;
1138 tpblksread++;
1139 }
1140
1141 static void
1142 findtapeblksize(void)
1143 {
1144 long i;
1145
1146 for (i = 0; i < ntrec; i++)
1147 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1148 blkcnt = 0;
1149 #ifdef RRESTORE
1150 if (host)
1151 i = rmtread(tapebuf, ntrec * TP_BSIZE);
1152 else
1153 #endif
1154 i = read(mt, tapebuf, ntrec * TP_BSIZE);
1155
1156 if (i <= 0) {
1157 fprintf(stderr, "tape read error: %s\n", strerror(errno));
1158 exit(1);
1159 }
1160 if (i % TP_BSIZE != 0) {
1161 fprintf(stderr, "Tape block size (%ld) %s (%ld)\n",
1162 (long)i, "is not a multiple of dump block size",
1163 (long)TP_BSIZE);
1164 exit(1);
1165 }
1166 ntrec = i / TP_BSIZE;
1167 numtrec = ntrec;
1168 vprintf(stdout, "Tape block size is %d\n", ntrec);
1169 }
1170
1171 void
1172 closemt(void)
1173 {
1174
1175 if (mt < 0)
1176 return;
1177 #ifdef RRESTORE
1178 if (host)
1179 rmtclose();
1180 else
1181 #endif
1182 (void) close(mt);
1183 }
1184
1185 /*
1186 * Read the next block from the tape.
1187 * Check to see if it is one of several vintage headers.
1188 * If it is an old style header, convert it to a new style header.
1189 * If it is not any valid header, return an error.
1190 */
1191 static int
1192 gethead(struct s_spcl *buf)
1193 {
1194 union u_ospcl u_ospcl;
1195
1196 if (!cvtflag) {
1197 readtape((char *)buf);
1198 if (buf->c_magic != NFS_MAGIC &&
1199 buf->c_magic != FS_UFS2_MAGIC) {
1200 if (bswap32(buf->c_magic) != NFS_MAGIC &&
1201 bswap32(buf->c_magic) != FS_UFS2_MAGIC)
1202 return (FAIL);
1203 if (!Bcvt) {
1204 vprintf(stdout, "Note: Doing Byte swapping\n");
1205 Bcvt = 1;
1206 }
1207 }
1208 if (checksum((int *)buf) == FAIL)
1209 return (FAIL);
1210 if (Bcvt)
1211 swap_header(buf);
1212 goto good;
1213 }
1214
1215 readtape((char *)(&u_ospcl.s_ospcl));
1216 if (checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
1217 return (FAIL);
1218 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC) {
1219 if (bswap32(u_ospcl.s_ospcl.c_magic) != OFS_MAGIC)
1220 return (FAIL);
1221 if (!Bcvt) {
1222 vprintf(stdout, "Note: Doing Byte swapping\n");
1223 Bcvt = 1;
1224 }
1225 swap_old_header(&u_ospcl.s_ospcl);
1226 }
1227
1228 memset(buf, 0, TP_BSIZE);
1229 buf->c_type = u_ospcl.s_ospcl.c_type;
1230 buf->c_date = u_ospcl.s_ospcl.c_date;
1231 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1232 buf->c_volume = u_ospcl.s_ospcl.c_volume;
1233 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1234 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1235 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1236 buf->c_mode = u_ospcl.s_ospcl.c_odinode.odi_mode;
1237 buf->c_uid = u_ospcl.s_ospcl.c_odinode.odi_uid;
1238 buf->c_gid = u_ospcl.s_ospcl.c_odinode.odi_gid;
1239 buf->c_size = u_ospcl.s_ospcl.c_odinode.odi_size;
1240 buf->c_rdev = u_ospcl.s_ospcl.c_odinode.odi_rdev;
1241 buf->c_atime = u_ospcl.s_ospcl.c_odinode.odi_atime;
1242 buf->c_mtime = u_ospcl.s_ospcl.c_odinode.odi_mtime;
1243 buf->c_count = u_ospcl.s_ospcl.c_count;
1244 memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
1245 buf->c_magic = FS_UFS2_MAGIC;
1246 good:
1247 switch (buf->c_type) {
1248
1249 case TS_CLRI:
1250 case TS_BITS:
1251 /*
1252 * Have to patch up missing information in bit map headers
1253 */
1254 buf->c_inumber = 0;
1255 buf->c_size = buf->c_count * TP_BSIZE;
1256 break;
1257
1258 case TS_TAPE:
1259 if ((buf->c_flags & DR_NEWINODEFMT) == 0)
1260 oldinofmt = 1;
1261 /* fall through */
1262 case TS_END:
1263 buf->c_inumber = 0;
1264 break;
1265
1266 case TS_INODE:
1267 if (buf->c_magic == NFS_MAGIC) {
1268 buf->c_tapea = buf->c_old_tapea;
1269 buf->c_firstrec = buf->c_old_firstrec;
1270 buf->c_date = buf->c_old_date;
1271 buf->c_ddate = buf->c_old_ddate;
1272 buf->c_atime = buf->c_old_atime;
1273 buf->c_mtime = buf->c_old_mtime;
1274 buf->c_birthtime = 0;
1275 buf->c_birthtimensec = 0;
1276 buf->c_atimensec = buf->c_mtimensec = 0;
1277 }
1278
1279 case TS_ADDR:
1280 break;
1281
1282 default:
1283 panic("gethead: unknown inode type %d\n", buf->c_type);
1284 break;
1285 }
1286
1287 buf->c_magic = FS_UFS2_MAGIC;
1288
1289 /*
1290 * If we are restoring a filesystem with old format inodes,
1291 * copy the uid/gid to the new location.
1292 */
1293 if (oldinofmt) {
1294 buf->c_uid = buf->c_spare1[1];
1295 buf->c_gid = buf->c_spare1[2];
1296 }
1297 if (dflag)
1298 accthdr(buf);
1299 return(GOOD);
1300 }
1301
1302 /*
1303 * Check that a header is where it belongs and predict the next header
1304 */
1305 static void
1306 accthdr(struct s_spcl *header)
1307 {
1308 static ino_t previno = 0x7fffffff;
1309 static int prevtype;
1310 static long predict;
1311 long blks, i;
1312
1313 if (header->c_type == TS_TAPE) {
1314 fprintf(stderr, "Volume header (%s inode format) ",
1315 oldinofmt ? "old" : "new");
1316 if (header->c_firstrec)
1317 fprintf(stderr, "begins with record %lld",
1318 (long long)header->c_firstrec);
1319 fprintf(stderr, "\n");
1320 previno = 0x7fffffff;
1321 return;
1322 }
1323 if (previno == 0x7fffffff)
1324 goto newcalc;
1325 switch (prevtype) {
1326 case TS_BITS:
1327 fprintf(stderr, "Dumped inodes map header");
1328 break;
1329 case TS_CLRI:
1330 fprintf(stderr, "Used inodes map header");
1331 break;
1332 case TS_INODE:
1333 fprintf(stderr, "File header, ino %llu",
1334 (unsigned long long)previno);
1335 break;
1336 case TS_ADDR:
1337 fprintf(stderr, "File continuation header, ino %llu",
1338 (unsigned long long)previno);
1339 break;
1340 case TS_END:
1341 fprintf(stderr, "End of tape header");
1342 break;
1343 }
1344 if (predict != blksread - 1)
1345 fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
1346 (long)predict, (long)(blksread - 1));
1347 fprintf(stderr, "\n");
1348 newcalc:
1349 blks = 0;
1350 switch (header->c_type) {
1351 case TS_END:
1352 break;
1353 case TS_CLRI:
1354 case TS_BITS:
1355 blks = header->c_count;
1356 break;
1357 default:
1358 for (i = 0; i < header->c_count; i++)
1359 if (header->c_addr[i] != 0)
1360 blks++;
1361 break;
1362 }
1363 predict = blks;
1364 blksread = 0;
1365 prevtype = header->c_type;
1366 previno = header->c_inumber;
1367 }
1368
1369 /*
1370 * Find an inode header.
1371 * Complain if had to skip, and complain is set.
1372 */
1373 static void
1374 findinode(struct s_spcl *header)
1375 {
1376 static long skipcnt = 0;
1377 long i;
1378 char buf[TP_BSIZE];
1379
1380 curfile.name = "<name unknown>";
1381 curfile.action = UNKNOWN;
1382 curfile.mode = 0;
1383 curfile.ino = 0;
1384 top:
1385 do {
1386 if (header->c_magic != FS_UFS2_MAGIC) {
1387 skipcnt++;
1388 while (gethead(header) == FAIL ||
1389 header->c_date != dumpdate)
1390 skipcnt++;
1391 }
1392 switch (header->c_type) {
1393
1394 case TS_ADDR:
1395 /*
1396 * Skip up to the beginning of the next record
1397 */
1398 for (i = 0; i < header->c_count; i++)
1399 if (header->c_addr[i])
1400 readtape(buf);
1401 while (gethead(header) == FAIL ||
1402 header->c_date != dumpdate)
1403 skipcnt++;
1404 /* We've read a header; don't drop it. */
1405 goto top;
1406
1407 case TS_INODE:
1408 curfile.mode = header->c_mode;
1409 curfile.uid = header->c_uid;
1410 curfile.gid = header->c_gid;
1411 curfile.file_flags = header->c_file_flags;
1412 curfile.rdev = header->c_rdev;
1413 curfile.atime_sec = header->c_atime;
1414 curfile.atime_nsec = header->c_atimensec;
1415 curfile.mtime_sec = header->c_mtime;
1416 curfile.mtime_nsec = header->c_mtimensec;
1417 curfile.birthtime_sec = header->c_birthtime;
1418 curfile.birthtime_nsec = header->c_birthtimensec;
1419 curfile.size = header->c_size;
1420 curfile.ino = header->c_inumber;
1421 break;
1422
1423 case TS_END:
1424 curfile.ino = maxino;
1425 break;
1426
1427 case TS_CLRI:
1428 curfile.name = "<file removal list>";
1429 break;
1430
1431 case TS_BITS:
1432 curfile.name = "<file dump list>";
1433 break;
1434
1435 case TS_TAPE:
1436 panic("unexpected tape header\n");
1437 break;
1438
1439 default:
1440 panic("unknown tape header type %d\n", spcl.c_type);
1441 break;
1442
1443 }
1444 } while (header->c_type == TS_ADDR);
1445 if (skipcnt > 0)
1446 fprintf(stderr, "resync restore, skipped %ld blocks\n",
1447 (long)skipcnt);
1448 skipcnt = 0;
1449 }
1450
1451 static int
1452 checksum(int *buf)
1453 {
1454 int i, j;
1455
1456 j = sizeof(union u_spcl) / sizeof(int);
1457 i = 0;
1458 if(!Bcvt) {
1459 do
1460 i += *buf++;
1461 while (--j);
1462 } else {
1463 do
1464 i += bswap32(*buf++);
1465 while (--j);
1466 }
1467
1468 if (i != CHECKSUM) {
1469 fprintf(stderr, "Checksum error %o, inode %llu file %s\n", i,
1470 (unsigned long long)curfile.ino, curfile.name);
1471 return(FAIL);
1472 }
1473 return(GOOD);
1474 }
1475
1476 #ifdef RRESTORE
1477 #include <stdarg.h>
1478
1479 void
1480 msg(const char *fmt, ...)
1481 {
1482 va_list ap;
1483
1484 va_start(ap, fmt);
1485 (void)vfprintf(stderr, fmt, ap);
1486 va_end(ap);
1487 }
1488 #endif /* RRESTORE */
1489
1490 static void
1491 swap_header(struct s_spcl *s)
1492 {
1493 s->c_type = bswap32(s->c_type);
1494 s->c_old_date = bswap32(s->c_old_date);
1495 s->c_old_ddate = bswap32(s->c_old_ddate);
1496 s->c_volume = bswap32(s->c_volume);
1497 s->c_old_tapea = bswap32(s->c_old_tapea);
1498 s->c_inumber = bswap32(s->c_inumber);
1499 s->c_magic = bswap32(s->c_magic);
1500 s->c_checksum = bswap32(s->c_checksum);
1501
1502 s->c_mode = bswap16(s->c_mode);
1503 s->c_size = bswap64(s->c_size);
1504 s->c_old_atime = bswap32(s->c_old_atime);
1505 s->c_atimensec = bswap32(s->c_atimensec);
1506 s->c_old_mtime = bswap32(s->c_old_mtime);
1507 s->c_mtimensec = bswap32(s->c_mtimensec);
1508 s->c_rdev = bswap32(s->c_rdev);
1509 s->c_birthtimensec = bswap32(s->c_birthtimensec);
1510 s->c_birthtime = bswap64(s->c_birthtime);
1511 s->c_atime = bswap64(s->c_atime);
1512 s->c_mtime = bswap64(s->c_mtime);
1513 s->c_file_flags = bswap32(s->c_file_flags);
1514 s->c_uid = bswap32(s->c_uid);
1515 s->c_gid = bswap32(s->c_gid);
1516
1517 s->c_count = bswap32(s->c_count);
1518 s->c_level = bswap32(s->c_level);
1519 s->c_flags = bswap32(s->c_flags);
1520 s->c_old_firstrec = bswap32(s->c_old_firstrec);
1521
1522 s->c_date = bswap64(s->c_date);
1523 s->c_ddate = bswap64(s->c_ddate);
1524 s->c_tapea = bswap64(s->c_tapea);
1525 s->c_firstrec = bswap64(s->c_firstrec);
1526
1527 /*
1528 * These are ouid and ogid.
1529 */
1530 s->c_spare1[1] = bswap16(s->c_spare1[1]);
1531 s->c_spare1[2] = bswap16(s->c_spare1[2]);
1532 }
1533
1534 static void
1535 swap_old_header(struct s_ospcl *os)
1536 {
1537 os->c_type = bswap32(os->c_type);
1538 os->c_date = bswap32(os->c_date);
1539 os->c_ddate = bswap32(os->c_ddate);
1540 os->c_volume = bswap32(os->c_volume);
1541 os->c_tapea = bswap32(os->c_tapea);
1542 os->c_inumber = bswap16(os->c_inumber);
1543 os->c_magic = bswap32(os->c_magic);
1544 os->c_checksum = bswap32(os->c_checksum);
1545
1546 os->c_odinode.odi_mode = bswap16(os->c_odinode.odi_mode);
1547 os->c_odinode.odi_nlink = bswap16(os->c_odinode.odi_nlink);
1548 os->c_odinode.odi_uid = bswap16(os->c_odinode.odi_uid);
1549 os->c_odinode.odi_gid = bswap16(os->c_odinode.odi_gid);
1550
1551 os->c_odinode.odi_size = bswap32(os->c_odinode.odi_size);
1552 os->c_odinode.odi_rdev = bswap32(os->c_odinode.odi_rdev);
1553 os->c_odinode.odi_atime = bswap32(os->c_odinode.odi_atime);
1554 os->c_odinode.odi_mtime = bswap32(os->c_odinode.odi_mtime);
1555 os->c_odinode.odi_ctime = bswap32(os->c_odinode.odi_ctime);
1556
1557 os->c_count = bswap32(os->c_count);
1558 }
1559