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 * 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 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 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 * 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 * 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 * 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 * 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 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 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 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 * 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 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 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 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