110314Smckusick /* Copyright (c) 1983 Regents of the University of California */ 210314Smckusick 310314Smckusick #ifndef lint 4*11734Smckusick static char sccsid[] = "@(#)symtab.c 3.8 (Berkeley) 83/03/27"; 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"); 20810314Smckusick np->e_links = ep->e_links; 20910314Smckusick ep->e_links = np; 21010314Smckusick } else if (inum != 0) { 21110314Smckusick if (lookupino(inum) != NIL) 21210314Smckusick panic("duplicate entry\n"); 21310314Smckusick addino(inum, np); 21410314Smckusick } 21510314Smckusick return (np); 21610314Smckusick } 21710314Smckusick 21810314Smckusick /* 21910314Smckusick * delete an entry from the symbol table 22010314Smckusick */ 22110314Smckusick freeentry(ep) 22210314Smckusick register struct entry *ep; 22310314Smckusick { 22410314Smckusick register struct entry *np; 22510314Smckusick 22610314Smckusick if (ep->e_flags != REMOVED) 22710314Smckusick badentry(ep, "not marked REMOVED"); 22811440Smckusick if (ep->e_type == NODE) { 22911440Smckusick if (ep->e_links != NIL) 23010314Smckusick badentry(ep, "freeing referenced directory"); 23110314Smckusick if (ep->e_entries != NIL) 23210314Smckusick badentry(ep, "freeing non-empty directory"); 23310314Smckusick } 23411440Smckusick if (ep->e_ino != 0) { 23511440Smckusick np = lookupino(ep->e_ino); 23611440Smckusick if (np == NIL) 23711440Smckusick badentry(ep, "lookupino failed"); 23811440Smckusick if (np == ep) { 23911440Smckusick deleteino(ep->e_ino); 24011440Smckusick if (ep->e_links != NIL) 24111440Smckusick addino(ep->e_ino, ep->e_links); 24211440Smckusick } else { 24311440Smckusick for (; np != NIL; np = np->e_links) { 24411440Smckusick if (np->e_links == ep) { 24511440Smckusick np->e_links = ep->e_links; 24611440Smckusick break; 24711440Smckusick } 24810314Smckusick } 24911440Smckusick if (np == NIL) 25011440Smckusick badentry(ep, "link not found"); 25110314Smckusick } 25210314Smckusick } 25310314Smckusick removeentry(ep); 25411646Smckusick freename(ep->e_name); 25511440Smckusick ep->e_next = freelist; 25610314Smckusick freelist = ep; 25710314Smckusick } 25810314Smckusick 25910314Smckusick /* 26010314Smckusick * Relocate an entry in the tree structure 26110314Smckusick */ 26210314Smckusick moveentry(ep, newname) 26310314Smckusick register struct entry *ep; 26410314Smckusick char *newname; 26510314Smckusick { 26610314Smckusick struct entry *np; 26710314Smckusick char *cp; 26810314Smckusick 26910314Smckusick np = lookupparent(newname); 27010314Smckusick if (np == NIL) 27110314Smckusick badentry(ep, "cannot move ROOT"); 27210314Smckusick if (np != ep->e_parent) { 27310314Smckusick removeentry(ep); 27410314Smckusick ep->e_parent = np; 27510314Smckusick ep->e_sibling = np->e_entries; 27610314Smckusick np->e_entries = ep; 27710314Smckusick } 27810314Smckusick cp = rindex(newname, '/') + 1; 27911646Smckusick freename(ep->e_name); 28011646Smckusick ep->e_name = savename(cp); 28111646Smckusick ep->e_namlen = strlen(cp); 28211646Smckusick if (strcmp(gentempname(ep), ep->e_name) == 0) 28310314Smckusick ep->e_flags |= TMPNAME; 28410314Smckusick else 28510314Smckusick ep->e_flags &= ~TMPNAME; 28610314Smckusick } 28710314Smckusick 28810314Smckusick /* 28910314Smckusick * Remove an entry in the tree structure 29010314Smckusick */ 29110314Smckusick removeentry(ep) 29210314Smckusick register struct entry *ep; 29310314Smckusick { 29410314Smckusick register struct entry *np; 29510314Smckusick 29610314Smckusick np = ep->e_parent; 29710314Smckusick if (np->e_entries == ep) { 29810314Smckusick np->e_entries = ep->e_sibling; 29910314Smckusick } else { 30010314Smckusick for (np = np->e_entries; np != NIL; np = np->e_sibling) { 30110314Smckusick if (np->e_sibling == ep) { 30210314Smckusick np->e_sibling = ep->e_sibling; 30310314Smckusick break; 30410314Smckusick } 30510314Smckusick } 30610314Smckusick if (np == NIL) 30710314Smckusick badentry(ep, "cannot find entry in parent list"); 30810314Smckusick } 30910314Smckusick } 31010314Smckusick 31110314Smckusick /* 31211646Smckusick * Table of unused string entries, sorted by length. 31311646Smckusick * 31411646Smckusick * Entries are allocated in STRTBLINCR sized pieces so that names 31511646Smckusick * of similar lengths can use the same entry. The value of STRTBLINCR 31611646Smckusick * is chosen so that every entry has at least enough space to hold 31711646Smckusick * a "struct strtbl" header. Thus every entry can be linked onto an 31811646Smckusick * apprpriate free list. 31911646Smckusick * 32011646Smckusick * NB. The macro "allocsize" below assumes that "struct strhdr" 32111646Smckusick * has a size that is a power of two. 32210314Smckusick */ 32311646Smckusick struct strhdr { 32411646Smckusick struct strhdr *next; 32511646Smckusick }; 32611646Smckusick 32711646Smckusick #define STRTBLINCR (sizeof(struct strhdr)) 32811646Smckusick #define allocsize(size) (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1)) 32911646Smckusick 33011646Smckusick static struct strhdr strtblhdr[allocsize(MAXNAMLEN) / STRTBLINCR]; 33111646Smckusick 33211646Smckusick /* 33311646Smckusick * Allocate space for a name. It first looks to see if it already 33411646Smckusick * has an appropriate sized entry, and if not allocates a new one. 33511646Smckusick */ 33610314Smckusick char * 33710314Smckusick savename(name) 33810314Smckusick char *name; 33910314Smckusick { 34011646Smckusick struct strhdr *np; 34110314Smckusick long len; 34211311Smckusick char *cp; 34310314Smckusick 34410314Smckusick if (name == NULL) 34510314Smckusick panic("bad name\n"); 34611646Smckusick len = strlen(name); 34711646Smckusick np = strtblhdr[len / STRTBLINCR].next; 34811646Smckusick if (np != NULL) { 34911646Smckusick strtblhdr[len / STRTBLINCR].next = np->next; 35011646Smckusick cp = (char *)np; 35111646Smckusick } else { 35211646Smckusick cp = malloc((unsigned)allocsize(len)); 35311646Smckusick if (cp == NULL) 35411646Smckusick panic("no space for string table\n"); 35511646Smckusick } 35611440Smckusick (void) strcpy(cp, name); 35711311Smckusick return (cp); 35810314Smckusick } 35910314Smckusick 36010314Smckusick /* 36111646Smckusick * Free space for a name. The resulting entry is linked onto the 36211646Smckusick * appropriate free list. 36311646Smckusick */ 36411646Smckusick freename(name) 36511646Smckusick char *name; 36611646Smckusick { 36711646Smckusick struct strhdr *tp, *np; 36811646Smckusick 36911646Smckusick tp = &strtblhdr[strlen(name) / STRTBLINCR]; 37011646Smckusick np = (struct strhdr *)name; 37111646Smckusick np->next = tp->next; 37211646Smckusick tp->next = np; 37311646Smckusick } 37411646Smckusick 37511646Smckusick /* 37611646Smckusick * Useful quantities placed at the end of a dumped symbol table. 37711646Smckusick */ 37811646Smckusick struct symtableheader { 37911646Smckusick long volno; 38011646Smckusick long stringsize; 38111646Smckusick long entrytblsize; 38211646Smckusick time_t dumptime; 38311646Smckusick time_t dumpdate; 38411646Smckusick ino_t maxino; 38511646Smckusick }; 38611646Smckusick 38711646Smckusick /* 38810314Smckusick * dump a snapshot of the symbol table 38910314Smckusick */ 39010314Smckusick dumpsymtable(filename, checkpt) 39110314Smckusick char *filename; 39210314Smckusick long checkpt; 39310314Smckusick { 39411440Smckusick register struct entry *ep, *tep; 39511440Smckusick register ino_t i; 39611440Smckusick struct entry temp, *tentry; 39711440Smckusick long mynum = 1, stroff = 0; 39810314Smckusick FILE *fd; 39910314Smckusick struct symtableheader hdr; 40010314Smckusick 40110314Smckusick vprintf(stdout, "Check pointing the restore\n"); 40210314Smckusick if ((fd = fopen(filename, "w")) == NULL) { 40310314Smckusick perror("fopen"); 40410314Smckusick panic("cannot create save file %s for symbol table\n", 40510314Smckusick filename); 40610314Smckusick } 40710314Smckusick clearerr(fd); 40810314Smckusick /* 40910314Smckusick * Assign indicies to each entry 41010314Smckusick * Write out the string entries 41110314Smckusick */ 41210314Smckusick for (i = ROOTINO; i < maxino; i++) { 41310314Smckusick for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 41411440Smckusick ep->e_index = mynum++; 415*11734Smckusick (void) fwrite(ep->e_name, sizeof(char), 416*11734Smckusick (int)allocsize(ep->e_namlen), fd); 41710314Smckusick } 41810314Smckusick } 41910314Smckusick /* 42010314Smckusick * Convert pointers to indexes, and output 42110314Smckusick */ 42211440Smckusick tep = &temp; 42311440Smckusick stroff = 0; 42410314Smckusick for (i = ROOTINO; i < maxino; i++) { 42511440Smckusick for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 426*11734Smckusick bcopy((char *)ep, (char *)tep, 427*11734Smckusick (long)sizeof(struct entry)); 42811440Smckusick tep->e_name = (char *)stroff; 42911646Smckusick stroff += allocsize(ep->e_namlen); 43011440Smckusick tep->e_parent = (struct entry *)ep->e_parent->e_index; 43111440Smckusick if (ep->e_links != NIL) 43211440Smckusick tep->e_links = 43311440Smckusick (struct entry *)ep->e_links->e_index; 43411440Smckusick if (ep->e_sibling != NIL) 43511440Smckusick tep->e_sibling = 43611440Smckusick (struct entry *)ep->e_sibling->e_index; 43711440Smckusick if (ep->e_entries != NIL) 43811440Smckusick tep->e_entries = 43911440Smckusick (struct entry *)ep->e_entries->e_index; 44011440Smckusick if (ep->e_next != NIL) 44111440Smckusick tep->e_next = 44211440Smckusick (struct entry *)ep->e_next->e_index; 443*11734Smckusick (void) fwrite((char *)tep, sizeof(struct entry), 1, fd); 44410314Smckusick } 44510314Smckusick } 44611440Smckusick /* 44711440Smckusick * Convert entry pointers to indexes, and output 44811440Smckusick */ 44911440Smckusick for (i = 0; i < entrytblsize; i++) { 45011440Smckusick if (entry[i] == NIL) 45111440Smckusick tentry = NIL; 45211440Smckusick else 45311440Smckusick tentry = (struct entry *)entry[i]->e_index; 454*11734Smckusick (void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd); 45511440Smckusick } 45610314Smckusick hdr.volno = checkpt; 45710314Smckusick hdr.maxino = maxino; 45811440Smckusick hdr.entrytblsize = entrytblsize; 45911646Smckusick hdr.stringsize = stroff; 46011303Smckusick hdr.dumptime = dumptime; 46111303Smckusick hdr.dumpdate = dumpdate; 462*11734Smckusick (void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd); 46310314Smckusick if (ferror(fd)) { 46410314Smckusick perror("fwrite"); 46510314Smckusick panic("output error to file %s writing symbol table\n", 46610314Smckusick filename); 46710314Smckusick } 468*11734Smckusick (void) fclose(fd); 46910314Smckusick } 47010314Smckusick 47110314Smckusick /* 47210314Smckusick * Initialize a symbol table from a file 47310314Smckusick */ 47410314Smckusick initsymtable(filename) 47510314Smckusick char *filename; 47610314Smckusick { 47710314Smckusick char *base; 47810314Smckusick long tblsize; 47910314Smckusick register struct entry *ep; 48010314Smckusick struct entry *baseep, *lep; 48110314Smckusick struct symtableheader hdr; 48210314Smckusick struct stat stbuf; 48310314Smckusick register long i; 48410314Smckusick int fd; 48510314Smckusick 48610314Smckusick vprintf(stdout, "Initialize symbol table.\n"); 48711440Smckusick if (filename == NULL) { 48811440Smckusick entrytblsize = maxino / HASHFACTOR; 48911440Smckusick entry = (struct entry **) 49011440Smckusick calloc((unsigned)entrytblsize, sizeof(struct entry *)); 49111440Smckusick if (entry == (struct entry **)NIL) 49211440Smckusick panic("no memory for entry table\n"); 49311440Smckusick (void)addentry(".", ROOTINO, NODE); 49411440Smckusick return; 49511440Smckusick } 49610314Smckusick if ((fd = open(filename, 0)) < 0) { 49710314Smckusick perror("open"); 49810314Smckusick panic("cannot open symbol table file %s\n", filename); 49910314Smckusick } 50010314Smckusick if (fstat(fd, &stbuf) < 0) { 50110314Smckusick perror("stat"); 50210314Smckusick panic("cannot stat symbol table file %s\n", filename); 50310314Smckusick } 50410314Smckusick tblsize = stbuf.st_size - sizeof(struct symtableheader); 50511440Smckusick base = calloc(sizeof(char *), (unsigned)tblsize); 50610314Smckusick if (base == NULL) 50710314Smckusick panic("cannot allocate space for symbol table\n"); 50810314Smckusick if (read(fd, base, (int)tblsize) < 0 || 50910314Smckusick read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) { 51010314Smckusick perror("read"); 51110314Smckusick panic("cannot read symbol table file %s\n", filename); 51210314Smckusick } 51311303Smckusick switch (command) { 51411303Smckusick case 'r': 51511303Smckusick /* 51611303Smckusick * For normal continuation, insure that we are using 51711303Smckusick * the next incremental tape 51811303Smckusick */ 51911440Smckusick if (hdr.dumpdate != dumptime) { 52011440Smckusick if (hdr.dumpdate < dumptime) 52111303Smckusick fprintf(stderr, "Incremental tape too low\n"); 52211303Smckusick else 52311303Smckusick fprintf(stderr, "Incremental tape too high\n"); 52411303Smckusick done(1); 52511303Smckusick } 52611303Smckusick break; 52711303Smckusick case 'R': 52811303Smckusick /* 52911303Smckusick * For restart, insure that we are using the same tape 53011303Smckusick */ 53111324Smckusick curfile.action = SKIP; 53211324Smckusick dumptime = hdr.dumptime; 53311324Smckusick dumpdate = hdr.dumpdate; 53411324Smckusick getvol(hdr.volno); 53511303Smckusick break; 53611303Smckusick default: 53711303Smckusick panic("initsymtable called from command %c\n", command); 53811303Smckusick break; 53911303Smckusick } 54010314Smckusick maxino = hdr.maxino; 54111440Smckusick entrytblsize = hdr.entrytblsize; 54211440Smckusick entry = (struct entry **) 54311440Smckusick (base + tblsize - (entrytblsize * sizeof(struct entry *))); 54411440Smckusick baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry)); 54511440Smckusick lep = (struct entry *)entry; 54611440Smckusick for (i = 0; i < entrytblsize; i++) { 54710314Smckusick if (entry[i] == NIL) 54810314Smckusick continue; 54910314Smckusick entry[i] = &baseep[(long)entry[i]]; 55010314Smckusick } 55111440Smckusick for (ep = &baseep[1]; ep < lep; ep++) { 55210314Smckusick ep->e_name = base + (long)ep->e_name; 55310314Smckusick ep->e_parent = &baseep[(long)ep->e_parent]; 55411440Smckusick if (ep->e_sibling != NIL) 55511440Smckusick ep->e_sibling = &baseep[(long)ep->e_sibling]; 55611440Smckusick if (ep->e_links != NIL) 55711440Smckusick ep->e_links = &baseep[(long)ep->e_links]; 55811440Smckusick if (ep->e_entries != NIL) 55911440Smckusick ep->e_entries = &baseep[(long)ep->e_entries]; 56011440Smckusick if (ep->e_next != NIL) 56111440Smckusick ep->e_next = &baseep[(long)ep->e_next]; 56210314Smckusick } 56310314Smckusick } 564