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