110314Smckusick /* Copyright (c) 1983 Regents of the University of California */ 210314Smckusick 310314Smckusick #ifndef lint 4*12456Smckusick static char sccsid[] = "@(#)symtab.c 3.12 (Berkeley) 83/05/15"; 510314Smckusick #endif 610314Smckusick 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> 1811646Smckusick #include <dir.h> 1910314Smckusick 2011646Smckusick /* 2111646Smckusick * The following variables define the inode symbol table. 2211646Smckusick * The primary hash table is dynamically allocated based on 2311646Smckusick * the number of inodes in the file system (maxino), scaled by 2411646Smckusick * HASHFACTOR. The variable "entry" points to the hash table; 2511646Smckusick * the variable "entrytblsize" indicates its size (in entries). 2611646Smckusick */ 2711646Smckusick #define HASHFACTOR 5 2811440Smckusick static struct entry **entry; 2911440Smckusick static long entrytblsize; 3010314Smckusick 3110314Smckusick /* 3210314Smckusick * Look up an entry by inode number 3310314Smckusick */ 3410314Smckusick struct entry * 3510314Smckusick lookupino(inum) 3610314Smckusick ino_t inum; 3710314Smckusick { 3811440Smckusick register struct entry *ep; 3910314Smckusick 4011440Smckusick if (inum < ROOTINO || inum >= maxino) 4111440Smckusick return (NIL); 4211440Smckusick for (ep = entry[inum % entrytblsize]; ep != NIL; ep = ep->e_next) 4311440Smckusick if (ep->e_ino == inum) 4411440Smckusick return (ep); 4511440Smckusick return (NIL); 4610314Smckusick } 4710314Smckusick 4810314Smckusick /* 4910314Smckusick * Add an entry into the entry table 5010314Smckusick */ 5110314Smckusick addino(inum, np) 5211440Smckusick ino_t inum; 5310314Smckusick struct entry *np; 5410314Smckusick { 5511440Smckusick struct entry **epp; 5610314Smckusick 5711440Smckusick if (inum < ROOTINO || inum >= maxino) 5811440Smckusick panic("addino: out of range %d\n", inum); 5911440Smckusick epp = &entry[inum % entrytblsize]; 6011440Smckusick np->e_ino = inum; 6111440Smckusick np->e_next = *epp; 6211440Smckusick *epp = np; 6311440Smckusick if (dflag) 6411440Smckusick for (np = np->e_next; np != NIL; np = np->e_next) 6511440Smckusick if (np->e_ino == inum) 6611440Smckusick badentry(np, "duplicate inum"); 6710314Smckusick } 6810314Smckusick 6910314Smckusick /* 7010314Smckusick * Delete an entry from the entry table 7110314Smckusick */ 7210314Smckusick deleteino(inum) 7311440Smckusick ino_t inum; 7410314Smckusick { 7511440Smckusick register struct entry *next; 7611440Smckusick struct entry **prev; 7710314Smckusick 7811440Smckusick if (inum < ROOTINO || inum >= maxino) 7911440Smckusick panic("deleteino: out of range %d\n", inum); 8011440Smckusick prev = &entry[inum % entrytblsize]; 8111440Smckusick for (next = *prev; next != NIL; next = next->e_next) { 8211440Smckusick if (next->e_ino == inum) { 8311440Smckusick next->e_ino = 0; 8411440Smckusick *prev = next->e_next; 8511440Smckusick return; 8611440Smckusick } 8711440Smckusick prev = &next->e_next; 8811440Smckusick } 8911440Smckusick panic("deleteino: %d not found\n", inum); 9010314Smckusick } 9110314Smckusick 9210314Smckusick /* 9310314Smckusick * Look up an entry by name 9410314Smckusick */ 9510314Smckusick struct entry * 9610314Smckusick lookupname(name) 9710314Smckusick char *name; 9810314Smckusick { 9910314Smckusick register struct entry *ep; 10010314Smckusick register char *np, *cp; 10111646Smckusick char buf[MAXPATHLEN]; 10210314Smckusick 10310314Smckusick cp = name; 10410314Smckusick for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) { 10510314Smckusick for (np = buf; *cp != '/' && *cp != '\0'; ) 10610314Smckusick *np++ = *cp++; 10710314Smckusick *np = '\0'; 10810314Smckusick for ( ; ep != NIL; ep = ep->e_sibling) 10910314Smckusick if (strcmp(ep->e_name, buf) == 0) 11010314Smckusick break; 11110314Smckusick if (ep == NIL) 11210314Smckusick break; 11311311Smckusick if (*cp++ == '\0') 11410314Smckusick return (ep); 11510314Smckusick } 11611311Smckusick return (NIL); 11710314Smckusick } 11810314Smckusick 11910314Smckusick /* 12010314Smckusick * Look up the parent of a pathname 12110314Smckusick */ 12210314Smckusick struct entry * 12310314Smckusick lookupparent(name) 12410314Smckusick char *name; 12510314Smckusick { 12610314Smckusick struct entry *ep; 12710314Smckusick char *tailindex; 12810314Smckusick 12910314Smckusick tailindex = rindex(name, '/'); 13010314Smckusick if (tailindex == 0) 13110314Smckusick return (NIL); 13210314Smckusick *tailindex = '\0'; 13310314Smckusick ep = lookupname(name); 13411311Smckusick *tailindex = '/'; 13510314Smckusick if (ep == NIL) 13610314Smckusick return (NIL); 13710314Smckusick if (ep->e_type != NODE) 13810314Smckusick panic("%s is not a directory\n", name); 13910314Smckusick return (ep); 14010314Smckusick } 14110314Smckusick 14210314Smckusick /* 14310314Smckusick * Determine the current pathname of a node or leaf 14410314Smckusick */ 14510314Smckusick char * 14610314Smckusick myname(ep) 14710314Smckusick register struct entry *ep; 14810314Smckusick { 14910314Smckusick register char *cp; 15011646Smckusick static char namebuf[MAXPATHLEN]; 15110314Smckusick 15211646Smckusick for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) { 15310314Smckusick cp -= ep->e_namlen; 15410314Smckusick bcopy(ep->e_name, cp, (long)ep->e_namlen); 15510314Smckusick if (ep == lookupino(ROOTINO)) 15610314Smckusick return (cp); 15710314Smckusick *(--cp) = '/'; 15810314Smckusick ep = ep->e_parent; 15910314Smckusick } 16010314Smckusick panic("%s: pathname too long\n", cp); 16110314Smckusick return(cp); 16210314Smckusick } 16310314Smckusick 16410314Smckusick /* 16511646Smckusick * Unused symbol table entries are linked together on a freelist 16611646Smckusick * headed by the following pointer. 16711646Smckusick */ 16811646Smckusick static struct entry *freelist = NIL; 16911646Smckusick 17011646Smckusick /* 17110314Smckusick * add an entry to the symbol table 17210314Smckusick */ 17310314Smckusick struct entry * 17410314Smckusick addentry(name, inum, type) 17510314Smckusick char *name; 17610314Smckusick ino_t inum; 17710314Smckusick int type; 17810314Smckusick { 17910314Smckusick register struct entry *np, *ep; 18010314Smckusick 18110314Smckusick if (freelist != NIL) { 18210314Smckusick np = freelist; 18311440Smckusick freelist = np->e_next; 18410314Smckusick bzero((char *)np, (long)sizeof(struct entry)); 18510314Smckusick } else { 18610314Smckusick np = (struct entry *)calloc(1, sizeof(struct entry)); 18710314Smckusick } 18810314Smckusick np->e_type = type & ~LINK; 18910314Smckusick ep = lookupparent(name); 19010314Smckusick if (ep == NIL) { 19110314Smckusick if (inum != ROOTINO || lookupino(ROOTINO) != NIL) 19210314Smckusick panic("bad name to addentry %s\n", name); 19310314Smckusick np->e_name = savename(name); 19410314Smckusick np->e_namlen = strlen(name); 19510314Smckusick np->e_parent = np; 19610314Smckusick addino(ROOTINO, np); 19710314Smckusick return (np); 19810314Smckusick } 19910314Smckusick np->e_name = savename(rindex(name, '/') + 1); 20010314Smckusick np->e_namlen = strlen(np->e_name); 20110314Smckusick np->e_parent = ep; 20210314Smckusick np->e_sibling = ep->e_entries; 20310314Smckusick ep->e_entries = np; 20410314Smckusick if (type & LINK) { 20510314Smckusick ep = lookupino(inum); 20610314Smckusick if (ep == NIL) 20710314Smckusick panic("link to non-existant name\n"); 20811741Smckusick np->e_ino = inum; 20910314Smckusick np->e_links = ep->e_links; 21010314Smckusick ep->e_links = np; 21110314Smckusick } else if (inum != 0) { 21210314Smckusick if (lookupino(inum) != NIL) 21310314Smckusick panic("duplicate entry\n"); 21410314Smckusick addino(inum, np); 21510314Smckusick } 21610314Smckusick return (np); 21710314Smckusick } 21810314Smckusick 21910314Smckusick /* 22010314Smckusick * delete an entry from the symbol table 22110314Smckusick */ 22210314Smckusick freeentry(ep) 22310314Smckusick register struct entry *ep; 22410314Smckusick { 22510314Smckusick register struct entry *np; 226*12456Smckusick ino_t inum; 22710314Smckusick 22810314Smckusick if (ep->e_flags != REMOVED) 22910314Smckusick badentry(ep, "not marked REMOVED"); 23011440Smckusick if (ep->e_type == NODE) { 23111440Smckusick if (ep->e_links != NIL) 23210314Smckusick badentry(ep, "freeing referenced directory"); 23310314Smckusick if (ep->e_entries != NIL) 23410314Smckusick badentry(ep, "freeing non-empty directory"); 23510314Smckusick } 23611440Smckusick if (ep->e_ino != 0) { 23711440Smckusick np = lookupino(ep->e_ino); 23811440Smckusick if (np == NIL) 23911440Smckusick badentry(ep, "lookupino failed"); 24011440Smckusick if (np == ep) { 241*12456Smckusick inum = ep->e_ino; 242*12456Smckusick deleteino(inum); 24311440Smckusick if (ep->e_links != NIL) 244*12456Smckusick addino(inum, ep->e_links); 24511440Smckusick } else { 24611440Smckusick for (; np != NIL; np = np->e_links) { 24711440Smckusick if (np->e_links == ep) { 24811440Smckusick np->e_links = ep->e_links; 24911440Smckusick break; 25011440Smckusick } 25110314Smckusick } 25211440Smckusick if (np == NIL) 25311440Smckusick badentry(ep, "link not found"); 25410314Smckusick } 25510314Smckusick } 25610314Smckusick removeentry(ep); 25711646Smckusick freename(ep->e_name); 25811440Smckusick ep->e_next = freelist; 25910314Smckusick freelist = ep; 26010314Smckusick } 26110314Smckusick 26210314Smckusick /* 26310314Smckusick * Relocate an entry in the tree structure 26410314Smckusick */ 26510314Smckusick moveentry(ep, newname) 26610314Smckusick register struct entry *ep; 26710314Smckusick char *newname; 26810314Smckusick { 26910314Smckusick struct entry *np; 27010314Smckusick char *cp; 27110314Smckusick 27210314Smckusick np = lookupparent(newname); 27310314Smckusick if (np == NIL) 27410314Smckusick badentry(ep, "cannot move ROOT"); 27510314Smckusick if (np != ep->e_parent) { 27610314Smckusick removeentry(ep); 27710314Smckusick ep->e_parent = np; 27810314Smckusick ep->e_sibling = np->e_entries; 27910314Smckusick np->e_entries = ep; 28010314Smckusick } 28110314Smckusick cp = rindex(newname, '/') + 1; 28211646Smckusick freename(ep->e_name); 28311646Smckusick ep->e_name = savename(cp); 28411646Smckusick ep->e_namlen = strlen(cp); 28511646Smckusick if (strcmp(gentempname(ep), ep->e_name) == 0) 28610314Smckusick ep->e_flags |= TMPNAME; 28710314Smckusick else 28810314Smckusick ep->e_flags &= ~TMPNAME; 28910314Smckusick } 29010314Smckusick 29110314Smckusick /* 29210314Smckusick * Remove an entry in the tree structure 29310314Smckusick */ 29410314Smckusick removeentry(ep) 29510314Smckusick register struct entry *ep; 29610314Smckusick { 29710314Smckusick register struct entry *np; 29810314Smckusick 29910314Smckusick np = ep->e_parent; 30010314Smckusick if (np->e_entries == ep) { 30110314Smckusick np->e_entries = ep->e_sibling; 30210314Smckusick } else { 30310314Smckusick for (np = np->e_entries; np != NIL; np = np->e_sibling) { 30410314Smckusick if (np->e_sibling == ep) { 30510314Smckusick np->e_sibling = ep->e_sibling; 30610314Smckusick break; 30710314Smckusick } 30810314Smckusick } 30910314Smckusick if (np == NIL) 31010314Smckusick badentry(ep, "cannot find entry in parent list"); 31110314Smckusick } 31210314Smckusick } 31310314Smckusick 31410314Smckusick /* 31511646Smckusick * Table of unused string entries, sorted by length. 31611646Smckusick * 31711646Smckusick * Entries are allocated in STRTBLINCR sized pieces so that names 31811646Smckusick * of similar lengths can use the same entry. The value of STRTBLINCR 31911646Smckusick * is chosen so that every entry has at least enough space to hold 32011646Smckusick * a "struct strtbl" header. Thus every entry can be linked onto an 32111646Smckusick * apprpriate free list. 32211646Smckusick * 32311646Smckusick * NB. The macro "allocsize" below assumes that "struct strhdr" 32411646Smckusick * has a size that is a power of two. 32510314Smckusick */ 32611646Smckusick struct strhdr { 32711646Smckusick struct strhdr *next; 32811646Smckusick }; 32911646Smckusick 33011646Smckusick #define STRTBLINCR (sizeof(struct strhdr)) 33111646Smckusick #define allocsize(size) (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1)) 33211646Smckusick 33311646Smckusick static struct strhdr strtblhdr[allocsize(MAXNAMLEN) / STRTBLINCR]; 33411646Smckusick 33511646Smckusick /* 33611646Smckusick * Allocate space for a name. It first looks to see if it already 33711646Smckusick * has an appropriate sized entry, and if not allocates a new one. 33811646Smckusick */ 33910314Smckusick char * 34010314Smckusick savename(name) 34110314Smckusick char *name; 34210314Smckusick { 34311646Smckusick struct strhdr *np; 34410314Smckusick long len; 34511311Smckusick char *cp; 34610314Smckusick 34710314Smckusick if (name == NULL) 34810314Smckusick panic("bad name\n"); 34911646Smckusick len = strlen(name); 35011646Smckusick np = strtblhdr[len / STRTBLINCR].next; 35111646Smckusick if (np != NULL) { 35211646Smckusick strtblhdr[len / STRTBLINCR].next = np->next; 35311646Smckusick cp = (char *)np; 35411646Smckusick } else { 35511646Smckusick cp = malloc((unsigned)allocsize(len)); 35611646Smckusick if (cp == NULL) 35711646Smckusick panic("no space for string table\n"); 35811646Smckusick } 35911440Smckusick (void) strcpy(cp, name); 36011311Smckusick return (cp); 36110314Smckusick } 36210314Smckusick 36310314Smckusick /* 36411646Smckusick * Free space for a name. The resulting entry is linked onto the 36511646Smckusick * appropriate free list. 36611646Smckusick */ 36711646Smckusick freename(name) 36811646Smckusick char *name; 36911646Smckusick { 37011646Smckusick struct strhdr *tp, *np; 37111646Smckusick 37211646Smckusick tp = &strtblhdr[strlen(name) / STRTBLINCR]; 37311646Smckusick np = (struct strhdr *)name; 37411646Smckusick np->next = tp->next; 37511646Smckusick tp->next = np; 37611646Smckusick } 37711646Smckusick 37811646Smckusick /* 37911646Smckusick * Useful quantities placed at the end of a dumped symbol table. 38011646Smckusick */ 38111646Smckusick struct symtableheader { 38211646Smckusick long volno; 38311646Smckusick long stringsize; 38411646Smckusick long entrytblsize; 38511646Smckusick time_t dumptime; 38611646Smckusick time_t dumpdate; 38711646Smckusick ino_t maxino; 38811646Smckusick }; 38911646Smckusick 39011646Smckusick /* 39110314Smckusick * dump a snapshot of the symbol table 39210314Smckusick */ 39310314Smckusick dumpsymtable(filename, checkpt) 39410314Smckusick char *filename; 39510314Smckusick long checkpt; 39610314Smckusick { 39711440Smckusick register struct entry *ep, *tep; 39811440Smckusick register ino_t i; 39911440Smckusick struct entry temp, *tentry; 40011440Smckusick long mynum = 1, stroff = 0; 40110314Smckusick FILE *fd; 40210314Smckusick struct symtableheader hdr; 40310314Smckusick 40410314Smckusick vprintf(stdout, "Check pointing the restore\n"); 40510314Smckusick if ((fd = fopen(filename, "w")) == NULL) { 40610314Smckusick perror("fopen"); 40710314Smckusick panic("cannot create save file %s for symbol table\n", 40810314Smckusick filename); 40910314Smckusick } 41010314Smckusick clearerr(fd); 41110314Smckusick /* 41210314Smckusick * Assign indicies to each entry 41310314Smckusick * Write out the string entries 41410314Smckusick */ 41510314Smckusick for (i = ROOTINO; i < maxino; i++) { 41610314Smckusick for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 41711440Smckusick ep->e_index = mynum++; 41811734Smckusick (void) fwrite(ep->e_name, sizeof(char), 41911734Smckusick (int)allocsize(ep->e_namlen), fd); 42010314Smckusick } 42110314Smckusick } 42210314Smckusick /* 42310314Smckusick * Convert pointers to indexes, and output 42410314Smckusick */ 42511440Smckusick tep = &temp; 42611440Smckusick stroff = 0; 42710314Smckusick for (i = ROOTINO; i < maxino; i++) { 42811440Smckusick for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 42911734Smckusick bcopy((char *)ep, (char *)tep, 43011734Smckusick (long)sizeof(struct entry)); 43111440Smckusick tep->e_name = (char *)stroff; 43211646Smckusick stroff += allocsize(ep->e_namlen); 43311440Smckusick tep->e_parent = (struct entry *)ep->e_parent->e_index; 43411440Smckusick if (ep->e_links != NIL) 43511440Smckusick tep->e_links = 43611440Smckusick (struct entry *)ep->e_links->e_index; 43711440Smckusick if (ep->e_sibling != NIL) 43811440Smckusick tep->e_sibling = 43911440Smckusick (struct entry *)ep->e_sibling->e_index; 44011440Smckusick if (ep->e_entries != NIL) 44111440Smckusick tep->e_entries = 44211440Smckusick (struct entry *)ep->e_entries->e_index; 44311440Smckusick if (ep->e_next != NIL) 44411440Smckusick tep->e_next = 44511440Smckusick (struct entry *)ep->e_next->e_index; 44611734Smckusick (void) fwrite((char *)tep, sizeof(struct entry), 1, fd); 44710314Smckusick } 44810314Smckusick } 44911440Smckusick /* 45011440Smckusick * Convert entry pointers to indexes, and output 45111440Smckusick */ 45211440Smckusick for (i = 0; i < entrytblsize; i++) { 45311440Smckusick if (entry[i] == NIL) 45411440Smckusick tentry = NIL; 45511440Smckusick else 45611440Smckusick tentry = (struct entry *)entry[i]->e_index; 45711734Smckusick (void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd); 45811440Smckusick } 45910314Smckusick hdr.volno = checkpt; 46010314Smckusick hdr.maxino = maxino; 46111440Smckusick hdr.entrytblsize = entrytblsize; 46211646Smckusick hdr.stringsize = stroff; 46311303Smckusick hdr.dumptime = dumptime; 46411303Smckusick hdr.dumpdate = dumpdate; 46511734Smckusick (void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd); 46610314Smckusick if (ferror(fd)) { 46710314Smckusick perror("fwrite"); 46810314Smckusick panic("output error to file %s writing symbol table\n", 46910314Smckusick filename); 47010314Smckusick } 47111734Smckusick (void) fclose(fd); 47210314Smckusick } 47310314Smckusick 47410314Smckusick /* 47510314Smckusick * Initialize a symbol table from a file 47610314Smckusick */ 47710314Smckusick initsymtable(filename) 47810314Smckusick char *filename; 47910314Smckusick { 48010314Smckusick char *base; 48110314Smckusick long tblsize; 48210314Smckusick register struct entry *ep; 48310314Smckusick struct entry *baseep, *lep; 48410314Smckusick struct symtableheader hdr; 48510314Smckusick struct stat stbuf; 48610314Smckusick register long i; 48710314Smckusick int fd; 48810314Smckusick 48910314Smckusick vprintf(stdout, "Initialize symbol table.\n"); 49011440Smckusick if (filename == NULL) { 49111440Smckusick entrytblsize = maxino / HASHFACTOR; 49211440Smckusick entry = (struct entry **) 49311440Smckusick calloc((unsigned)entrytblsize, sizeof(struct entry *)); 49411440Smckusick if (entry == (struct entry **)NIL) 49511440Smckusick panic("no memory for entry table\n"); 49612221Smckusick ep = addentry(".", ROOTINO, NODE); 49712221Smckusick ep->e_flags |= NEW; 49811440Smckusick return; 49911440Smckusick } 50010314Smckusick if ((fd = open(filename, 0)) < 0) { 50110314Smckusick perror("open"); 50210314Smckusick panic("cannot open symbol table file %s\n", filename); 50310314Smckusick } 50410314Smckusick if (fstat(fd, &stbuf) < 0) { 50510314Smckusick perror("stat"); 50610314Smckusick panic("cannot stat symbol table file %s\n", filename); 50710314Smckusick } 50810314Smckusick tblsize = stbuf.st_size - sizeof(struct symtableheader); 50912439Smckusick base = calloc(sizeof(char), (unsigned)tblsize); 51010314Smckusick if (base == NULL) 51110314Smckusick panic("cannot allocate space for symbol table\n"); 51210314Smckusick if (read(fd, base, (int)tblsize) < 0 || 51310314Smckusick read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) { 51410314Smckusick perror("read"); 51510314Smckusick panic("cannot read symbol table file %s\n", filename); 51610314Smckusick } 51711303Smckusick switch (command) { 51811303Smckusick case 'r': 51911303Smckusick /* 52011303Smckusick * For normal continuation, insure that we are using 52111303Smckusick * the next incremental tape 52211303Smckusick */ 52311440Smckusick if (hdr.dumpdate != dumptime) { 52411440Smckusick if (hdr.dumpdate < dumptime) 52511303Smckusick fprintf(stderr, "Incremental tape too low\n"); 52611303Smckusick else 52711303Smckusick fprintf(stderr, "Incremental tape too high\n"); 52811303Smckusick done(1); 52911303Smckusick } 53011303Smckusick break; 53111303Smckusick case 'R': 53211303Smckusick /* 53311303Smckusick * For restart, insure that we are using the same tape 53411303Smckusick */ 53511324Smckusick curfile.action = SKIP; 53611324Smckusick dumptime = hdr.dumptime; 53711324Smckusick dumpdate = hdr.dumpdate; 53811324Smckusick getvol(hdr.volno); 53911303Smckusick break; 54011303Smckusick default: 54111303Smckusick panic("initsymtable called from command %c\n", command); 54211303Smckusick break; 54311303Smckusick } 54410314Smckusick maxino = hdr.maxino; 54511440Smckusick entrytblsize = hdr.entrytblsize; 54611440Smckusick entry = (struct entry **) 54711440Smckusick (base + tblsize - (entrytblsize * sizeof(struct entry *))); 54811440Smckusick baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry)); 54911440Smckusick lep = (struct entry *)entry; 55011440Smckusick for (i = 0; i < entrytblsize; i++) { 55110314Smckusick if (entry[i] == NIL) 55210314Smckusick continue; 55310314Smckusick entry[i] = &baseep[(long)entry[i]]; 55410314Smckusick } 55511440Smckusick for (ep = &baseep[1]; ep < lep; ep++) { 55610314Smckusick ep->e_name = base + (long)ep->e_name; 55710314Smckusick ep->e_parent = &baseep[(long)ep->e_parent]; 55811440Smckusick if (ep->e_sibling != NIL) 55911440Smckusick ep->e_sibling = &baseep[(long)ep->e_sibling]; 56011440Smckusick if (ep->e_links != NIL) 56111440Smckusick ep->e_links = &baseep[(long)ep->e_links]; 56211440Smckusick if (ep->e_entries != NIL) 56311440Smckusick ep->e_entries = &baseep[(long)ep->e_entries]; 56411440Smckusick if (ep->e_next != NIL) 56511440Smckusick ep->e_next = &baseep[(long)ep->e_next]; 56610314Smckusick } 56710314Smckusick } 568