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