Home | History | Annotate | Line # | Download | only in restore
      1 /*	$NetBSD: restore.c,v 1.22 2021/06/19 13:56:35 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1983, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 #if 0
     35 static char sccsid[] = "@(#)restore.c	8.3 (Berkeley) 9/13/94";
     36 #else
     37 __RCSID("$NetBSD: restore.c,v 1.22 2021/06/19 13:56:35 christos Exp $");
     38 #endif
     39 #endif /* not lint */
     40 
     41 #include <sys/types.h>
     42 #include <sys/stat.h>
     43 
     44 #include <ufs/ufs/dinode.h>
     45 
     46 #include <stdio.h>
     47 #include <string.h>
     48 
     49 #include "restore.h"
     50 #include "extern.h"
     51 
     52 static char *keyval(int);
     53 
     54 /*
     55  * This implements the 't' option.
     56  * List entries on the tape.
     57  */
     58 long
     59 listfile(const char *name, ino_t ino, int type)
     60 {
     61 	long descend = hflag ? GOOD : FAIL;
     62 
     63 	if (TSTINO(ino, dumpmap) == 0)
     64 		return (descend);
     65 	vprintf(stdout, "%s", type == LEAF ? "leaf" : "dir ");
     66 	fprintf(stdout, "%10ju\t%s\n", (uintmax_t)ino, name);
     67 	return (descend);
     68 }
     69 
     70 /*
     71  * This implements the 'x' option.
     72  * Request that new entries be extracted.
     73  */
     74 long
     75 addfile(const char *name, ino_t ino, int type)
     76 {
     77 	struct entry *ep;
     78 	long descend = hflag ? GOOD : FAIL;
     79 	char buf[100];
     80 
     81 	if (TSTINO(ino, dumpmap) == 0) {
     82 		dprintf(stdout, "%s: not on the tape\n", name);
     83 		return (descend);
     84 	}
     85 	if (ino == UFS_WINO && command == 'i' && !vflag)
     86 		return (descend);
     87 	if (!mflag) {
     88 		(void) snprintf(buf, sizeof(buf), "./%ju",
     89 		    (uintmax_t)ino);
     90 		name = buf;
     91 		if (type == NODE) {
     92 			(void) genliteraldir(name, ino);
     93 			return (descend);
     94 		}
     95 	}
     96 	ep = lookupino(ino);
     97 	if (ep != NULL) {
     98 		if (strcmp(name, myname(ep)) == 0) {
     99 			ep->e_flags |= NEW;
    100 			return (descend);
    101 		}
    102 		type |= LINK;
    103 	}
    104 	ep = addentry(name, ino, type);
    105 	if (type == NODE)
    106 		newnode(ep);
    107 	ep->e_flags |= NEW;
    108 	return (descend);
    109 }
    110 
    111 /*
    112  * This is used by the 'i' option to undo previous requests made by addfile.
    113  * Delete entries from the request queue.
    114  */
    115 /* ARGSUSED */
    116 long
    117 deletefile(const char *name, ino_t ino, int type __unused)
    118 {
    119 	long descend = hflag ? GOOD : FAIL;
    120 	struct entry *ep;
    121 
    122 	if (TSTINO(ino, dumpmap) == 0)
    123 		return (descend);
    124 	ep = lookupname(name);
    125 	if (ep != NULL) {
    126 		ep->e_flags &= ~NEW;
    127 		ep->e_flags |= REMOVED;
    128 		if (ep->e_type != NODE)
    129 			freeentry(ep);
    130 	}
    131 	return (descend);
    132 }
    133 
    134 /*
    135  * The following four routines implement the incremental
    136  * restore algorithm. The first removes old entries, the second
    137  * does renames and calculates the extraction list, the third
    138  * cleans up link names missed by the first two, and the final
    139  * one deletes old directories.
    140  *
    141  * Directories cannot be immediately deleted, as they may have
    142  * other files in them which need to be moved out first. As
    143  * directories to be deleted are found, they are put on the
    144  * following deletion list. After all deletions and renames
    145  * are done, this list is actually deleted.
    146  */
    147 static struct entry *removelist;
    148 
    149 /*
    150  *	Remove invalid whiteouts from the old tree.
    151  *	Remove unneeded leaves from the old tree.
    152  *	Remove directories from the lookup chains.
    153  */
    154 void
    155 removeoldleaves(void)
    156 {
    157 	struct entry *ep, *nextep;
    158 	ino_t i, mydirino;
    159 
    160 	vprintf(stdout, "Mark entries to be removed.\n");
    161 	if ((ep = lookupino(UFS_WINO)) != NULL) {
    162 		vprintf(stdout, "Delete whiteouts\n");
    163 		for ( ; ep != NULL; ep = nextep) {
    164 			nextep = ep->e_links;
    165 			mydirino = ep->e_parent->e_ino;
    166 			/*
    167 			 * We remove all whiteouts that are in directories
    168 			 * that have been removed or that have been dumped.
    169 			 */
    170 			if (TSTINO(mydirino, usedinomap) &&
    171 			    !TSTINO(mydirino, dumpmap))
    172 				continue;
    173 			delwhiteout(ep);
    174 			freeentry(ep);
    175 		}
    176 	}
    177 	for (i = UFS_ROOTINO + 1; i < maxino; i++) {
    178 		ep = lookupino(i);
    179 		if (ep == NULL)
    180 			continue;
    181 		if (TSTINO(i, usedinomap))
    182 			continue;
    183 		for ( ; ep != NULL; ep = ep->e_links) {
    184 			dprintf(stdout, "%s: REMOVE\n", myname(ep));
    185 			if (ep->e_type == LEAF) {
    186 				removeleaf(ep);
    187 				freeentry(ep);
    188 			} else {
    189 				mktempname(ep);
    190 				deleteino(ep->e_ino);
    191 				ep->e_next = removelist;
    192 				removelist = ep;
    193 			}
    194 		}
    195 	}
    196 }
    197 
    198 /*
    199  *	For each directory entry on the incremental tape, determine which
    200  *	category it falls into as follows:
    201  *	KEEP - entries that are to be left alone.
    202  *	NEW - new entries to be added.
    203  *	EXTRACT - files that must be updated with new contents.
    204  *	LINK - new links to be added.
    205  *	Renames are done at the same time.
    206  */
    207 long
    208 nodeupdates(const char *name, ino_t ino, int type)
    209 {
    210 	struct entry *ep, *np, *ip;
    211 	long descend = GOOD;
    212 	int lookuptype = 0;
    213 	int key = 0;
    214 		/* key values */
    215 #		define ONTAPE	0x1	/* inode is on the tape */
    216 #		define INOFND	0x2	/* inode already exists */
    217 #		define NAMEFND	0x4	/* name already exists */
    218 #		define MODECHG	0x8	/* mode of inode changed */
    219 
    220 	/*
    221 	 * This routine is called once for each element in the
    222 	 * directory hierarchy, with a full path name.
    223 	 * The "type" value is incorrectly specified as LEAF for
    224 	 * directories that are not on the dump tape.
    225 	 *
    226 	 * Check to see if the file is on the tape.
    227 	 */
    228 	if (TSTINO(ino, dumpmap))
    229 		key |= ONTAPE;
    230 	/*
    231 	 * Check to see if the name exists, and if the name is a link.
    232 	 */
    233 	np = lookupname(name);
    234 	if (np != NULL) {
    235 		key |= NAMEFND;
    236 		ip = lookupino(np->e_ino);
    237 		if (ip == NULL)
    238 			panic("corrupted symbol table\n");
    239 		if (ip != np)
    240 			lookuptype = LINK;
    241 	}
    242 	/*
    243 	 * Check to see if the inode exists, and if one of its links
    244 	 * corresponds to the name (if one was found).
    245 	 */
    246 	ip = lookupino(ino);
    247 	if (ip != NULL) {
    248 		key |= INOFND;
    249 		for (ep = ip->e_links; ep != NULL; ep = ep->e_links) {
    250 			if (ep == np) {
    251 				ip = ep;
    252 				break;
    253 			}
    254 		}
    255 	}
    256 	/*
    257 	 * If both a name and an inode are found, but they do not
    258 	 * correspond to the same file, then both the inode that has
    259 	 * been found and the inode corresponding to the name that
    260 	 * has been found need to be renamed. The current pathname
    261 	 * is the new name for the inode that has been found. Since
    262 	 * all files to be deleted have already been removed, the
    263 	 * named file is either a now unneeded link, or it must live
    264 	 * under a new name in this dump level. If it is a link, it
    265 	 * can be removed. If it is not a link, it is given a
    266 	 * temporary name in anticipation that it will be renamed
    267 	 * when it is later found by inode number.
    268 	 */
    269 	if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) {
    270 		if (lookuptype == LINK) {
    271 			removeleaf(np);
    272 			freeentry(np);
    273 		} else {
    274 			dprintf(stdout, "name/inode conflict, mktempname %s\n",
    275 				myname(np));
    276 			mktempname(np);
    277 		}
    278 		np = NULL;
    279 		key &= ~NAMEFND;
    280 	}
    281 	if ((key & ONTAPE) &&
    282 	  (((key & INOFND) && ip->e_type != type) ||
    283 	   ((key & NAMEFND) && np->e_type != type)))
    284 		key |= MODECHG;
    285 
    286 	/*
    287 	 * Decide on the disposition of the file based on its flags.
    288 	 * Note that we have already handled the case in which
    289 	 * a name and inode are found that correspond to different files.
    290 	 * Thus if both NAMEFND and INOFND are set then ip == np.
    291 	 */
    292 	switch (key) {
    293 
    294 	/*
    295 	 * A previously existing file has been found.
    296 	 * Mark it as KEEP so that other links to the inode can be
    297 	 * detected, and so that it will not be reclaimed by the search
    298 	 * for unreferenced names.
    299 	 */
    300 	case INOFND|NAMEFND:
    301 		ip->e_flags |= KEEP;
    302 		dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
    303 			flagvalues(ip));
    304 		break;
    305 
    306 	/*
    307 	 * A file on the tape has a name which is the same as a name
    308 	 * corresponding to a different file in the previous dump.
    309 	 * Since all files to be deleted have already been removed,
    310 	 * this file is either a now unneeded link, or it must live
    311 	 * under a new name in this dump level. If it is a link, it
    312 	 * can simply be removed. If it is not a link, it is given a
    313 	 * temporary name in anticipation that it will be renamed
    314 	 * when it is later found by inode number (see INOFND case
    315 	 * below). The entry is then treated as a new file.
    316 	 */
    317 	case ONTAPE|NAMEFND:
    318 	case ONTAPE|NAMEFND|MODECHG:
    319 		if (lookuptype == LINK) {
    320 			removeleaf(np);
    321 			freeentry(np);
    322 		} else {
    323 			mktempname(np);
    324 		}
    325 		/* FALLTHROUGH */
    326 
    327 	/*
    328 	 * A previously non-existent file.
    329 	 * Add it to the file system, and request its extraction.
    330 	 * If it is a directory, create it immediately.
    331 	 * (Since the name is unused there can be no conflict)
    332 	 */
    333 	case ONTAPE:
    334 		ep = addentry(name, ino, type);
    335 		if (type == NODE)
    336 			newnode(ep);
    337 		ep->e_flags |= NEW|KEEP;
    338 		dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
    339 			flagvalues(ep));
    340 		break;
    341 
    342 	/*
    343 	 * A file with the same inode number, but a different
    344 	 * name has been found. If the other name has not already
    345 	 * been found (indicated by the KEEP flag, see above) then
    346 	 * this must be a new name for the file, and it is renamed.
    347 	 * If the other name has been found then this must be a
    348 	 * link to the file. Hard links to directories are not
    349 	 * permitted, and are either deleted or converted to
    350 	 * symbolic links. Finally, if the file is on the tape,
    351 	 * a request is made to extract it.
    352 	 */
    353 	case ONTAPE|INOFND:
    354 		if (type == LEAF && (ip->e_flags & KEEP) == 0)
    355 			ip->e_flags |= EXTRACT;
    356 		/* FALLTHROUGH */
    357 	case INOFND:
    358 		if ((ip->e_flags & KEEP) == 0) {
    359 			renameit(myname(ip), name);
    360 			moveentry(ip, name);
    361 			ip->e_flags |= KEEP;
    362 			dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
    363 				flagvalues(ip));
    364 			break;
    365 		}
    366 		if (ip->e_type == NODE) {
    367 			descend = FAIL;
    368 			fprintf(stderr,
    369 				"deleted hard link %s to directory %s\n",
    370 				name, myname(ip));
    371 			break;
    372 		}
    373 		ep = addentry(name, ino, type|LINK);
    374 		ep->e_flags |= NEW;
    375 		dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
    376 			flagvalues(ep));
    377 		break;
    378 
    379 	/*
    380 	 * A previously known file which is to be updated. If it is a link,
    381 	 * then all names referring to the previous file must be removed
    382 	 * so that the subset of them that remain can be recreated.
    383 	 */
    384 	case ONTAPE|INOFND|NAMEFND:
    385 		if (lookuptype == LINK) {
    386 			removeleaf(np);
    387 			freeentry(np);
    388 			ep = addentry(name, ino, type|LINK);
    389 			if (type == NODE)
    390 			        newnode(ep);
    391 			ep->e_flags |= NEW|KEEP;
    392 			dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
    393 				flagvalues(ep));
    394 			break;
    395 		}
    396 		if (type == LEAF && lookuptype != LINK)
    397 			np->e_flags |= EXTRACT;
    398 		np->e_flags |= KEEP;
    399 		dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
    400 			flagvalues(np));
    401 		break;
    402 
    403 	/*
    404 	 * An inode is being reused in a completely different way.
    405 	 * Normally an extract can simply do an "unlink" followed
    406 	 * by a "creat". Here we must do effectively the same
    407 	 * thing. The complications arise because we cannot really
    408 	 * delete a directory since it may still contain files
    409 	 * that we need to rename, so we delete it from the symbol
    410 	 * table, and put it on the list to be deleted eventually.
    411 	 * Conversely if a directory is to be created, it must be
    412 	 * done immediately, rather than waiting until the
    413 	 * extraction phase.
    414 	 */
    415 	case ONTAPE|INOFND|MODECHG:
    416 	case ONTAPE|INOFND|NAMEFND|MODECHG:
    417 		if (ip->e_flags & KEEP) {
    418 			badentry(ip, "cannot KEEP and change modes");
    419 			break;
    420 		}
    421 		if (ip->e_type == LEAF) {
    422 			/* changing from leaf to node */
    423 			for ( ; ip != NULL; ip = ip->e_links) {
    424 				if (ip->e_type != LEAF)
    425 					badentry(ip,
    426 					    "NODE and LEAF links to same inode");
    427 				removeleaf(ip);
    428 				freeentry(ip);
    429 			}
    430 			ip = addentry(name, ino, type);
    431 			newnode(ip);
    432 		} else {
    433 			/* changing from node to leaf */
    434 			if ((ip->e_flags & TMPNAME) == 0)
    435 				mktempname(ip);
    436 			deleteino(ip->e_ino);
    437 			ip->e_next = removelist;
    438 			removelist = ip;
    439 			ip = addentry(name, ino, type);
    440 		}
    441 		ip->e_flags |= NEW|KEEP;
    442 		dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
    443 			flagvalues(ip));
    444 		break;
    445 
    446 	/*
    447 	 * A hard link to a diirectory that has been removed.
    448 	 * Ignore it.
    449 	 */
    450 	case NAMEFND:
    451 		dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key),
    452 			name);
    453 		descend = FAIL;
    454 		break;
    455 
    456 	/*
    457 	 * If we find a directory entry for a file that is not on
    458 	 * the tape, then we must have found a file that was created
    459 	 * while the dump was in progress. Since we have no contents
    460 	 * for it, we discard the name knowing that it will be on the
    461 	 * next incremental tape.
    462 	 */
    463 	case 0:
    464 		fprintf(stderr, "%s: (inode %ju) not found on tape\n",
    465 			name, (uintmax_t)ino);
    466 		break;
    467 
    468 	/*
    469 	 * If any of these arise, something is grievously wrong with
    470 	 * the current state of the symbol table.
    471 	 */
    472 	case INOFND|NAMEFND|MODECHG:
    473 	case NAMEFND|MODECHG:
    474 	case INOFND|MODECHG:
    475 		fprintf(stderr, "[%s] %s: inconsistent state\n", keyval(key),
    476 			name);
    477 		break;
    478 
    479 	/*
    480 	 * These states "cannot" arise for any state of the symbol table.
    481 	 */
    482 	case ONTAPE|MODECHG:
    483 	case MODECHG:
    484 	default:
    485 		panic("[%s] %s: impossible state\n", keyval(key), name);
    486 		break;
    487 	}
    488 	return (descend);
    489 }
    490 
    491 /*
    492  * Calculate the active flags in a key.
    493  */
    494 static char *
    495 keyval(int key)
    496 {
    497 	static char keybuf[32];
    498 
    499 	(void) strcpy(keybuf, "|NIL");
    500 	keybuf[0] = '\0';
    501 	if (key & ONTAPE)
    502 		(void) strcat(keybuf, "|ONTAPE");
    503 	if (key & INOFND)
    504 		(void) strcat(keybuf, "|INOFND");
    505 	if (key & NAMEFND)
    506 		(void) strcat(keybuf, "|NAMEFND");
    507 	if (key & MODECHG)
    508 		(void) strcat(keybuf, "|MODECHG");
    509 	return (&keybuf[1]);
    510 }
    511 
    512 /*
    513  * Find unreferenced link names.
    514  */
    515 void
    516 findunreflinks(void)
    517 {
    518 	struct entry *ep, *np;
    519 	ino_t i;
    520 
    521 	vprintf(stdout, "Find unreferenced names.\n");
    522 	for (i = UFS_ROOTINO; i < maxino; i++) {
    523 		ep = lookupino(i);
    524 		if (ep == NULL || ep->e_type == LEAF || TSTINO(i, dumpmap) == 0)
    525 			continue;
    526 		for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
    527 			if (np->e_flags == 0) {
    528 				dprintf(stdout,
    529 				    "%s: remove unreferenced name\n",
    530 				    myname(np));
    531 				removeleaf(np);
    532 				freeentry(np);
    533 			}
    534 		}
    535 	}
    536 	/*
    537 	 * Any leaves remaining in removed directories is unreferenced.
    538 	 */
    539 	for (ep = removelist; ep != NULL; ep = ep->e_next) {
    540 		for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
    541 			if (np->e_type == LEAF) {
    542 				if (np->e_flags != 0)
    543 					badentry(np, "unreferenced with flags");
    544 				dprintf(stdout,
    545 				    "%s: remove unreferenced name\n",
    546 				    myname(np));
    547 				removeleaf(np);
    548 				freeentry(np);
    549 			}
    550 		}
    551 	}
    552 }
    553 
    554 /*
    555  * Remove old nodes (directories).
    556  * Note that this routine runs in O(N*D) where:
    557  *	N is the number of directory entries to be removed.
    558  *	D is the maximum depth of the tree.
    559  * If N == D this can be quite slow. If the list were
    560  * topologically sorted, the deletion could be done in
    561  * time O(N).
    562  */
    563 void
    564 removeoldnodes(void)
    565 {
    566 	struct entry *ep, **prev;
    567 	long change;
    568 
    569 	vprintf(stdout, "Remove old nodes (directories).\n");
    570 	do	{
    571 		change = 0;
    572 		prev = &removelist;
    573 		for (ep = removelist; ep != NULL; ep = *prev) {
    574 			if (ep->e_entries != NULL) {
    575 				prev = &ep->e_next;
    576 				continue;
    577 			}
    578 			*prev = ep->e_next;
    579 			removenode(ep);
    580 			freeentry(ep);
    581 			change++;
    582 		}
    583 	} while (change);
    584 	for (ep = removelist; ep != NULL; ep = ep->e_next)
    585 		badentry(ep, "cannot remove, non-empty");
    586 }
    587 
    588 /*
    589  * This is the routine used to extract files for the 'r' command.
    590  * Extract new leaves.
    591  */
    592 void
    593 createleaves(const char *symtabfile)
    594 {
    595 	struct entry *ep;
    596 	ino_t first;
    597 	long curvol;
    598 
    599 	if (command == 'R') {
    600 		vprintf(stdout, "Continue extraction of new leaves\n");
    601 	} else {
    602 		vprintf(stdout, "Extract new leaves.\n");
    603 		dumpsymtable(symtabfile, volno);
    604 	}
    605 	first = lowerbnd(UFS_ROOTINO);
    606 	curvol = volno;
    607 	while (curfile.ino < maxino) {
    608 		first = lowerbnd(first);
    609 		/*
    610 		 * If the next available file is not the one which we
    611 		 * expect then we have missed one or more files. Since
    612 		 * we do not request files that were not on the tape,
    613 		 * the lost files must have been due to a tape read error,
    614 		 * or a file that was removed while the dump was in progress.
    615 		 */
    616 		while (first < curfile.ino) {
    617 			ep = lookupino(first);
    618 			if (ep == NULL)
    619 				panic("%ju: bad first\n",
    620 				    (uintmax_t)first);
    621 			fprintf(stderr, "%s: not found on tape\n", myname(ep));
    622 			ep->e_flags &= ~(NEW|EXTRACT);
    623 			first = lowerbnd(first);
    624 		}
    625 		/*
    626 		 * If we find files on the tape that have no corresponding
    627 		 * directory entries, then we must have found a file that
    628 		 * was created while the dump was in progress. Since we have
    629 		 * no name for it, we discard it knowing that it will be
    630 		 * on the next incremental tape.
    631 		 */
    632 		if (first != curfile.ino) {
    633 			fprintf(stderr, "expected next file %ju, got %ju\n",
    634 			    (uintmax_t)first,
    635 			    (uintmax_t)curfile.ino);
    636 			skipfile();
    637 			goto next;
    638 		}
    639 		ep = lookupino(curfile.ino);
    640 		if (ep == NULL)
    641 			panic("unknown file on tape\n");
    642 		if ((ep->e_flags & (NEW|EXTRACT)) == 0)
    643 			badentry(ep, "unexpected file on tape");
    644 		/*
    645 		 * If the file is to be extracted, then the old file must
    646 		 * be removed since its type may change from one leaf type
    647 		 * to another (eg "file" to "character special").
    648 		 */
    649 		if ((ep->e_flags & EXTRACT) != 0) {
    650 			removeleaf(ep);
    651 			ep->e_flags &= ~REMOVED;
    652 		}
    653 		(void) extractfile(myname(ep));
    654 		ep->e_flags &= ~(NEW|EXTRACT);
    655 		/*
    656 		 * We checkpoint the restore after every tape reel, so
    657 		 * as to simplify the amount of work re quired by the
    658 		 * 'R' command.
    659 		 */
    660 	next:
    661 		if (curvol != volno) {
    662 			dumpsymtable(symtabfile, volno);
    663 			skipmaps();
    664 			curvol = volno;
    665 		}
    666 	}
    667 }
    668 
    669 /*
    670  * This is the routine used to extract files for the 'x' and 'i' commands.
    671  * Efficiently extract a subset of the files on a tape.
    672  */
    673 void
    674 createfiles(void)
    675 {
    676 	ino_t first, next, last;
    677 	struct entry *ep;
    678 	long curvol;
    679 
    680 	vprintf(stdout, "Extract requested files\n");
    681 	curfile.action = SKIP;
    682 	getvol((long)1);
    683 	skipmaps();
    684 	skipdirs();
    685 	first = lowerbnd(UFS_ROOTINO);
    686 	last = upperbnd(maxino - 1);
    687 
    688 new_volume:
    689 	/*
    690 	 * Decide on the next inode needed in this volume.
    691 	 */
    692 	next = lowerbnd(curfile.ino);
    693 	for (;;) {
    694 		first = lowerbnd(first);
    695 		last = upperbnd(last);
    696 		/*
    697 		 * Check to see if any files remain to be extracted
    698 		 */
    699 		if (first > last)
    700 			return;
    701 		/*
    702 		 * Reject any volumes with inodes greater
    703 		 * than the last one needed
    704 		 */
    705 		if (curfile.ino > last) {
    706 			do {
    707 				curfile.action = SKIP;
    708 				getvol((long)0);
    709 				skipmaps();
    710 				skipdirs();
    711 			} while (curfile.ino > last);
    712 			goto new_volume;
    713 		}
    714 		/*
    715 		 * Skip across the inodes until the next inode is found
    716 		 * or an out of order volume change is encountered
    717 		 */
    718 		do {
    719 			curvol = volno;
    720 			while (next > curfile.ino && volno == curvol)
    721 				skipfile();
    722 			skipmaps();
    723 			skipdirs();
    724 		} while (volno == curvol + 1);
    725 		/*
    726 		 * If volume change out of order occurred the
    727 		 * current state must be recalculated
    728 		 */
    729 		if (volno != curvol)
    730 			goto new_volume;
    731 		/*
    732 		 * If the current inode is greater than the one we were
    733 		 * looking for then we missed the one we were looking for.
    734 		 * Since we only attempt to extract files listed in the
    735 		 * dump map, the lost files must have been due to a tape
    736 		 * read error, or a file that was removed while the dump
    737 		 * was in progress. Thus we report all requested files
    738 		 * between the one we were looking for, and the one we
    739 		 * found as missing, and delete their request flags.
    740 		 */
    741 		while (next < curfile.ino) {
    742 			ep = lookupino(next);
    743 			if (ep == NULL)
    744 				panic("corrupted symbol table\n");
    745 			fprintf(stderr, "%s: not found on tape\n", myname(ep));
    746 			ep->e_flags &= ~NEW;
    747 			next = lowerbnd(next);
    748 		}
    749 		/*
    750 		 * The current inode is the one that we are looking for,
    751 		 * so extract it per its requested name.
    752 		 */
    753 		if (next == curfile.ino && next <= last) {
    754 			ep = lookupino(next);
    755 			if (ep == NULL)
    756 				panic("corrupted symbol table\n");
    757 			(void) extractfile(myname(ep));
    758 			ep->e_flags &= ~NEW;
    759 			if (volno != curvol) {
    760 				skipmaps();
    761 				goto new_volume;
    762 			}
    763 			/*
    764 			 * Decide the next inode.  Note that curfile.ino
    765 			 * already updated to the next file on the tape,
    766 			 * and we can't used it since it may be greater
    767 			 * than `next'.
    768 			 */
    769 			next = lowerbnd(next);
    770 		}
    771 	}
    772 }
    773 
    774 /*
    775  * Add links.
    776  */
    777 void
    778 createlinks(void)
    779 {
    780 	struct entry *np, *ep;
    781 	ino_t i;
    782 	char name[BUFSIZ];
    783 
    784 	if ((ep = lookupino(UFS_WINO)) != NULL) {
    785 		vprintf(stdout, "Add whiteouts\n");
    786 		for ( ; ep != NULL; ep = ep->e_links) {
    787 			if ((ep->e_flags & NEW) == 0)
    788 				continue;
    789 			(void) addwhiteout(myname(ep));
    790 			ep->e_flags &= ~NEW;
    791 		}
    792 	}
    793 	vprintf(stdout, "Add links\n");
    794 	for (i = UFS_ROOTINO; i < maxino; i++) {
    795 		ep = lookupino(i);
    796 		if (ep == NULL)
    797 			continue;
    798 		for (np = ep->e_links; np != NULL; np = np->e_links) {
    799 			if ((np->e_flags & NEW) == 0)
    800 				continue;
    801 			(void) strcpy(name, myname(ep));
    802 			if (ep->e_type == NODE) {
    803 				(void) linkit(name, myname(np), SYMLINK);
    804 			} else {
    805 				(void) linkit(name, myname(np), HARDLINK);
    806 			}
    807 			np->e_flags &= ~NEW;
    808 		}
    809 	}
    810 }
    811 
    812 /*
    813  * Check the symbol table.
    814  * We do this to insure that all the requested work was done, and
    815  * that no temporary names remain.
    816  */
    817 void
    818 checkrestore(void)
    819 {
    820 	struct entry *ep;
    821 	ino_t i;
    822 
    823 	vprintf(stdout, "Check the symbol table.\n");
    824 	for (i = UFS_WINO; i < maxino; i++) {
    825 		for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
    826 			ep->e_flags &= ~KEEP;
    827 			if (ep->e_type == NODE)
    828 				ep->e_flags &= ~(NEW|EXISTED);
    829 			if (ep->e_flags != 0)
    830 				badentry(ep, "incomplete operations");
    831 		}
    832 	}
    833 }
    834 
    835 /*
    836  * Compare with the directory structure on the tape
    837  * A paranoid check that things are as they should be.
    838  */
    839 long
    840 verifyfile(const char *name, ino_t ino, int type)
    841 {
    842 	struct entry *np, *ep;
    843 	long descend = GOOD;
    844 
    845 	ep = lookupname(name);
    846 	if (ep == NULL) {
    847 		fprintf(stderr, "Warning: missing name %s\n", name);
    848 		return (FAIL);
    849 	}
    850 	np = lookupino(ino);
    851 	if (np != ep)
    852 		descend = FAIL;
    853 	for ( ; np != NULL; np = np->e_links)
    854 		if (np == ep)
    855 			break;
    856 	if (np == NULL)
    857 		panic("missing inumber %ju\n", (uintmax_t)ino);
    858 	if (ep->e_type == LEAF && type != LEAF)
    859 		badentry(ep, "type should be LEAF");
    860 	return (descend);
    861 }
    862