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 *
lookupino(inum)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
addino(inum,np)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
deleteino(inum)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 *
lookupname(name)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 *
lookupparent(name)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 *
myname(ep)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 *
addentry(name,inum,type)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
freeentry(ep)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
moveentry(ep,newname)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
removeentry(ep)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 *
savename(name)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
freename(name)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
dumpsymtable(filename,checkpt)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
initsymtable(filename)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