110314Smckusick #ifndef lint 2*18497Smckusick static char sccsid[] = "@(#)symtab.c 3.17 (Berkeley) 85/03/24"; 310314Smckusick #endif 410314Smckusick 514566Ssam /* Copyright (c) 1983 Regents of the University of California */ 614566Ssam 711646Smckusick /* 811646Smckusick * These routines maintain the symbol table which tracks the state 911646Smckusick * of the file system being restored. They provide lookup by either 1011646Smckusick * name or inode number. They also provide for creation, deletion, 1111646Smckusick * and renaming of entries. Because of the dynamic nature of pathnames, 1211646Smckusick * names should not be saved, but always constructed just before they 1311646Smckusick * are needed, by calling "myname". 1411646Smckusick */ 1511646Smckusick 1610314Smckusick #include "restore.h" 1710314Smckusick #include <sys/stat.h> 1810314Smckusick 1911646Smckusick /* 2011646Smckusick * The following variables define the inode symbol table. 2111646Smckusick * The primary hash table is dynamically allocated based on 2211646Smckusick * the number of inodes in the file system (maxino), scaled by 2311646Smckusick * HASHFACTOR. The variable "entry" points to the hash table; 2411646Smckusick * the variable "entrytblsize" indicates its size (in entries). 2511646Smckusick */ 2611646Smckusick #define HASHFACTOR 5 2711440Smckusick static struct entry **entry; 2811440Smckusick static long entrytblsize; 2910314Smckusick 3010314Smckusick /* 3110314Smckusick * Look up an entry by inode number 3210314Smckusick */ 3310314Smckusick struct entry * 3410314Smckusick lookupino(inum) 3510314Smckusick ino_t inum; 3610314Smckusick { 3711440Smckusick register struct entry *ep; 3810314Smckusick 3911440Smckusick if (inum < ROOTINO || inum >= maxino) 4011440Smckusick return (NIL); 4111440Smckusick for (ep = entry[inum % entrytblsize]; ep != NIL; ep = ep->e_next) 4211440Smckusick if (ep->e_ino == inum) 4311440Smckusick return (ep); 4411440Smckusick return (NIL); 4510314Smckusick } 4610314Smckusick 4710314Smckusick /* 4810314Smckusick * Add an entry into the entry table 4910314Smckusick */ 5010314Smckusick addino(inum, np) 5111440Smckusick ino_t inum; 5210314Smckusick struct entry *np; 5310314Smckusick { 5411440Smckusick struct entry **epp; 5510314Smckusick 5611440Smckusick if (inum < ROOTINO || inum >= maxino) 5711440Smckusick panic("addino: out of range %d\n", inum); 5811440Smckusick epp = &entry[inum % entrytblsize]; 5911440Smckusick np->e_ino = inum; 6011440Smckusick np->e_next = *epp; 6111440Smckusick *epp = np; 6211440Smckusick if (dflag) 6311440Smckusick for (np = np->e_next; np != NIL; np = np->e_next) 6411440Smckusick if (np->e_ino == inum) 6511440Smckusick badentry(np, "duplicate inum"); 6610314Smckusick } 6710314Smckusick 6810314Smckusick /* 6910314Smckusick * Delete an entry from the entry table 7010314Smckusick */ 7110314Smckusick deleteino(inum) 7211440Smckusick ino_t inum; 7310314Smckusick { 7411440Smckusick register struct entry *next; 7511440Smckusick struct entry **prev; 7610314Smckusick 7711440Smckusick if (inum < ROOTINO || inum >= maxino) 7811440Smckusick panic("deleteino: out of range %d\n", inum); 7911440Smckusick prev = &entry[inum % entrytblsize]; 8011440Smckusick for (next = *prev; next != NIL; next = next->e_next) { 8111440Smckusick if (next->e_ino == inum) { 8211440Smckusick next->e_ino = 0; 8311440Smckusick *prev = next->e_next; 8411440Smckusick return; 8511440Smckusick } 8611440Smckusick prev = &next->e_next; 8711440Smckusick } 8811440Smckusick panic("deleteino: %d not found\n", inum); 8910314Smckusick } 9010314Smckusick 9110314Smckusick /* 9210314Smckusick * Look up an entry by name 9310314Smckusick */ 9410314Smckusick struct entry * 9510314Smckusick lookupname(name) 9610314Smckusick char *name; 9710314Smckusick { 9810314Smckusick register struct entry *ep; 9910314Smckusick register char *np, *cp; 10011646Smckusick char buf[MAXPATHLEN]; 10110314Smckusick 10210314Smckusick cp = name; 10310314Smckusick for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) { 10410314Smckusick for (np = buf; *cp != '/' && *cp != '\0'; ) 10510314Smckusick *np++ = *cp++; 10610314Smckusick *np = '\0'; 10710314Smckusick for ( ; ep != NIL; ep = ep->e_sibling) 10810314Smckusick if (strcmp(ep->e_name, buf) == 0) 10910314Smckusick break; 11010314Smckusick if (ep == NIL) 11110314Smckusick break; 11211311Smckusick if (*cp++ == '\0') 11310314Smckusick return (ep); 11410314Smckusick } 11511311Smckusick return (NIL); 11610314Smckusick } 11710314Smckusick 11810314Smckusick /* 11910314Smckusick * Look up the parent of a pathname 12010314Smckusick */ 12110314Smckusick struct entry * 12210314Smckusick lookupparent(name) 12310314Smckusick char *name; 12410314Smckusick { 12510314Smckusick struct entry *ep; 12610314Smckusick char *tailindex; 12710314Smckusick 12810314Smckusick tailindex = rindex(name, '/'); 12910314Smckusick if (tailindex == 0) 13010314Smckusick return (NIL); 13110314Smckusick *tailindex = '\0'; 13210314Smckusick ep = lookupname(name); 13311311Smckusick *tailindex = '/'; 13410314Smckusick if (ep == NIL) 13510314Smckusick return (NIL); 13610314Smckusick if (ep->e_type != NODE) 13710314Smckusick panic("%s is not a directory\n", name); 13810314Smckusick return (ep); 13910314Smckusick } 14010314Smckusick 14110314Smckusick /* 14210314Smckusick * Determine the current pathname of a node or leaf 14310314Smckusick */ 14410314Smckusick char * 14510314Smckusick myname(ep) 14610314Smckusick register struct entry *ep; 14710314Smckusick { 14810314Smckusick register char *cp; 14911646Smckusick static char namebuf[MAXPATHLEN]; 15010314Smckusick 15111646Smckusick for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) { 15210314Smckusick cp -= ep->e_namlen; 15310314Smckusick bcopy(ep->e_name, cp, (long)ep->e_namlen); 15410314Smckusick if (ep == lookupino(ROOTINO)) 15510314Smckusick return (cp); 15610314Smckusick *(--cp) = '/'; 15710314Smckusick ep = ep->e_parent; 15810314Smckusick } 15910314Smckusick panic("%s: pathname too long\n", cp); 16010314Smckusick return(cp); 16110314Smckusick } 16210314Smckusick 16310314Smckusick /* 16411646Smckusick * Unused symbol table entries are linked together on a freelist 16511646Smckusick * headed by the following pointer. 16611646Smckusick */ 16711646Smckusick static struct entry *freelist = NIL; 16811646Smckusick 16911646Smckusick /* 17010314Smckusick * add an entry to the symbol table 17110314Smckusick */ 17210314Smckusick struct entry * 17310314Smckusick addentry(name, inum, type) 17410314Smckusick char *name; 17510314Smckusick ino_t inum; 17610314Smckusick int type; 17710314Smckusick { 17810314Smckusick register struct entry *np, *ep; 17910314Smckusick 18010314Smckusick if (freelist != NIL) { 18110314Smckusick np = freelist; 18211440Smckusick freelist = np->e_next; 18310314Smckusick bzero((char *)np, (long)sizeof(struct entry)); 18410314Smckusick } else { 18510314Smckusick np = (struct entry *)calloc(1, sizeof(struct entry)); 18613860Smckusick if (np == NIL) 18713860Smckusick panic("no memory to extend symbol table\n"); 18810314Smckusick } 18910314Smckusick np->e_type = type & ~LINK; 19010314Smckusick ep = lookupparent(name); 19110314Smckusick if (ep == NIL) { 19210314Smckusick if (inum != ROOTINO || lookupino(ROOTINO) != NIL) 19310314Smckusick panic("bad name to addentry %s\n", name); 19410314Smckusick np->e_name = savename(name); 19510314Smckusick np->e_namlen = strlen(name); 19610314Smckusick np->e_parent = np; 19710314Smckusick addino(ROOTINO, np); 19810314Smckusick return (np); 19910314Smckusick } 20010314Smckusick np->e_name = savename(rindex(name, '/') + 1); 20110314Smckusick np->e_namlen = strlen(np->e_name); 20210314Smckusick np->e_parent = ep; 20310314Smckusick np->e_sibling = ep->e_entries; 20410314Smckusick ep->e_entries = np; 20510314Smckusick if (type & LINK) { 20610314Smckusick ep = lookupino(inum); 20710314Smckusick if (ep == NIL) 20810314Smckusick panic("link to non-existant name\n"); 20911741Smckusick np->e_ino = inum; 21010314Smckusick np->e_links = ep->e_links; 21110314Smckusick ep->e_links = np; 21210314Smckusick } else if (inum != 0) { 21310314Smckusick if (lookupino(inum) != NIL) 21410314Smckusick panic("duplicate entry\n"); 21510314Smckusick addino(inum, np); 21610314Smckusick } 21710314Smckusick return (np); 21810314Smckusick } 21910314Smckusick 22010314Smckusick /* 22110314Smckusick * delete an entry from the symbol table 22210314Smckusick */ 22310314Smckusick freeentry(ep) 22410314Smckusick register struct entry *ep; 22510314Smckusick { 22610314Smckusick register struct entry *np; 22712456Smckusick ino_t inum; 22810314Smckusick 22910314Smckusick if (ep->e_flags != REMOVED) 23010314Smckusick badentry(ep, "not marked REMOVED"); 23111440Smckusick if (ep->e_type == NODE) { 23211440Smckusick if (ep->e_links != NIL) 23310314Smckusick badentry(ep, "freeing referenced directory"); 23410314Smckusick if (ep->e_entries != NIL) 23510314Smckusick badentry(ep, "freeing non-empty directory"); 23610314Smckusick } 23711440Smckusick if (ep->e_ino != 0) { 23811440Smckusick np = lookupino(ep->e_ino); 23911440Smckusick if (np == NIL) 24011440Smckusick badentry(ep, "lookupino failed"); 24111440Smckusick if (np == ep) { 24212456Smckusick inum = ep->e_ino; 24312456Smckusick deleteino(inum); 24411440Smckusick if (ep->e_links != NIL) 24512456Smckusick addino(inum, ep->e_links); 24611440Smckusick } else { 24711440Smckusick for (; np != NIL; np = np->e_links) { 24811440Smckusick if (np->e_links == ep) { 24911440Smckusick np->e_links = ep->e_links; 25011440Smckusick break; 25111440Smckusick } 25210314Smckusick } 25311440Smckusick if (np == NIL) 25411440Smckusick badentry(ep, "link not found"); 25510314Smckusick } 25610314Smckusick } 25710314Smckusick removeentry(ep); 25811646Smckusick freename(ep->e_name); 25911440Smckusick ep->e_next = freelist; 26010314Smckusick freelist = ep; 26110314Smckusick } 26210314Smckusick 26310314Smckusick /* 26410314Smckusick * Relocate an entry in the tree structure 26510314Smckusick */ 26610314Smckusick moveentry(ep, newname) 26710314Smckusick register struct entry *ep; 26810314Smckusick char *newname; 26910314Smckusick { 27010314Smckusick struct entry *np; 27110314Smckusick char *cp; 27210314Smckusick 27310314Smckusick np = lookupparent(newname); 27410314Smckusick if (np == NIL) 27510314Smckusick badentry(ep, "cannot move ROOT"); 27610314Smckusick if (np != ep->e_parent) { 27710314Smckusick removeentry(ep); 27810314Smckusick ep->e_parent = np; 27910314Smckusick ep->e_sibling = np->e_entries; 28010314Smckusick np->e_entries = ep; 28110314Smckusick } 28210314Smckusick cp = rindex(newname, '/') + 1; 28311646Smckusick freename(ep->e_name); 28411646Smckusick ep->e_name = savename(cp); 28511646Smckusick ep->e_namlen = strlen(cp); 28611646Smckusick if (strcmp(gentempname(ep), ep->e_name) == 0) 28710314Smckusick ep->e_flags |= TMPNAME; 28810314Smckusick else 28910314Smckusick ep->e_flags &= ~TMPNAME; 29010314Smckusick } 29110314Smckusick 29210314Smckusick /* 29310314Smckusick * Remove an entry in the tree structure 29410314Smckusick */ 29510314Smckusick removeentry(ep) 29610314Smckusick register struct entry *ep; 29710314Smckusick { 29810314Smckusick register struct entry *np; 29910314Smckusick 30010314Smckusick np = ep->e_parent; 30110314Smckusick if (np->e_entries == ep) { 30210314Smckusick np->e_entries = ep->e_sibling; 30310314Smckusick } else { 30410314Smckusick for (np = np->e_entries; np != NIL; np = np->e_sibling) { 30510314Smckusick if (np->e_sibling == ep) { 30610314Smckusick np->e_sibling = ep->e_sibling; 30710314Smckusick break; 30810314Smckusick } 30910314Smckusick } 31010314Smckusick if (np == NIL) 31110314Smckusick badentry(ep, "cannot find entry in parent list"); 31210314Smckusick } 31310314Smckusick } 31410314Smckusick 31510314Smckusick /* 31611646Smckusick * Table of unused string entries, sorted by length. 31711646Smckusick * 31811646Smckusick * Entries are allocated in STRTBLINCR sized pieces so that names 31911646Smckusick * of similar lengths can use the same entry. The value of STRTBLINCR 32011646Smckusick * is chosen so that every entry has at least enough space to hold 32111646Smckusick * a "struct strtbl" header. Thus every entry can be linked onto an 32211646Smckusick * apprpriate free list. 32311646Smckusick * 32411646Smckusick * NB. The macro "allocsize" below assumes that "struct strhdr" 32511646Smckusick * has a size that is a power of two. 32610314Smckusick */ 32711646Smckusick struct strhdr { 32811646Smckusick struct strhdr *next; 32911646Smckusick }; 33011646Smckusick 33111646Smckusick #define STRTBLINCR (sizeof(struct strhdr)) 33211646Smckusick #define allocsize(size) (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1)) 33311646Smckusick 33411646Smckusick static struct strhdr strtblhdr[allocsize(MAXNAMLEN) / STRTBLINCR]; 33511646Smckusick 33611646Smckusick /* 33711646Smckusick * Allocate space for a name. It first looks to see if it already 33811646Smckusick * has an appropriate sized entry, and if not allocates a new one. 33911646Smckusick */ 34010314Smckusick char * 34110314Smckusick savename(name) 34210314Smckusick char *name; 34310314Smckusick { 34411646Smckusick struct strhdr *np; 34510314Smckusick long len; 34611311Smckusick char *cp; 34710314Smckusick 34810314Smckusick if (name == NULL) 34910314Smckusick panic("bad name\n"); 35011646Smckusick len = strlen(name); 35111646Smckusick np = strtblhdr[len / STRTBLINCR].next; 35211646Smckusick if (np != NULL) { 35311646Smckusick strtblhdr[len / STRTBLINCR].next = np->next; 35411646Smckusick cp = (char *)np; 35511646Smckusick } else { 35611646Smckusick cp = malloc((unsigned)allocsize(len)); 35711646Smckusick if (cp == NULL) 35811646Smckusick panic("no space for string table\n"); 35911646Smckusick } 36011440Smckusick (void) strcpy(cp, name); 36111311Smckusick return (cp); 36210314Smckusick } 36310314Smckusick 36410314Smckusick /* 36511646Smckusick * Free space for a name. The resulting entry is linked onto the 36611646Smckusick * appropriate free list. 36711646Smckusick */ 36811646Smckusick freename(name) 36911646Smckusick char *name; 37011646Smckusick { 37111646Smckusick struct strhdr *tp, *np; 37211646Smckusick 37311646Smckusick tp = &strtblhdr[strlen(name) / STRTBLINCR]; 37411646Smckusick np = (struct strhdr *)name; 37511646Smckusick np->next = tp->next; 37611646Smckusick tp->next = np; 37711646Smckusick } 37811646Smckusick 37911646Smckusick /* 38011646Smckusick * Useful quantities placed at the end of a dumped symbol table. 38111646Smckusick */ 38211646Smckusick struct symtableheader { 38311646Smckusick long volno; 38411646Smckusick long stringsize; 38511646Smckusick long entrytblsize; 38611646Smckusick time_t dumptime; 38711646Smckusick time_t dumpdate; 38811646Smckusick ino_t maxino; 389*18497Smckusick long ntrec; 39011646Smckusick }; 39111646Smckusick 39211646Smckusick /* 39310314Smckusick * dump a snapshot of the symbol table 39410314Smckusick */ 39510314Smckusick dumpsymtable(filename, checkpt) 39610314Smckusick char *filename; 39710314Smckusick long checkpt; 39810314Smckusick { 39911440Smckusick register struct entry *ep, *tep; 40011440Smckusick register ino_t i; 40111440Smckusick struct entry temp, *tentry; 40211440Smckusick long mynum = 1, stroff = 0; 40310314Smckusick FILE *fd; 40410314Smckusick struct symtableheader hdr; 40510314Smckusick 40610314Smckusick vprintf(stdout, "Check pointing the restore\n"); 40710314Smckusick if ((fd = fopen(filename, "w")) == NULL) { 40810314Smckusick perror("fopen"); 40910314Smckusick panic("cannot create save file %s for symbol table\n", 41010314Smckusick filename); 41110314Smckusick } 41210314Smckusick clearerr(fd); 41310314Smckusick /* 41410314Smckusick * Assign indicies to each entry 41510314Smckusick * Write out the string entries 41610314Smckusick */ 41710314Smckusick for (i = ROOTINO; i < maxino; i++) { 41810314Smckusick for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 41911440Smckusick ep->e_index = mynum++; 42011734Smckusick (void) fwrite(ep->e_name, sizeof(char), 42111734Smckusick (int)allocsize(ep->e_namlen), fd); 42210314Smckusick } 42310314Smckusick } 42410314Smckusick /* 42510314Smckusick * Convert pointers to indexes, and output 42610314Smckusick */ 42711440Smckusick tep = &temp; 42811440Smckusick stroff = 0; 42910314Smckusick for (i = ROOTINO; i < maxino; i++) { 43011440Smckusick for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 43111734Smckusick bcopy((char *)ep, (char *)tep, 43211734Smckusick (long)sizeof(struct entry)); 43311440Smckusick tep->e_name = (char *)stroff; 43411646Smckusick stroff += allocsize(ep->e_namlen); 43511440Smckusick tep->e_parent = (struct entry *)ep->e_parent->e_index; 43611440Smckusick if (ep->e_links != NIL) 43711440Smckusick tep->e_links = 43811440Smckusick (struct entry *)ep->e_links->e_index; 43911440Smckusick if (ep->e_sibling != NIL) 44011440Smckusick tep->e_sibling = 44111440Smckusick (struct entry *)ep->e_sibling->e_index; 44211440Smckusick if (ep->e_entries != NIL) 44311440Smckusick tep->e_entries = 44411440Smckusick (struct entry *)ep->e_entries->e_index; 44511440Smckusick if (ep->e_next != NIL) 44611440Smckusick tep->e_next = 44711440Smckusick (struct entry *)ep->e_next->e_index; 44811734Smckusick (void) fwrite((char *)tep, sizeof(struct entry), 1, fd); 44910314Smckusick } 45010314Smckusick } 45111440Smckusick /* 45211440Smckusick * Convert entry pointers to indexes, and output 45311440Smckusick */ 45411440Smckusick for (i = 0; i < entrytblsize; i++) { 45511440Smckusick if (entry[i] == NIL) 45611440Smckusick tentry = NIL; 45711440Smckusick else 45811440Smckusick tentry = (struct entry *)entry[i]->e_index; 45911734Smckusick (void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd); 46011440Smckusick } 46110314Smckusick hdr.volno = checkpt; 46210314Smckusick hdr.maxino = maxino; 46311440Smckusick hdr.entrytblsize = entrytblsize; 46411646Smckusick hdr.stringsize = stroff; 46511303Smckusick hdr.dumptime = dumptime; 46611303Smckusick hdr.dumpdate = dumpdate; 467*18497Smckusick hdr.ntrec = ntrec; 46811734Smckusick (void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd); 46910314Smckusick if (ferror(fd)) { 47010314Smckusick perror("fwrite"); 47110314Smckusick panic("output error to file %s writing symbol table\n", 47210314Smckusick filename); 47310314Smckusick } 47411734Smckusick (void) fclose(fd); 47510314Smckusick } 47610314Smckusick 47710314Smckusick /* 47810314Smckusick * Initialize a symbol table from a file 47910314Smckusick */ 48010314Smckusick initsymtable(filename) 48110314Smckusick char *filename; 48210314Smckusick { 48310314Smckusick char *base; 48410314Smckusick long tblsize; 48510314Smckusick register struct entry *ep; 48610314Smckusick struct entry *baseep, *lep; 48710314Smckusick struct symtableheader hdr; 48810314Smckusick struct stat stbuf; 48910314Smckusick register long i; 49010314Smckusick int fd; 49110314Smckusick 49210314Smckusick vprintf(stdout, "Initialize symbol table.\n"); 49311440Smckusick if (filename == NULL) { 49411440Smckusick entrytblsize = maxino / HASHFACTOR; 49511440Smckusick entry = (struct entry **) 49611440Smckusick calloc((unsigned)entrytblsize, sizeof(struct entry *)); 49711440Smckusick if (entry == (struct entry **)NIL) 49811440Smckusick panic("no memory for entry table\n"); 49912221Smckusick ep = addentry(".", ROOTINO, NODE); 50012221Smckusick ep->e_flags |= NEW; 50111440Smckusick return; 50211440Smckusick } 50310314Smckusick if ((fd = open(filename, 0)) < 0) { 50410314Smckusick perror("open"); 50510314Smckusick panic("cannot open symbol table file %s\n", filename); 50610314Smckusick } 50710314Smckusick if (fstat(fd, &stbuf) < 0) { 50810314Smckusick perror("stat"); 50910314Smckusick panic("cannot stat symbol table file %s\n", filename); 51010314Smckusick } 51110314Smckusick tblsize = stbuf.st_size - sizeof(struct symtableheader); 51212439Smckusick base = calloc(sizeof(char), (unsigned)tblsize); 51310314Smckusick if (base == NULL) 51410314Smckusick panic("cannot allocate space for symbol table\n"); 51510314Smckusick if (read(fd, base, (int)tblsize) < 0 || 51610314Smckusick read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) { 51710314Smckusick perror("read"); 51810314Smckusick panic("cannot read symbol table file %s\n", filename); 51910314Smckusick } 52011303Smckusick switch (command) { 52111303Smckusick case 'r': 52211303Smckusick /* 52311303Smckusick * For normal continuation, insure that we are using 52411303Smckusick * the next incremental tape 52511303Smckusick */ 52611440Smckusick if (hdr.dumpdate != dumptime) { 52711440Smckusick if (hdr.dumpdate < dumptime) 52811303Smckusick fprintf(stderr, "Incremental tape too low\n"); 52911303Smckusick else 53011303Smckusick fprintf(stderr, "Incremental tape too high\n"); 53111303Smckusick done(1); 53211303Smckusick } 53311303Smckusick break; 53411303Smckusick case 'R': 53511303Smckusick /* 53611303Smckusick * For restart, insure that we are using the same tape 53711303Smckusick */ 53811324Smckusick curfile.action = SKIP; 53911324Smckusick dumptime = hdr.dumptime; 54011324Smckusick dumpdate = hdr.dumpdate; 541*18497Smckusick if (!bflag) 542*18497Smckusick newtapebuf(hdr.ntrec); 54311324Smckusick getvol(hdr.volno); 54411303Smckusick break; 54511303Smckusick default: 54611303Smckusick panic("initsymtable called from command %c\n", command); 54711303Smckusick break; 54811303Smckusick } 54910314Smckusick maxino = hdr.maxino; 55011440Smckusick entrytblsize = hdr.entrytblsize; 55111440Smckusick entry = (struct entry **) 55211440Smckusick (base + tblsize - (entrytblsize * sizeof(struct entry *))); 55311440Smckusick baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry)); 55411440Smckusick lep = (struct entry *)entry; 55511440Smckusick for (i = 0; i < entrytblsize; i++) { 55610314Smckusick if (entry[i] == NIL) 55710314Smckusick continue; 55810314Smckusick entry[i] = &baseep[(long)entry[i]]; 55910314Smckusick } 56011440Smckusick for (ep = &baseep[1]; ep < lep; ep++) { 56110314Smckusick ep->e_name = base + (long)ep->e_name; 56210314Smckusick ep->e_parent = &baseep[(long)ep->e_parent]; 56311440Smckusick if (ep->e_sibling != NIL) 56411440Smckusick ep->e_sibling = &baseep[(long)ep->e_sibling]; 56511440Smckusick if (ep->e_links != NIL) 56611440Smckusick ep->e_links = &baseep[(long)ep->e_links]; 56711440Smckusick if (ep->e_entries != NIL) 56811440Smckusick ep->e_entries = &baseep[(long)ep->e_entries]; 56911440Smckusick if (ep->e_next != NIL) 57011440Smckusick ep->e_next = &baseep[(long)ep->e_next]; 57110314Smckusick } 57210314Smckusick } 573