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