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