xref: /titanic_51/usr/src/cmd/backup/restore/symtab.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
3*7c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
4*7c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
5*7c478bd9Sstevel@tonic-gate  */
6*7c478bd9Sstevel@tonic-gate 
7*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
8*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
9*7c478bd9Sstevel@tonic-gate 
10*7c478bd9Sstevel@tonic-gate /*
11*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1996,1998,2001 by Sun Microsystems, Inc.
12*7c478bd9Sstevel@tonic-gate  * All rights reserved.
13*7c478bd9Sstevel@tonic-gate  */
14*7c478bd9Sstevel@tonic-gate 
15*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
16*7c478bd9Sstevel@tonic-gate 
17*7c478bd9Sstevel@tonic-gate /*
18*7c478bd9Sstevel@tonic-gate  * These routines maintain the symbol table which tracks the state
19*7c478bd9Sstevel@tonic-gate  * of the file system being restored. They provide lookup by either
20*7c478bd9Sstevel@tonic-gate  * name or inode number. They also provide for creation, deletion,
21*7c478bd9Sstevel@tonic-gate  * and renaming of entries. Because of the dynamic nature of pathnames,
22*7c478bd9Sstevel@tonic-gate  * names should not be saved, but always constructed just before they
23*7c478bd9Sstevel@tonic-gate  * are needed, by calling "myname".
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #include "restore.h"
27*7c478bd9Sstevel@tonic-gate #include <limits.h>
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * The following variables define the inode symbol table.
31*7c478bd9Sstevel@tonic-gate  * The primary hash table is dynamically allocated based on
32*7c478bd9Sstevel@tonic-gate  * the number of inodes in the file system (maxino), scaled by
33*7c478bd9Sstevel@tonic-gate  * HASHFACTOR. The variable "entry" points to the hash table;
34*7c478bd9Sstevel@tonic-gate  * the variable "entrytblsize" indicates its size (in entries).
35*7c478bd9Sstevel@tonic-gate  */
36*7c478bd9Sstevel@tonic-gate #define	HASHFACTOR 5
37*7c478bd9Sstevel@tonic-gate static struct entry **entry;
38*7c478bd9Sstevel@tonic-gate static uint_t entrytblsize;
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
41*7c478bd9Sstevel@tonic-gate static void addino(ino_t, struct entry *);
42*7c478bd9Sstevel@tonic-gate static struct entry *lookupparent(char *);
43*7c478bd9Sstevel@tonic-gate static void removeentry(struct entry *);
44*7c478bd9Sstevel@tonic-gate #else
45*7c478bd9Sstevel@tonic-gate static void addino();
46*7c478bd9Sstevel@tonic-gate static struct entry *lookupparent();
47*7c478bd9Sstevel@tonic-gate static void removeentry();
48*7c478bd9Sstevel@tonic-gate #endif
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate /*
51*7c478bd9Sstevel@tonic-gate  * Look up an entry by inode number
52*7c478bd9Sstevel@tonic-gate  */
53*7c478bd9Sstevel@tonic-gate struct entry *
54*7c478bd9Sstevel@tonic-gate lookupino(inum)
55*7c478bd9Sstevel@tonic-gate 	ino_t inum;
56*7c478bd9Sstevel@tonic-gate {
57*7c478bd9Sstevel@tonic-gate 	struct entry *ep;
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate 	if (inum < ROOTINO || inum >= maxino)
60*7c478bd9Sstevel@tonic-gate 		return (NIL);
61*7c478bd9Sstevel@tonic-gate 	for (ep = entry[inum % entrytblsize]; ep != NIL; ep = ep->e_next)
62*7c478bd9Sstevel@tonic-gate 		if (ep->e_ino == inum)
63*7c478bd9Sstevel@tonic-gate 			return (ep);
64*7c478bd9Sstevel@tonic-gate 	return (NIL);
65*7c478bd9Sstevel@tonic-gate }
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate /*
68*7c478bd9Sstevel@tonic-gate  * We now ignore inodes that are out of range.  This
69*7c478bd9Sstevel@tonic-gate  * allows us to attempt to proceed in the face of
70*7c478bd9Sstevel@tonic-gate  * a corrupted archive, albeit with future complaints
71*7c478bd9Sstevel@tonic-gate  * about failed inode lookups.  We only complain once
72*7c478bd9Sstevel@tonic-gate  * about range problems, to avoid irritating the user
73*7c478bd9Sstevel@tonic-gate  * without providing any useful information.  Failed
74*7c478bd9Sstevel@tonic-gate  * lookups have the bogus name, which is useful, so
75*7c478bd9Sstevel@tonic-gate  * they always happen.
76*7c478bd9Sstevel@tonic-gate  */
77*7c478bd9Sstevel@tonic-gate static int complained_about_range = 0;
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate /*
80*7c478bd9Sstevel@tonic-gate  * Add an entry into the entry table
81*7c478bd9Sstevel@tonic-gate  */
82*7c478bd9Sstevel@tonic-gate static void
83*7c478bd9Sstevel@tonic-gate addino(inum, np)
84*7c478bd9Sstevel@tonic-gate 	ino_t inum;
85*7c478bd9Sstevel@tonic-gate 	struct entry *np;
86*7c478bd9Sstevel@tonic-gate {
87*7c478bd9Sstevel@tonic-gate 	struct entry **epp;
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 	if (inum < ROOTINO || inum >= maxino) {
90*7c478bd9Sstevel@tonic-gate 		if (!complained_about_range) {
91*7c478bd9Sstevel@tonic-gate 			panic(gettext("%s: out of range %d\n"),
92*7c478bd9Sstevel@tonic-gate 			    "addino", inum);
93*7c478bd9Sstevel@tonic-gate 			complained_about_range = 1;
94*7c478bd9Sstevel@tonic-gate 		}
95*7c478bd9Sstevel@tonic-gate 		return;
96*7c478bd9Sstevel@tonic-gate 	}
97*7c478bd9Sstevel@tonic-gate 	epp = &entry[inum % entrytblsize];
98*7c478bd9Sstevel@tonic-gate 	np->e_ino = inum;
99*7c478bd9Sstevel@tonic-gate 	np->e_next = *epp;
100*7c478bd9Sstevel@tonic-gate 	*epp = np;
101*7c478bd9Sstevel@tonic-gate 	if (dflag)
102*7c478bd9Sstevel@tonic-gate 		for (np = np->e_next; np != NIL; np = np->e_next)
103*7c478bd9Sstevel@tonic-gate 			if (np->e_ino == inum)
104*7c478bd9Sstevel@tonic-gate 				badentry(np, gettext("duplicate inum"));
105*7c478bd9Sstevel@tonic-gate }
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate /*
108*7c478bd9Sstevel@tonic-gate  * Delete an entry from the entry table.  We assume our caller
109*7c478bd9Sstevel@tonic-gate  * arranges for the necessary memory reclamation, if needed.
110*7c478bd9Sstevel@tonic-gate  */
111*7c478bd9Sstevel@tonic-gate void
112*7c478bd9Sstevel@tonic-gate deleteino(inum)
113*7c478bd9Sstevel@tonic-gate 	ino_t inum;
114*7c478bd9Sstevel@tonic-gate {
115*7c478bd9Sstevel@tonic-gate 	struct entry *next;
116*7c478bd9Sstevel@tonic-gate 	struct entry **prev;
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	if (inum < ROOTINO || inum >= maxino) {
119*7c478bd9Sstevel@tonic-gate 		if (!complained_about_range) {
120*7c478bd9Sstevel@tonic-gate 			panic(gettext("%s: out of range %d\n"),
121*7c478bd9Sstevel@tonic-gate 			    "deleteino", inum);
122*7c478bd9Sstevel@tonic-gate 			complained_about_range = 1;
123*7c478bd9Sstevel@tonic-gate 		}
124*7c478bd9Sstevel@tonic-gate 		return;
125*7c478bd9Sstevel@tonic-gate 	}
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	prev = &entry[inum % entrytblsize];
128*7c478bd9Sstevel@tonic-gate 	for (next = *prev; next != NIL; next = next->e_next) {
129*7c478bd9Sstevel@tonic-gate 		if (next->e_ino == inum) {
130*7c478bd9Sstevel@tonic-gate 			next->e_ino = 0;
131*7c478bd9Sstevel@tonic-gate 			*prev = next->e_next;
132*7c478bd9Sstevel@tonic-gate 			return;
133*7c478bd9Sstevel@tonic-gate 		}
134*7c478bd9Sstevel@tonic-gate 		prev = &next->e_next;
135*7c478bd9Sstevel@tonic-gate 	}
136*7c478bd9Sstevel@tonic-gate }
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate /*
139*7c478bd9Sstevel@tonic-gate  * Look up an entry by name.
140*7c478bd9Sstevel@tonic-gate  *	NOTE: this function handles "complex" pathnames (as returned
141*7c478bd9Sstevel@tonic-gate  *	by myname()) for extended file attributes.  The name string
142*7c478bd9Sstevel@tonic-gate  *	provided to this function should be terminated with *two*
143*7c478bd9Sstevel@tonic-gate  *	NULL characters.
144*7c478bd9Sstevel@tonic-gate  */
145*7c478bd9Sstevel@tonic-gate struct entry *
146*7c478bd9Sstevel@tonic-gate lookupname(name)
147*7c478bd9Sstevel@tonic-gate 	char *name;
148*7c478bd9Sstevel@tonic-gate {
149*7c478bd9Sstevel@tonic-gate 	struct entry *ep;
150*7c478bd9Sstevel@tonic-gate 	char *np, *cp;
151*7c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 	if (strlen(name) > (sizeof (buf) - 1)) {
154*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: ignoring too-long name\n"),
155*7c478bd9Sstevel@tonic-gate 		    "lookupname");
156*7c478bd9Sstevel@tonic-gate 		return (NIL);
157*7c478bd9Sstevel@tonic-gate 	}
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 	cp = name;
160*7c478bd9Sstevel@tonic-gate 	for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) {
161*7c478bd9Sstevel@tonic-gate 		np = buf;
162*7c478bd9Sstevel@tonic-gate 		while (*cp != '/' && *cp != '\0')
163*7c478bd9Sstevel@tonic-gate 			*np++ = *cp++;
164*7c478bd9Sstevel@tonic-gate 		*np = '\0';
165*7c478bd9Sstevel@tonic-gate 		for (; ep != NIL; ep = ep->e_sibling)
166*7c478bd9Sstevel@tonic-gate 			if (strcmp(ep->e_name, buf) == 0)
167*7c478bd9Sstevel@tonic-gate 				break;
168*7c478bd9Sstevel@tonic-gate 		if (*cp++ == '\0') {
169*7c478bd9Sstevel@tonic-gate 			if (*cp != '\0') {
170*7c478bd9Sstevel@tonic-gate 				ep = ep->e_xattrs;
171*7c478bd9Sstevel@tonic-gate 				/*
172*7c478bd9Sstevel@tonic-gate 				 * skip over the "./" prefix on all
173*7c478bd9Sstevel@tonic-gate 				 * extended attribute paths
174*7c478bd9Sstevel@tonic-gate 				 */
175*7c478bd9Sstevel@tonic-gate 				cp += 2;
176*7c478bd9Sstevel@tonic-gate 			}
177*7c478bd9Sstevel@tonic-gate 			if (*cp == '\0')
178*7c478bd9Sstevel@tonic-gate 				return (ep);
179*7c478bd9Sstevel@tonic-gate 		}
180*7c478bd9Sstevel@tonic-gate 		if (ep == NIL)
181*7c478bd9Sstevel@tonic-gate 			break;
182*7c478bd9Sstevel@tonic-gate 	}
183*7c478bd9Sstevel@tonic-gate 	return (NIL);
184*7c478bd9Sstevel@tonic-gate }
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate /*
187*7c478bd9Sstevel@tonic-gate  * Look up the parent of a pathname.  This routine accepts complex
188*7c478bd9Sstevel@tonic-gate  * names so the provided name argument must terminate with two NULLs.
189*7c478bd9Sstevel@tonic-gate  */
190*7c478bd9Sstevel@tonic-gate static struct entry *
191*7c478bd9Sstevel@tonic-gate lookupparent(name)
192*7c478bd9Sstevel@tonic-gate 	char *name;
193*7c478bd9Sstevel@tonic-gate {
194*7c478bd9Sstevel@tonic-gate 	struct entry *ep;
195*7c478bd9Sstevel@tonic-gate 	char *tailindex, savechar, *lastpart;
196*7c478bd9Sstevel@tonic-gate 	int xattrparent = 0;
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	/* find the last component of the complex name */
199*7c478bd9Sstevel@tonic-gate 	lastpart = name;
200*7c478bd9Sstevel@tonic-gate 	LASTPART(lastpart);
201*7c478bd9Sstevel@tonic-gate 	tailindex = strrchr(lastpart, '/');
202*7c478bd9Sstevel@tonic-gate 	if (tailindex == 0) {
203*7c478bd9Sstevel@tonic-gate 		if (lastpart == name)
204*7c478bd9Sstevel@tonic-gate 			return (NIL);
205*7c478bd9Sstevel@tonic-gate 		/*
206*7c478bd9Sstevel@tonic-gate 		 * tailindex normaly points to the '/' character
207*7c478bd9Sstevel@tonic-gate 		 * dividing the path, but in the case of an extended
208*7c478bd9Sstevel@tonic-gate 		 * attribute transition it will point to the NULL
209*7c478bd9Sstevel@tonic-gate 		 * separator in front of the attribute path.
210*7c478bd9Sstevel@tonic-gate 		 */
211*7c478bd9Sstevel@tonic-gate 		tailindex = lastpart - 1;
212*7c478bd9Sstevel@tonic-gate 		xattrparent = 1;
213*7c478bd9Sstevel@tonic-gate 	} else {
214*7c478bd9Sstevel@tonic-gate 		*tailindex = '\0';
215*7c478bd9Sstevel@tonic-gate 	}
216*7c478bd9Sstevel@tonic-gate 	savechar = *(tailindex+1);
217*7c478bd9Sstevel@tonic-gate 	*(tailindex+1) = '\0';
218*7c478bd9Sstevel@tonic-gate 	ep = lookupname(name);
219*7c478bd9Sstevel@tonic-gate 	if (ep != NIL && !xattrparent && ep->e_type != NODE)
220*7c478bd9Sstevel@tonic-gate 		panic(gettext("%s is not a directory\n"), name);
221*7c478bd9Sstevel@tonic-gate 	if (!xattrparent) *tailindex = '/';
222*7c478bd9Sstevel@tonic-gate 	*(tailindex+1) = savechar;
223*7c478bd9Sstevel@tonic-gate 	return (ep);
224*7c478bd9Sstevel@tonic-gate }
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate /*
227*7c478bd9Sstevel@tonic-gate  * Determine the current pathname of a node or leaf.
228*7c478bd9Sstevel@tonic-gate  * The returned pathname will be multiple strings with NULL separators:
229*7c478bd9Sstevel@tonic-gate  *
230*7c478bd9Sstevel@tonic-gate  *	./<path>/entry\0<path>/attrentry\0<path>/...\0\0
231*7c478bd9Sstevel@tonic-gate  *	^	        ^		  ^	    ^
232*7c478bd9Sstevel@tonic-gate  *   return pntr    entry attr	    recursive attr  terminator
233*7c478bd9Sstevel@tonic-gate  *
234*7c478bd9Sstevel@tonic-gate  * Guaranteed to return a name that fits within MAXCOMPLEXLEN and is
235*7c478bd9Sstevel@tonic-gate  * terminated with two NULLs.
236*7c478bd9Sstevel@tonic-gate  */
237*7c478bd9Sstevel@tonic-gate char *
238*7c478bd9Sstevel@tonic-gate myname(ep)
239*7c478bd9Sstevel@tonic-gate 	struct entry *ep;
240*7c478bd9Sstevel@tonic-gate {
241*7c478bd9Sstevel@tonic-gate 	char *cp;
242*7c478bd9Sstevel@tonic-gate 	struct entry *root = lookupino(ROOTINO);
243*7c478bd9Sstevel@tonic-gate 	static char namebuf[MAXCOMPLEXLEN];
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	cp = &namebuf[MAXCOMPLEXLEN - 3];
246*7c478bd9Sstevel@tonic-gate 	*(cp + 1) = '\0';
247*7c478bd9Sstevel@tonic-gate 	*(cp + 2) = '\0';
248*7c478bd9Sstevel@tonic-gate 	while (cp > &namebuf[ep->e_namlen]) {
249*7c478bd9Sstevel@tonic-gate 		cp -= ep->e_namlen;
250*7c478bd9Sstevel@tonic-gate 		bcopy(ep->e_name, cp, (size_t)ep->e_namlen);
251*7c478bd9Sstevel@tonic-gate 		if (ep == root)
252*7c478bd9Sstevel@tonic-gate 			return (cp);
253*7c478bd9Sstevel@tonic-gate 		if (ep->e_flags & XATTRROOT)
254*7c478bd9Sstevel@tonic-gate 			*(--cp) = '\0';
255*7c478bd9Sstevel@tonic-gate 		else
256*7c478bd9Sstevel@tonic-gate 			*(--cp) = '/';
257*7c478bd9Sstevel@tonic-gate 		ep = ep->e_parent;
258*7c478bd9Sstevel@tonic-gate 	}
259*7c478bd9Sstevel@tonic-gate 	panic(gettext("%s%s: pathname too long\n"), "...", cp);
260*7c478bd9Sstevel@tonic-gate 	return (cp);
261*7c478bd9Sstevel@tonic-gate }
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate /*
264*7c478bd9Sstevel@tonic-gate  * Unused symbol table entries are linked together on a freelist
265*7c478bd9Sstevel@tonic-gate  * headed by the following pointer.
266*7c478bd9Sstevel@tonic-gate  */
267*7c478bd9Sstevel@tonic-gate static struct entry *freelist = NIL;
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate /*
270*7c478bd9Sstevel@tonic-gate  * add an entry to the symbol table
271*7c478bd9Sstevel@tonic-gate  */
272*7c478bd9Sstevel@tonic-gate struct entry *
273*7c478bd9Sstevel@tonic-gate addentry(name, inum, type)
274*7c478bd9Sstevel@tonic-gate 	char *name;
275*7c478bd9Sstevel@tonic-gate 	ino_t inum;
276*7c478bd9Sstevel@tonic-gate 	int type;
277*7c478bd9Sstevel@tonic-gate {
278*7c478bd9Sstevel@tonic-gate 	struct entry *np, *ep;
279*7c478bd9Sstevel@tonic-gate 	char *cp;
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	if (freelist != NIL) {
282*7c478bd9Sstevel@tonic-gate 		np = freelist;
283*7c478bd9Sstevel@tonic-gate 		freelist = np->e_next;
284*7c478bd9Sstevel@tonic-gate 		(void) bzero((char *)np, (size_t)sizeof (*np));
285*7c478bd9Sstevel@tonic-gate 	} else {
286*7c478bd9Sstevel@tonic-gate 		np = (struct entry *)calloc(1, sizeof (*np));
287*7c478bd9Sstevel@tonic-gate 		if (np == NIL) {
288*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
289*7c478bd9Sstevel@tonic-gate 			    gettext("no memory to extend symbol table\n"));
290*7c478bd9Sstevel@tonic-gate 			done(1);
291*7c478bd9Sstevel@tonic-gate 		}
292*7c478bd9Sstevel@tonic-gate 	}
293*7c478bd9Sstevel@tonic-gate 	np->e_type = type & ~(LINK|ROOT);
294*7c478bd9Sstevel@tonic-gate 	if (inattrspace)
295*7c478bd9Sstevel@tonic-gate 		np->e_flags |= XATTR;
296*7c478bd9Sstevel@tonic-gate 	ep = lookupparent(name);
297*7c478bd9Sstevel@tonic-gate 	if (ep == NIL) {
298*7c478bd9Sstevel@tonic-gate 		if (inum != ROOTINO || lookupino(ROOTINO) != NIL) {
299*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
300*7c478bd9Sstevel@tonic-gate 			    "%s: bad name %s\n"), "addentry", name);
301*7c478bd9Sstevel@tonic-gate 			assert(0);
302*7c478bd9Sstevel@tonic-gate 			done(1);
303*7c478bd9Sstevel@tonic-gate 		}
304*7c478bd9Sstevel@tonic-gate 		np->e_name = savename(name);
305*7c478bd9Sstevel@tonic-gate 		/* LINTED: savename guarantees that strlen fits in e_namlen */
306*7c478bd9Sstevel@tonic-gate 		np->e_namlen = strlen(name);
307*7c478bd9Sstevel@tonic-gate 		np->e_parent = np;
308*7c478bd9Sstevel@tonic-gate 		addino(ROOTINO, np);
309*7c478bd9Sstevel@tonic-gate 		return (np);
310*7c478bd9Sstevel@tonic-gate 	}
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	if (np->e_flags & XATTR) {
313*7c478bd9Sstevel@tonic-gate 		/*
314*7c478bd9Sstevel@tonic-gate 		 * skip to the last part of the complex string: it
315*7c478bd9Sstevel@tonic-gate 		 * containes the extended attribute file name.
316*7c478bd9Sstevel@tonic-gate 		 */
317*7c478bd9Sstevel@tonic-gate 		LASTPART(name);
318*7c478bd9Sstevel@tonic-gate 	}
319*7c478bd9Sstevel@tonic-gate 	cp = strrchr(name, '/');
320*7c478bd9Sstevel@tonic-gate 	if (cp == NULL)
321*7c478bd9Sstevel@tonic-gate 		cp = name;
322*7c478bd9Sstevel@tonic-gate 	else
323*7c478bd9Sstevel@tonic-gate 		cp++;
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	np->e_name = savename(cp);
326*7c478bd9Sstevel@tonic-gate 	/* LINTED: savename guarantees that strlen will fit */
327*7c478bd9Sstevel@tonic-gate 	np->e_namlen = strlen(np->e_name);
328*7c478bd9Sstevel@tonic-gate 	np->e_parent = ep;
329*7c478bd9Sstevel@tonic-gate 	/*
330*7c478bd9Sstevel@tonic-gate 	 * Extended attribute root directories must be linked to their
331*7c478bd9Sstevel@tonic-gate 	 * "parents" via the e_xattrs field.  Other entries are simply
332*7c478bd9Sstevel@tonic-gate 	 * added to their parent directories e_entries list.
333*7c478bd9Sstevel@tonic-gate 	 */
334*7c478bd9Sstevel@tonic-gate 	if ((type & ROOT) && (np->e_flags & XATTR)) {
335*7c478bd9Sstevel@tonic-gate 		/* link this extended attribute root dir to its "parent" */
336*7c478bd9Sstevel@tonic-gate 		ep->e_xattrs = np;
337*7c478bd9Sstevel@tonic-gate 	} else {
338*7c478bd9Sstevel@tonic-gate 		/* add this entry to the entry list of the parent dir */
339*7c478bd9Sstevel@tonic-gate 		np->e_sibling = ep->e_entries;
340*7c478bd9Sstevel@tonic-gate 		ep->e_entries = np;
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate 	if (type & LINK) {
343*7c478bd9Sstevel@tonic-gate 		ep = lookupino(inum);
344*7c478bd9Sstevel@tonic-gate 		if (ep == NIL) {
345*7c478bd9Sstevel@tonic-gate 			/* XXX just bail on this one and continue? */
346*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
347*7c478bd9Sstevel@tonic-gate 			    gettext("link to non-existent name\n"));
348*7c478bd9Sstevel@tonic-gate 			done(1);
349*7c478bd9Sstevel@tonic-gate 		}
350*7c478bd9Sstevel@tonic-gate 		np->e_ino = inum;
351*7c478bd9Sstevel@tonic-gate 		np->e_links = ep->e_links;
352*7c478bd9Sstevel@tonic-gate 		ep->e_links = np;
353*7c478bd9Sstevel@tonic-gate 	} else if (inum != 0) {
354*7c478bd9Sstevel@tonic-gate 		ep = lookupino(inum);
355*7c478bd9Sstevel@tonic-gate 		if (ep != NIL)
356*7c478bd9Sstevel@tonic-gate 			panic(gettext("duplicate entry\n"));
357*7c478bd9Sstevel@tonic-gate 		else
358*7c478bd9Sstevel@tonic-gate 			addino(inum, np);
359*7c478bd9Sstevel@tonic-gate 	}
360*7c478bd9Sstevel@tonic-gate 	return (np);
361*7c478bd9Sstevel@tonic-gate }
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate /*
364*7c478bd9Sstevel@tonic-gate  * delete an entry from the symbol table
365*7c478bd9Sstevel@tonic-gate  */
366*7c478bd9Sstevel@tonic-gate void
367*7c478bd9Sstevel@tonic-gate freeentry(ep)
368*7c478bd9Sstevel@tonic-gate 	struct entry *ep;
369*7c478bd9Sstevel@tonic-gate {
370*7c478bd9Sstevel@tonic-gate 	struct entry *np;
371*7c478bd9Sstevel@tonic-gate 	ino_t inum;
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	if ((ep->e_flags & REMOVED) == 0)
374*7c478bd9Sstevel@tonic-gate 		badentry(ep, gettext("not marked REMOVED"));
375*7c478bd9Sstevel@tonic-gate 	if (ep->e_type == NODE) {
376*7c478bd9Sstevel@tonic-gate 		if (ep->e_links != NIL)
377*7c478bd9Sstevel@tonic-gate 			badentry(ep, gettext("freeing referenced directory"));
378*7c478bd9Sstevel@tonic-gate 		if (ep->e_entries != NIL)
379*7c478bd9Sstevel@tonic-gate 			badentry(ep, gettext("freeing non-empty directory"));
380*7c478bd9Sstevel@tonic-gate 	}
381*7c478bd9Sstevel@tonic-gate 	if (ep->e_ino != 0) {
382*7c478bd9Sstevel@tonic-gate 		np = lookupino(ep->e_ino);
383*7c478bd9Sstevel@tonic-gate 		if (np == NIL)
384*7c478bd9Sstevel@tonic-gate 			badentry(ep, gettext("lookupino failed"));
385*7c478bd9Sstevel@tonic-gate 		if (np == ep) {
386*7c478bd9Sstevel@tonic-gate 			inum = ep->e_ino;
387*7c478bd9Sstevel@tonic-gate 			deleteino(inum);
388*7c478bd9Sstevel@tonic-gate 			if (ep->e_links != NIL)
389*7c478bd9Sstevel@tonic-gate 				addino(inum, ep->e_links);
390*7c478bd9Sstevel@tonic-gate 		} else {
391*7c478bd9Sstevel@tonic-gate 			for (; np != NIL; np = np->e_links) {
392*7c478bd9Sstevel@tonic-gate 				if (np->e_links == ep) {
393*7c478bd9Sstevel@tonic-gate 					np->e_links = ep->e_links;
394*7c478bd9Sstevel@tonic-gate 					break;
395*7c478bd9Sstevel@tonic-gate 				}
396*7c478bd9Sstevel@tonic-gate 			}
397*7c478bd9Sstevel@tonic-gate 			if (np == NIL)
398*7c478bd9Sstevel@tonic-gate 				badentry(ep, gettext("link not found"));
399*7c478bd9Sstevel@tonic-gate 		}
400*7c478bd9Sstevel@tonic-gate 	}
401*7c478bd9Sstevel@tonic-gate 	removeentry(ep);
402*7c478bd9Sstevel@tonic-gate 	freename(ep->e_name);
403*7c478bd9Sstevel@tonic-gate 	ep->e_next = freelist;
404*7c478bd9Sstevel@tonic-gate 	freelist = ep;
405*7c478bd9Sstevel@tonic-gate }
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate /*
408*7c478bd9Sstevel@tonic-gate  * Relocate an entry in the tree structure
409*7c478bd9Sstevel@tonic-gate  */
410*7c478bd9Sstevel@tonic-gate void
411*7c478bd9Sstevel@tonic-gate moveentry(ep, newname)
412*7c478bd9Sstevel@tonic-gate 	struct entry *ep;
413*7c478bd9Sstevel@tonic-gate 	char *newname;
414*7c478bd9Sstevel@tonic-gate {
415*7c478bd9Sstevel@tonic-gate 	struct entry *np;
416*7c478bd9Sstevel@tonic-gate 	char *cp;
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	np = lookupparent(newname);
419*7c478bd9Sstevel@tonic-gate 	if (np == NIL)
420*7c478bd9Sstevel@tonic-gate 		badentry(ep, gettext("cannot move ROOT"));
421*7c478bd9Sstevel@tonic-gate 	if (np != ep->e_parent) {
422*7c478bd9Sstevel@tonic-gate 		removeentry(ep);
423*7c478bd9Sstevel@tonic-gate 		ep->e_parent = np;
424*7c478bd9Sstevel@tonic-gate 		ep->e_sibling = np->e_entries;
425*7c478bd9Sstevel@tonic-gate 		np->e_entries = ep;
426*7c478bd9Sstevel@tonic-gate 	}
427*7c478bd9Sstevel@tonic-gate 	/* find the last component of the complex name */
428*7c478bd9Sstevel@tonic-gate 	LASTPART(newname);
429*7c478bd9Sstevel@tonic-gate 	cp = strrchr(newname, '/') + 1;
430*7c478bd9Sstevel@tonic-gate 	if (cp == (char *)1)
431*7c478bd9Sstevel@tonic-gate 		cp = newname;
432*7c478bd9Sstevel@tonic-gate 	freename(ep->e_name);
433*7c478bd9Sstevel@tonic-gate 	ep->e_name = savename(cp);
434*7c478bd9Sstevel@tonic-gate 	/* LINTED: savename guarantees that strlen will fit */
435*7c478bd9Sstevel@tonic-gate 	ep->e_namlen = strlen(cp);
436*7c478bd9Sstevel@tonic-gate 	if (strcmp(gentempname(ep), ep->e_name) == 0) {
437*7c478bd9Sstevel@tonic-gate 		/* LINTED: result fits in a short */
438*7c478bd9Sstevel@tonic-gate 		ep->e_flags |= TMPNAME;
439*7c478bd9Sstevel@tonic-gate 	} else {
440*7c478bd9Sstevel@tonic-gate 		/* LINTED: result fits in a short */
441*7c478bd9Sstevel@tonic-gate 		ep->e_flags &= ~TMPNAME;
442*7c478bd9Sstevel@tonic-gate 	}
443*7c478bd9Sstevel@tonic-gate }
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate /*
446*7c478bd9Sstevel@tonic-gate  * Remove an entry in the tree structure
447*7c478bd9Sstevel@tonic-gate  */
448*7c478bd9Sstevel@tonic-gate static void
449*7c478bd9Sstevel@tonic-gate removeentry(ep)
450*7c478bd9Sstevel@tonic-gate 	struct entry *ep;
451*7c478bd9Sstevel@tonic-gate {
452*7c478bd9Sstevel@tonic-gate 	struct entry *np;
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 	np = ep->e_parent;
455*7c478bd9Sstevel@tonic-gate 	if (ep->e_flags & XATTRROOT) {
456*7c478bd9Sstevel@tonic-gate 		if (np->e_xattrs == ep)
457*7c478bd9Sstevel@tonic-gate 			np->e_xattrs = NIL;
458*7c478bd9Sstevel@tonic-gate 		else
459*7c478bd9Sstevel@tonic-gate 			badentry(ep, gettext(
460*7c478bd9Sstevel@tonic-gate 				"parent does not reference this xattr tree"));
461*7c478bd9Sstevel@tonic-gate 	} else if (np->e_entries == ep) {
462*7c478bd9Sstevel@tonic-gate 		np->e_entries = ep->e_sibling;
463*7c478bd9Sstevel@tonic-gate 	} else {
464*7c478bd9Sstevel@tonic-gate 		for (np = np->e_entries; np != NIL; np = np->e_sibling) {
465*7c478bd9Sstevel@tonic-gate 			if (np->e_sibling == ep) {
466*7c478bd9Sstevel@tonic-gate 				np->e_sibling = ep->e_sibling;
467*7c478bd9Sstevel@tonic-gate 				break;
468*7c478bd9Sstevel@tonic-gate 			}
469*7c478bd9Sstevel@tonic-gate 		}
470*7c478bd9Sstevel@tonic-gate 		if (np == NIL)
471*7c478bd9Sstevel@tonic-gate 			badentry(ep, gettext(
472*7c478bd9Sstevel@tonic-gate 				"cannot find entry in parent list"));
473*7c478bd9Sstevel@tonic-gate 	}
474*7c478bd9Sstevel@tonic-gate }
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate /*
477*7c478bd9Sstevel@tonic-gate  * Table of unused string entries, sorted by length.
478*7c478bd9Sstevel@tonic-gate  *
479*7c478bd9Sstevel@tonic-gate  * Entries are allocated in STRTBLINCR sized pieces so that names
480*7c478bd9Sstevel@tonic-gate  * of similar lengths can use the same entry. The value of STRTBLINCR
481*7c478bd9Sstevel@tonic-gate  * is chosen so that every entry has at least enough space to hold
482*7c478bd9Sstevel@tonic-gate  * a "struct strtbl" header. Thus every entry can be linked onto an
483*7c478bd9Sstevel@tonic-gate  * apprpriate free list.
484*7c478bd9Sstevel@tonic-gate  *
485*7c478bd9Sstevel@tonic-gate  * NB. The macro "allocsize" below assumes that "struct strhdr"
486*7c478bd9Sstevel@tonic-gate  *	has a size that is a power of two. Also, an extra byte is
487*7c478bd9Sstevel@tonic-gate  *	allocated for the string to provide space for the two NULL
488*7c478bd9Sstevel@tonic-gate  *	string terminator required for extended attribute paths.
489*7c478bd9Sstevel@tonic-gate  */
490*7c478bd9Sstevel@tonic-gate struct strhdr {
491*7c478bd9Sstevel@tonic-gate 	struct strhdr *next;
492*7c478bd9Sstevel@tonic-gate };
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate #define	STRTBLINCR	((size_t)sizeof (struct strhdr))
495*7c478bd9Sstevel@tonic-gate #define	allocsize(size)	(((size) + 2 + STRTBLINCR - 1) & ~(STRTBLINCR - 1))
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate static struct strhdr strtblhdr[allocsize(MAXCOMPLEXLEN) / STRTBLINCR];
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate /*
500*7c478bd9Sstevel@tonic-gate  * Allocate space for a name. It first looks to see if it already
501*7c478bd9Sstevel@tonic-gate  * has an appropriate sized entry, and if not allocates a new one.
502*7c478bd9Sstevel@tonic-gate  */
503*7c478bd9Sstevel@tonic-gate char *
504*7c478bd9Sstevel@tonic-gate savename(name)
505*7c478bd9Sstevel@tonic-gate 	char *name;
506*7c478bd9Sstevel@tonic-gate {
507*7c478bd9Sstevel@tonic-gate 	struct strhdr *np;
508*7c478bd9Sstevel@tonic-gate 	size_t len, as;
509*7c478bd9Sstevel@tonic-gate 	char *cp;
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 	if (name == NULL) {
512*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("bad name\n"));
513*7c478bd9Sstevel@tonic-gate 		done(1);
514*7c478bd9Sstevel@tonic-gate 	}
515*7c478bd9Sstevel@tonic-gate 	len = strlen(name);
516*7c478bd9Sstevel@tonic-gate 	if (len > MAXPATHLEN) {
517*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("name too long\n"));
518*7c478bd9Sstevel@tonic-gate 		done(1);
519*7c478bd9Sstevel@tonic-gate 	}
520*7c478bd9Sstevel@tonic-gate 	as = allocsize(len);
521*7c478bd9Sstevel@tonic-gate 	np = strtblhdr[as / STRTBLINCR].next;
522*7c478bd9Sstevel@tonic-gate 	if (np != NULL) {
523*7c478bd9Sstevel@tonic-gate 		strtblhdr[as / STRTBLINCR].next = np->next;
524*7c478bd9Sstevel@tonic-gate 		cp = (char *)np;
525*7c478bd9Sstevel@tonic-gate 	} else {
526*7c478bd9Sstevel@tonic-gate 		/* Note that allocsize() adds 2 for the trailing \0s */
527*7c478bd9Sstevel@tonic-gate 		cp = malloc(as);
528*7c478bd9Sstevel@tonic-gate 		if (cp == NULL) {
529*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
530*7c478bd9Sstevel@tonic-gate 			    gettext("no space for string table\n"));
531*7c478bd9Sstevel@tonic-gate 			done(1);
532*7c478bd9Sstevel@tonic-gate 		}
533*7c478bd9Sstevel@tonic-gate 	}
534*7c478bd9Sstevel@tonic-gate 	(void) strcpy(cp, name);
535*7c478bd9Sstevel@tonic-gate 	/* add an extra null for complex (attribute) name support */
536*7c478bd9Sstevel@tonic-gate 	cp[len+1] = '\0';
537*7c478bd9Sstevel@tonic-gate 	return (cp);
538*7c478bd9Sstevel@tonic-gate }
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate /*
541*7c478bd9Sstevel@tonic-gate  * Free space for a name. The resulting entry is linked onto the
542*7c478bd9Sstevel@tonic-gate  * appropriate free list.
543*7c478bd9Sstevel@tonic-gate  */
544*7c478bd9Sstevel@tonic-gate void
545*7c478bd9Sstevel@tonic-gate freename(name)
546*7c478bd9Sstevel@tonic-gate 	char *name;
547*7c478bd9Sstevel@tonic-gate {
548*7c478bd9Sstevel@tonic-gate 	struct strhdr *tp, *np;
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	/* NULL case should never happen, but might as well be careful */
551*7c478bd9Sstevel@tonic-gate 	if (name != NULL) {
552*7c478bd9Sstevel@tonic-gate 		tp = &strtblhdr[allocsize(strlen(name)) / STRTBLINCR];
553*7c478bd9Sstevel@tonic-gate 		/*LINTED [name points to at least sizeof (struct strhdr)]*/
554*7c478bd9Sstevel@tonic-gate 		np = (struct strhdr *)name;
555*7c478bd9Sstevel@tonic-gate 		np->next = tp->next;
556*7c478bd9Sstevel@tonic-gate 		tp->next = np;
557*7c478bd9Sstevel@tonic-gate 	}
558*7c478bd9Sstevel@tonic-gate }
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate /*
561*7c478bd9Sstevel@tonic-gate  * Useful quantities placed at the end of a dumped symbol table.
562*7c478bd9Sstevel@tonic-gate  */
563*7c478bd9Sstevel@tonic-gate struct symtableheader {
564*7c478bd9Sstevel@tonic-gate 	int	volno;
565*7c478bd9Sstevel@tonic-gate 	uint_t	stringsize;
566*7c478bd9Sstevel@tonic-gate 	uint_t	entrytblsize;
567*7c478bd9Sstevel@tonic-gate 	time_t	dumptime;
568*7c478bd9Sstevel@tonic-gate 	time_t	dumpdate;
569*7c478bd9Sstevel@tonic-gate 	ino_t	maxino;
570*7c478bd9Sstevel@tonic-gate 	uint_t	ntrec;
571*7c478bd9Sstevel@tonic-gate };
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate /*
574*7c478bd9Sstevel@tonic-gate  * dump a snapshot of the symbol table
575*7c478bd9Sstevel@tonic-gate  */
576*7c478bd9Sstevel@tonic-gate void
577*7c478bd9Sstevel@tonic-gate dumpsymtable(filename, checkpt)
578*7c478bd9Sstevel@tonic-gate 	char *filename;
579*7c478bd9Sstevel@tonic-gate 	int checkpt;
580*7c478bd9Sstevel@tonic-gate {
581*7c478bd9Sstevel@tonic-gate 	struct entry *ep, *tep;
582*7c478bd9Sstevel@tonic-gate 	ino_t i;
583*7c478bd9Sstevel@tonic-gate 	struct entry temp, *tentry;
584*7c478bd9Sstevel@tonic-gate 	int mynum = 1;
585*7c478bd9Sstevel@tonic-gate 	uint_t stroff;
586*7c478bd9Sstevel@tonic-gate 	FILE *fp;
587*7c478bd9Sstevel@tonic-gate 	struct symtableheader hdr;
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 	vprintf(stdout, gettext("Check pointing the restore\n"));
590*7c478bd9Sstevel@tonic-gate 	if ((fp = safe_fopen(filename, "w", 0600)) == (FILE *)NULL) {
591*7c478bd9Sstevel@tonic-gate 		perror("fopen");
592*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
593*7c478bd9Sstevel@tonic-gate 		    gettext("cannot create save file %s for symbol table\n"),
594*7c478bd9Sstevel@tonic-gate 		    filename);
595*7c478bd9Sstevel@tonic-gate 		done(1);
596*7c478bd9Sstevel@tonic-gate 	}
597*7c478bd9Sstevel@tonic-gate 	clearerr(fp);
598*7c478bd9Sstevel@tonic-gate 	/*
599*7c478bd9Sstevel@tonic-gate 	 * Assign an index to each entry
600*7c478bd9Sstevel@tonic-gate 	 * Write out the string entries
601*7c478bd9Sstevel@tonic-gate 	 */
602*7c478bd9Sstevel@tonic-gate 	for (i = ROOTINO; i < maxino; i++) {
603*7c478bd9Sstevel@tonic-gate 		for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
604*7c478bd9Sstevel@tonic-gate 			ep->e_index = mynum++;
605*7c478bd9Sstevel@tonic-gate 			(void) fwrite(ep->e_name, sizeof (ep->e_name[0]),
606*7c478bd9Sstevel@tonic-gate 			    (size_t)allocsize(ep->e_namlen), fp);
607*7c478bd9Sstevel@tonic-gate 		}
608*7c478bd9Sstevel@tonic-gate 	}
609*7c478bd9Sstevel@tonic-gate 	/*
610*7c478bd9Sstevel@tonic-gate 	 * Convert e_name pointers to offsets, other pointers
611*7c478bd9Sstevel@tonic-gate 	 * to indices, and output
612*7c478bd9Sstevel@tonic-gate 	 */
613*7c478bd9Sstevel@tonic-gate 	tep = &temp;
614*7c478bd9Sstevel@tonic-gate 	stroff = 0;
615*7c478bd9Sstevel@tonic-gate 	for (i = ROOTINO; !ferror(fp) && i < maxino; i++) {
616*7c478bd9Sstevel@tonic-gate 		for (ep = lookupino(i);
617*7c478bd9Sstevel@tonic-gate 		    !ferror(fp) && ep != NIL;
618*7c478bd9Sstevel@tonic-gate 		    ep = ep->e_links) {
619*7c478bd9Sstevel@tonic-gate 			bcopy((char *)ep, (char *)tep, sizeof (*tep));
620*7c478bd9Sstevel@tonic-gate 			/* LINTED: type pun ok */
621*7c478bd9Sstevel@tonic-gate 			tep->e_name = (char *)stroff;
622*7c478bd9Sstevel@tonic-gate 			stroff += allocsize(ep->e_namlen);
623*7c478bd9Sstevel@tonic-gate 			tep->e_parent = (struct entry *)ep->e_parent->e_index;
624*7c478bd9Sstevel@tonic-gate 			if (ep->e_links != NIL)
625*7c478bd9Sstevel@tonic-gate 				tep->e_links =
626*7c478bd9Sstevel@tonic-gate 					(struct entry *)ep->e_links->e_index;
627*7c478bd9Sstevel@tonic-gate 			if (ep->e_sibling != NIL)
628*7c478bd9Sstevel@tonic-gate 				tep->e_sibling =
629*7c478bd9Sstevel@tonic-gate 					(struct entry *)ep->e_sibling->e_index;
630*7c478bd9Sstevel@tonic-gate 			if (ep->e_entries != NIL)
631*7c478bd9Sstevel@tonic-gate 				tep->e_entries =
632*7c478bd9Sstevel@tonic-gate 					(struct entry *)ep->e_entries->e_index;
633*7c478bd9Sstevel@tonic-gate 			if (ep->e_xattrs != NIL)
634*7c478bd9Sstevel@tonic-gate 				tep->e_xattrs =
635*7c478bd9Sstevel@tonic-gate 					(struct entry *)ep->e_xattrs->e_index;
636*7c478bd9Sstevel@tonic-gate 			if (ep->e_next != NIL)
637*7c478bd9Sstevel@tonic-gate 				tep->e_next =
638*7c478bd9Sstevel@tonic-gate 					(struct entry *)ep->e_next->e_index;
639*7c478bd9Sstevel@tonic-gate 			(void) fwrite((char *)tep, sizeof (*tep), 1, fp);
640*7c478bd9Sstevel@tonic-gate 		}
641*7c478bd9Sstevel@tonic-gate 	}
642*7c478bd9Sstevel@tonic-gate 	/*
643*7c478bd9Sstevel@tonic-gate 	 * Convert entry pointers to indices, and output
644*7c478bd9Sstevel@tonic-gate 	 */
645*7c478bd9Sstevel@tonic-gate 	for (i = 0; !ferror(fp) && i < (ino_t)entrytblsize; i++) {
646*7c478bd9Sstevel@tonic-gate 		if (entry[i] == NIL)
647*7c478bd9Sstevel@tonic-gate 			tentry = NIL;
648*7c478bd9Sstevel@tonic-gate 		else
649*7c478bd9Sstevel@tonic-gate 			tentry = (struct entry *)entry[i]->e_index;
650*7c478bd9Sstevel@tonic-gate 		(void) fwrite((char *)&tentry, sizeof (tentry), 1, fp);
651*7c478bd9Sstevel@tonic-gate 	}
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 	if (!ferror(fp)) {
654*7c478bd9Sstevel@tonic-gate 		/* Ought to have a checksum or magic number */
655*7c478bd9Sstevel@tonic-gate 		hdr.volno = checkpt;
656*7c478bd9Sstevel@tonic-gate 		hdr.maxino = maxino;
657*7c478bd9Sstevel@tonic-gate 		hdr.entrytblsize = entrytblsize;
658*7c478bd9Sstevel@tonic-gate 		hdr.stringsize = stroff;
659*7c478bd9Sstevel@tonic-gate 		hdr.dumptime = dumptime;
660*7c478bd9Sstevel@tonic-gate 		hdr.dumpdate = dumpdate;
661*7c478bd9Sstevel@tonic-gate 		hdr.ntrec = ntrec;
662*7c478bd9Sstevel@tonic-gate 		(void) fwrite((char *)&hdr, sizeof (hdr), 1, fp);
663*7c478bd9Sstevel@tonic-gate 	}
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	if (ferror(fp)) {
666*7c478bd9Sstevel@tonic-gate 		perror("fwrite");
667*7c478bd9Sstevel@tonic-gate 		panic(gettext("output error to file %s writing symbol table\n"),
668*7c478bd9Sstevel@tonic-gate 		    filename);
669*7c478bd9Sstevel@tonic-gate 	}
670*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
671*7c478bd9Sstevel@tonic-gate }
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate /*
674*7c478bd9Sstevel@tonic-gate  * Initialize a symbol table from a file
675*7c478bd9Sstevel@tonic-gate  */
676*7c478bd9Sstevel@tonic-gate void
677*7c478bd9Sstevel@tonic-gate initsymtable(filename)
678*7c478bd9Sstevel@tonic-gate 	char *filename;
679*7c478bd9Sstevel@tonic-gate {
680*7c478bd9Sstevel@tonic-gate 	char *base;
681*7c478bd9Sstevel@tonic-gate 	off64_t tblsize;
682*7c478bd9Sstevel@tonic-gate 	struct entry *ep;
683*7c478bd9Sstevel@tonic-gate 	struct entry *baseep, *lep;
684*7c478bd9Sstevel@tonic-gate 	struct symtableheader hdr;
685*7c478bd9Sstevel@tonic-gate 	struct stat64 stbuf;
686*7c478bd9Sstevel@tonic-gate 	uint_t i;
687*7c478bd9Sstevel@tonic-gate 	int fd;
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate 	vprintf(stdout, gettext("Initialize symbol table.\n"));
690*7c478bd9Sstevel@tonic-gate 	if (filename == NULL) {
691*7c478bd9Sstevel@tonic-gate 		if ((maxino / HASHFACTOR) > UINT_MAX) {
692*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
693*7c478bd9Sstevel@tonic-gate 			    gettext("file system too large\n"));
694*7c478bd9Sstevel@tonic-gate 			done(1);
695*7c478bd9Sstevel@tonic-gate 		}
696*7c478bd9Sstevel@tonic-gate 		/* LINTED: result fits in entrytblsize */
697*7c478bd9Sstevel@tonic-gate 		entrytblsize = maxino / HASHFACTOR;
698*7c478bd9Sstevel@tonic-gate 		entry = (struct entry **)
699*7c478bd9Sstevel@tonic-gate 			/* LINTED entrytblsize fits in a size_t */
700*7c478bd9Sstevel@tonic-gate 			calloc((size_t)entrytblsize, sizeof (*entry));
701*7c478bd9Sstevel@tonic-gate 		if (entry == (struct entry **)NULL) {
702*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
703*7c478bd9Sstevel@tonic-gate 			    gettext("no memory for entry table\n"));
704*7c478bd9Sstevel@tonic-gate 			done(1);
705*7c478bd9Sstevel@tonic-gate 		}
706*7c478bd9Sstevel@tonic-gate 		ep = addentry(".", ROOTINO, NODE);
707*7c478bd9Sstevel@tonic-gate 		/* LINTED: result fits in a short */
708*7c478bd9Sstevel@tonic-gate 		ep->e_flags |= NEW;
709*7c478bd9Sstevel@tonic-gate 		return;
710*7c478bd9Sstevel@tonic-gate 	}
711*7c478bd9Sstevel@tonic-gate 	if ((fd = open(filename, O_RDONLY|O_LARGEFILE)) < 0) {
712*7c478bd9Sstevel@tonic-gate 		perror("open");
713*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
714*7c478bd9Sstevel@tonic-gate 		    gettext("cannot open symbol table file %s\n"), filename);
715*7c478bd9Sstevel@tonic-gate 		done(1);
716*7c478bd9Sstevel@tonic-gate 	}
717*7c478bd9Sstevel@tonic-gate 	if (fstat64(fd, &stbuf) < 0) {
718*7c478bd9Sstevel@tonic-gate 		perror("stat");
719*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
720*7c478bd9Sstevel@tonic-gate 		    gettext("cannot stat symbol table file %s\n"), filename);
721*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
722*7c478bd9Sstevel@tonic-gate 		done(1);
723*7c478bd9Sstevel@tonic-gate 	}
724*7c478bd9Sstevel@tonic-gate 	/*
725*7c478bd9Sstevel@tonic-gate 	 * The symbol table file is too small so say we can't read it.
726*7c478bd9Sstevel@tonic-gate 	 */
727*7c478bd9Sstevel@tonic-gate 	if (stbuf.st_size < sizeof (hdr)) {
728*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
729*7c478bd9Sstevel@tonic-gate 		    gettext("cannot read symbol table file %s\n"), filename);
730*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
731*7c478bd9Sstevel@tonic-gate 		done(1);
732*7c478bd9Sstevel@tonic-gate 	}
733*7c478bd9Sstevel@tonic-gate 	tblsize = stbuf.st_size - sizeof (hdr);
734*7c478bd9Sstevel@tonic-gate 	if (tblsize > ULONG_MAX) {
735*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
736*7c478bd9Sstevel@tonic-gate 		    gettext("symbol table file too large\n"));
737*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
738*7c478bd9Sstevel@tonic-gate 		done(1);
739*7c478bd9Sstevel@tonic-gate 	}
740*7c478bd9Sstevel@tonic-gate 	/* LINTED tblsize fits in a size_t */
741*7c478bd9Sstevel@tonic-gate 	base = calloc((size_t)sizeof (char), (size_t)tblsize);
742*7c478bd9Sstevel@tonic-gate 	if (base == NULL) {
743*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
744*7c478bd9Sstevel@tonic-gate 		    gettext("cannot allocate space for symbol table\n"));
745*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
746*7c478bd9Sstevel@tonic-gate 		done(1);
747*7c478bd9Sstevel@tonic-gate 	}
748*7c478bd9Sstevel@tonic-gate 	/* LINTED tblsize fits in a size_t */
749*7c478bd9Sstevel@tonic-gate 	if (read(fd, base, (size_t)tblsize) < 0 ||
750*7c478bd9Sstevel@tonic-gate 	    read(fd, (char *)&hdr, sizeof (hdr)) < 0) {
751*7c478bd9Sstevel@tonic-gate 		perror("read");
752*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
753*7c478bd9Sstevel@tonic-gate 		    gettext("cannot read symbol table file %s\n"), filename);
754*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
755*7c478bd9Sstevel@tonic-gate 		done(1);
756*7c478bd9Sstevel@tonic-gate 	}
757*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
758*7c478bd9Sstevel@tonic-gate 	switch (command) {
759*7c478bd9Sstevel@tonic-gate 	case 'r':
760*7c478bd9Sstevel@tonic-gate 	case 'M':
761*7c478bd9Sstevel@tonic-gate 		/*
762*7c478bd9Sstevel@tonic-gate 		 * For normal continuation, insure that we are using
763*7c478bd9Sstevel@tonic-gate 		 * the next incremental tape
764*7c478bd9Sstevel@tonic-gate 		 */
765*7c478bd9Sstevel@tonic-gate 		if (hdr.dumpdate != dumptime) {
766*7c478bd9Sstevel@tonic-gate 			if (hdr.dumpdate < dumptime)
767*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
768*7c478bd9Sstevel@tonic-gate 					"Incremental volume too low\n"));
769*7c478bd9Sstevel@tonic-gate 			else
770*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
771*7c478bd9Sstevel@tonic-gate 					"Incremental volume too high\n"));
772*7c478bd9Sstevel@tonic-gate 			done(1);
773*7c478bd9Sstevel@tonic-gate 		}
774*7c478bd9Sstevel@tonic-gate 		break;
775*7c478bd9Sstevel@tonic-gate 	case 'R':
776*7c478bd9Sstevel@tonic-gate 		/*
777*7c478bd9Sstevel@tonic-gate 		 * For restart, insure that we are using the same tape
778*7c478bd9Sstevel@tonic-gate 		 */
779*7c478bd9Sstevel@tonic-gate 		curfile.action = SKIP;
780*7c478bd9Sstevel@tonic-gate 		dumptime = hdr.dumptime;
781*7c478bd9Sstevel@tonic-gate 		dumpdate = hdr.dumpdate;
782*7c478bd9Sstevel@tonic-gate 		if (!bflag)
783*7c478bd9Sstevel@tonic-gate 			newtapebuf(hdr.ntrec);
784*7c478bd9Sstevel@tonic-gate 		getvol(hdr.volno);
785*7c478bd9Sstevel@tonic-gate 		break;
786*7c478bd9Sstevel@tonic-gate 	default:
787*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
788*7c478bd9Sstevel@tonic-gate 		    gettext("initsymtable called from command %c\n"),
789*7c478bd9Sstevel@tonic-gate 		    (uchar_t)command);
790*7c478bd9Sstevel@tonic-gate 		done(1);
791*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
792*7c478bd9Sstevel@tonic-gate 	}
793*7c478bd9Sstevel@tonic-gate 	maxino = hdr.maxino;
794*7c478bd9Sstevel@tonic-gate 	entrytblsize = hdr.entrytblsize;
795*7c478bd9Sstevel@tonic-gate 	/*LINTED [pointer cast alignment]*/
796*7c478bd9Sstevel@tonic-gate 	entry = (struct entry **)
797*7c478bd9Sstevel@tonic-gate 	    (base + tblsize - (entrytblsize * sizeof (*entry)));
798*7c478bd9Sstevel@tonic-gate 	if (((ulong_t)entry % 4) != 0) {
799*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
800*7c478bd9Sstevel@tonic-gate 		    gettext("Symbol table file corrupted\n"));
801*7c478bd9Sstevel@tonic-gate 		done(1);
802*7c478bd9Sstevel@tonic-gate 	}
803*7c478bd9Sstevel@tonic-gate 	/*LINTED [rvalue % 4 == 0] */
804*7c478bd9Sstevel@tonic-gate 	baseep = (struct entry *)
805*7c478bd9Sstevel@tonic-gate 	    (base + hdr.stringsize - sizeof (*baseep));
806*7c478bd9Sstevel@tonic-gate 	if (((ulong_t)baseep % 4) != 0) {
807*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
808*7c478bd9Sstevel@tonic-gate 		    gettext("Symbol table file corrupted\n"));
809*7c478bd9Sstevel@tonic-gate 		done(1);
810*7c478bd9Sstevel@tonic-gate 	}
811*7c478bd9Sstevel@tonic-gate 	lep = (struct entry *)entry;
812*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < entrytblsize; i++) {
813*7c478bd9Sstevel@tonic-gate 		if (entry[i] == NIL)
814*7c478bd9Sstevel@tonic-gate 			continue;
815*7c478bd9Sstevel@tonic-gate 		entry[i] = &baseep[(long)entry[i]];
816*7c478bd9Sstevel@tonic-gate 	}
817*7c478bd9Sstevel@tonic-gate 	for (ep = &baseep[1]; ep < lep; ep++) {
818*7c478bd9Sstevel@tonic-gate 		ep->e_name = base + (long)ep->e_name;
819*7c478bd9Sstevel@tonic-gate 		ep->e_parent = &baseep[(long)ep->e_parent];
820*7c478bd9Sstevel@tonic-gate 		if (ep->e_sibling != NIL)
821*7c478bd9Sstevel@tonic-gate 			ep->e_sibling = &baseep[(long)ep->e_sibling];
822*7c478bd9Sstevel@tonic-gate 		if (ep->e_links != NIL)
823*7c478bd9Sstevel@tonic-gate 			ep->e_links = &baseep[(long)ep->e_links];
824*7c478bd9Sstevel@tonic-gate 		if (ep->e_entries != NIL)
825*7c478bd9Sstevel@tonic-gate 			ep->e_entries = &baseep[(long)ep->e_entries];
826*7c478bd9Sstevel@tonic-gate 		if (ep->e_xattrs != NIL)
827*7c478bd9Sstevel@tonic-gate 			ep->e_xattrs = &baseep[(long)ep->e_xattrs];
828*7c478bd9Sstevel@tonic-gate 		if (ep->e_next != NIL)
829*7c478bd9Sstevel@tonic-gate 			ep->e_next = &baseep[(long)ep->e_next];
830*7c478bd9Sstevel@tonic-gate 	}
831*7c478bd9Sstevel@tonic-gate }
832