xref: /illumos-gate/usr/src/cmd/backup/restore/symtab.c (revision d9529689)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
37c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
47c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
57c478bd9Sstevel@tonic-gate  */
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
87c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
97c478bd9Sstevel@tonic-gate 
107c478bd9Sstevel@tonic-gate /*
117c478bd9Sstevel@tonic-gate  * Copyright (c) 1996,1998,2001 by Sun Microsystems, Inc.
127c478bd9Sstevel@tonic-gate  * All rights reserved.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate /*
167c478bd9Sstevel@tonic-gate  * These routines maintain the symbol table which tracks the state
177c478bd9Sstevel@tonic-gate  * of the file system being restored. They provide lookup by either
187c478bd9Sstevel@tonic-gate  * name or inode number. They also provide for creation, deletion,
197c478bd9Sstevel@tonic-gate  * and renaming of entries. Because of the dynamic nature of pathnames,
207c478bd9Sstevel@tonic-gate  * names should not be saved, but always constructed just before they
217c478bd9Sstevel@tonic-gate  * are needed, by calling "myname".
227c478bd9Sstevel@tonic-gate  */
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate #include "restore.h"
257c478bd9Sstevel@tonic-gate #include <limits.h>
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * The following variables define the inode symbol table.
297c478bd9Sstevel@tonic-gate  * The primary hash table is dynamically allocated based on
307c478bd9Sstevel@tonic-gate  * the number of inodes in the file system (maxino), scaled by
317c478bd9Sstevel@tonic-gate  * HASHFACTOR. The variable "entry" points to the hash table;
327c478bd9Sstevel@tonic-gate  * the variable "entrytblsize" indicates its size (in entries).
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate #define	HASHFACTOR 5
357c478bd9Sstevel@tonic-gate static struct entry **entry;
367c478bd9Sstevel@tonic-gate static uint_t entrytblsize;
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate static void addino(ino_t, struct entry *);
397c478bd9Sstevel@tonic-gate static struct entry *lookupparent(char *);
407c478bd9Sstevel@tonic-gate static void removeentry(struct entry *);
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * Look up an entry by inode number
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate struct entry *
lookupino(ino_t inum)46*d9529689SToomas Soome lookupino(ino_t inum)
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate 	struct entry *ep;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate 	if (inum < ROOTINO || inum >= maxino)
517c478bd9Sstevel@tonic-gate 		return (NIL);
527c478bd9Sstevel@tonic-gate 	for (ep = entry[inum % entrytblsize]; ep != NIL; ep = ep->e_next)
537c478bd9Sstevel@tonic-gate 		if (ep->e_ino == inum)
547c478bd9Sstevel@tonic-gate 			return (ep);
557c478bd9Sstevel@tonic-gate 	return (NIL);
567c478bd9Sstevel@tonic-gate }
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /*
597c478bd9Sstevel@tonic-gate  * We now ignore inodes that are out of range.  This
607c478bd9Sstevel@tonic-gate  * allows us to attempt to proceed in the face of
617c478bd9Sstevel@tonic-gate  * a corrupted archive, albeit with future complaints
627c478bd9Sstevel@tonic-gate  * about failed inode lookups.  We only complain once
637c478bd9Sstevel@tonic-gate  * about range problems, to avoid irritating the user
647c478bd9Sstevel@tonic-gate  * without providing any useful information.  Failed
657c478bd9Sstevel@tonic-gate  * lookups have the bogus name, which is useful, so
667c478bd9Sstevel@tonic-gate  * they always happen.
677c478bd9Sstevel@tonic-gate  */
687c478bd9Sstevel@tonic-gate static int complained_about_range = 0;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * Add an entry into the entry table
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate static void
addino(ino_t inum,struct entry * np)74*d9529689SToomas Soome addino(ino_t inum, struct entry *np)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 	struct entry **epp;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	if (inum < ROOTINO || inum >= maxino) {
797c478bd9Sstevel@tonic-gate 		if (!complained_about_range) {
807c478bd9Sstevel@tonic-gate 			panic(gettext("%s: out of range %d\n"),
817c478bd9Sstevel@tonic-gate 			    "addino", inum);
827c478bd9Sstevel@tonic-gate 			complained_about_range = 1;
837c478bd9Sstevel@tonic-gate 		}
847c478bd9Sstevel@tonic-gate 		return;
857c478bd9Sstevel@tonic-gate 	}
867c478bd9Sstevel@tonic-gate 	epp = &entry[inum % entrytblsize];
877c478bd9Sstevel@tonic-gate 	np->e_ino = inum;
887c478bd9Sstevel@tonic-gate 	np->e_next = *epp;
897c478bd9Sstevel@tonic-gate 	*epp = np;
907c478bd9Sstevel@tonic-gate 	if (dflag)
917c478bd9Sstevel@tonic-gate 		for (np = np->e_next; np != NIL; np = np->e_next)
927c478bd9Sstevel@tonic-gate 			if (np->e_ino == inum)
937c478bd9Sstevel@tonic-gate 				badentry(np, gettext("duplicate inum"));
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * Delete an entry from the entry table.  We assume our caller
987c478bd9Sstevel@tonic-gate  * arranges for the necessary memory reclamation, if needed.
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate void
deleteino(ino_t inum)101*d9529689SToomas Soome deleteino(ino_t inum)
1027c478bd9Sstevel@tonic-gate {
1037c478bd9Sstevel@tonic-gate 	struct entry *next;
1047c478bd9Sstevel@tonic-gate 	struct entry **prev;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	if (inum < ROOTINO || inum >= maxino) {
1077c478bd9Sstevel@tonic-gate 		if (!complained_about_range) {
1087c478bd9Sstevel@tonic-gate 			panic(gettext("%s: out of range %d\n"),
1097c478bd9Sstevel@tonic-gate 			    "deleteino", inum);
1107c478bd9Sstevel@tonic-gate 			complained_about_range = 1;
1117c478bd9Sstevel@tonic-gate 		}
1127c478bd9Sstevel@tonic-gate 		return;
1137c478bd9Sstevel@tonic-gate 	}
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	prev = &entry[inum % entrytblsize];
1167c478bd9Sstevel@tonic-gate 	for (next = *prev; next != NIL; next = next->e_next) {
1177c478bd9Sstevel@tonic-gate 		if (next->e_ino == inum) {
1187c478bd9Sstevel@tonic-gate 			next->e_ino = 0;
1197c478bd9Sstevel@tonic-gate 			*prev = next->e_next;
1207c478bd9Sstevel@tonic-gate 			return;
1217c478bd9Sstevel@tonic-gate 		}
1227c478bd9Sstevel@tonic-gate 		prev = &next->e_next;
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate  * Look up an entry by name.
1287c478bd9Sstevel@tonic-gate  *	NOTE: this function handles "complex" pathnames (as returned
1297c478bd9Sstevel@tonic-gate  *	by myname()) for extended file attributes.  The name string
1307c478bd9Sstevel@tonic-gate  *	provided to this function should be terminated with *two*
1317c478bd9Sstevel@tonic-gate  *	NULL characters.
1327c478bd9Sstevel@tonic-gate  */
1337c478bd9Sstevel@tonic-gate struct entry *
lookupname(char * name)134*d9529689SToomas Soome lookupname(char *name)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	struct entry *ep;
1377c478bd9Sstevel@tonic-gate 	char *np, *cp;
1387c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	if (strlen(name) > (sizeof (buf) - 1)) {
1417c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: ignoring too-long name\n"),
1427c478bd9Sstevel@tonic-gate 		    "lookupname");
1437c478bd9Sstevel@tonic-gate 		return (NIL);
1447c478bd9Sstevel@tonic-gate 	}
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	cp = name;
1477c478bd9Sstevel@tonic-gate 	for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) {
1487c478bd9Sstevel@tonic-gate 		np = buf;
1497c478bd9Sstevel@tonic-gate 		while (*cp != '/' && *cp != '\0')
1507c478bd9Sstevel@tonic-gate 			*np++ = *cp++;
1517c478bd9Sstevel@tonic-gate 		*np = '\0';
1527c478bd9Sstevel@tonic-gate 		for (; ep != NIL; ep = ep->e_sibling)
1537c478bd9Sstevel@tonic-gate 			if (strcmp(ep->e_name, buf) == 0)
1547c478bd9Sstevel@tonic-gate 				break;
1557c478bd9Sstevel@tonic-gate 		if (*cp++ == '\0') {
1567c478bd9Sstevel@tonic-gate 			if (*cp != '\0') {
1577c478bd9Sstevel@tonic-gate 				ep = ep->e_xattrs;
1587c478bd9Sstevel@tonic-gate 				/*
1597c478bd9Sstevel@tonic-gate 				 * skip over the "./" prefix on all
1607c478bd9Sstevel@tonic-gate 				 * extended attribute paths
1617c478bd9Sstevel@tonic-gate 				 */
1627c478bd9Sstevel@tonic-gate 				cp += 2;
1637c478bd9Sstevel@tonic-gate 			}
1647c478bd9Sstevel@tonic-gate 			if (*cp == '\0')
1657c478bd9Sstevel@tonic-gate 				return (ep);
1667c478bd9Sstevel@tonic-gate 		}
1677c478bd9Sstevel@tonic-gate 		if (ep == NIL)
1687c478bd9Sstevel@tonic-gate 			break;
1697c478bd9Sstevel@tonic-gate 	}
1707c478bd9Sstevel@tonic-gate 	return (NIL);
1717c478bd9Sstevel@tonic-gate }
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate /*
1747c478bd9Sstevel@tonic-gate  * Look up the parent of a pathname.  This routine accepts complex
1757c478bd9Sstevel@tonic-gate  * names so the provided name argument must terminate with two NULLs.
1767c478bd9Sstevel@tonic-gate  */
1777c478bd9Sstevel@tonic-gate static struct entry *
lookupparent(char * name)178*d9529689SToomas Soome lookupparent(char *name)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate 	struct entry *ep;
1817c478bd9Sstevel@tonic-gate 	char *tailindex, savechar, *lastpart;
1827c478bd9Sstevel@tonic-gate 	int xattrparent = 0;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	/* find the last component of the complex name */
1857c478bd9Sstevel@tonic-gate 	lastpart = name;
1867c478bd9Sstevel@tonic-gate 	LASTPART(lastpart);
1877c478bd9Sstevel@tonic-gate 	tailindex = strrchr(lastpart, '/');
1887c478bd9Sstevel@tonic-gate 	if (tailindex == 0) {
1897c478bd9Sstevel@tonic-gate 		if (lastpart == name)
1907c478bd9Sstevel@tonic-gate 			return (NIL);
1917c478bd9Sstevel@tonic-gate 		/*
1927c478bd9Sstevel@tonic-gate 		 * tailindex normaly points to the '/' character
1937c478bd9Sstevel@tonic-gate 		 * dividing the path, but in the case of an extended
1947c478bd9Sstevel@tonic-gate 		 * attribute transition it will point to the NULL
1957c478bd9Sstevel@tonic-gate 		 * separator in front of the attribute path.
1967c478bd9Sstevel@tonic-gate 		 */
1977c478bd9Sstevel@tonic-gate 		tailindex = lastpart - 1;
1987c478bd9Sstevel@tonic-gate 		xattrparent = 1;
1997c478bd9Sstevel@tonic-gate 	} else {
2007c478bd9Sstevel@tonic-gate 		*tailindex = '\0';
2017c478bd9Sstevel@tonic-gate 	}
2027c478bd9Sstevel@tonic-gate 	savechar = *(tailindex+1);
2037c478bd9Sstevel@tonic-gate 	*(tailindex+1) = '\0';
2047c478bd9Sstevel@tonic-gate 	ep = lookupname(name);
2057c478bd9Sstevel@tonic-gate 	if (ep != NIL && !xattrparent && ep->e_type != NODE)
2067c478bd9Sstevel@tonic-gate 		panic(gettext("%s is not a directory\n"), name);
2077c478bd9Sstevel@tonic-gate 	if (!xattrparent) *tailindex = '/';
2087c478bd9Sstevel@tonic-gate 	*(tailindex+1) = savechar;
2097c478bd9Sstevel@tonic-gate 	return (ep);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate  * Determine the current pathname of a node or leaf.
2147c478bd9Sstevel@tonic-gate  * The returned pathname will be multiple strings with NULL separators:
2157c478bd9Sstevel@tonic-gate  *
2167c478bd9Sstevel@tonic-gate  *	./<path>/entry\0<path>/attrentry\0<path>/...\0\0
2177c478bd9Sstevel@tonic-gate  *	^	        ^		  ^	    ^
2187c478bd9Sstevel@tonic-gate  *   return pntr    entry attr	    recursive attr  terminator
2197c478bd9Sstevel@tonic-gate  *
2207c478bd9Sstevel@tonic-gate  * Guaranteed to return a name that fits within MAXCOMPLEXLEN and is
2217c478bd9Sstevel@tonic-gate  * terminated with two NULLs.
2227c478bd9Sstevel@tonic-gate  */
2237c478bd9Sstevel@tonic-gate char *
myname(struct entry * ep)224*d9529689SToomas Soome myname(struct entry *ep)
2257c478bd9Sstevel@tonic-gate {
2267c478bd9Sstevel@tonic-gate 	char *cp;
2277c478bd9Sstevel@tonic-gate 	struct entry *root = lookupino(ROOTINO);
2287c478bd9Sstevel@tonic-gate 	static char namebuf[MAXCOMPLEXLEN];
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	cp = &namebuf[MAXCOMPLEXLEN - 3];
2317c478bd9Sstevel@tonic-gate 	*(cp + 1) = '\0';
2327c478bd9Sstevel@tonic-gate 	*(cp + 2) = '\0';
2337c478bd9Sstevel@tonic-gate 	while (cp > &namebuf[ep->e_namlen]) {
2347c478bd9Sstevel@tonic-gate 		cp -= ep->e_namlen;
2357c478bd9Sstevel@tonic-gate 		bcopy(ep->e_name, cp, (size_t)ep->e_namlen);
2367c478bd9Sstevel@tonic-gate 		if (ep == root)
2377c478bd9Sstevel@tonic-gate 			return (cp);
2387c478bd9Sstevel@tonic-gate 		if (ep->e_flags & XATTRROOT)
2397c478bd9Sstevel@tonic-gate 			*(--cp) = '\0';
2407c478bd9Sstevel@tonic-gate 		else
2417c478bd9Sstevel@tonic-gate 			*(--cp) = '/';
2427c478bd9Sstevel@tonic-gate 		ep = ep->e_parent;
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate 	panic(gettext("%s%s: pathname too long\n"), "...", cp);
2457c478bd9Sstevel@tonic-gate 	return (cp);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate  * Unused symbol table entries are linked together on a freelist
2507c478bd9Sstevel@tonic-gate  * headed by the following pointer.
2517c478bd9Sstevel@tonic-gate  */
2527c478bd9Sstevel@tonic-gate static struct entry *freelist = NIL;
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate /*
2557c478bd9Sstevel@tonic-gate  * add an entry to the symbol table
2567c478bd9Sstevel@tonic-gate  */
2577c478bd9Sstevel@tonic-gate struct entry *
addentry(char * name,ino_t inum,int type)258*d9529689SToomas Soome addentry(char *name, ino_t inum, int type)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate 	struct entry *np, *ep;
2617c478bd9Sstevel@tonic-gate 	char *cp;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	if (freelist != NIL) {
2647c478bd9Sstevel@tonic-gate 		np = freelist;
2657c478bd9Sstevel@tonic-gate 		freelist = np->e_next;
2667c478bd9Sstevel@tonic-gate 		(void) bzero((char *)np, (size_t)sizeof (*np));
2677c478bd9Sstevel@tonic-gate 	} else {
2687c478bd9Sstevel@tonic-gate 		np = (struct entry *)calloc(1, sizeof (*np));
2697c478bd9Sstevel@tonic-gate 		if (np == NIL) {
2707c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
2717c478bd9Sstevel@tonic-gate 			    gettext("no memory to extend symbol table\n"));
2727c478bd9Sstevel@tonic-gate 			done(1);
2737c478bd9Sstevel@tonic-gate 		}
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 	np->e_type = type & ~(LINK|ROOT);
2767c478bd9Sstevel@tonic-gate 	if (inattrspace)
2777c478bd9Sstevel@tonic-gate 		np->e_flags |= XATTR;
2787c478bd9Sstevel@tonic-gate 	ep = lookupparent(name);
2797c478bd9Sstevel@tonic-gate 	if (ep == NIL) {
2807c478bd9Sstevel@tonic-gate 		if (inum != ROOTINO || lookupino(ROOTINO) != NIL) {
2817c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
2827c478bd9Sstevel@tonic-gate 			    "%s: bad name %s\n"), "addentry", name);
2837c478bd9Sstevel@tonic-gate 			assert(0);
2847c478bd9Sstevel@tonic-gate 			done(1);
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 		np->e_name = savename(name);
2877c478bd9Sstevel@tonic-gate 		/* LINTED: savename guarantees that strlen fits in e_namlen */
2887c478bd9Sstevel@tonic-gate 		np->e_namlen = strlen(name);
2897c478bd9Sstevel@tonic-gate 		np->e_parent = np;
2907c478bd9Sstevel@tonic-gate 		addino(ROOTINO, np);
2917c478bd9Sstevel@tonic-gate 		return (np);
2927c478bd9Sstevel@tonic-gate 	}
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	if (np->e_flags & XATTR) {
2957c478bd9Sstevel@tonic-gate 		/*
2967c478bd9Sstevel@tonic-gate 		 * skip to the last part of the complex string: it
2977c478bd9Sstevel@tonic-gate 		 * containes the extended attribute file name.
2987c478bd9Sstevel@tonic-gate 		 */
2997c478bd9Sstevel@tonic-gate 		LASTPART(name);
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 	cp = strrchr(name, '/');
3027c478bd9Sstevel@tonic-gate 	if (cp == NULL)
3037c478bd9Sstevel@tonic-gate 		cp = name;
3047c478bd9Sstevel@tonic-gate 	else
3057c478bd9Sstevel@tonic-gate 		cp++;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	np->e_name = savename(cp);
3087c478bd9Sstevel@tonic-gate 	/* LINTED: savename guarantees that strlen will fit */
3097c478bd9Sstevel@tonic-gate 	np->e_namlen = strlen(np->e_name);
3107c478bd9Sstevel@tonic-gate 	np->e_parent = ep;
3117c478bd9Sstevel@tonic-gate 	/*
3127c478bd9Sstevel@tonic-gate 	 * Extended attribute root directories must be linked to their
3137c478bd9Sstevel@tonic-gate 	 * "parents" via the e_xattrs field.  Other entries are simply
3147c478bd9Sstevel@tonic-gate 	 * added to their parent directories e_entries list.
3157c478bd9Sstevel@tonic-gate 	 */
3167c478bd9Sstevel@tonic-gate 	if ((type & ROOT) && (np->e_flags & XATTR)) {
3177c478bd9Sstevel@tonic-gate 		/* link this extended attribute root dir to its "parent" */
3187c478bd9Sstevel@tonic-gate 		ep->e_xattrs = np;
3197c478bd9Sstevel@tonic-gate 	} else {
3207c478bd9Sstevel@tonic-gate 		/* add this entry to the entry list of the parent dir */
3217c478bd9Sstevel@tonic-gate 		np->e_sibling = ep->e_entries;
3227c478bd9Sstevel@tonic-gate 		ep->e_entries = np;
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 	if (type & LINK) {
3257c478bd9Sstevel@tonic-gate 		ep = lookupino(inum);
3267c478bd9Sstevel@tonic-gate 		if (ep == NIL) {
3277c478bd9Sstevel@tonic-gate 			/* XXX just bail on this one and continue? */
3287c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
3297c478bd9Sstevel@tonic-gate 			    gettext("link to non-existent name\n"));
3307c478bd9Sstevel@tonic-gate 			done(1);
3317c478bd9Sstevel@tonic-gate 		}
3327c478bd9Sstevel@tonic-gate 		np->e_ino = inum;
3337c478bd9Sstevel@tonic-gate 		np->e_links = ep->e_links;
3347c478bd9Sstevel@tonic-gate 		ep->e_links = np;
3357c478bd9Sstevel@tonic-gate 	} else if (inum != 0) {
3367c478bd9Sstevel@tonic-gate 		ep = lookupino(inum);
3377c478bd9Sstevel@tonic-gate 		if (ep != NIL)
3387c478bd9Sstevel@tonic-gate 			panic(gettext("duplicate entry\n"));
3397c478bd9Sstevel@tonic-gate 		else
3407c478bd9Sstevel@tonic-gate 			addino(inum, np);
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate 	return (np);
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate  * delete an entry from the symbol table
3477c478bd9Sstevel@tonic-gate  */
3487c478bd9Sstevel@tonic-gate void
freeentry(struct entry * ep)349*d9529689SToomas Soome freeentry(struct entry *ep)
3507c478bd9Sstevel@tonic-gate {
3517c478bd9Sstevel@tonic-gate 	struct entry *np;
3527c478bd9Sstevel@tonic-gate 	ino_t inum;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	if ((ep->e_flags & REMOVED) == 0)
3557c478bd9Sstevel@tonic-gate 		badentry(ep, gettext("not marked REMOVED"));
3567c478bd9Sstevel@tonic-gate 	if (ep->e_type == NODE) {
3577c478bd9Sstevel@tonic-gate 		if (ep->e_links != NIL)
3587c478bd9Sstevel@tonic-gate 			badentry(ep, gettext("freeing referenced directory"));
3597c478bd9Sstevel@tonic-gate 		if (ep->e_entries != NIL)
3607c478bd9Sstevel@tonic-gate 			badentry(ep, gettext("freeing non-empty directory"));
3617c478bd9Sstevel@tonic-gate 	}
3627c478bd9Sstevel@tonic-gate 	if (ep->e_ino != 0) {
3637c478bd9Sstevel@tonic-gate 		np = lookupino(ep->e_ino);
3647c478bd9Sstevel@tonic-gate 		if (np == NIL)
3657c478bd9Sstevel@tonic-gate 			badentry(ep, gettext("lookupino failed"));
3667c478bd9Sstevel@tonic-gate 		if (np == ep) {
3677c478bd9Sstevel@tonic-gate 			inum = ep->e_ino;
3687c478bd9Sstevel@tonic-gate 			deleteino(inum);
3697c478bd9Sstevel@tonic-gate 			if (ep->e_links != NIL)
3707c478bd9Sstevel@tonic-gate 				addino(inum, ep->e_links);
3717c478bd9Sstevel@tonic-gate 		} else {
3727c478bd9Sstevel@tonic-gate 			for (; np != NIL; np = np->e_links) {
3737c478bd9Sstevel@tonic-gate 				if (np->e_links == ep) {
3747c478bd9Sstevel@tonic-gate 					np->e_links = ep->e_links;
3757c478bd9Sstevel@tonic-gate 					break;
3767c478bd9Sstevel@tonic-gate 				}
3777c478bd9Sstevel@tonic-gate 			}
3787c478bd9Sstevel@tonic-gate 			if (np == NIL)
3797c478bd9Sstevel@tonic-gate 				badentry(ep, gettext("link not found"));
3807c478bd9Sstevel@tonic-gate 		}
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 	removeentry(ep);
3837c478bd9Sstevel@tonic-gate 	freename(ep->e_name);
3847c478bd9Sstevel@tonic-gate 	ep->e_next = freelist;
3857c478bd9Sstevel@tonic-gate 	freelist = ep;
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate /*
3897c478bd9Sstevel@tonic-gate  * Relocate an entry in the tree structure
3907c478bd9Sstevel@tonic-gate  */
3917c478bd9Sstevel@tonic-gate void
moveentry(struct entry * ep,char * newname)392*d9529689SToomas Soome moveentry(struct entry *ep, char *newname)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate 	struct entry *np;
3957c478bd9Sstevel@tonic-gate 	char *cp;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	np = lookupparent(newname);
3987c478bd9Sstevel@tonic-gate 	if (np == NIL)
3997c478bd9Sstevel@tonic-gate 		badentry(ep, gettext("cannot move ROOT"));
4007c478bd9Sstevel@tonic-gate 	if (np != ep->e_parent) {
4017c478bd9Sstevel@tonic-gate 		removeentry(ep);
4027c478bd9Sstevel@tonic-gate 		ep->e_parent = np;
4037c478bd9Sstevel@tonic-gate 		ep->e_sibling = np->e_entries;
4047c478bd9Sstevel@tonic-gate 		np->e_entries = ep;
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 	/* find the last component of the complex name */
4077c478bd9Sstevel@tonic-gate 	LASTPART(newname);
4087c478bd9Sstevel@tonic-gate 	cp = strrchr(newname, '/') + 1;
4097c478bd9Sstevel@tonic-gate 	if (cp == (char *)1)
4107c478bd9Sstevel@tonic-gate 		cp = newname;
4117c478bd9Sstevel@tonic-gate 	freename(ep->e_name);
4127c478bd9Sstevel@tonic-gate 	ep->e_name = savename(cp);
4137c478bd9Sstevel@tonic-gate 	/* LINTED: savename guarantees that strlen will fit */
4147c478bd9Sstevel@tonic-gate 	ep->e_namlen = strlen(cp);
4157c478bd9Sstevel@tonic-gate 	if (strcmp(gentempname(ep), ep->e_name) == 0) {
4167c478bd9Sstevel@tonic-gate 		/* LINTED: result fits in a short */
4177c478bd9Sstevel@tonic-gate 		ep->e_flags |= TMPNAME;
4187c478bd9Sstevel@tonic-gate 	} else {
4197c478bd9Sstevel@tonic-gate 		/* LINTED: result fits in a short */
4207c478bd9Sstevel@tonic-gate 		ep->e_flags &= ~TMPNAME;
4217c478bd9Sstevel@tonic-gate 	}
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate /*
4257c478bd9Sstevel@tonic-gate  * Remove an entry in the tree structure
4267c478bd9Sstevel@tonic-gate  */
4277c478bd9Sstevel@tonic-gate static void
removeentry(struct entry * ep)428*d9529689SToomas Soome removeentry(struct entry *ep)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	struct entry *np;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	np = ep->e_parent;
4337c478bd9Sstevel@tonic-gate 	if (ep->e_flags & XATTRROOT) {
4347c478bd9Sstevel@tonic-gate 		if (np->e_xattrs == ep)
4357c478bd9Sstevel@tonic-gate 			np->e_xattrs = NIL;
4367c478bd9Sstevel@tonic-gate 		else
4377c478bd9Sstevel@tonic-gate 			badentry(ep, gettext(
438*d9529689SToomas Soome 			    "parent does not reference this xattr tree"));
4397c478bd9Sstevel@tonic-gate 	} else if (np->e_entries == ep) {
4407c478bd9Sstevel@tonic-gate 		np->e_entries = ep->e_sibling;
4417c478bd9Sstevel@tonic-gate 	} else {
4427c478bd9Sstevel@tonic-gate 		for (np = np->e_entries; np != NIL; np = np->e_sibling) {
4437c478bd9Sstevel@tonic-gate 			if (np->e_sibling == ep) {
4447c478bd9Sstevel@tonic-gate 				np->e_sibling = ep->e_sibling;
4457c478bd9Sstevel@tonic-gate 				break;
4467c478bd9Sstevel@tonic-gate 			}
4477c478bd9Sstevel@tonic-gate 		}
4487c478bd9Sstevel@tonic-gate 		if (np == NIL)
4497c478bd9Sstevel@tonic-gate 			badentry(ep, gettext(
450*d9529689SToomas Soome 			    "cannot find entry in parent list"));
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate /*
4557c478bd9Sstevel@tonic-gate  * Table of unused string entries, sorted by length.
4567c478bd9Sstevel@tonic-gate  *
4577c478bd9Sstevel@tonic-gate  * Entries are allocated in STRTBLINCR sized pieces so that names
4587c478bd9Sstevel@tonic-gate  * of similar lengths can use the same entry. The value of STRTBLINCR
4597c478bd9Sstevel@tonic-gate  * is chosen so that every entry has at least enough space to hold
4607c478bd9Sstevel@tonic-gate  * a "struct strtbl" header. Thus every entry can be linked onto an
4617c478bd9Sstevel@tonic-gate  * apprpriate free list.
4627c478bd9Sstevel@tonic-gate  *
4637c478bd9Sstevel@tonic-gate  * NB. The macro "allocsize" below assumes that "struct strhdr"
4647c478bd9Sstevel@tonic-gate  *	has a size that is a power of two. Also, an extra byte is
4657c478bd9Sstevel@tonic-gate  *	allocated for the string to provide space for the two NULL
4667c478bd9Sstevel@tonic-gate  *	string terminator required for extended attribute paths.
4677c478bd9Sstevel@tonic-gate  */
4687c478bd9Sstevel@tonic-gate struct strhdr {
4697c478bd9Sstevel@tonic-gate 	struct strhdr *next;
4707c478bd9Sstevel@tonic-gate };
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate #define	STRTBLINCR	((size_t)sizeof (struct strhdr))
4737c478bd9Sstevel@tonic-gate #define	allocsize(size)	(((size) + 2 + STRTBLINCR - 1) & ~(STRTBLINCR - 1))
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate static struct strhdr strtblhdr[allocsize(MAXCOMPLEXLEN) / STRTBLINCR];
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate /*
4787c478bd9Sstevel@tonic-gate  * Allocate space for a name. It first looks to see if it already
4797c478bd9Sstevel@tonic-gate  * has an appropriate sized entry, and if not allocates a new one.
4807c478bd9Sstevel@tonic-gate  */
4817c478bd9Sstevel@tonic-gate char *
savename(char * name)482*d9529689SToomas Soome savename(char *name)
4837c478bd9Sstevel@tonic-gate {
4847c478bd9Sstevel@tonic-gate 	struct strhdr *np;
4857c478bd9Sstevel@tonic-gate 	size_t len, as;
4867c478bd9Sstevel@tonic-gate 	char *cp;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	if (name == NULL) {
4897c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("bad name\n"));
4907c478bd9Sstevel@tonic-gate 		done(1);
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 	len = strlen(name);
4937c478bd9Sstevel@tonic-gate 	if (len > MAXPATHLEN) {
4947c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("name too long\n"));
4957c478bd9Sstevel@tonic-gate 		done(1);
4967c478bd9Sstevel@tonic-gate 	}
4977c478bd9Sstevel@tonic-gate 	as = allocsize(len);
4987c478bd9Sstevel@tonic-gate 	np = strtblhdr[as / STRTBLINCR].next;
4997c478bd9Sstevel@tonic-gate 	if (np != NULL) {
5007c478bd9Sstevel@tonic-gate 		strtblhdr[as / STRTBLINCR].next = np->next;
5017c478bd9Sstevel@tonic-gate 		cp = (char *)np;
5027c478bd9Sstevel@tonic-gate 	} else {
5037c478bd9Sstevel@tonic-gate 		/* Note that allocsize() adds 2 for the trailing \0s */
5047c478bd9Sstevel@tonic-gate 		cp = malloc(as);
5057c478bd9Sstevel@tonic-gate 		if (cp == NULL) {
5067c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
5077c478bd9Sstevel@tonic-gate 			    gettext("no space for string table\n"));
5087c478bd9Sstevel@tonic-gate 			done(1);
5097c478bd9Sstevel@tonic-gate 		}
5107c478bd9Sstevel@tonic-gate 	}
5117c478bd9Sstevel@tonic-gate 	(void) strcpy(cp, name);
5127c478bd9Sstevel@tonic-gate 	/* add an extra null for complex (attribute) name support */
5137c478bd9Sstevel@tonic-gate 	cp[len+1] = '\0';
5147c478bd9Sstevel@tonic-gate 	return (cp);
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate /*
5187c478bd9Sstevel@tonic-gate  * Free space for a name. The resulting entry is linked onto the
5197c478bd9Sstevel@tonic-gate  * appropriate free list.
5207c478bd9Sstevel@tonic-gate  */
5217c478bd9Sstevel@tonic-gate void
freename(char * name)522*d9529689SToomas Soome freename(char *name)
5237c478bd9Sstevel@tonic-gate {
5247c478bd9Sstevel@tonic-gate 	struct strhdr *tp, *np;
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	/* NULL case should never happen, but might as well be careful */
5277c478bd9Sstevel@tonic-gate 	if (name != NULL) {
5287c478bd9Sstevel@tonic-gate 		tp = &strtblhdr[allocsize(strlen(name)) / STRTBLINCR];
5297c478bd9Sstevel@tonic-gate 		/*LINTED [name points to at least sizeof (struct strhdr)]*/
5307c478bd9Sstevel@tonic-gate 		np = (struct strhdr *)name;
5317c478bd9Sstevel@tonic-gate 		np->next = tp->next;
5327c478bd9Sstevel@tonic-gate 		tp->next = np;
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate /*
5377c478bd9Sstevel@tonic-gate  * Useful quantities placed at the end of a dumped symbol table.
5387c478bd9Sstevel@tonic-gate  */
5397c478bd9Sstevel@tonic-gate struct symtableheader {
5407c478bd9Sstevel@tonic-gate 	int	volno;
5417c478bd9Sstevel@tonic-gate 	uint_t	stringsize;
5427c478bd9Sstevel@tonic-gate 	uint_t	entrytblsize;
5437c478bd9Sstevel@tonic-gate 	time_t	dumptime;
5447c478bd9Sstevel@tonic-gate 	time_t	dumpdate;
5457c478bd9Sstevel@tonic-gate 	ino_t	maxino;
5467c478bd9Sstevel@tonic-gate 	uint_t	ntrec;
5477c478bd9Sstevel@tonic-gate };
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate /*
5507c478bd9Sstevel@tonic-gate  * dump a snapshot of the symbol table
5517c478bd9Sstevel@tonic-gate  */
5527c478bd9Sstevel@tonic-gate void
dumpsymtable(char * filename,int checkpt)553*d9529689SToomas Soome dumpsymtable(char *filename, int checkpt)
5547c478bd9Sstevel@tonic-gate {
5557c478bd9Sstevel@tonic-gate 	struct entry *ep, *tep;
5567c478bd9Sstevel@tonic-gate 	ino_t i;
5577c478bd9Sstevel@tonic-gate 	struct entry temp, *tentry;
5587c478bd9Sstevel@tonic-gate 	int mynum = 1;
5597c478bd9Sstevel@tonic-gate 	uint_t stroff;
5607c478bd9Sstevel@tonic-gate 	FILE *fp;
5617c478bd9Sstevel@tonic-gate 	struct symtableheader hdr;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	vprintf(stdout, gettext("Check pointing the restore\n"));
5647c478bd9Sstevel@tonic-gate 	if ((fp = safe_fopen(filename, "w", 0600)) == (FILE *)NULL) {
5657c478bd9Sstevel@tonic-gate 		perror("fopen");
5667c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
5677c478bd9Sstevel@tonic-gate 		    gettext("cannot create save file %s for symbol table\n"),
5687c478bd9Sstevel@tonic-gate 		    filename);
5697c478bd9Sstevel@tonic-gate 		done(1);
5707c478bd9Sstevel@tonic-gate 	}
5717c478bd9Sstevel@tonic-gate 	clearerr(fp);
5727c478bd9Sstevel@tonic-gate 	/*
5737c478bd9Sstevel@tonic-gate 	 * Assign an index to each entry
5747c478bd9Sstevel@tonic-gate 	 * Write out the string entries
5757c478bd9Sstevel@tonic-gate 	 */
5767c478bd9Sstevel@tonic-gate 	for (i = ROOTINO; i < maxino; i++) {
5777c478bd9Sstevel@tonic-gate 		for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
5787c478bd9Sstevel@tonic-gate 			ep->e_index = mynum++;
5797c478bd9Sstevel@tonic-gate 			(void) fwrite(ep->e_name, sizeof (ep->e_name[0]),
5807c478bd9Sstevel@tonic-gate 			    (size_t)allocsize(ep->e_namlen), fp);
5817c478bd9Sstevel@tonic-gate 		}
5827c478bd9Sstevel@tonic-gate 	}
5837c478bd9Sstevel@tonic-gate 	/*
5847c478bd9Sstevel@tonic-gate 	 * Convert e_name pointers to offsets, other pointers
5857c478bd9Sstevel@tonic-gate 	 * to indices, and output
5867c478bd9Sstevel@tonic-gate 	 */
5877c478bd9Sstevel@tonic-gate 	tep = &temp;
5887c478bd9Sstevel@tonic-gate 	stroff = 0;
5897c478bd9Sstevel@tonic-gate 	for (i = ROOTINO; !ferror(fp) && i < maxino; i++) {
5907c478bd9Sstevel@tonic-gate 		for (ep = lookupino(i);
5917c478bd9Sstevel@tonic-gate 		    !ferror(fp) && ep != NIL;
5927c478bd9Sstevel@tonic-gate 		    ep = ep->e_links) {
5937c478bd9Sstevel@tonic-gate 			bcopy((char *)ep, (char *)tep, sizeof (*tep));
5947c478bd9Sstevel@tonic-gate 			/* LINTED: type pun ok */
5957c478bd9Sstevel@tonic-gate 			tep->e_name = (char *)stroff;
5967c478bd9Sstevel@tonic-gate 			stroff += allocsize(ep->e_namlen);
5977c478bd9Sstevel@tonic-gate 			tep->e_parent = (struct entry *)ep->e_parent->e_index;
5987c478bd9Sstevel@tonic-gate 			if (ep->e_links != NIL)
5997c478bd9Sstevel@tonic-gate 				tep->e_links =
600*d9529689SToomas Soome 				    (struct entry *)ep->e_links->e_index;
6017c478bd9Sstevel@tonic-gate 			if (ep->e_sibling != NIL)
6027c478bd9Sstevel@tonic-gate 				tep->e_sibling =
603*d9529689SToomas Soome 				    (struct entry *)ep->e_sibling->e_index;
6047c478bd9Sstevel@tonic-gate 			if (ep->e_entries != NIL)
6057c478bd9Sstevel@tonic-gate 				tep->e_entries =
606*d9529689SToomas Soome 				    (struct entry *)ep->e_entries->e_index;
6077c478bd9Sstevel@tonic-gate 			if (ep->e_xattrs != NIL)
6087c478bd9Sstevel@tonic-gate 				tep->e_xattrs =
609*d9529689SToomas Soome 				    (struct entry *)ep->e_xattrs->e_index;
6107c478bd9Sstevel@tonic-gate 			if (ep->e_next != NIL)
6117c478bd9Sstevel@tonic-gate 				tep->e_next =
612*d9529689SToomas Soome 				    (struct entry *)ep->e_next->e_index;
6137c478bd9Sstevel@tonic-gate 			(void) fwrite((char *)tep, sizeof (*tep), 1, fp);
6147c478bd9Sstevel@tonic-gate 		}
6157c478bd9Sstevel@tonic-gate 	}
6167c478bd9Sstevel@tonic-gate 	/*
6177c478bd9Sstevel@tonic-gate 	 * Convert entry pointers to indices, and output
6187c478bd9Sstevel@tonic-gate 	 */
6197c478bd9Sstevel@tonic-gate 	for (i = 0; !ferror(fp) && i < (ino_t)entrytblsize; i++) {
6207c478bd9Sstevel@tonic-gate 		if (entry[i] == NIL)
6217c478bd9Sstevel@tonic-gate 			tentry = NIL;
6227c478bd9Sstevel@tonic-gate 		else
6237c478bd9Sstevel@tonic-gate 			tentry = (struct entry *)entry[i]->e_index;
6247c478bd9Sstevel@tonic-gate 		(void) fwrite((char *)&tentry, sizeof (tentry), 1, fp);
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	if (!ferror(fp)) {
6287c478bd9Sstevel@tonic-gate 		/* Ought to have a checksum or magic number */
6297c478bd9Sstevel@tonic-gate 		hdr.volno = checkpt;
6307c478bd9Sstevel@tonic-gate 		hdr.maxino = maxino;
6317c478bd9Sstevel@tonic-gate 		hdr.entrytblsize = entrytblsize;
6327c478bd9Sstevel@tonic-gate 		hdr.stringsize = stroff;
6337c478bd9Sstevel@tonic-gate 		hdr.dumptime = dumptime;
6347c478bd9Sstevel@tonic-gate 		hdr.dumpdate = dumpdate;
6357c478bd9Sstevel@tonic-gate 		hdr.ntrec = ntrec;
6367c478bd9Sstevel@tonic-gate 		(void) fwrite((char *)&hdr, sizeof (hdr), 1, fp);
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	if (ferror(fp)) {
6407c478bd9Sstevel@tonic-gate 		perror("fwrite");
6417c478bd9Sstevel@tonic-gate 		panic(gettext("output error to file %s writing symbol table\n"),
6427c478bd9Sstevel@tonic-gate 		    filename);
6437c478bd9Sstevel@tonic-gate 	}
6447c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
6457c478bd9Sstevel@tonic-gate }
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate /*
6487c478bd9Sstevel@tonic-gate  * Initialize a symbol table from a file
6497c478bd9Sstevel@tonic-gate  */
6507c478bd9Sstevel@tonic-gate void
initsymtable(char * filename)651*d9529689SToomas Soome initsymtable(char *filename)
6527c478bd9Sstevel@tonic-gate {
6537c478bd9Sstevel@tonic-gate 	char *base;
6547c478bd9Sstevel@tonic-gate 	off64_t tblsize;
6557c478bd9Sstevel@tonic-gate 	struct entry *ep;
6567c478bd9Sstevel@tonic-gate 	struct entry *baseep, *lep;
6577c478bd9Sstevel@tonic-gate 	struct symtableheader hdr;
6587c478bd9Sstevel@tonic-gate 	struct stat64 stbuf;
6597c478bd9Sstevel@tonic-gate 	uint_t i;
6607c478bd9Sstevel@tonic-gate 	int fd;
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	vprintf(stdout, gettext("Initialize symbol table.\n"));
6637c478bd9Sstevel@tonic-gate 	if (filename == NULL) {
6647c478bd9Sstevel@tonic-gate 		if ((maxino / HASHFACTOR) > UINT_MAX) {
6657c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
6667c478bd9Sstevel@tonic-gate 			    gettext("file system too large\n"));
6677c478bd9Sstevel@tonic-gate 			done(1);
6687c478bd9Sstevel@tonic-gate 		}
6697c478bd9Sstevel@tonic-gate 		/* LINTED: result fits in entrytblsize */
6707c478bd9Sstevel@tonic-gate 		entrytblsize = maxino / HASHFACTOR;
671*d9529689SToomas Soome 		entry = calloc((size_t)entrytblsize, sizeof (*entry));
672*d9529689SToomas Soome 		if (entry == NULL) {
6737c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
6747c478bd9Sstevel@tonic-gate 			    gettext("no memory for entry table\n"));
6757c478bd9Sstevel@tonic-gate 			done(1);
6767c478bd9Sstevel@tonic-gate 		}
677*d9529689SToomas Soome 		ep = calloc(1, sizeof (*ep));
678*d9529689SToomas Soome 		if (ep == NULL) {
679*d9529689SToomas Soome 			(void) fprintf(stderr,
680*d9529689SToomas Soome 			    gettext("no memory for entry\n"));
681*d9529689SToomas Soome 			done(1);
682*d9529689SToomas Soome 		}
683*d9529689SToomas Soome 		ep->e_type = NODE;
684*d9529689SToomas Soome 		ep->e_name = savename(".");
685*d9529689SToomas Soome 		ep->e_namlen = 1;
686*d9529689SToomas Soome 		ep->e_parent = ep;
687*d9529689SToomas Soome 		addino(ROOTINO, ep);
6887c478bd9Sstevel@tonic-gate 		/* LINTED: result fits in a short */
6897c478bd9Sstevel@tonic-gate 		ep->e_flags |= NEW;
6907c478bd9Sstevel@tonic-gate 		return;
6917c478bd9Sstevel@tonic-gate 	}
6927c478bd9Sstevel@tonic-gate 	if ((fd = open(filename, O_RDONLY|O_LARGEFILE)) < 0) {
6937c478bd9Sstevel@tonic-gate 		perror("open");
6947c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
6957c478bd9Sstevel@tonic-gate 		    gettext("cannot open symbol table file %s\n"), filename);
6967c478bd9Sstevel@tonic-gate 		done(1);
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 	if (fstat64(fd, &stbuf) < 0) {
6997c478bd9Sstevel@tonic-gate 		perror("stat");
7007c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
7017c478bd9Sstevel@tonic-gate 		    gettext("cannot stat symbol table file %s\n"), filename);
7027c478bd9Sstevel@tonic-gate 		(void) close(fd);
7037c478bd9Sstevel@tonic-gate 		done(1);
7047c478bd9Sstevel@tonic-gate 	}
7057c478bd9Sstevel@tonic-gate 	/*
7067c478bd9Sstevel@tonic-gate 	 * The symbol table file is too small so say we can't read it.
7077c478bd9Sstevel@tonic-gate 	 */
7087c478bd9Sstevel@tonic-gate 	if (stbuf.st_size < sizeof (hdr)) {
7097c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
7107c478bd9Sstevel@tonic-gate 		    gettext("cannot read symbol table file %s\n"), filename);
7117c478bd9Sstevel@tonic-gate 		(void) close(fd);
7127c478bd9Sstevel@tonic-gate 		done(1);
7137c478bd9Sstevel@tonic-gate 	}
7147c478bd9Sstevel@tonic-gate 	tblsize = stbuf.st_size - sizeof (hdr);
7157c478bd9Sstevel@tonic-gate 	if (tblsize > ULONG_MAX) {
7167c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
7177c478bd9Sstevel@tonic-gate 		    gettext("symbol table file too large\n"));
7187c478bd9Sstevel@tonic-gate 		(void) close(fd);
7197c478bd9Sstevel@tonic-gate 		done(1);
7207c478bd9Sstevel@tonic-gate 	}
7217c478bd9Sstevel@tonic-gate 	/* LINTED tblsize fits in a size_t */
7227c478bd9Sstevel@tonic-gate 	base = calloc((size_t)sizeof (char), (size_t)tblsize);
7237c478bd9Sstevel@tonic-gate 	if (base == NULL) {
7247c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
7257c478bd9Sstevel@tonic-gate 		    gettext("cannot allocate space for symbol table\n"));
7267c478bd9Sstevel@tonic-gate 		(void) close(fd);
7277c478bd9Sstevel@tonic-gate 		done(1);
7287c478bd9Sstevel@tonic-gate 	}
7297c478bd9Sstevel@tonic-gate 	/* LINTED tblsize fits in a size_t */
7307c478bd9Sstevel@tonic-gate 	if (read(fd, base, (size_t)tblsize) < 0 ||
7317c478bd9Sstevel@tonic-gate 	    read(fd, (char *)&hdr, sizeof (hdr)) < 0) {
7327c478bd9Sstevel@tonic-gate 		perror("read");
7337c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
7347c478bd9Sstevel@tonic-gate 		    gettext("cannot read symbol table file %s\n"), filename);
7357c478bd9Sstevel@tonic-gate 		(void) close(fd);
7367c478bd9Sstevel@tonic-gate 		done(1);
7377c478bd9Sstevel@tonic-gate 	}
7387c478bd9Sstevel@tonic-gate 	(void) close(fd);
7397c478bd9Sstevel@tonic-gate 	switch (command) {
7407c478bd9Sstevel@tonic-gate 	case 'r':
7417c478bd9Sstevel@tonic-gate 	case 'M':
7427c478bd9Sstevel@tonic-gate 		/*
7437c478bd9Sstevel@tonic-gate 		 * For normal continuation, insure that we are using
7447c478bd9Sstevel@tonic-gate 		 * the next incremental tape
7457c478bd9Sstevel@tonic-gate 		 */
7467c478bd9Sstevel@tonic-gate 		if (hdr.dumpdate != dumptime) {
7477c478bd9Sstevel@tonic-gate 			if (hdr.dumpdate < dumptime)
7487c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
749*d9529689SToomas Soome 				    "Incremental volume too low\n"));
7507c478bd9Sstevel@tonic-gate 			else
7517c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
752*d9529689SToomas Soome 				    "Incremental volume too high\n"));
7537c478bd9Sstevel@tonic-gate 			done(1);
7547c478bd9Sstevel@tonic-gate 		}
7557c478bd9Sstevel@tonic-gate 		break;
7567c478bd9Sstevel@tonic-gate 	case 'R':
7577c478bd9Sstevel@tonic-gate 		/*
7587c478bd9Sstevel@tonic-gate 		 * For restart, insure that we are using the same tape
7597c478bd9Sstevel@tonic-gate 		 */
7607c478bd9Sstevel@tonic-gate 		curfile.action = SKIP;
7617c478bd9Sstevel@tonic-gate 		dumptime = hdr.dumptime;
7627c478bd9Sstevel@tonic-gate 		dumpdate = hdr.dumpdate;
7637c478bd9Sstevel@tonic-gate 		if (!bflag)
7647c478bd9Sstevel@tonic-gate 			newtapebuf(hdr.ntrec);
7657c478bd9Sstevel@tonic-gate 		getvol(hdr.volno);
7667c478bd9Sstevel@tonic-gate 		break;
7677c478bd9Sstevel@tonic-gate 	default:
7687c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
7697c478bd9Sstevel@tonic-gate 		    gettext("initsymtable called from command %c\n"),
7707c478bd9Sstevel@tonic-gate 		    (uchar_t)command);
7717c478bd9Sstevel@tonic-gate 		done(1);
7727c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
7737c478bd9Sstevel@tonic-gate 	}
7747c478bd9Sstevel@tonic-gate 	maxino = hdr.maxino;
7757c478bd9Sstevel@tonic-gate 	entrytblsize = hdr.entrytblsize;
7767c478bd9Sstevel@tonic-gate 	/*LINTED [pointer cast alignment]*/
7777c478bd9Sstevel@tonic-gate 	entry = (struct entry **)
7787c478bd9Sstevel@tonic-gate 	    (base + tblsize - (entrytblsize * sizeof (*entry)));
7797c478bd9Sstevel@tonic-gate 	if (((ulong_t)entry % 4) != 0) {
7807c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
7817c478bd9Sstevel@tonic-gate 		    gettext("Symbol table file corrupted\n"));
7827c478bd9Sstevel@tonic-gate 		done(1);
7837c478bd9Sstevel@tonic-gate 	}
7847c478bd9Sstevel@tonic-gate 	/*LINTED [rvalue % 4 == 0] */
7857c478bd9Sstevel@tonic-gate 	baseep = (struct entry *)
7867c478bd9Sstevel@tonic-gate 	    (base + hdr.stringsize - sizeof (*baseep));
7877c478bd9Sstevel@tonic-gate 	if (((ulong_t)baseep % 4) != 0) {
7887c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
7897c478bd9Sstevel@tonic-gate 		    gettext("Symbol table file corrupted\n"));
7907c478bd9Sstevel@tonic-gate 		done(1);
7917c478bd9Sstevel@tonic-gate 	}
7927c478bd9Sstevel@tonic-gate 	lep = (struct entry *)entry;
7937c478bd9Sstevel@tonic-gate 	for (i = 0; i < entrytblsize; i++) {
7947c478bd9Sstevel@tonic-gate 		if (entry[i] == NIL)
7957c478bd9Sstevel@tonic-gate 			continue;
7967c478bd9Sstevel@tonic-gate 		entry[i] = &baseep[(long)entry[i]];
7977c478bd9Sstevel@tonic-gate 	}
7987c478bd9Sstevel@tonic-gate 	for (ep = &baseep[1]; ep < lep; ep++) {
7997c478bd9Sstevel@tonic-gate 		ep->e_name = base + (long)ep->e_name;
8007c478bd9Sstevel@tonic-gate 		ep->e_parent = &baseep[(long)ep->e_parent];
8017c478bd9Sstevel@tonic-gate 		if (ep->e_sibling != NIL)
8027c478bd9Sstevel@tonic-gate 			ep->e_sibling = &baseep[(long)ep->e_sibling];
8037c478bd9Sstevel@tonic-gate 		if (ep->e_links != NIL)
8047c478bd9Sstevel@tonic-gate 			ep->e_links = &baseep[(long)ep->e_links];
8057c478bd9Sstevel@tonic-gate 		if (ep->e_entries != NIL)
8067c478bd9Sstevel@tonic-gate 			ep->e_entries = &baseep[(long)ep->e_entries];
8077c478bd9Sstevel@tonic-gate 		if (ep->e_xattrs != NIL)
8087c478bd9Sstevel@tonic-gate 			ep->e_xattrs = &baseep[(long)ep->e_xattrs];
8097c478bd9Sstevel@tonic-gate 		if (ep->e_next != NIL)
8107c478bd9Sstevel@tonic-gate 			ep->e_next = &baseep[(long)ep->e_next];
8117c478bd9Sstevel@tonic-gate 	}
8127c478bd9Sstevel@tonic-gate }
813