xref: /csrg-svn/local/ukc/restore/restore.c (revision 32024)
132021Spc /*
232021Spc  * Copyright (c) 1983 Regents of the University of California.
332021Spc  * All rights reserved.  The Berkeley software License Agreement
432021Spc  * specifies the terms and conditions for redistribution.
532021Spc  */
632021Spc 
732021Spc #ifndef lint
8*32024Spc static char sccsid[] = "@(#)restore.c	5.3 (Berkeley) 6/18/87";
932021Spc #endif not lint
1032021Spc 
1132021Spc #include "restore.h"
1232021Spc 
1332021Spc /*
1432021Spc  * This implements the 't' option.
1532021Spc  * List entries on the tape.
1632021Spc  */
1732021Spc long
listfile(name,ino,type)1832021Spc listfile(name, ino, type)
1932021Spc 	char *name;
2032021Spc 	ino_t ino;
2132021Spc 	int type;
2232021Spc {
2332021Spc 	long descend = hflag ? GOOD : FAIL;
2432021Spc 
2532021Spc 	if (BIT(ino, dumpmap) == 0) {
2632021Spc 		return (descend);
2732021Spc 	}
2832021Spc 	vprintf(stdout, "%s", type == LEAF ? "leaf" : "dir ");
2932021Spc 	fprintf(stdout, "%10d\t%s\n", ino, name);
3032021Spc 	return (descend);
3132021Spc }
3232021Spc 
3332021Spc /*
3432021Spc  * This implements the 'x' option.
3532021Spc  * Request that new entries be extracted.
3632021Spc  */
3732021Spc long
addfile(name,ino,type)3832021Spc addfile(name, ino, type)
3932021Spc 	char *name;
4032021Spc 	ino_t ino;
4132021Spc 	int type;
4232021Spc {
4332021Spc 	register struct entry *ep;
4432021Spc 	long descend = hflag ? GOOD : FAIL;
4532021Spc 	char buf[100];
4632021Spc 
4732021Spc 	if (BIT(ino, dumpmap) == 0) {
4832021Spc 		vprintf(stdout, "%s: not on the tape\n", name);
4932021Spc 		return (descend);
5032021Spc 	}
5132021Spc 	if (!mflag) {
5232021Spc 		(void) sprintf(buf, "./%u", ino);
5332021Spc 		name = buf;
5432021Spc 		if (type == NODE) {
5532021Spc 			(void) genliteraldir(name, ino);
5632021Spc 			return (descend);
5732021Spc 		}
5832021Spc 	}
5932021Spc 	ep = lookupino(ino);
6032021Spc 	if (ep != NIL) {
6132021Spc 		if (strcmp(name, myname(ep)) == 0) {
6232021Spc 			ep->e_flags |= NEW;
6332021Spc 			return (descend);
6432021Spc 		}
6532021Spc 		type |= LINK;
6632021Spc 	}
6732021Spc 	ep = addentry(name, ino, type);
6832021Spc 	if (type == NODE)
6932021Spc 		newnode(ep);
7032021Spc 	ep->e_flags |= NEW;
7132021Spc 	return (descend);
7232021Spc }
7332021Spc 
7432021Spc /*
7532021Spc  * This is used by the 'i' option to undo previous requests made by addfile.
7632021Spc  * Delete entries from the request queue.
7732021Spc  */
7832021Spc /* ARGSUSED */
7932021Spc long
deletefile(name,ino,type)8032021Spc deletefile(name, ino, type)
8132021Spc 	char *name;
8232021Spc 	ino_t ino;
8332021Spc 	int type;
8432021Spc {
8532021Spc 	long descend = hflag ? GOOD : FAIL;
8632021Spc 	struct entry *ep;
8732021Spc 
8832021Spc 	if (BIT(ino, dumpmap) == 0) {
8932021Spc 		return (descend);
9032021Spc 	}
9132021Spc 	ep = lookupino(ino);
9232021Spc 	if (ep != NIL)
9332021Spc 		ep->e_flags &= ~NEW;
9432021Spc 	return (descend);
9532021Spc }
9632021Spc 
9732021Spc /*
9832021Spc  * The following four routines implement the incremental
9932021Spc  * restore algorithm. The first removes old entries, the second
10032021Spc  * does renames and calculates the extraction list, the third
10132021Spc  * cleans up link names missed by the first two, and the final
10232021Spc  * one deletes old directories.
10332021Spc  *
10432021Spc  * Directories cannot be immediately deleted, as they may have
10532021Spc  * other files in them which need to be moved out first. As
10632021Spc  * directories to be deleted are found, they are put on the
10732021Spc  * following deletion list. After all deletions and renames
10832021Spc  * are done, this list is actually deleted.
10932021Spc  */
11032021Spc static struct entry *removelist;
11132021Spc 
11232021Spc /*
11332021Spc  *	Remove unneeded leaves from the old tree.
11432021Spc  *	Remove directories from the lookup chains.
11532021Spc  */
removeoldleaves()11632021Spc removeoldleaves()
11732021Spc {
11832021Spc 	register struct entry *ep;
11932021Spc 	register ino_t i;
12032021Spc 
12132021Spc 	vprintf(stdout, "Mark entries to be removed.\n");
12232021Spc 	for (i = ROOTINO + 1; i < maxino; i++) {
12332021Spc 		ep = lookupino(i);
12432021Spc 		if (ep == NIL)
12532021Spc 			continue;
12632021Spc 		if (BIT(i, clrimap))
12732021Spc 			continue;
12832021Spc 		for ( ; ep != NIL; ep = ep->e_links) {
12932021Spc 			dprintf(stdout, "%s: REMOVE\n", myname(ep));
13032021Spc 			if (ep->e_type == LEAF) {
13132021Spc 				removeleaf(ep);
13232021Spc 				freeentry(ep);
13332021Spc 			} else {
13432021Spc 				mktempname(ep);
13532021Spc 				deleteino(ep->e_ino);
13632021Spc 				ep->e_next = removelist;
13732021Spc 				removelist = ep;
13832021Spc 			}
13932021Spc 		}
14032021Spc 	}
14132021Spc }
14232021Spc 
14332021Spc /*
14432021Spc  *	For each directory entry on the incremental tape, determine which
14532021Spc  *	category it falls into as follows:
14632021Spc  *	KEEP - entries that are to be left alone.
14732021Spc  *	NEW - new entries to be added.
14832021Spc  *	EXTRACT - files that must be updated with new contents.
14932021Spc  *	LINK - new links to be added.
15032021Spc  *	Renames are done at the same time.
15132021Spc  */
15232021Spc long
nodeupdates(name,ino,type)15332021Spc nodeupdates(name, ino, type)
15432021Spc 	char *name;
15532021Spc 	ino_t ino;
15632021Spc 	int type;
15732021Spc {
15832021Spc 	register struct entry *ep, *np, *ip;
15932021Spc 	long descend = GOOD;
16032021Spc 	int lookuptype = 0;
16132021Spc 	int key = 0;
16232021Spc 		/* key values */
16332021Spc #		define ONTAPE	0x1	/* inode is on the tape */
16432021Spc #		define INOFND	0x2	/* inode already exists */
16532021Spc #		define NAMEFND	0x4	/* name already exists */
16632021Spc #		define MODECHG	0x8	/* mode of inode changed */
16732021Spc 	extern char *keyval();
16832021Spc 
16932021Spc 	/*
17032021Spc 	 * This routine is called once for each element in the
17132021Spc 	 * directory hierarchy, with a full path name.
17232021Spc 	 * The "type" value is incorrectly specified as LEAF for
17332021Spc 	 * directories that are not on the dump tape.
17432021Spc 	 *
17532021Spc 	 * Check to see if the file is on the tape.
17632021Spc 	 */
17732021Spc 	if (BIT(ino, dumpmap))
17832021Spc 		key |= ONTAPE;
17932021Spc 	/*
18032021Spc 	 * Check to see if the name exists, and if the name is a link.
18132021Spc 	 */
18232021Spc 	np = lookupname(name);
18332021Spc 	if (np != NIL) {
18432021Spc 		key |= NAMEFND;
18532021Spc 		ip = lookupino(np->e_ino);
18632021Spc 		if (ip == NULL)
18732021Spc 			panic("corrupted symbol table\n");
18832021Spc 		if (ip != np)
18932021Spc 			lookuptype = LINK;
19032021Spc 	}
19132021Spc 	/*
19232021Spc 	 * Check to see if the inode exists, and if one of its links
19332021Spc 	 * corresponds to the name (if one was found).
19432021Spc 	 */
19532021Spc 	ip = lookupino(ino);
19632021Spc 	if (ip != NIL) {
19732021Spc 		key |= INOFND;
19832021Spc 		for (ep = ip->e_links; ep != NIL; ep = ep->e_links) {
19932021Spc 			if (ep == np) {
20032021Spc 				ip = ep;
20132021Spc 				break;
20232021Spc 			}
20332021Spc 		}
20432021Spc 	}
20532021Spc 	/*
20632021Spc 	 * If both a name and an inode are found, but they do not
20732021Spc 	 * correspond to the same file, then both the inode that has
20832021Spc 	 * been found and the inode corresponding to the name that
20932021Spc 	 * has been found need to be renamed. The current pathname
21032021Spc 	 * is the new name for the inode that has been found. Since
21132021Spc 	 * all files to be deleted have already been removed, the
21232021Spc 	 * named file is either a now unneeded link, or it must live
21332021Spc 	 * under a new name in this dump level. If it is a link, it
21432021Spc 	 * can be removed. If it is not a link, it is given a
21532021Spc 	 * temporary name in anticipation that it will be renamed
21632021Spc 	 * when it is later found by inode number.
21732021Spc 	 */
21832021Spc 	if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) {
21932021Spc 		if (lookuptype == LINK) {
22032021Spc 			removeleaf(np);
22132021Spc 			freeentry(np);
22232021Spc 		} else {
22332021Spc 			dprintf(stdout, "name/inode conflict, mktempname %s\n",
22432021Spc 				myname(np));
22532021Spc 			mktempname(np);
22632021Spc 		}
22732021Spc 		np = NIL;
22832021Spc 		key &= ~NAMEFND;
22932021Spc 	}
23032021Spc 	if ((key & ONTAPE) &&
23132021Spc 	  (((key & INOFND) && ip->e_type != type) ||
23232021Spc 	   ((key & NAMEFND) && np->e_type != type)))
23332021Spc 		key |= MODECHG;
23432021Spc 
23532021Spc 	/*
23632021Spc 	 * Decide on the disposition of the file based on its flags.
23732021Spc 	 * Note that we have already handled the case in which
23832021Spc 	 * a name and inode are found that correspond to different files.
23932021Spc 	 * Thus if both NAMEFND and INOFND are set then ip == np.
24032021Spc 	 */
24132021Spc 	switch (key) {
24232021Spc 
24332021Spc 	/*
24432021Spc 	 * A previously existing file has been found.
24532021Spc 	 * Mark it as KEEP so that other links to the inode can be
24632021Spc 	 * detected, and so that it will not be reclaimed by the search
24732021Spc 	 * for unreferenced names.
24832021Spc 	 */
24932021Spc 	case INOFND|NAMEFND:
25032021Spc 		ip->e_flags |= KEEP;
25132021Spc 		dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
25232021Spc 			flagvalues(ip));
25332021Spc 		break;
25432021Spc 
25532021Spc 	/*
25632021Spc 	 * A file on the tape has a name which is the same as a name
25732021Spc 	 * corresponding to a different file in the previous dump.
25832021Spc 	 * Since all files to be deleted have already been removed,
25932021Spc 	 * this file is either a now unneeded link, or it must live
26032021Spc 	 * under a new name in this dump level. If it is a link, it
26132021Spc 	 * can simply be removed. If it is not a link, it is given a
26232021Spc 	 * temporary name in anticipation that it will be renamed
26332021Spc 	 * when it is later found by inode number (see INOFND case
26432021Spc 	 * below). The entry is then treated as a new file.
26532021Spc 	 */
26632021Spc 	case ONTAPE|NAMEFND:
26732021Spc 	case ONTAPE|NAMEFND|MODECHG:
26832021Spc 		if (lookuptype == LINK) {
26932021Spc 			removeleaf(np);
27032021Spc 			freeentry(np);
27132021Spc 		} else {
27232021Spc 			mktempname(np);
27332021Spc 		}
27432021Spc 		/* fall through */
27532021Spc 
27632021Spc 	/*
27732021Spc 	 * A previously non-existent file.
27832021Spc 	 * Add it to the file system, and request its extraction.
27932021Spc 	 * If it is a directory, create it immediately.
28032021Spc 	 * (Since the name is unused there can be no conflict)
28132021Spc 	 */
28232021Spc 	case ONTAPE:
28332021Spc 		ep = addentry(name, ino, type);
28432021Spc 		if (type == NODE)
28532021Spc 			newnode(ep);
28632021Spc 		ep->e_flags |= NEW|KEEP;
28732021Spc 		dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
28832021Spc 			flagvalues(ep));
28932021Spc 		break;
29032021Spc 
29132021Spc 	/*
29232021Spc 	 * A file with the same inode number, but a different
29332021Spc 	 * name has been found. If the other name has not already
29432021Spc 	 * been found (indicated by the KEEP flag, see above) then
29532021Spc 	 * this must be a new name for the file, and it is renamed.
29632021Spc 	 * If the other name has been found then this must be a
29732021Spc 	 * link to the file. Hard links to directories are not
29832021Spc 	 * permitted, and are either deleted or converted to
29932021Spc 	 * symbolic links. Finally, if the file is on the tape,
30032021Spc 	 * a request is made to extract it.
30132021Spc 	 */
30232021Spc 	case ONTAPE|INOFND:
30332021Spc 		if (type == LEAF && (ip->e_flags & KEEP) == 0)
30432021Spc 			ip->e_flags |= EXTRACT;
30532021Spc 		/* fall through */
30632021Spc 	case INOFND:
30732021Spc 		if ((ip->e_flags & KEEP) == 0) {
30832021Spc 			renameit(myname(ip), name);
30932021Spc 			moveentry(ip, name);
31032021Spc 			ip->e_flags |= KEEP;
31132021Spc 			dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
31232021Spc 				flagvalues(ip));
31332021Spc 			break;
31432021Spc 		}
31532021Spc 		if (ip->e_type == NODE) {
31632021Spc 			descend = FAIL;
31732021Spc 			fprintf(stderr,
31832021Spc 				"deleted hard link %s to directory %s\n",
31932021Spc 				name, myname(ip));
32032021Spc 			break;
32132021Spc 		}
32232021Spc 		ep = addentry(name, ino, type|LINK);
32332021Spc 		ep->e_flags |= NEW;
32432021Spc 		dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
32532021Spc 			flagvalues(ep));
32632021Spc 		break;
32732021Spc 
32832021Spc 	/*
32932021Spc 	 * A previously known file which is to be updated.
33032021Spc 	 */
33132021Spc 	case ONTAPE|INOFND|NAMEFND:
33232021Spc 		if (type == LEAF && lookuptype != LINK)
33332021Spc 			np->e_flags |= EXTRACT;
33432021Spc 		np->e_flags |= KEEP;
33532021Spc 		dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
33632021Spc 			flagvalues(np));
33732021Spc 		break;
33832021Spc 
33932021Spc 	/*
34032021Spc 	 * An inode is being reused in a completely different way.
34132021Spc 	 * Normally an extract can simply do an "unlink" followed
34232021Spc 	 * by a "creat". Here we must do effectively the same
34332021Spc 	 * thing. The complications arise because we cannot really
34432021Spc 	 * delete a directory since it may still contain files
34532021Spc 	 * that we need to rename, so we delete it from the symbol
34632021Spc 	 * table, and put it on the list to be deleted eventually.
34732021Spc 	 * Conversely if a directory is to be created, it must be
34832021Spc 	 * done immediately, rather than waiting until the
34932021Spc 	 * extraction phase.
35032021Spc 	 */
35132021Spc 	case ONTAPE|INOFND|MODECHG:
35232021Spc 	case ONTAPE|INOFND|NAMEFND|MODECHG:
35332021Spc 		if (ip->e_flags & KEEP) {
35432021Spc 			badentry(ip, "cannot KEEP and change modes");
35532021Spc 			break;
35632021Spc 		}
35732021Spc 		if (ip->e_type == LEAF) {
35832021Spc 			/* changing from leaf to node */
35932021Spc 			removeleaf(ip);
36032021Spc 			freeentry(ip);
36132021Spc 			ip = addentry(name, ino, type);
36232021Spc 			newnode(ip);
36332021Spc 		} else {
36432021Spc 			/* changing from node to leaf */
36532021Spc 			if ((ip->e_flags & TMPNAME) == 0)
36632021Spc 				mktempname(ip);
36732021Spc 			deleteino(ip->e_ino);
36832021Spc 			ip->e_next = removelist;
36932021Spc 			removelist = ip;
37032021Spc 			ip = addentry(name, ino, type);
37132021Spc 		}
37232021Spc 		ip->e_flags |= NEW|KEEP;
37332021Spc 		dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
37432021Spc 			flagvalues(ip));
37532021Spc 		break;
37632021Spc 
37732021Spc 	/*
37832021Spc 	 * A hard link to a diirectory that has been removed.
37932021Spc 	 * Ignore it.
38032021Spc 	 */
38132021Spc 	case NAMEFND:
38232021Spc 		dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key),
38332021Spc 			name);
38432021Spc 		descend = FAIL;
38532021Spc 		break;
38632021Spc 
38732021Spc 	/*
38832021Spc 	 * If we find a directory entry for a file that is not on
38932021Spc 	 * the tape, then we must have found a file that was created
39032021Spc 	 * while the dump was in progress. Since we have no contents
39132021Spc 	 * for it, we discard the name knowing that it will be on the
39232021Spc 	 * next incremental tape.
39332021Spc 	 */
39432021Spc 	case NIL:
395*32024Spc 		fprintf(stderr, "%s: (inode %d) not found on tape\n",
396*32024Spc 			name, ino);
39732021Spc 		break;
39832021Spc 
39932021Spc 	/*
40032021Spc 	 * If any of these arise, something is grievously wrong with
40132021Spc 	 * the current state of the symbol table.
40232021Spc 	 */
40332021Spc 	case INOFND|NAMEFND|MODECHG:
40432021Spc 	case NAMEFND|MODECHG:
40532021Spc 	case INOFND|MODECHG:
40632021Spc 		panic("[%s] %s: inconsistent state\n", keyval(key), name);
40732021Spc 		break;
40832021Spc 
40932021Spc 	/*
41032021Spc 	 * These states "cannot" arise for any state of the symbol table.
41132021Spc 	 */
41232021Spc 	case ONTAPE|MODECHG:
41332021Spc 	case MODECHG:
41432021Spc 	default:
41532021Spc 		panic("[%s] %s: impossible state\n", keyval(key), name);
41632021Spc 		break;
41732021Spc 	}
41832021Spc 	return (descend);
41932021Spc }
42032021Spc 
42132021Spc /*
42232021Spc  * Calculate the active flags in a key.
42332021Spc  */
42432021Spc char *
keyval(key)42532021Spc keyval(key)
42632021Spc 	int key;
42732021Spc {
42832021Spc 	static char keybuf[32];
42932021Spc 
43032021Spc 	(void) strcpy(keybuf, "|NIL");
43132021Spc 	keybuf[0] = '\0';
43232021Spc 	if (key & ONTAPE)
43332021Spc 		(void) strcat(keybuf, "|ONTAPE");
43432021Spc 	if (key & INOFND)
43532021Spc 		(void) strcat(keybuf, "|INOFND");
43632021Spc 	if (key & NAMEFND)
43732021Spc 		(void) strcat(keybuf, "|NAMEFND");
43832021Spc 	if (key & MODECHG)
43932021Spc 		(void) strcat(keybuf, "|MODECHG");
44032021Spc 	return (&keybuf[1]);
44132021Spc }
44232021Spc 
44332021Spc /*
44432021Spc  * Find unreferenced link names.
44532021Spc  */
findunreflinks()44632021Spc findunreflinks()
44732021Spc {
44832021Spc 	register struct entry *ep, *np;
44932021Spc 	register ino_t i;
45032021Spc 
45132021Spc 	vprintf(stdout, "Find unreferenced names.\n");
45232021Spc 	for (i = ROOTINO; i < maxino; i++) {
45332021Spc 		ep = lookupino(i);
45432021Spc 		if (ep == NIL || ep->e_type == LEAF || BIT(i, dumpmap) == 0)
45532021Spc 			continue;
45632021Spc 		for (np = ep->e_entries; np != NIL; np = np->e_sibling) {
45732021Spc 			if (np->e_flags == 0) {
45832021Spc 				dprintf(stdout,
45932021Spc 				    "%s: remove unreferenced name\n",
46032021Spc 				    myname(np));
46132021Spc 				removeleaf(np);
46232021Spc 				freeentry(np);
46332021Spc 			}
46432021Spc 		}
46532021Spc 	}
46632021Spc 	/*
46732021Spc 	 * Any leaves remaining in removed directories is unreferenced.
46832021Spc 	 */
46932021Spc 	for (ep = removelist; ep != NIL; ep = ep->e_next) {
47032021Spc 		for (np = ep->e_entries; np != NIL; np = np->e_sibling) {
47132021Spc 			if (np->e_type == LEAF) {
47232021Spc 				if (np->e_flags != 0)
47332021Spc 					badentry(np, "unreferenced with flags");
47432021Spc 				dprintf(stdout,
47532021Spc 				    "%s: remove unreferenced name\n",
47632021Spc 				    myname(np));
47732021Spc 				removeleaf(np);
47832021Spc 				freeentry(np);
47932021Spc 			}
48032021Spc 		}
48132021Spc 	}
48232021Spc }
48332021Spc 
48432021Spc /*
48532021Spc  * Remove old nodes (directories).
48632021Spc  * Note that this routine runs in O(N*D) where:
48732021Spc  *	N is the number of directory entries to be removed.
48832021Spc  *	D is the maximum depth of the tree.
48932021Spc  * If N == D this can be quite slow. If the list were
49032021Spc  * topologically sorted, the deletion could be done in
49132021Spc  * time O(N).
49232021Spc  */
removeoldnodes()49332021Spc removeoldnodes()
49432021Spc {
49532021Spc 	register struct entry *ep, **prev;
49632021Spc 	long change;
49732021Spc 
49832021Spc 	vprintf(stdout, "Remove old nodes (directories).\n");
49932021Spc 	do	{
50032021Spc 		change = 0;
50132021Spc 		prev = &removelist;
50232021Spc 		for (ep = removelist; ep != NIL; ep = *prev) {
50332021Spc 			if (ep->e_entries != NIL) {
50432021Spc 				prev = &ep->e_next;
50532021Spc 				continue;
50632021Spc 			}
50732021Spc 			*prev = ep->e_next;
50832021Spc 			removenode(ep);
50932021Spc 			freeentry(ep);
51032021Spc 			change++;
51132021Spc 		}
51232021Spc 	} while (change);
51332021Spc 	for (ep = removelist; ep != NIL; ep = ep->e_next)
51432021Spc 		badentry(ep, "cannot remove, non-empty");
51532021Spc }
51632021Spc 
51732021Spc /*
51832021Spc  * This is the routine used to extract files for the 'r' command.
51932021Spc  * Extract new leaves.
52032021Spc  */
createleaves(symtabfile)52132021Spc createleaves(symtabfile)
52232021Spc 	char *symtabfile;
52332021Spc {
52432021Spc 	register struct entry *ep;
52532021Spc 	ino_t first;
52632021Spc 	long curvol;
52732021Spc 
52832021Spc 	if (command == 'R') {
52932021Spc 		vprintf(stdout, "Continue extraction of new leaves\n");
53032021Spc 	} else {
53132021Spc 		vprintf(stdout, "Extract new leaves.\n");
53232021Spc 		dumpsymtable(symtabfile, volno);
53332021Spc 	}
53432021Spc 	first = lowerbnd(ROOTINO);
53532021Spc 	curvol = volno;
53632021Spc 	while (curfile.ino < maxino) {
53732021Spc 		first = lowerbnd(first);
53832021Spc 		/*
53932021Spc 		 * If the next available file is not the one which we
54032021Spc 		 * expect then we have missed one or more files. Since
54132021Spc 		 * we do not request files that were not on the tape,
54232021Spc 		 * the lost files must have been due to a tape read error,
54332021Spc 		 * or a file that was removed while the dump was in progress.
54432021Spc 		 */
54532021Spc 		while (first < curfile.ino) {
54632021Spc 			ep = lookupino(first);
54732021Spc 			if (ep == NIL)
54832021Spc 				panic("%d: bad first\n", first);
54932021Spc 			fprintf(stderr, "%s: not found on tape\n", myname(ep));
55032021Spc 			ep->e_flags &= ~(NEW|EXTRACT);
55132021Spc 			first = lowerbnd(first);
55232021Spc 		}
55332021Spc 		/*
55432021Spc 		 * If we find files on the tape that have no corresponding
55532021Spc 		 * directory entries, then we must have found a file that
55632021Spc 		 * was created while the dump was in progress. Since we have
55732021Spc 		 * no name for it, we discard it knowing that it will be
55832021Spc 		 * on the next incremental tape.
55932021Spc 		 */
56032021Spc 		if (first != curfile.ino) {
56132021Spc 			fprintf(stderr, "expected next file %d, got %d\n",
56232021Spc 				first, curfile.ino);
56332021Spc 			skipfile();
56432021Spc 			goto next;
56532021Spc 		}
56632021Spc 		ep = lookupino(curfile.ino);
56732021Spc 		if (ep == NIL)
56832021Spc 			panic("unknown file on tape\n");
56932021Spc 		if ((ep->e_flags & (NEW|EXTRACT)) == 0)
57032021Spc 			badentry(ep, "unexpected file on tape");
57132021Spc 		/*
57232021Spc 		 * If the file is to be extracted, then the old file must
57332021Spc 		 * be removed since its type may change from one leaf type
57432021Spc 		 * to another (eg "file" to "character special").
57532021Spc 		 */
57632021Spc 		if ((ep->e_flags & EXTRACT) != 0) {
57732021Spc 			removeleaf(ep);
57832021Spc 			ep->e_flags &= ~REMOVED;
57932021Spc 		}
58032021Spc 		(void) extractfile(myname(ep));
58132021Spc 		ep->e_flags &= ~(NEW|EXTRACT);
58232021Spc 		/*
58332021Spc 		 * We checkpoint the restore after every tape reel, so
58432021Spc 		 * as to simplify the amount of work re quired by the
58532021Spc 		 * 'R' command.
58632021Spc 		 */
58732021Spc 	next:
58832021Spc 		if (curvol != volno) {
58932021Spc 			dumpsymtable(symtabfile, volno);
59032021Spc 			skipmaps();
59132021Spc 			curvol = volno;
59232021Spc 		}
59332021Spc 	}
59432021Spc }
59532021Spc 
59632021Spc /*
59732021Spc  * This is the routine used to extract files for the 'x' and 'i' commands.
59832021Spc  * Efficiently extract a subset of the files on a tape.
59932021Spc  */
createfiles()60032021Spc createfiles()
60132021Spc {
60232021Spc 	register ino_t first, next, last;
60332021Spc 	register struct entry *ep;
60432021Spc 	long curvol;
60532021Spc 
60632021Spc 	vprintf(stdout, "Extract requested files\n");
60732021Spc 	curfile.action = SKIP;
60832021Spc 	getvol((long)1);
60932021Spc 	skipmaps();
61032021Spc 	skipdirs();
61132021Spc 	first = lowerbnd(ROOTINO);
61232021Spc 	last = upperbnd(maxino - 1);
61332021Spc 	for (;;) {
61432021Spc 		first = lowerbnd(first);
61532021Spc 		last = upperbnd(last);
61632021Spc 		/*
61732021Spc 		 * Check to see if any files remain to be extracted
61832021Spc 		 */
61932021Spc 		if (first > last)
62032021Spc 			return;
62132021Spc 		/*
62232021Spc 		 * Reject any volumes with inodes greater
62332021Spc 		 * than the last one needed
62432021Spc 		 */
62532021Spc 		while (curfile.ino > last) {
62632021Spc 			curfile.action = SKIP;
62732021Spc 			getvol((long)0);
62832021Spc 			skipmaps();
62932021Spc 			skipdirs();
63032021Spc 		}
63132021Spc 		/*
63232021Spc 		 * Decide on the next inode needed.
63332021Spc 		 * Skip across the inodes until it is found
63432021Spc 		 * or an out of order volume change is encountered
63532021Spc 		 */
63632021Spc 		next = lowerbnd(curfile.ino);
63732021Spc 		do	{
63832021Spc 			curvol = volno;
63932021Spc 			while (next > curfile.ino && volno == curvol)
64032021Spc 				skipfile();
64132021Spc 			skipmaps();
64232021Spc 			skipdirs();
64332021Spc 		} while (volno == curvol + 1);
64432021Spc 		/*
64532021Spc 		 * If volume change out of order occurred the
64632021Spc 		 * current state must be recalculated
64732021Spc 		 */
64832021Spc 		if (volno != curvol)
64932021Spc 			continue;
65032021Spc 		/*
65132021Spc 		 * If the current inode is greater than the one we were
65232021Spc 		 * looking for then we missed the one we were looking for.
65332021Spc 		 * Since we only attempt to extract files listed in the
65432021Spc 		 * dump map, the lost files must have been due to a tape
65532021Spc 		 * read error, or a file that was removed while the dump
65632021Spc 		 * was in progress. Thus we report all requested files
65732021Spc 		 * between the one we were looking for, and the one we
65832021Spc 		 * found as missing, and delete their request flags.
65932021Spc 		 */
66032021Spc 		while (next < curfile.ino) {
66132021Spc 			ep = lookupino(next);
66232021Spc 			if (ep == NIL)
66332021Spc 				panic("corrupted symbol table\n");
66432021Spc 			fprintf(stderr, "%s: not found on tape\n", myname(ep));
66532021Spc 			ep->e_flags &= ~NEW;
66632021Spc 			next = lowerbnd(next);
66732021Spc 		}
66832021Spc 		/*
66932021Spc 		 * The current inode is the one that we are looking for,
67032021Spc 		 * so extract it per its requested name.
67132021Spc 		 */
67232021Spc 		if (next == curfile.ino && next <= last) {
67332021Spc 			ep = lookupino(next);
67432021Spc 			if (ep == NIL)
67532021Spc 				panic("corrupted symbol table\n");
67632021Spc 			(void) extractfile(myname(ep));
67732021Spc 			ep->e_flags &= ~NEW;
67832021Spc 			if (volno != curvol)
67932021Spc 				skipmaps();
68032021Spc 		}
68132021Spc 	}
68232021Spc }
68332021Spc 
68432021Spc /*
68532021Spc  * Add links.
68632021Spc  */
createlinks()68732021Spc createlinks()
68832021Spc {
68932021Spc 	register struct entry *np, *ep;
69032021Spc 	register ino_t i;
69132021Spc 	char name[BUFSIZ];
69232021Spc 
69332021Spc 	vprintf(stdout, "Add links\n");
69432021Spc 	for (i = ROOTINO; i < maxino; i++) {
69532021Spc 		ep = lookupino(i);
69632021Spc 		if (ep == NIL)
69732021Spc 			continue;
69832021Spc 		for (np = ep->e_links; np != NIL; np = np->e_links) {
69932021Spc 			if ((np->e_flags & NEW) == 0)
70032021Spc 				continue;
70132021Spc 			(void) strcpy(name, myname(ep));
70232021Spc 			if (ep->e_type == NODE) {
70332021Spc 				(void) linkit(name, myname(np), SYMLINK);
70432021Spc 			} else {
70532021Spc 				(void) linkit(name, myname(np), HARDLINK);
70632021Spc 			}
70732021Spc 			np->e_flags &= ~NEW;
70832021Spc 		}
70932021Spc 	}
71032021Spc }
71132021Spc 
71232021Spc /*
71332021Spc  * Check the symbol table.
71432021Spc  * We do this to insure that all the requested work was done, and
71532021Spc  * that no temporary names remain.
71632021Spc  */
checkrestore()71732021Spc checkrestore()
71832021Spc {
71932021Spc 	register struct entry *ep;
72032021Spc 	register ino_t i;
72132021Spc 
72232021Spc 	vprintf(stdout, "Check the symbol table.\n");
72332021Spc 	for (i = ROOTINO; i < maxino; i++) {
72432021Spc 		for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
72532021Spc 			ep->e_flags &= ~KEEP;
72632021Spc 			if (ep->e_type == NODE)
72732021Spc 				ep->e_flags &= ~(NEW|EXISTED);
72832021Spc 			if (ep->e_flags != NULL)
72932021Spc 				badentry(ep, "incomplete operations");
73032021Spc 		}
73132021Spc 	}
73232021Spc }
73332021Spc 
73432021Spc /*
73532021Spc  * Compare with the directory structure on the tape
73632021Spc  * A paranoid check that things are as they should be.
73732021Spc  */
73832021Spc long
verifyfile(name,ino,type)73932021Spc verifyfile(name, ino, type)
74032021Spc 	char *name;
74132021Spc 	ino_t ino;
74232021Spc 	int type;
74332021Spc {
74432021Spc 	struct entry *np, *ep;
74532021Spc 	long descend = GOOD;
74632021Spc 
74732021Spc 	ep = lookupname(name);
74832021Spc 	if (ep == NIL) {
74932021Spc 		fprintf(stderr, "Warning: missing name %s\n", name);
75032021Spc 		return (FAIL);
75132021Spc 	}
75232021Spc 	np = lookupino(ino);
75332021Spc 	if (np != ep)
75432021Spc 		descend = FAIL;
75532021Spc 	for ( ; np != NIL; np = np->e_links)
75632021Spc 		if (np == ep)
75732021Spc 			break;
75832021Spc 	if (np == NIL)
75932021Spc 		panic("missing inumber %d\n", ino);
76032021Spc 	if (ep->e_type == LEAF && type != LEAF)
76132021Spc 		badentry(ep, "type should be LEAF");
76232021Spc 	return (descend);
76332021Spc }
764