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