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