symtab.c revision 92806
1709Swollman/* 210873Sjkh * Copyright (c) 1983, 1993 3709Swollman * The Regents of the University of California. All rights reserved. 437Srgrimes * 537Srgrimes * Redistribution and use in source and binary forms, with or without 637Srgrimes * modification, are permitted provided that the following conditions 737Srgrimes * are met: 837Srgrimes * 1. Redistributions of source code must retain the above copyright 937Srgrimes * notice, this list of conditions and the following disclaimer. 108460Sjkh * 2. Redistributions in binary form must reproduce the above copyright 118460Sjkh * notice, this list of conditions and the following disclaimer in the 128460Sjkh * documentation and/or other materials provided with the distribution. 138460Sjkh * 3. All advertising materials mentioning features or use of this software 1437Srgrimes * must display the following acknowledgement: 1537Srgrimes * This product includes software developed by the University of 1637Srgrimes * California, Berkeley and its contributors. 1737Srgrimes * 4. Neither the name of the University nor the names of its contributors 1837Srgrimes * may be used to endorse or promote products derived from this software 1937Srgrimes * without specific prior written permission. 2037Srgrimes * 2137Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2237Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2337Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2437Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 253843Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 263843Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 272164Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2837Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2937Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3037Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3137Srgrimes * SUCH DAMAGE. 3237Srgrimes */ 3337Srgrimes 3437Srgrimes#ifndef lint 3537Srgrimes#if 0 3637Srgrimesstatic char sccsid[] = "@(#)symtab.c 8.3 (Berkeley) 4/28/95"; 3737Srgrimes#endif 3837Srgrimesstatic const char rcsid[] = 3937Srgrimes "$FreeBSD: head/sbin/restore/symtab.c 92806 2002-03-20 17:55:10Z obrien $"; 4037Srgrimes#endif /* not lint */ 4137Srgrimes 4237Srgrimes/* 4337Srgrimes * These routines maintain the symbol table which tracks the state 4437Srgrimes * of the file system being restored. They provide lookup by either 4537Srgrimes * name or inode number. They also provide for creation, deletion, 4637Srgrimes * and renaming of entries. Because of the dynamic nature of pathnames, 4737Srgrimes * names should not be saved, but always constructed just before they 4837Srgrimes * are needed, by calling "myname". 4937Srgrimes */ 5037Srgrimes 5137Srgrimes#include <sys/param.h> 5237Srgrimes#include <sys/stat.h> 5337Srgrimes 5437Srgrimes#include <ufs/ufs/dinode.h> 5537Srgrimes 5637Srgrimes#include <errno.h> 5737Srgrimes#include <fcntl.h> 5837Srgrimes#include <stdio.h> 592164Sdg#include <stdlib.h> 602164Sdg#include <string.h> 6137Srgrimes#include <unistd.h> 6237Srgrimes 6337Srgrimes#include "restore.h" 6437Srgrimes#include "extern.h" 653036Sdg 663036Sdg/* 673036Sdg * The following variables define the inode symbol table. 688530Sdg * The primary hash table is dynamically allocated based on 698530Sdg * the number of inodes in the file system (maxino), scaled by 708530Sdg * HASHFACTOR. The variable "entry" points to the hash table; 718530Sdg * the variable "entrytblsize" indicates its size (in entries). 721692Sphk */ 7337Srgrimes#define HASHFACTOR 5 748530Sdgstatic struct entry **entry; 7537Srgrimesstatic long entrytblsize; 768530Sdg 778530Sdgstatic void addino __P((ino_t, struct entry *)); 788530Sdgstatic struct entry *lookupparent __P((char *)); 798530Sdgstatic void removeentry __P((struct entry *)); 8037Srgrimes 81872Sache/* 82872Sache * Look up an entry by inode number 83872Sache */ 84872Sachestruct entry * 854091Sachelookupino(inum) 86872Sache ino_t inum; 877219Sjkh{ 887219Sjkh struct entry *ep; 897219Sjkh 907219Sjkh if (inum < WINO || inum >= maxino) 917219Sjkh return (NULL); 921675Sache for (ep = entry[inum % entrytblsize]; ep != NULL; ep = ep->e_next) 937219Sjkh if (ep->e_ino == inum) 947293Sjkh return (ep); 951675Sache return (NULL); 961675Sache} 977487Srgrimes 987460Sjkh/* 997750Srgrimes * Add an entry into the entry table 1007460Sjkh */ 1017460Sjkhstatic void 1028540Srgrimesaddino(inum, np) 1037487Srgrimes ino_t inum; 1047487Srgrimes struct entry *np; 1057487Srgrimes{ 1067487Srgrimes struct entry **epp; 1077487Srgrimes 1087487Srgrimes if (inum < WINO || inum >= maxino) 1097487Srgrimes panic("addino: out of range %d\n", inum); 1107761Sache epp = &entry[inum % entrytblsize]; 1117487Srgrimes np->e_ino = inum; 1127487Srgrimes np->e_next = *epp; 1137487Srgrimes *epp = np; 1147487Srgrimes if (dflag) 1157487Srgrimes for (np = np->e_next; np != NULL; np = np->e_next) 1167487Srgrimes if (np->e_ino == inum) 1177487Srgrimes badentry(np, "duplicate inum"); 1187487Srgrimes} 1197487Srgrimes 1207487Srgrimes/* 1219305Sbde * Delete an entry from the entry table 1229305Sbde */ 1239305Sbdevoid 1249305Sbdedeleteino(inum) 1259305Sbde ino_t inum; 1267487Srgrimes{ 1277487Srgrimes struct entry *next; 1287487Srgrimes struct entry **prev; 1297487Srgrimes 1307487Srgrimes if (inum < WINO || inum >= maxino) 1317487Srgrimes panic("deleteino: out of range %d\n", inum); 1327487Srgrimes prev = &entry[inum % entrytblsize]; 1337487Srgrimes for (next = *prev; next != NULL; next = next->e_next) { 1347487Srgrimes if (next->e_ino == inum) { 1357487Srgrimes next->e_ino = 0; 1367487Srgrimes *prev = next->e_next; 1377487Srgrimes return; 1387487Srgrimes } 1397487Srgrimes prev = &next->e_next; 1407487Srgrimes } 1417487Srgrimes panic("deleteino: %d not found\n", inum); 1427487Srgrimes} 1437487Srgrimes 1447487Srgrimes/* 1457487Srgrimes * Look up an entry by name 1467487Srgrimes */ 1477259Sjkhstruct entry * 1487487Srgrimeslookupname(name) 1497487Srgrimes char *name; 1507708Srgrimes{ 1517487Srgrimes struct entry *ep; 1527487Srgrimes char *np, *cp; 1537487Srgrimes char buf[MAXPATHLEN]; 1547487Srgrimes 1557487Srgrimes cp = name; 1567708Srgrimes for (ep = lookupino(ROOTINO); ep != NULL; ep = ep->e_entries) { 157857Sdg for (np = buf; *cp != '/' && *cp != '\0' && 15837Srgrimes np < &buf[sizeof(buf)]; ) 1597487Srgrimes *np++ = *cp++; 1607487Srgrimes if (np == &buf[sizeof(buf)]) 1617487Srgrimes break; 1627487Srgrimes *np = '\0'; 1637487Srgrimes for ( ; ep != NULL; ep = ep->e_sibling) 1647487Srgrimes if (strcmp(ep->e_name, buf) == 0) 1657487Srgrimes break; 166958Sache if (ep == NULL) 1677487Srgrimes break; 1687487Srgrimes if (*cp++ == '\0') 1697487Srgrimes return (ep); 1707487Srgrimes } 1717487Srgrimes return (NULL); 1727487Srgrimes} 1737487Srgrimes 1741186Srgrimes/* 1751186Srgrimes * Look up the parent of a pathname 1767487Srgrimes */ 1777487Srgrimesstatic struct entry * 1787487Srgrimeslookupparent(name) 1797487Srgrimes char *name; 1807487Srgrimes{ 1817219Sjkh struct entry *ep; 1827487Srgrimes char *tailindex; 1837487Srgrimes 1847487Srgrimes tailindex = strrchr(name, '/'); 1857487Srgrimes if (tailindex == NULL) 1867238Sache return (NULL); 1877487Srgrimes *tailindex = '\0'; 1887487Srgrimes ep = lookupname(name); 1897487Srgrimes *tailindex = '/'; 1907708Srgrimes if (ep == NULL) 1917238Sache return (NULL); 1927487Srgrimes if (ep->e_type != NODE) 1937708Srgrimes panic("%s is not a directory\n", name); 1947487Srgrimes return (ep); 1957487Srgrimes} 1967238Sache 1977487Srgrimes/* 1987487Srgrimes * Determine the current pathname of a node or leaf 1997708Srgrimes */ 2009593Swollmanchar * 2019593Swollmanmyname(ep) 2029593Swollman struct entry *ep; 2037219Sjkh{ 2047219Sjkh char *cp; 2057487Srgrimes static char namebuf[MAXPATHLEN]; 2067487Srgrimes 2077487Srgrimes for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) { 2087487Srgrimes cp -= ep->e_namlen; 2097238Sache memmove(cp, ep->e_name, (long)ep->e_namlen); 2107238Sache if (ep == lookupino(ROOTINO)) 2117487Srgrimes return (cp); 21210716Sjkh *(--cp) = '/'; 21310716Sjkh ep = ep->e_parent; 21410716Sjkh } 21510716Sjkh panic("%s: pathname too long\n", cp); 21610716Sjkh return(cp); 21710716Sjkh} 2187487Srgrimes 2197477Sache/* 2207477Sache * Unused symbol table entries are linked together on a free list 2217487Srgrimes * headed by the following pointer. 2227487Srgrimes */ 2237487Srgrimesstatic struct entry *freelist = NULL; 2247238Sache 2257487Srgrimes/* 2267487Srgrimes * add an entry to the symbol table 2277238Sache */ 2287238Sachestruct entry * 22910716Sjkhaddentry(name, inum, type) 23010716Sjkh char *name; 23110716Sjkh ino_t inum; 23210716Sjkh int type; 23310716Sjkh{ 23410716Sjkh struct entry *np, *ep; 23510716Sjkh 23610716Sjkh if (freelist != NULL) { 23710716Sjkh np = freelist; 23810716Sjkh freelist = np->e_next; 2397487Srgrimes memset(np, 0, (long)sizeof(struct entry)); 2407487Srgrimes } else { 2417487Srgrimes np = (struct entry *)calloc(1, sizeof(struct entry)); 2427487Srgrimes if (np == NULL) 2437487Srgrimes panic("no memory to extend symbol table\n"); 2447238Sache } 2457238Sache np->e_type = type & ~LINK; 2467487Srgrimes ep = lookupparent(name); 2477487Srgrimes if (ep == NULL) { 2487487Srgrimes if (inum != ROOTINO || lookupino(ROOTINO) != NULL) 2497487Srgrimes panic("bad name to addentry %s\n", name); 2507487Srgrimes np->e_name = savename(name); 2517487Srgrimes np->e_namlen = strlen(name); 2527487Srgrimes np->e_parent = np; 2537487Srgrimes addino(ROOTINO, np); 2547487Srgrimes return (np); 2557487Srgrimes } 2567487Srgrimes np->e_name = savename(strrchr(name, '/') + 1); 2577487Srgrimes np->e_namlen = strlen(np->e_name); 2587238Sache np->e_parent = ep; 2597238Sache np->e_sibling = ep->e_entries; 2607487Srgrimes ep->e_entries = np; 2617487Srgrimes if (type & LINK) { 2627487Srgrimes ep = lookupino(inum); 2637487Srgrimes if (ep == NULL) 2647487Srgrimes panic("link to non-existent name\n"); 2657487Srgrimes np->e_ino = inum; 2667487Srgrimes np->e_links = ep->e_links; 2677238Sache ep->e_links = np; 2687238Sache } else if (inum != 0) { 2697487Srgrimes if (lookupino(inum) != NULL) 2707487Srgrimes panic("duplicate entry\n"); 2717238Sache addino(inum, np); 2727238Sache } 2737487Srgrimes return (np); 2747487Srgrimes} 2757487Srgrimes 2767487Srgrimes/* 2777708Srgrimes * delete an entry from the symbol table 2787238Sache */ 2797487Srgrimesvoid 2807487Srgrimesfreeentry(ep) 2817487Srgrimes struct entry *ep; 2827487Srgrimes{ 2837238Sache struct entry *np; 2847238Sache ino_t inum; 2857487Srgrimes 2867238Sache if (ep->e_flags != REMOVED) 2877487Srgrimes badentry(ep, "not marked REMOVED"); 2887487Srgrimes if (ep->e_type == NODE) { 2897487Srgrimes if (ep->e_links != NULL) 2907487Srgrimes badentry(ep, "freeing referenced directory"); 2917487Srgrimes if (ep->e_entries != NULL) 2927487Srgrimes badentry(ep, "freeing non-empty directory"); 2937487Srgrimes } 2947487Srgrimes if (ep->e_ino != 0) { 2957487Srgrimes np = lookupino(ep->e_ino); 2967487Srgrimes if (np == NULL) 2977296Sjkh badentry(ep, "lookupino failed"); 2987296Sjkh if (np == ep) { 2997487Srgrimes inum = ep->e_ino; 3007487Srgrimes deleteino(inum); 3017487Srgrimes if (ep->e_links != NULL) 3027487Srgrimes addino(inum, ep->e_links); 3037487Srgrimes } else { 3047487Srgrimes for (; np != NULL; np = np->e_links) { 30510873Sjkh if (np->e_links == ep) { 30610873Sjkh np->e_links = ep->e_links; 30710873Sjkh break; 30810873Sjkh } 3097259Sjkh } 31037Srgrimes if (np == NULL) 31110873Sjkh badentry(ep, "link not found"); 31210873Sjkh } 31310873Sjkh } 31437Srgrimes removeentry(ep); 31537Srgrimes freename(ep->e_name); 316 ep->e_next = freelist; 317 freelist = ep; 318} 319 320/* 321 * Relocate an entry in the tree structure 322 */ 323void 324moveentry(ep, newname) 325 struct entry *ep; 326 char *newname; 327{ 328 struct entry *np; 329 char *cp; 330 331 np = lookupparent(newname); 332 if (np == NULL) 333 badentry(ep, "cannot move ROOT"); 334 if (np != ep->e_parent) { 335 removeentry(ep); 336 ep->e_parent = np; 337 ep->e_sibling = np->e_entries; 338 np->e_entries = ep; 339 } 340 cp = strrchr(newname, '/') + 1; 341 freename(ep->e_name); 342 ep->e_name = savename(cp); 343 ep->e_namlen = strlen(cp); 344 if (strcmp(gentempname(ep), ep->e_name) == 0) 345 ep->e_flags |= TMPNAME; 346 else 347 ep->e_flags &= ~TMPNAME; 348} 349 350/* 351 * Remove an entry in the tree structure 352 */ 353static void 354removeentry(ep) 355 struct entry *ep; 356{ 357 struct entry *np; 358 359 np = ep->e_parent; 360 if (np->e_entries == ep) { 361 np->e_entries = ep->e_sibling; 362 } else { 363 for (np = np->e_entries; np != NULL; np = np->e_sibling) { 364 if (np->e_sibling == ep) { 365 np->e_sibling = ep->e_sibling; 366 break; 367 } 368 } 369 if (np == NULL) 370 badentry(ep, "cannot find entry in parent list"); 371 } 372} 373 374/* 375 * Table of unused string entries, sorted by length. 376 * 377 * Entries are allocated in STRTBLINCR sized pieces so that names 378 * of similar lengths can use the same entry. The value of STRTBLINCR 379 * is chosen so that every entry has at least enough space to hold 380 * a "struct strtbl" header. Thus every entry can be linked onto an 381 * appropriate free list. 382 * 383 * NB. The macro "allocsize" below assumes that "struct strhdr" 384 * has a size that is a power of two. 385 */ 386struct strhdr { 387 struct strhdr *next; 388}; 389 390#define STRTBLINCR (sizeof(struct strhdr)) 391#define allocsize(size) (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1)) 392 393static struct strhdr strtblhdr[allocsize(NAME_MAX) / STRTBLINCR]; 394 395/* 396 * Allocate space for a name. It first looks to see if it already 397 * has an appropriate sized entry, and if not allocates a new one. 398 */ 399char * 400savename(name) 401 char *name; 402{ 403 struct strhdr *np; 404 long len; 405 char *cp; 406 407 if (name == NULL) 408 panic("bad name\n"); 409 len = strlen(name); 410 np = strtblhdr[len / STRTBLINCR].next; 411 if (np != NULL) { 412 strtblhdr[len / STRTBLINCR].next = np->next; 413 cp = (char *)np; 414 } else { 415 cp = malloc((unsigned)allocsize(len)); 416 if (cp == NULL) 417 panic("no space for string table\n"); 418 } 419 (void) strcpy(cp, name); 420 return (cp); 421} 422 423/* 424 * Free space for a name. The resulting entry is linked onto the 425 * appropriate free list. 426 */ 427void 428freename(name) 429 char *name; 430{ 431 struct strhdr *tp, *np; 432 433 tp = &strtblhdr[strlen(name) / STRTBLINCR]; 434 np = (struct strhdr *)name; 435 np->next = tp->next; 436 tp->next = np; 437} 438 439/* 440 * Useful quantities placed at the end of a dumped symbol table. 441 */ 442struct symtableheader { 443 int32_t volno; 444 int32_t stringsize; 445 int32_t entrytblsize; 446 time_t dumptime; 447 time_t dumpdate; 448 ino_t maxino; 449 int32_t ntrec; 450}; 451 452/* 453 * dump a snapshot of the symbol table 454 */ 455void 456dumpsymtable(filename, checkpt) 457 char *filename; 458 long checkpt; 459{ 460 struct entry *ep, *tep; 461 ino_t i; 462 struct entry temp, *tentry; 463 long mynum = 1, stroff = 0; 464 FILE *fd; 465 struct symtableheader hdr; 466 467 vprintf(stdout, "Check pointing the restore\n"); 468 if (Nflag) 469 return; 470 if ((fd = fopen(filename, "w")) == NULL) { 471 fprintf(stderr, "fopen: %s\n", strerror(errno)); 472 panic("cannot create save file %s for symbol table\n", 473 filename); 474 done(1); 475 } 476 clearerr(fd); 477 /* 478 * Assign indices to each entry 479 * Write out the string entries 480 */ 481 for (i = WINO; i <= maxino; i++) { 482 for (ep = lookupino(i); ep != NULL; ep = ep->e_links) { 483 ep->e_index = mynum++; 484 (void) fwrite(ep->e_name, sizeof(char), 485 (int)allocsize(ep->e_namlen), fd); 486 } 487 } 488 /* 489 * Convert pointers to indexes, and output 490 */ 491 tep = &temp; 492 stroff = 0; 493 for (i = WINO; i <= maxino; i++) { 494 for (ep = lookupino(i); ep != NULL; ep = ep->e_links) { 495 memmove(tep, ep, (long)sizeof(struct entry)); 496 tep->e_name = (char *)stroff; 497 stroff += allocsize(ep->e_namlen); 498 tep->e_parent = (struct entry *)ep->e_parent->e_index; 499 if (ep->e_links != NULL) 500 tep->e_links = 501 (struct entry *)ep->e_links->e_index; 502 if (ep->e_sibling != NULL) 503 tep->e_sibling = 504 (struct entry *)ep->e_sibling->e_index; 505 if (ep->e_entries != NULL) 506 tep->e_entries = 507 (struct entry *)ep->e_entries->e_index; 508 if (ep->e_next != NULL) 509 tep->e_next = 510 (struct entry *)ep->e_next->e_index; 511 (void) fwrite((char *)tep, sizeof(struct entry), 1, fd); 512 } 513 } 514 /* 515 * Convert entry pointers to indexes, and output 516 */ 517 for (i = 0; i < entrytblsize; i++) { 518 if (entry[i] == NULL) 519 tentry = NULL; 520 else 521 tentry = (struct entry *)entry[i]->e_index; 522 (void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd); 523 } 524 hdr.volno = checkpt; 525 hdr.maxino = maxino; 526 hdr.entrytblsize = entrytblsize; 527 hdr.stringsize = stroff; 528 hdr.dumptime = dumptime; 529 hdr.dumpdate = dumpdate; 530 hdr.ntrec = ntrec; 531 (void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd); 532 if (ferror(fd)) { 533 fprintf(stderr, "fwrite: %s\n", strerror(errno)); 534 panic("output error to file %s writing symbol table\n", 535 filename); 536 } 537 (void) fclose(fd); 538} 539 540/* 541 * Initialize a symbol table from a file 542 */ 543void 544initsymtable(filename) 545 char *filename; 546{ 547 char *base; 548 long tblsize; 549 struct entry *ep; 550 struct entry *baseep, *lep; 551 struct symtableheader hdr; 552 struct stat stbuf; 553 long i; 554 int fd; 555 556 vprintf(stdout, "Initialize symbol table.\n"); 557 if (filename == NULL) { 558 entrytblsize = maxino / HASHFACTOR; 559 entry = (struct entry **) 560 calloc((unsigned)entrytblsize, sizeof(struct entry *)); 561 if (entry == (struct entry **)NULL) 562 panic("no memory for entry table\n"); 563 ep = addentry(".", ROOTINO, NODE); 564 ep->e_flags |= NEW; 565 return; 566 } 567 if ((fd = open(filename, O_RDONLY, 0)) < 0) { 568 fprintf(stderr, "open: %s\n", strerror(errno)); 569 panic("cannot open symbol table file %s\n", filename); 570 } 571 if (fstat(fd, &stbuf) < 0) { 572 fprintf(stderr, "stat: %s\n", strerror(errno)); 573 panic("cannot stat symbol table file %s\n", filename); 574 } 575 tblsize = stbuf.st_size - sizeof(struct symtableheader); 576 base = calloc(sizeof(char), (unsigned)tblsize); 577 if (base == NULL) 578 panic("cannot allocate space for symbol table\n"); 579 if (read(fd, base, (int)tblsize) < 0 || 580 read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) { 581 fprintf(stderr, "read: %s\n", strerror(errno)); 582 panic("cannot read symbol table file %s\n", filename); 583 } 584 switch (command) { 585 case 'r': 586 /* 587 * For normal continuation, insure that we are using 588 * the next incremental tape 589 */ 590 if (hdr.dumpdate != dumptime) { 591 if (hdr.dumpdate < dumptime) 592 fprintf(stderr, "Incremental tape too low\n"); 593 else 594 fprintf(stderr, "Incremental tape too high\n"); 595 done(1); 596 } 597 break; 598 case 'R': 599 /* 600 * For restart, insure that we are using the same tape 601 */ 602 curfile.action = SKIP; 603 dumptime = hdr.dumptime; 604 dumpdate = hdr.dumpdate; 605 if (!bflag) 606 newtapebuf(hdr.ntrec); 607 getvol(hdr.volno); 608 break; 609 default: 610 panic("initsymtable called from command %c\n", command); 611 break; 612 } 613 maxino = hdr.maxino; 614 entrytblsize = hdr.entrytblsize; 615 entry = (struct entry **) 616 (base + tblsize - (entrytblsize * sizeof(struct entry *))); 617 baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry)); 618 lep = (struct entry *)entry; 619 for (i = 0; i < entrytblsize; i++) { 620 if (entry[i] == NULL) 621 continue; 622 entry[i] = &baseep[(long)entry[i]]; 623 } 624 for (ep = &baseep[1]; ep < lep; ep++) { 625 ep->e_name = base + (long)ep->e_name; 626 ep->e_parent = &baseep[(long)ep->e_parent]; 627 if (ep->e_sibling != NULL) 628 ep->e_sibling = &baseep[(long)ep->e_sibling]; 629 if (ep->e_links != NULL) 630 ep->e_links = &baseep[(long)ep->e_links]; 631 if (ep->e_entries != NULL) 632 ep->e_entries = &baseep[(long)ep->e_entries]; 633 if (ep->e_next != NULL) 634 ep->e_next = &baseep[(long)ep->e_next]; 635 } 636} 637