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