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