xref: /freebsd/sbin/restore/restore.c (revision 32e86a82f54826f14ea381affa6674db3aa3b5ae)
1*8a16b7a1SPedro F. Giffuni /*-
2*8a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3*8a16b7a1SPedro F. Giffuni  *
48fae3551SRodney W. Grimes  * Copyright (c) 1983, 1993
58fae3551SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
68fae3551SRodney W. Grimes  *
78fae3551SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
88fae3551SRodney W. Grimes  * modification, are permitted provided that the following conditions
98fae3551SRodney W. Grimes  * are met:
108fae3551SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
118fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
128fae3551SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
138fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
148fae3551SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
168fae3551SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
178fae3551SRodney W. Grimes  *    without specific prior written permission.
188fae3551SRodney W. Grimes  *
198fae3551SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
208fae3551SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
218fae3551SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
228fae3551SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
238fae3551SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
248fae3551SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
258fae3551SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
268fae3551SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
278fae3551SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
288fae3551SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
298fae3551SRodney W. Grimes  * SUCH DAMAGE.
308fae3551SRodney W. Grimes  */
318fae3551SRodney W. Grimes 
328fae3551SRodney W. Grimes #include <sys/types.h>
338fae3551SRodney W. Grimes 
3489fdc4e1SMike Barcroft #include <limits.h>
35e25a029eSMatthew D Fleming #include <stdint.h>
368fae3551SRodney W. Grimes #include <stdio.h>
378fae3551SRodney W. Grimes #include <string.h>
388fae3551SRodney W. Grimes 
391c85e6a3SKirk McKusick #include <ufs/ufs/dinode.h>
401c85e6a3SKirk McKusick 
418fae3551SRodney W. Grimes #include "restore.h"
428fae3551SRodney W. Grimes #include "extern.h"
438fae3551SRodney W. Grimes 
442db673abSWarner Losh static char *keyval(int);
458fae3551SRodney W. Grimes 
468fae3551SRodney W. Grimes /*
478fae3551SRodney W. Grimes  * This implements the 't' option.
488fae3551SRodney W. Grimes  * List entries on the tape.
498fae3551SRodney W. Grimes  */
508fae3551SRodney W. Grimes long
listfile(char * name,ino_t ino,int type)512db673abSWarner Losh listfile(char *name, ino_t ino, int type)
528fae3551SRodney W. Grimes {
538fae3551SRodney W. Grimes 	long descend = hflag ? GOOD : FAIL;
548fae3551SRodney W. Grimes 
558fae3551SRodney W. Grimes 	if (TSTINO(ino, dumpmap) == 0)
568fae3551SRodney W. Grimes 		return (descend);
578fae3551SRodney W. Grimes 	vprintf(stdout, "%s", type == LEAF ? "leaf" : "dir ");
58e25a029eSMatthew D Fleming 	fprintf(stdout, "%10ju\t%s\n", (uintmax_t)ino, name);
598fae3551SRodney W. Grimes 	return (descend);
608fae3551SRodney W. Grimes }
618fae3551SRodney W. Grimes 
628fae3551SRodney W. Grimes /*
638fae3551SRodney W. Grimes  * This implements the 'x' option.
648fae3551SRodney W. Grimes  * Request that new entries be extracted.
658fae3551SRodney W. Grimes  */
668fae3551SRodney W. Grimes long
addfile(char * name,ino_t ino,int type)672db673abSWarner Losh addfile(char *name, ino_t ino, int type)
688fae3551SRodney W. Grimes {
693d438ad6SDavid E. O'Brien 	struct entry *ep;
708fae3551SRodney W. Grimes 	long descend = hflag ? GOOD : FAIL;
718fae3551SRodney W. Grimes 	char buf[100];
728fae3551SRodney W. Grimes 
738fae3551SRodney W. Grimes 	if (TSTINO(ino, dumpmap) == 0) {
748fae3551SRodney W. Grimes 		dprintf(stdout, "%s: not on the tape\n", name);
758fae3551SRodney W. Grimes 		return (descend);
768fae3551SRodney W. Grimes 	}
771dc349abSEd Maste 	if (ino == UFS_WINO && command == 'i' && !vflag)
78d87d79aeSPeter Wemm 		return (descend);
798fae3551SRodney W. Grimes 	if (!mflag) {
80e25a029eSMatthew D Fleming 		(void) sprintf(buf, "./%ju", (uintmax_t)ino);
818fae3551SRodney W. Grimes 		name = buf;
828fae3551SRodney W. Grimes 		if (type == NODE) {
838fae3551SRodney W. Grimes 			(void) genliteraldir(name, ino);
848fae3551SRodney W. Grimes 			return (descend);
858fae3551SRodney W. Grimes 		}
868fae3551SRodney W. Grimes 	}
878fae3551SRodney W. Grimes 	ep = lookupino(ino);
888fae3551SRodney W. Grimes 	if (ep != NULL) {
898fae3551SRodney W. Grimes 		if (strcmp(name, myname(ep)) == 0) {
908fae3551SRodney W. Grimes 			ep->e_flags |= NEW;
918fae3551SRodney W. Grimes 			return (descend);
928fae3551SRodney W. Grimes 		}
938fae3551SRodney W. Grimes 		type |= LINK;
948fae3551SRodney W. Grimes 	}
958fae3551SRodney W. Grimes 	ep = addentry(name, ino, type);
968fae3551SRodney W. Grimes 	if (type == NODE)
978fae3551SRodney W. Grimes 		newnode(ep);
988fae3551SRodney W. Grimes 	ep->e_flags |= NEW;
998fae3551SRodney W. Grimes 	return (descend);
1008fae3551SRodney W. Grimes }
1018fae3551SRodney W. Grimes 
1028fae3551SRodney W. Grimes /*
1038fae3551SRodney W. Grimes  * This is used by the 'i' option to undo previous requests made by addfile.
1048fae3551SRodney W. Grimes  * Delete entries from the request queue.
1058fae3551SRodney W. Grimes  */
1068fae3551SRodney W. Grimes /* ARGSUSED */
1078fae3551SRodney W. Grimes long
deletefile(char * name,ino_t ino,int type)1082db673abSWarner Losh deletefile(char *name, ino_t ino, int type)
1098fae3551SRodney W. Grimes {
1108fae3551SRodney W. Grimes 	long descend = hflag ? GOOD : FAIL;
1118fae3551SRodney W. Grimes 	struct entry *ep;
1128fae3551SRodney W. Grimes 
1138fae3551SRodney W. Grimes 	if (TSTINO(ino, dumpmap) == 0)
1148fae3551SRodney W. Grimes 		return (descend);
115d87d79aeSPeter Wemm 	ep = lookupname(name);
116d87d79aeSPeter Wemm 	if (ep != NULL) {
1178fae3551SRodney W. Grimes 		ep->e_flags &= ~NEW;
118d87d79aeSPeter Wemm 		ep->e_flags |= REMOVED;
119d87d79aeSPeter Wemm 		if (ep->e_type != NODE)
120d87d79aeSPeter Wemm 			freeentry(ep);
121d87d79aeSPeter Wemm 	}
1228fae3551SRodney W. Grimes 	return (descend);
1238fae3551SRodney W. Grimes }
1248fae3551SRodney W. Grimes 
1258fae3551SRodney W. Grimes /*
1268fae3551SRodney W. Grimes  * The following four routines implement the incremental
1278fae3551SRodney W. Grimes  * restore algorithm. The first removes old entries, the second
1288fae3551SRodney W. Grimes  * does renames and calculates the extraction list, the third
1298fae3551SRodney W. Grimes  * cleans up link names missed by the first two, and the final
1308fae3551SRodney W. Grimes  * one deletes old directories.
1318fae3551SRodney W. Grimes  *
1328fae3551SRodney W. Grimes  * Directories cannot be immediately deleted, as they may have
1338fae3551SRodney W. Grimes  * other files in them which need to be moved out first. As
1348fae3551SRodney W. Grimes  * directories to be deleted are found, they are put on the
1358fae3551SRodney W. Grimes  * following deletion list. After all deletions and renames
1368fae3551SRodney W. Grimes  * are done, this list is actually deleted.
1378fae3551SRodney W. Grimes  */
1388fae3551SRodney W. Grimes static struct entry *removelist;
1398fae3551SRodney W. Grimes 
1408fae3551SRodney W. Grimes /*
141d87d79aeSPeter Wemm  *	Remove invalid whiteouts from the old tree.
1428fae3551SRodney W. Grimes  *	Remove unneeded leaves from the old tree.
1438fae3551SRodney W. Grimes  *	Remove directories from the lookup chains.
1448fae3551SRodney W. Grimes  */
1458fae3551SRodney W. Grimes void
removeoldleaves(void)1462db673abSWarner Losh removeoldleaves(void)
1478fae3551SRodney W. Grimes {
1483d438ad6SDavid E. O'Brien 	struct entry *ep, *nextep;
1493d438ad6SDavid E. O'Brien 	ino_t i, mydirino;
1508fae3551SRodney W. Grimes 
1518fae3551SRodney W. Grimes 	vprintf(stdout, "Mark entries to be removed.\n");
1521dc349abSEd Maste 	if ((ep = lookupino(UFS_WINO))) {
153d87d79aeSPeter Wemm 		vprintf(stdout, "Delete whiteouts\n");
154d87d79aeSPeter Wemm 		for ( ; ep != NULL; ep = nextep) {
155d87d79aeSPeter Wemm 			nextep = ep->e_links;
156d87d79aeSPeter Wemm 			mydirino = ep->e_parent->e_ino;
157d87d79aeSPeter Wemm 			/*
158d87d79aeSPeter Wemm 			 * We remove all whiteouts that are in directories
159d87d79aeSPeter Wemm 			 * that have been removed or that have been dumped.
160d87d79aeSPeter Wemm 			 */
161d87d79aeSPeter Wemm 			if (TSTINO(mydirino, usedinomap) &&
162d87d79aeSPeter Wemm 			    !TSTINO(mydirino, dumpmap))
163d87d79aeSPeter Wemm 				continue;
164d87d79aeSPeter Wemm 			delwhiteout(ep);
165d87d79aeSPeter Wemm 			freeentry(ep);
166d87d79aeSPeter Wemm 		}
167d87d79aeSPeter Wemm 	}
1681dc349abSEd Maste 	for (i = UFS_ROOTINO + 1; i < maxino; i++) {
1698fae3551SRodney W. Grimes 		ep = lookupino(i);
1708fae3551SRodney W. Grimes 		if (ep == NULL)
1718fae3551SRodney W. Grimes 			continue;
172d87d79aeSPeter Wemm 		if (TSTINO(i, usedinomap))
1738fae3551SRodney W. Grimes 			continue;
1748fae3551SRodney W. Grimes 		for ( ; ep != NULL; ep = ep->e_links) {
1758fae3551SRodney W. Grimes 			dprintf(stdout, "%s: REMOVE\n", myname(ep));
1768fae3551SRodney W. Grimes 			if (ep->e_type == LEAF) {
1778fae3551SRodney W. Grimes 				removeleaf(ep);
1788fae3551SRodney W. Grimes 				freeentry(ep);
1798fae3551SRodney W. Grimes 			} else {
1808fae3551SRodney W. Grimes 				mktempname(ep);
1818fae3551SRodney W. Grimes 				deleteino(ep->e_ino);
1828fae3551SRodney W. Grimes 				ep->e_next = removelist;
1838fae3551SRodney W. Grimes 				removelist = ep;
1848fae3551SRodney W. Grimes 			}
1858fae3551SRodney W. Grimes 		}
1868fae3551SRodney W. Grimes 	}
1878fae3551SRodney W. Grimes }
1888fae3551SRodney W. Grimes 
1898fae3551SRodney W. Grimes /*
1908fae3551SRodney W. Grimes  *	For each directory entry on the incremental tape, determine which
1918fae3551SRodney W. Grimes  *	category it falls into as follows:
1928fae3551SRodney W. Grimes  *	KEEP - entries that are to be left alone.
1938fae3551SRodney W. Grimes  *	NEW - new entries to be added.
1948fae3551SRodney W. Grimes  *	EXTRACT - files that must be updated with new contents.
1958fae3551SRodney W. Grimes  *	LINK - new links to be added.
1968fae3551SRodney W. Grimes  *	Renames are done at the same time.
1978fae3551SRodney W. Grimes  */
1988fae3551SRodney W. Grimes long
nodeupdates(char * name,ino_t ino,int type)1992db673abSWarner Losh nodeupdates(char *name, ino_t ino, int type)
2008fae3551SRodney W. Grimes {
2013d438ad6SDavid E. O'Brien 	struct entry *ep, *np, *ip;
2028fae3551SRodney W. Grimes 	long descend = GOOD;
2038fae3551SRodney W. Grimes 	int lookuptype = 0;
2048fae3551SRodney W. Grimes 	int key = 0;
2058fae3551SRodney W. Grimes 		/* key values */
2068fae3551SRodney W. Grimes #		define ONTAPE	0x1	/* inode is on the tape */
2078fae3551SRodney W. Grimes #		define INOFND	0x2	/* inode already exists */
2088fae3551SRodney W. Grimes #		define NAMEFND	0x4	/* name already exists */
2098fae3551SRodney W. Grimes #		define MODECHG	0x8	/* mode of inode changed */
2108fae3551SRodney W. Grimes 
2118fae3551SRodney W. Grimes 	/*
2128fae3551SRodney W. Grimes 	 * This routine is called once for each element in the
2138fae3551SRodney W. Grimes 	 * directory hierarchy, with a full path name.
2148fae3551SRodney W. Grimes 	 * The "type" value is incorrectly specified as LEAF for
2158fae3551SRodney W. Grimes 	 * directories that are not on the dump tape.
2168fae3551SRodney W. Grimes 	 *
2178fae3551SRodney W. Grimes 	 * Check to see if the file is on the tape.
2188fae3551SRodney W. Grimes 	 */
2198fae3551SRodney W. Grimes 	if (TSTINO(ino, dumpmap))
2208fae3551SRodney W. Grimes 		key |= ONTAPE;
2218fae3551SRodney W. Grimes 	/*
2228fae3551SRodney W. Grimes 	 * Check to see if the name exists, and if the name is a link.
2238fae3551SRodney W. Grimes 	 */
2248fae3551SRodney W. Grimes 	np = lookupname(name);
2258fae3551SRodney W. Grimes 	if (np != NULL) {
2268fae3551SRodney W. Grimes 		key |= NAMEFND;
2278fae3551SRodney W. Grimes 		ip = lookupino(np->e_ino);
2288fae3551SRodney W. Grimes 		if (ip == NULL)
2298fae3551SRodney W. Grimes 			panic("corrupted symbol table\n");
2308fae3551SRodney W. Grimes 		if (ip != np)
2318fae3551SRodney W. Grimes 			lookuptype = LINK;
2328fae3551SRodney W. Grimes 	}
2338fae3551SRodney W. Grimes 	/*
2348fae3551SRodney W. Grimes 	 * Check to see if the inode exists, and if one of its links
2358fae3551SRodney W. Grimes 	 * corresponds to the name (if one was found).
2368fae3551SRodney W. Grimes 	 */
2378fae3551SRodney W. Grimes 	ip = lookupino(ino);
2388fae3551SRodney W. Grimes 	if (ip != NULL) {
2398fae3551SRodney W. Grimes 		key |= INOFND;
2408fae3551SRodney W. Grimes 		for (ep = ip->e_links; ep != NULL; ep = ep->e_links) {
2418fae3551SRodney W. Grimes 			if (ep == np) {
2428fae3551SRodney W. Grimes 				ip = ep;
2438fae3551SRodney W. Grimes 				break;
2448fae3551SRodney W. Grimes 			}
2458fae3551SRodney W. Grimes 		}
2468fae3551SRodney W. Grimes 	}
2478fae3551SRodney W. Grimes 	/*
2488fae3551SRodney W. Grimes 	 * If both a name and an inode are found, but they do not
2498fae3551SRodney W. Grimes 	 * correspond to the same file, then both the inode that has
2508fae3551SRodney W. Grimes 	 * been found and the inode corresponding to the name that
2518fae3551SRodney W. Grimes 	 * has been found need to be renamed. The current pathname
2528fae3551SRodney W. Grimes 	 * is the new name for the inode that has been found. Since
2538fae3551SRodney W. Grimes 	 * all files to be deleted have already been removed, the
2548fae3551SRodney W. Grimes 	 * named file is either a now unneeded link, or it must live
2558fae3551SRodney W. Grimes 	 * under a new name in this dump level. If it is a link, it
2568fae3551SRodney W. Grimes 	 * can be removed. If it is not a link, it is given a
2578fae3551SRodney W. Grimes 	 * temporary name in anticipation that it will be renamed
2588fae3551SRodney W. Grimes 	 * when it is later found by inode number.
2598fae3551SRodney W. Grimes 	 */
2608fae3551SRodney W. Grimes 	if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) {
2618fae3551SRodney W. Grimes 		if (lookuptype == LINK) {
2628fae3551SRodney W. Grimes 			removeleaf(np);
2638fae3551SRodney W. Grimes 			freeentry(np);
2648fae3551SRodney W. Grimes 		} else {
2658fae3551SRodney W. Grimes 			dprintf(stdout, "name/inode conflict, mktempname %s\n",
2668fae3551SRodney W. Grimes 				myname(np));
2678fae3551SRodney W. Grimes 			mktempname(np);
2688fae3551SRodney W. Grimes 		}
2698fae3551SRodney W. Grimes 		np = NULL;
2708fae3551SRodney W. Grimes 		key &= ~NAMEFND;
2718fae3551SRodney W. Grimes 	}
2728fae3551SRodney W. Grimes 	if ((key & ONTAPE) &&
2738fae3551SRodney W. Grimes 	  (((key & INOFND) && ip->e_type != type) ||
2748fae3551SRodney W. Grimes 	   ((key & NAMEFND) && np->e_type != type)))
2758fae3551SRodney W. Grimes 		key |= MODECHG;
2768fae3551SRodney W. Grimes 
2778fae3551SRodney W. Grimes 	/*
2788fae3551SRodney W. Grimes 	 * Decide on the disposition of the file based on its flags.
2798fae3551SRodney W. Grimes 	 * Note that we have already handled the case in which
2808fae3551SRodney W. Grimes 	 * a name and inode are found that correspond to different files.
2818fae3551SRodney W. Grimes 	 * Thus if both NAMEFND and INOFND are set then ip == np.
2828fae3551SRodney W. Grimes 	 */
2838fae3551SRodney W. Grimes 	switch (key) {
2848fae3551SRodney W. Grimes 
2858fae3551SRodney W. Grimes 	/*
2868fae3551SRodney W. Grimes 	 * A previously existing file has been found.
2878fae3551SRodney W. Grimes 	 * Mark it as KEEP so that other links to the inode can be
2888fae3551SRodney W. Grimes 	 * detected, and so that it will not be reclaimed by the search
2898fae3551SRodney W. Grimes 	 * for unreferenced names.
2908fae3551SRodney W. Grimes 	 */
2918fae3551SRodney W. Grimes 	case INOFND|NAMEFND:
2928fae3551SRodney W. Grimes 		ip->e_flags |= KEEP;
2938fae3551SRodney W. Grimes 		dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
2948fae3551SRodney W. Grimes 			flagvalues(ip));
2958fae3551SRodney W. Grimes 		break;
2968fae3551SRodney W. Grimes 
2978fae3551SRodney W. Grimes 	/*
2988fae3551SRodney W. Grimes 	 * A file on the tape has a name which is the same as a name
2998fae3551SRodney W. Grimes 	 * corresponding to a different file in the previous dump.
3008fae3551SRodney W. Grimes 	 * Since all files to be deleted have already been removed,
3018fae3551SRodney W. Grimes 	 * this file is either a now unneeded link, or it must live
3028fae3551SRodney W. Grimes 	 * under a new name in this dump level. If it is a link, it
3038fae3551SRodney W. Grimes 	 * can simply be removed. If it is not a link, it is given a
3048fae3551SRodney W. Grimes 	 * temporary name in anticipation that it will be renamed
3058fae3551SRodney W. Grimes 	 * when it is later found by inode number (see INOFND case
3068fae3551SRodney W. Grimes 	 * below). The entry is then treated as a new file.
3078fae3551SRodney W. Grimes 	 */
3088fae3551SRodney W. Grimes 	case ONTAPE|NAMEFND:
3098fae3551SRodney W. Grimes 	case ONTAPE|NAMEFND|MODECHG:
3108fae3551SRodney W. Grimes 		if (lookuptype == LINK) {
3118fae3551SRodney W. Grimes 			removeleaf(np);
3128fae3551SRodney W. Grimes 			freeentry(np);
3138fae3551SRodney W. Grimes 		} else {
3148fae3551SRodney W. Grimes 			mktempname(np);
3158fae3551SRodney W. Grimes 		}
3167fed38d0SPhilippe Charnier 		/* FALLTHROUGH */
3178fae3551SRodney W. Grimes 
3188fae3551SRodney W. Grimes 	/*
3198fae3551SRodney W. Grimes 	 * A previously non-existent file.
3208fae3551SRodney W. Grimes 	 * Add it to the file system, and request its extraction.
3218fae3551SRodney W. Grimes 	 * If it is a directory, create it immediately.
3228fae3551SRodney W. Grimes 	 * (Since the name is unused there can be no conflict)
3238fae3551SRodney W. Grimes 	 */
3248fae3551SRodney W. Grimes 	case ONTAPE:
3258fae3551SRodney W. Grimes 		ep = addentry(name, ino, type);
3268fae3551SRodney W. Grimes 		if (type == NODE)
3278fae3551SRodney W. Grimes 			newnode(ep);
3288fae3551SRodney W. Grimes 		ep->e_flags |= NEW|KEEP;
3298fae3551SRodney W. Grimes 		dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
3308fae3551SRodney W. Grimes 			flagvalues(ep));
3318fae3551SRodney W. Grimes 		break;
3328fae3551SRodney W. Grimes 
3338fae3551SRodney W. Grimes 	/*
3348fae3551SRodney W. Grimes 	 * A file with the same inode number, but a different
3358fae3551SRodney W. Grimes 	 * name has been found. If the other name has not already
3368fae3551SRodney W. Grimes 	 * been found (indicated by the KEEP flag, see above) then
3378fae3551SRodney W. Grimes 	 * this must be a new name for the file, and it is renamed.
3388fae3551SRodney W. Grimes 	 * If the other name has been found then this must be a
3398fae3551SRodney W. Grimes 	 * link to the file. Hard links to directories are not
3408fae3551SRodney W. Grimes 	 * permitted, and are either deleted or converted to
3418fae3551SRodney W. Grimes 	 * symbolic links. Finally, if the file is on the tape,
3428fae3551SRodney W. Grimes 	 * a request is made to extract it.
3438fae3551SRodney W. Grimes 	 */
3448fae3551SRodney W. Grimes 	case ONTAPE|INOFND:
3458fae3551SRodney W. Grimes 		if (type == LEAF && (ip->e_flags & KEEP) == 0)
3468fae3551SRodney W. Grimes 			ip->e_flags |= EXTRACT;
3477fed38d0SPhilippe Charnier 		/* FALLTHROUGH */
3488fae3551SRodney W. Grimes 	case INOFND:
3498fae3551SRodney W. Grimes 		if ((ip->e_flags & KEEP) == 0) {
3508fae3551SRodney W. Grimes 			renameit(myname(ip), name);
3518fae3551SRodney W. Grimes 			moveentry(ip, name);
3528fae3551SRodney W. Grimes 			ip->e_flags |= KEEP;
3538fae3551SRodney W. Grimes 			dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
3548fae3551SRodney W. Grimes 				flagvalues(ip));
3558fae3551SRodney W. Grimes 			break;
3568fae3551SRodney W. Grimes 		}
3578fae3551SRodney W. Grimes 		if (ip->e_type == NODE) {
3588fae3551SRodney W. Grimes 			descend = FAIL;
3598fae3551SRodney W. Grimes 			fprintf(stderr,
3608fae3551SRodney W. Grimes 				"deleted hard link %s to directory %s\n",
3618fae3551SRodney W. Grimes 				name, myname(ip));
3628fae3551SRodney W. Grimes 			break;
3638fae3551SRodney W. Grimes 		}
3648fae3551SRodney W. Grimes 		ep = addentry(name, ino, type|LINK);
3658fae3551SRodney W. Grimes 		ep->e_flags |= NEW;
3668fae3551SRodney W. Grimes 		dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
3678fae3551SRodney W. Grimes 			flagvalues(ep));
3688fae3551SRodney W. Grimes 		break;
3698fae3551SRodney W. Grimes 
3708fae3551SRodney W. Grimes 	/*
3718fae3551SRodney W. Grimes 	 * A previously known file which is to be updated. If it is a link,
3728fae3551SRodney W. Grimes 	 * then all names referring to the previous file must be removed
3738fae3551SRodney W. Grimes 	 * so that the subset of them that remain can be recreated.
3748fae3551SRodney W. Grimes 	 */
3758fae3551SRodney W. Grimes 	case ONTAPE|INOFND|NAMEFND:
3768fae3551SRodney W. Grimes 		if (lookuptype == LINK) {
3778fae3551SRodney W. Grimes 			removeleaf(np);
3788fae3551SRodney W. Grimes 			freeentry(np);
3798fae3551SRodney W. Grimes 			ep = addentry(name, ino, type|LINK);
3808fae3551SRodney W. Grimes 			if (type == NODE)
3818fae3551SRodney W. Grimes 			        newnode(ep);
3828fae3551SRodney W. Grimes 			ep->e_flags |= NEW|KEEP;
3838fae3551SRodney W. Grimes 			dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
3848fae3551SRodney W. Grimes 				flagvalues(ep));
3858fae3551SRodney W. Grimes 			break;
3868fae3551SRodney W. Grimes 		}
3878fae3551SRodney W. Grimes 		if (type == LEAF && lookuptype != LINK)
3888fae3551SRodney W. Grimes 			np->e_flags |= EXTRACT;
3898fae3551SRodney W. Grimes 		np->e_flags |= KEEP;
3908fae3551SRodney W. Grimes 		dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
3918fae3551SRodney W. Grimes 			flagvalues(np));
3928fae3551SRodney W. Grimes 		break;
3938fae3551SRodney W. Grimes 
3948fae3551SRodney W. Grimes 	/*
3958fae3551SRodney W. Grimes 	 * An inode is being reused in a completely different way.
3968fae3551SRodney W. Grimes 	 * Normally an extract can simply do an "unlink" followed
3978fae3551SRodney W. Grimes 	 * by a "creat". Here we must do effectively the same
3988fae3551SRodney W. Grimes 	 * thing. The complications arise because we cannot really
3998fae3551SRodney W. Grimes 	 * delete a directory since it may still contain files
4008fae3551SRodney W. Grimes 	 * that we need to rename, so we delete it from the symbol
4018fae3551SRodney W. Grimes 	 * table, and put it on the list to be deleted eventually.
4028fae3551SRodney W. Grimes 	 * Conversely if a directory is to be created, it must be
4038fae3551SRodney W. Grimes 	 * done immediately, rather than waiting until the
4048fae3551SRodney W. Grimes 	 * extraction phase.
4058fae3551SRodney W. Grimes 	 */
4068fae3551SRodney W. Grimes 	case ONTAPE|INOFND|MODECHG:
4078fae3551SRodney W. Grimes 	case ONTAPE|INOFND|NAMEFND|MODECHG:
4088fae3551SRodney W. Grimes 		if (ip->e_flags & KEEP) {
4098fae3551SRodney W. Grimes 			badentry(ip, "cannot KEEP and change modes");
4108fae3551SRodney W. Grimes 			break;
4118fae3551SRodney W. Grimes 		}
4128fae3551SRodney W. Grimes 		if (ip->e_type == LEAF) {
4138fae3551SRodney W. Grimes 			/* changing from leaf to node */
414edb398d7SJoerg Wunsch 			for (ip = lookupino(ino); ip != NULL; ip = ip->e_links) {
415edb398d7SJoerg Wunsch 				if (ip->e_type != LEAF)
416edb398d7SJoerg Wunsch 					badentry(ip, "NODE and LEAF links to same inode");
4178fae3551SRodney W. Grimes 				removeleaf(ip);
4188fae3551SRodney W. Grimes 				freeentry(ip);
419edb398d7SJoerg Wunsch 			}
4208fae3551SRodney W. Grimes 			ip = addentry(name, ino, type);
4218fae3551SRodney W. Grimes 			newnode(ip);
4228fae3551SRodney W. Grimes 		} else {
4238fae3551SRodney W. Grimes 			/* changing from node to leaf */
4248fae3551SRodney W. Grimes 			if ((ip->e_flags & TMPNAME) == 0)
4258fae3551SRodney W. Grimes 				mktempname(ip);
4268fae3551SRodney W. Grimes 			deleteino(ip->e_ino);
4278fae3551SRodney W. Grimes 			ip->e_next = removelist;
4288fae3551SRodney W. Grimes 			removelist = ip;
4298fae3551SRodney W. Grimes 			ip = addentry(name, ino, type);
4308fae3551SRodney W. Grimes 		}
4318fae3551SRodney W. Grimes 		ip->e_flags |= NEW|KEEP;
4328fae3551SRodney W. Grimes 		dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
4338fae3551SRodney W. Grimes 			flagvalues(ip));
4348fae3551SRodney W. Grimes 		break;
4358fae3551SRodney W. Grimes 
4368fae3551SRodney W. Grimes 	/*
43791ac32e4SPhilippe Charnier 	 * A hard link to a directory that has been removed.
4388fae3551SRodney W. Grimes 	 * Ignore it.
4398fae3551SRodney W. Grimes 	 */
4408fae3551SRodney W. Grimes 	case NAMEFND:
4418fae3551SRodney W. Grimes 		dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key),
4428fae3551SRodney W. Grimes 			name);
4438fae3551SRodney W. Grimes 		descend = FAIL;
4448fae3551SRodney W. Grimes 		break;
4458fae3551SRodney W. Grimes 
4468fae3551SRodney W. Grimes 	/*
4478fae3551SRodney W. Grimes 	 * If we find a directory entry for a file that is not on
4488fae3551SRodney W. Grimes 	 * the tape, then we must have found a file that was created
4498fae3551SRodney W. Grimes 	 * while the dump was in progress. Since we have no contents
4508fae3551SRodney W. Grimes 	 * for it, we discard the name knowing that it will be on the
4518fae3551SRodney W. Grimes 	 * next incremental tape.
4528fae3551SRodney W. Grimes 	 */
4530b0fe61dSWarner Losh 	case 0:
454e25a029eSMatthew D Fleming 		fprintf(stderr, "%s: (inode %ju) not found on tape\n",
455e25a029eSMatthew D Fleming 		    name, (uintmax_t)ino);
4568fae3551SRodney W. Grimes 		break;
4578fae3551SRodney W. Grimes 
4588fae3551SRodney W. Grimes 	/*
4598fae3551SRodney W. Grimes 	 * If any of these arise, something is grievously wrong with
4608fae3551SRodney W. Grimes 	 * the current state of the symbol table.
4618fae3551SRodney W. Grimes 	 */
4628fae3551SRodney W. Grimes 	case INOFND|NAMEFND|MODECHG:
4638fae3551SRodney W. Grimes 	case NAMEFND|MODECHG:
4648fae3551SRodney W. Grimes 	case INOFND|MODECHG:
4658fae3551SRodney W. Grimes 		fprintf(stderr, "[%s] %s: inconsistent state\n", keyval(key),
4668fae3551SRodney W. Grimes 			name);
4678fae3551SRodney W. Grimes 		break;
4688fae3551SRodney W. Grimes 
4698fae3551SRodney W. Grimes 	/*
4708fae3551SRodney W. Grimes 	 * These states "cannot" arise for any state of the symbol table.
4718fae3551SRodney W. Grimes 	 */
4728fae3551SRodney W. Grimes 	case ONTAPE|MODECHG:
4738fae3551SRodney W. Grimes 	case MODECHG:
4748fae3551SRodney W. Grimes 	default:
4758fae3551SRodney W. Grimes 		panic("[%s] %s: impossible state\n", keyval(key), name);
4768fae3551SRodney W. Grimes 		break;
4778fae3551SRodney W. Grimes 	}
4788fae3551SRodney W. Grimes 	return (descend);
4798fae3551SRodney W. Grimes }
4808fae3551SRodney W. Grimes 
4818fae3551SRodney W. Grimes /*
4828fae3551SRodney W. Grimes  * Calculate the active flags in a key.
4838fae3551SRodney W. Grimes  */
4848fae3551SRodney W. Grimes static char *
keyval(int key)4852db673abSWarner Losh keyval(int key)
4868fae3551SRodney W. Grimes {
4878fae3551SRodney W. Grimes 	static char keybuf[32];
4888fae3551SRodney W. Grimes 
4898fae3551SRodney W. Grimes 	(void) strcpy(keybuf, "|NIL");
4908fae3551SRodney W. Grimes 	keybuf[0] = '\0';
4918fae3551SRodney W. Grimes 	if (key & ONTAPE)
4928fae3551SRodney W. Grimes 		(void) strcat(keybuf, "|ONTAPE");
4938fae3551SRodney W. Grimes 	if (key & INOFND)
4948fae3551SRodney W. Grimes 		(void) strcat(keybuf, "|INOFND");
4958fae3551SRodney W. Grimes 	if (key & NAMEFND)
4968fae3551SRodney W. Grimes 		(void) strcat(keybuf, "|NAMEFND");
4978fae3551SRodney W. Grimes 	if (key & MODECHG)
4988fae3551SRodney W. Grimes 		(void) strcat(keybuf, "|MODECHG");
4998fae3551SRodney W. Grimes 	return (&keybuf[1]);
5008fae3551SRodney W. Grimes }
5018fae3551SRodney W. Grimes 
5028fae3551SRodney W. Grimes /*
5038fae3551SRodney W. Grimes  * Find unreferenced link names.
5048fae3551SRodney W. Grimes  */
5058fae3551SRodney W. Grimes void
findunreflinks(void)5062db673abSWarner Losh findunreflinks(void)
5078fae3551SRodney W. Grimes {
5083d438ad6SDavid E. O'Brien 	struct entry *ep, *np;
5093d438ad6SDavid E. O'Brien 	ino_t i;
5108fae3551SRodney W. Grimes 
5118fae3551SRodney W. Grimes 	vprintf(stdout, "Find unreferenced names.\n");
5121dc349abSEd Maste 	for (i = UFS_ROOTINO; i < maxino; i++) {
5138fae3551SRodney W. Grimes 		ep = lookupino(i);
5148fae3551SRodney W. Grimes 		if (ep == NULL || ep->e_type == LEAF || TSTINO(i, dumpmap) == 0)
5158fae3551SRodney W. Grimes 			continue;
5168fae3551SRodney W. Grimes 		for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
5178fae3551SRodney W. Grimes 			if (np->e_flags == 0) {
5188fae3551SRodney W. Grimes 				dprintf(stdout,
5198fae3551SRodney W. Grimes 				    "%s: remove unreferenced name\n",
5208fae3551SRodney W. Grimes 				    myname(np));
5218fae3551SRodney W. Grimes 				removeleaf(np);
5228fae3551SRodney W. Grimes 				freeentry(np);
5238fae3551SRodney W. Grimes 			}
5248fae3551SRodney W. Grimes 		}
5258fae3551SRodney W. Grimes 	}
5268fae3551SRodney W. Grimes 	/*
5278fae3551SRodney W. Grimes 	 * Any leaves remaining in removed directories is unreferenced.
5288fae3551SRodney W. Grimes 	 */
5298fae3551SRodney W. Grimes 	for (ep = removelist; ep != NULL; ep = ep->e_next) {
5308fae3551SRodney W. Grimes 		for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
5318fae3551SRodney W. Grimes 			if (np->e_type == LEAF) {
5328fae3551SRodney W. Grimes 				if (np->e_flags != 0)
5338fae3551SRodney W. Grimes 					badentry(np, "unreferenced with flags");
5348fae3551SRodney W. Grimes 				dprintf(stdout,
5358fae3551SRodney W. Grimes 				    "%s: remove unreferenced name\n",
5368fae3551SRodney W. Grimes 				    myname(np));
5378fae3551SRodney W. Grimes 				removeleaf(np);
5388fae3551SRodney W. Grimes 				freeentry(np);
5398fae3551SRodney W. Grimes 			}
5408fae3551SRodney W. Grimes 		}
5418fae3551SRodney W. Grimes 	}
5428fae3551SRodney W. Grimes }
5438fae3551SRodney W. Grimes 
5448fae3551SRodney W. Grimes /*
5458fae3551SRodney W. Grimes  * Remove old nodes (directories).
5468fae3551SRodney W. Grimes  * Note that this routine runs in O(N*D) where:
5478fae3551SRodney W. Grimes  *	N is the number of directory entries to be removed.
5488fae3551SRodney W. Grimes  *	D is the maximum depth of the tree.
5498fae3551SRodney W. Grimes  * If N == D this can be quite slow. If the list were
5508fae3551SRodney W. Grimes  * topologically sorted, the deletion could be done in
5518fae3551SRodney W. Grimes  * time O(N).
5528fae3551SRodney W. Grimes  */
5538fae3551SRodney W. Grimes void
removeoldnodes(void)5542db673abSWarner Losh removeoldnodes(void)
5558fae3551SRodney W. Grimes {
5563d438ad6SDavid E. O'Brien 	struct entry *ep, **prev;
5578fae3551SRodney W. Grimes 	long change;
5588fae3551SRodney W. Grimes 
5598fae3551SRodney W. Grimes 	vprintf(stdout, "Remove old nodes (directories).\n");
5608fae3551SRodney W. Grimes 	do	{
5618fae3551SRodney W. Grimes 		change = 0;
5628fae3551SRodney W. Grimes 		prev = &removelist;
5638fae3551SRodney W. Grimes 		for (ep = removelist; ep != NULL; ep = *prev) {
5648fae3551SRodney W. Grimes 			if (ep->e_entries != NULL) {
5658fae3551SRodney W. Grimes 				prev = &ep->e_next;
5668fae3551SRodney W. Grimes 				continue;
5678fae3551SRodney W. Grimes 			}
5688fae3551SRodney W. Grimes 			*prev = ep->e_next;
5698fae3551SRodney W. Grimes 			removenode(ep);
5708fae3551SRodney W. Grimes 			freeentry(ep);
5718fae3551SRodney W. Grimes 			change++;
5728fae3551SRodney W. Grimes 		}
5738fae3551SRodney W. Grimes 	} while (change);
5748fae3551SRodney W. Grimes 	for (ep = removelist; ep != NULL; ep = ep->e_next)
5758fae3551SRodney W. Grimes 		badentry(ep, "cannot remove, non-empty");
5768fae3551SRodney W. Grimes }
5778fae3551SRodney W. Grimes 
5788fae3551SRodney W. Grimes /*
5798fae3551SRodney W. Grimes  * This is the routine used to extract files for the 'r' command.
5808fae3551SRodney W. Grimes  * Extract new leaves.
5818fae3551SRodney W. Grimes  */
5828fae3551SRodney W. Grimes void
createleaves(char * symtabfile)5832db673abSWarner Losh createleaves(char *symtabfile)
5848fae3551SRodney W. Grimes {
5853d438ad6SDavid E. O'Brien 	struct entry *ep;
5868fae3551SRodney W. Grimes 	ino_t first;
5878fae3551SRodney W. Grimes 	long curvol;
5888fae3551SRodney W. Grimes 
5898fae3551SRodney W. Grimes 	if (command == 'R') {
5908fae3551SRodney W. Grimes 		vprintf(stdout, "Continue extraction of new leaves\n");
5918fae3551SRodney W. Grimes 	} else {
5928fae3551SRodney W. Grimes 		vprintf(stdout, "Extract new leaves.\n");
5938fae3551SRodney W. Grimes 		dumpsymtable(symtabfile, volno);
5948fae3551SRodney W. Grimes 	}
5951dc349abSEd Maste 	first = lowerbnd(UFS_ROOTINO);
5968fae3551SRodney W. Grimes 	curvol = volno;
5978fae3551SRodney W. Grimes 	while (curfile.ino < maxino) {
5988fae3551SRodney W. Grimes 		first = lowerbnd(first);
5998fae3551SRodney W. Grimes 		/*
6008fae3551SRodney W. Grimes 		 * If the next available file is not the one which we
6018fae3551SRodney W. Grimes 		 * expect then we have missed one or more files. Since
6028fae3551SRodney W. Grimes 		 * we do not request files that were not on the tape,
6038fae3551SRodney W. Grimes 		 * the lost files must have been due to a tape read error,
6048fae3551SRodney W. Grimes 		 * or a file that was removed while the dump was in progress.
6058fae3551SRodney W. Grimes 		 */
6068fae3551SRodney W. Grimes 		while (first < curfile.ino) {
6078fae3551SRodney W. Grimes 			ep = lookupino(first);
6088fae3551SRodney W. Grimes 			if (ep == NULL)
609e25a029eSMatthew D Fleming 				panic("%ju: bad first\n", (uintmax_t)first);
6108fae3551SRodney W. Grimes 			fprintf(stderr, "%s: not found on tape\n", myname(ep));
6118fae3551SRodney W. Grimes 			ep->e_flags &= ~(NEW|EXTRACT);
6128fae3551SRodney W. Grimes 			first = lowerbnd(first);
6138fae3551SRodney W. Grimes 		}
6148fae3551SRodney W. Grimes 		/*
6158fae3551SRodney W. Grimes 		 * If we find files on the tape that have no corresponding
6168fae3551SRodney W. Grimes 		 * directory entries, then we must have found a file that
6178fae3551SRodney W. Grimes 		 * was created while the dump was in progress. Since we have
6188fae3551SRodney W. Grimes 		 * no name for it, we discard it knowing that it will be
6198fae3551SRodney W. Grimes 		 * on the next incremental tape.
6208fae3551SRodney W. Grimes 		 */
6218fae3551SRodney W. Grimes 		if (first != curfile.ino) {
622e25a029eSMatthew D Fleming 			fprintf(stderr, "expected next file %ju, got %ju\n",
623e25a029eSMatthew D Fleming 			    (uintmax_t)first, (uintmax_t)curfile.ino);
6248fae3551SRodney W. Grimes 			skipfile();
6258fae3551SRodney W. Grimes 			goto next;
6268fae3551SRodney W. Grimes 		}
6278fae3551SRodney W. Grimes 		ep = lookupino(curfile.ino);
6288fae3551SRodney W. Grimes 		if (ep == NULL)
6298fae3551SRodney W. Grimes 			panic("unknown file on tape\n");
6308fae3551SRodney W. Grimes 		if ((ep->e_flags & (NEW|EXTRACT)) == 0)
6318fae3551SRodney W. Grimes 			badentry(ep, "unexpected file on tape");
6328fae3551SRodney W. Grimes 		/*
6338fae3551SRodney W. Grimes 		 * If the file is to be extracted, then the old file must
6348fae3551SRodney W. Grimes 		 * be removed since its type may change from one leaf type
63591ac32e4SPhilippe Charnier 		 * to another (e.g. "file" to "character special").
6368fae3551SRodney W. Grimes 		 */
6378fae3551SRodney W. Grimes 		if ((ep->e_flags & EXTRACT) != 0) {
6388fae3551SRodney W. Grimes 			removeleaf(ep);
6398fae3551SRodney W. Grimes 			ep->e_flags &= ~REMOVED;
6408fae3551SRodney W. Grimes 		}
6418fae3551SRodney W. Grimes 		(void) extractfile(myname(ep));
6428fae3551SRodney W. Grimes 		ep->e_flags &= ~(NEW|EXTRACT);
6438fae3551SRodney W. Grimes 		/*
6448fae3551SRodney W. Grimes 		 * We checkpoint the restore after every tape reel, so
6458fae3551SRodney W. Grimes 		 * as to simplify the amount of work required by the
6468fae3551SRodney W. Grimes 		 * 'R' command.
6478fae3551SRodney W. Grimes 		 */
6488fae3551SRodney W. Grimes 	next:
6498fae3551SRodney W. Grimes 		if (curvol != volno) {
6508fae3551SRodney W. Grimes 			dumpsymtable(symtabfile, volno);
6518fae3551SRodney W. Grimes 			skipmaps();
6528fae3551SRodney W. Grimes 			curvol = volno;
6538fae3551SRodney W. Grimes 		}
6548fae3551SRodney W. Grimes 	}
6558fae3551SRodney W. Grimes }
6568fae3551SRodney W. Grimes 
6578fae3551SRodney W. Grimes /*
6588fae3551SRodney W. Grimes  * This is the routine used to extract files for the 'x' and 'i' commands.
6598fae3551SRodney W. Grimes  * Efficiently extract a subset of the files on a tape.
6608fae3551SRodney W. Grimes  */
6618fae3551SRodney W. Grimes void
createfiles(void)6622db673abSWarner Losh createfiles(void)
6638fae3551SRodney W. Grimes {
6643d438ad6SDavid E. O'Brien 	ino_t first, next, last;
6653d438ad6SDavid E. O'Brien 	struct entry *ep;
6668fae3551SRodney W. Grimes 	long curvol;
6678fae3551SRodney W. Grimes 
6688fae3551SRodney W. Grimes 	vprintf(stdout, "Extract requested files\n");
6698fae3551SRodney W. Grimes 	curfile.action = SKIP;
6708fae3551SRodney W. Grimes 	getvol((long)1);
6718fae3551SRodney W. Grimes 	skipmaps();
6728fae3551SRodney W. Grimes 	skipdirs();
6731dc349abSEd Maste 	first = lowerbnd(UFS_ROOTINO);
6748fae3551SRodney W. Grimes 	last = upperbnd(maxino - 1);
6758fae3551SRodney W. Grimes 	for (;;) {
676cfd8a009SIan Dowse 		curvol = volno;
6778fae3551SRodney W. Grimes 		first = lowerbnd(first);
6788fae3551SRodney W. Grimes 		last = upperbnd(last);
6798fae3551SRodney W. Grimes 		/*
6808fae3551SRodney W. Grimes 		 * Check to see if any files remain to be extracted
6818fae3551SRodney W. Grimes 		 */
6828fae3551SRodney W. Grimes 		if (first > last)
6838fae3551SRodney W. Grimes 			return;
684cbc8bb98SDavid Malone 		if (Dflag) {
685cbc8bb98SDavid Malone 			if (curfile.ino == maxino)
686cbc8bb98SDavid Malone 				return;
687cbc8bb98SDavid Malone 			if((ep = lookupino(curfile.ino)) != NULL &&
688cbc8bb98SDavid Malone 			    (ep->e_flags & (NEW|EXTRACT))) {
689cbc8bb98SDavid Malone 				goto justgetit;
690cbc8bb98SDavid Malone 			} else {
691cbc8bb98SDavid Malone 				skipfile();
692cbc8bb98SDavid Malone 				continue;
693cbc8bb98SDavid Malone 			}
694cbc8bb98SDavid Malone 		}
6958fae3551SRodney W. Grimes 		/*
696cfd8a009SIan Dowse 		 * Reject any volumes with inodes greater than the last
697cfd8a009SIan Dowse 		 * one needed, so that we can quickly skip backwards to
698cfd8a009SIan Dowse 		 * a volume containing useful inodes. We can't do this
699cfd8a009SIan Dowse 		 * if there are no further volumes available (curfile.ino
700cfd8a009SIan Dowse 		 * >= maxino) or if we are already at the first tape.
7018fae3551SRodney W. Grimes 		 */
702cfd8a009SIan Dowse 		if (curfile.ino > last && curfile.ino < maxino && volno > 1) {
7038fae3551SRodney W. Grimes 			curfile.action = SKIP;
7048fae3551SRodney W. Grimes 			getvol((long)0);
7058fae3551SRodney W. Grimes 			skipmaps();
7068fae3551SRodney W. Grimes 			skipdirs();
707cfd8a009SIan Dowse 			continue;
7088fae3551SRodney W. Grimes 		}
7098fae3551SRodney W. Grimes 		/*
7108fae3551SRodney W. Grimes 		 * Decide on the next inode needed.
7118fae3551SRodney W. Grimes 		 * Skip across the inodes until it is found
712cfd8a009SIan Dowse 		 * or a volume change is encountered
7138fae3551SRodney W. Grimes 		 */
714cfd8a009SIan Dowse 		if (curfile.ino < maxino) {
7158fae3551SRodney W. Grimes 			next = lowerbnd(curfile.ino);
7168fae3551SRodney W. Grimes 			while (next > curfile.ino && volno == curvol)
7178fae3551SRodney W. Grimes 				skipfile();
718cfd8a009SIan Dowse 			if (volno != curvol) {
7198fae3551SRodney W. Grimes 				skipmaps();
7208fae3551SRodney W. Grimes 				skipdirs();
7218fae3551SRodney W. Grimes 				continue;
722cfd8a009SIan Dowse 			}
723cfd8a009SIan Dowse 		} else {
724cfd8a009SIan Dowse 			/*
725cfd8a009SIan Dowse 			 * No further volumes or inodes available. Set
726cfd8a009SIan Dowse 			 * `next' to the first inode, so that a warning
727cfd8a009SIan Dowse 			 * is emitted below for each missing file.
728cfd8a009SIan Dowse 			 */
729cfd8a009SIan Dowse 			next = first;
730cfd8a009SIan Dowse 		}
7318fae3551SRodney W. Grimes 		/*
7328fae3551SRodney W. Grimes 		 * If the current inode is greater than the one we were
7338fae3551SRodney W. Grimes 		 * looking for then we missed the one we were looking for.
7348fae3551SRodney W. Grimes 		 * Since we only attempt to extract files listed in the
7358fae3551SRodney W. Grimes 		 * dump map, the lost files must have been due to a tape
7368fae3551SRodney W. Grimes 		 * read error, or a file that was removed while the dump
7378fae3551SRodney W. Grimes 		 * was in progress. Thus we report all requested files
7388fae3551SRodney W. Grimes 		 * between the one we were looking for, and the one we
7398fae3551SRodney W. Grimes 		 * found as missing, and delete their request flags.
7408fae3551SRodney W. Grimes 		 */
7418fae3551SRodney W. Grimes 		while (next < curfile.ino) {
7428fae3551SRodney W. Grimes 			ep = lookupino(next);
7438fae3551SRodney W. Grimes 			if (ep == NULL)
7448fae3551SRodney W. Grimes 				panic("corrupted symbol table\n");
7458fae3551SRodney W. Grimes 			fprintf(stderr, "%s: not found on tape\n", myname(ep));
7468fae3551SRodney W. Grimes 			ep->e_flags &= ~NEW;
7478fae3551SRodney W. Grimes 			next = lowerbnd(next);
7488fae3551SRodney W. Grimes 		}
7498fae3551SRodney W. Grimes 		/*
7508fae3551SRodney W. Grimes 		 * The current inode is the one that we are looking for,
7518fae3551SRodney W. Grimes 		 * so extract it per its requested name.
7528fae3551SRodney W. Grimes 		 */
7538fae3551SRodney W. Grimes 		if (next == curfile.ino && next <= last) {
7548fae3551SRodney W. Grimes 			ep = lookupino(next);
7558fae3551SRodney W. Grimes 			if (ep == NULL)
7568fae3551SRodney W. Grimes 				panic("corrupted symbol table\n");
757cbc8bb98SDavid Malone justgetit:
7588fae3551SRodney W. Grimes 			(void) extractfile(myname(ep));
7598fae3551SRodney W. Grimes 			ep->e_flags &= ~NEW;
7608fae3551SRodney W. Grimes 			if (volno != curvol)
7618fae3551SRodney W. Grimes 				skipmaps();
7628fae3551SRodney W. Grimes 		}
7638fae3551SRodney W. Grimes 	}
7648fae3551SRodney W. Grimes }
7658fae3551SRodney W. Grimes 
7668fae3551SRodney W. Grimes /*
7678fae3551SRodney W. Grimes  * Add links.
7688fae3551SRodney W. Grimes  */
7698fae3551SRodney W. Grimes void
createlinks(void)7702db673abSWarner Losh createlinks(void)
7718fae3551SRodney W. Grimes {
7723d438ad6SDavid E. O'Brien 	struct entry *np, *ep;
7733d438ad6SDavid E. O'Brien 	ino_t i;
7748fae3551SRodney W. Grimes 	char name[BUFSIZ];
7758fae3551SRodney W. Grimes 
7761dc349abSEd Maste 	if ((ep = lookupino(UFS_WINO))) {
777d87d79aeSPeter Wemm 		vprintf(stdout, "Add whiteouts\n");
778d87d79aeSPeter Wemm 		for ( ; ep != NULL; ep = ep->e_links) {
779d87d79aeSPeter Wemm 			if ((ep->e_flags & NEW) == 0)
780d87d79aeSPeter Wemm 				continue;
781d87d79aeSPeter Wemm 			(void) addwhiteout(myname(ep));
782d87d79aeSPeter Wemm 			ep->e_flags &= ~NEW;
783d87d79aeSPeter Wemm 		}
784d87d79aeSPeter Wemm 	}
7858fae3551SRodney W. Grimes 	vprintf(stdout, "Add links\n");
7861dc349abSEd Maste 	for (i = UFS_ROOTINO; i < maxino; i++) {
7878fae3551SRodney W. Grimes 		ep = lookupino(i);
7888fae3551SRodney W. Grimes 		if (ep == NULL)
7898fae3551SRodney W. Grimes 			continue;
7908fae3551SRodney W. Grimes 		for (np = ep->e_links; np != NULL; np = np->e_links) {
7918fae3551SRodney W. Grimes 			if ((np->e_flags & NEW) == 0)
7928fae3551SRodney W. Grimes 				continue;
7938fae3551SRodney W. Grimes 			(void) strcpy(name, myname(ep));
7948fae3551SRodney W. Grimes 			if (ep->e_type == NODE) {
7958fae3551SRodney W. Grimes 				(void) linkit(name, myname(np), SYMLINK);
7968fae3551SRodney W. Grimes 			} else {
7978fae3551SRodney W. Grimes 				(void) linkit(name, myname(np), HARDLINK);
7988fae3551SRodney W. Grimes 			}
7998fae3551SRodney W. Grimes 			np->e_flags &= ~NEW;
8008fae3551SRodney W. Grimes 		}
8018fae3551SRodney W. Grimes 	}
8028fae3551SRodney W. Grimes }
8038fae3551SRodney W. Grimes 
8048fae3551SRodney W. Grimes /*
8058fae3551SRodney W. Grimes  * Check the symbol table.
8068fae3551SRodney W. Grimes  * We do this to insure that all the requested work was done, and
8078fae3551SRodney W. Grimes  * that no temporary names remain.
8088fae3551SRodney W. Grimes  */
8098fae3551SRodney W. Grimes void
checkrestore(void)8102db673abSWarner Losh checkrestore(void)
8118fae3551SRodney W. Grimes {
8123d438ad6SDavid E. O'Brien 	struct entry *ep;
8133d438ad6SDavid E. O'Brien 	ino_t i;
8148fae3551SRodney W. Grimes 
8158fae3551SRodney W. Grimes 	vprintf(stdout, "Check the symbol table.\n");
8161dc349abSEd Maste 	for (i = UFS_WINO; i < maxino; i++) {
8178fae3551SRodney W. Grimes 		for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
8188fae3551SRodney W. Grimes 			ep->e_flags &= ~KEEP;
8198fae3551SRodney W. Grimes 			if (ep->e_type == NODE)
8208fae3551SRodney W. Grimes 				ep->e_flags &= ~(NEW|EXISTED);
821d030d2d2SPoul-Henning Kamp 			if (ep->e_flags != 0)
8228fae3551SRodney W. Grimes 				badentry(ep, "incomplete operations");
8238fae3551SRodney W. Grimes 		}
8248fae3551SRodney W. Grimes 	}
8258fae3551SRodney W. Grimes }
8268fae3551SRodney W. Grimes 
8278fae3551SRodney W. Grimes /*
8288fae3551SRodney W. Grimes  * Compare with the directory structure on the tape
8298fae3551SRodney W. Grimes  * A paranoid check that things are as they should be.
8308fae3551SRodney W. Grimes  */
8318fae3551SRodney W. Grimes long
verifyfile(char * name,ino_t ino,int type)8322db673abSWarner Losh verifyfile(char *name, ino_t ino, int type)
8338fae3551SRodney W. Grimes {
8348fae3551SRodney W. Grimes 	struct entry *np, *ep;
8358fae3551SRodney W. Grimes 	long descend = GOOD;
8368fae3551SRodney W. Grimes 
8378fae3551SRodney W. Grimes 	ep = lookupname(name);
8388fae3551SRodney W. Grimes 	if (ep == NULL) {
8398fae3551SRodney W. Grimes 		fprintf(stderr, "Warning: missing name %s\n", name);
8408fae3551SRodney W. Grimes 		return (FAIL);
8418fae3551SRodney W. Grimes 	}
8428fae3551SRodney W. Grimes 	np = lookupino(ino);
8438fae3551SRodney W. Grimes 	if (np != ep)
8448fae3551SRodney W. Grimes 		descend = FAIL;
8458fae3551SRodney W. Grimes 	for ( ; np != NULL; np = np->e_links)
8468fae3551SRodney W. Grimes 		if (np == ep)
8478fae3551SRodney W. Grimes 			break;
8488fae3551SRodney W. Grimes 	if (np == NULL)
849e25a029eSMatthew D Fleming 		panic("missing inumber %ju\n", (uintmax_t)ino);
8508fae3551SRodney W. Grimes 	if (ep->e_type == LEAF && type != LEAF)
8518fae3551SRodney W. Grimes 		badentry(ep, "type should be LEAF");
8528fae3551SRodney W. Grimes 	return (descend);
8538fae3551SRodney W. Grimes }
854