xref: /csrg-svn/sbin/restore/symtab.c (revision 10314)
1*10314Smckusick /* Copyright (c) 1983 Regents of the University of California */
2*10314Smckusick 
3*10314Smckusick #ifndef lint
4*10314Smckusick static char sccsid[] = "@(#)symtab.c	3.5	(Berkeley)	83/01/16";
5*10314Smckusick #endif
6*10314Smckusick 
7*10314Smckusick #include "restore.h"
8*10314Smckusick #include <sys/stat.h>
9*10314Smckusick 
10*10314Smckusick struct symtableheader {
11*10314Smckusick 	long	volno;
12*10314Smckusick 	long	stringsize;
13*10314Smckusick 	long	entrytblsize;
14*10314Smckusick 	time_t	dumptime;
15*10314Smckusick 	time_t	dumpdate;
16*10314Smckusick 	ino_t	maxino;
17*10314Smckusick };
18*10314Smckusick 
19*10314Smckusick static struct entry *freelist = NIL;
20*10314Smckusick static struct entry **entry;
21*10314Smckusick static long entrytblsize;
22*10314Smckusick /* used to scale maxino to get inode hash table size */
23*10314Smckusick #define HASHFACTOR 5
24*10314Smckusick 
25*10314Smckusick /*
26*10314Smckusick  * Look up an entry by inode number
27*10314Smckusick  */
28*10314Smckusick struct entry *
29*10314Smckusick lookupino(inum)
30*10314Smckusick 	ino_t inum;
31*10314Smckusick {
32*10314Smckusick 	register struct entry *ep;
33*10314Smckusick 
34*10314Smckusick 	if (inum < ROOTINO || inum >= maxino)
35*10314Smckusick 		return (NIL);
36*10314Smckusick 	for (ep = entry[inum % entrytblsize]; ep != NIL; ep = ep->e_next)
37*10314Smckusick 		if (ep->e_ino == inum)
38*10314Smckusick 			return (ep);
39*10314Smckusick 	return (NIL);
40*10314Smckusick }
41*10314Smckusick 
42*10314Smckusick /*
43*10314Smckusick  * Add an entry into the entry table
44*10314Smckusick  */
45*10314Smckusick addino(inum, np)
46*10314Smckusick 	ino_t inum;
47*10314Smckusick 	struct entry *np;
48*10314Smckusick {
49*10314Smckusick 	struct entry **epp;
50*10314Smckusick 
51*10314Smckusick 	if (inum < ROOTINO || inum >= maxino)
52*10314Smckusick 		panic("addino: out of range %d\n", inum);
53*10314Smckusick 	epp = &entry[inum % entrytblsize];
54*10314Smckusick 	np->e_next = *epp;
55*10314Smckusick 	*epp = np;
56*10314Smckusick 	if (dflag)
57*10314Smckusick 		for (np = np->e_next; np != NIL; np = np->e_next)
58*10314Smckusick 			if (np->e_ino == inum)
59*10314Smckusick 				badentry(np, "duplicate inum");
60*10314Smckusick }
61*10314Smckusick 
62*10314Smckusick /*
63*10314Smckusick  * Delete an entry from the entry table
64*10314Smckusick  */
65*10314Smckusick deleteino(inum)
66*10314Smckusick 	ino_t inum;
67*10314Smckusick {
68*10314Smckusick 	register struct entry *next;
69*10314Smckusick 	struct entry **prev;
70*10314Smckusick 
71*10314Smckusick 	if (inum < ROOTINO || inum >= maxino)
72*10314Smckusick 		panic("deleteino: out of range %d\n", inum);
73*10314Smckusick 	prev = &entry[inum % entrytblsize];
74*10314Smckusick 	for (next = *prev; next != NIL; next = next->e_next) {
75*10314Smckusick 		if (next->e_ino == inum) {
76*10314Smckusick 			*prev = next->e_next;
77*10314Smckusick 			return;
78*10314Smckusick 		}
79*10314Smckusick 		prev = &next->e_next;
80*10314Smckusick 	}
81*10314Smckusick 	panic("deleteino: %d not found\n", inum);
82*10314Smckusick }
83*10314Smckusick 
84*10314Smckusick /*
85*10314Smckusick  * Look up an entry by name
86*10314Smckusick  */
87*10314Smckusick struct entry *
88*10314Smckusick lookupname(name)
89*10314Smckusick 	char *name;
90*10314Smckusick {
91*10314Smckusick 	register struct entry *ep;
92*10314Smckusick 	register char *np, *cp;
93*10314Smckusick 	char buf[BUFSIZ];
94*10314Smckusick 
95*10314Smckusick 	cp = name;
96*10314Smckusick 	for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) {
97*10314Smckusick 		for (np = buf; *cp != '/' && *cp != '\0'; )
98*10314Smckusick 			*np++ = *cp++;
99*10314Smckusick 		*np = '\0';
100*10314Smckusick 		for ( ; ep != NIL; ep = ep->e_sibling)
101*10314Smckusick 			if (strcmp(ep->e_name, buf) == 0)
102*10314Smckusick 				break;
103*10314Smckusick 		if (ep == NIL)
104*10314Smckusick 			break;
105*10314Smckusick 		if (*cp++ == '\0')
106*10314Smckusick 			return (ep);
107*10314Smckusick 	}
108*10314Smckusick 	return (NIL);
109*10314Smckusick }
110*10314Smckusick 
111*10314Smckusick /*
112*10314Smckusick  * Look up the parent of a pathname
113*10314Smckusick  */
114*10314Smckusick struct entry *
115*10314Smckusick lookupparent(name)
116*10314Smckusick 	char *name;
117*10314Smckusick {
118*10314Smckusick 	struct entry *ep;
119*10314Smckusick 	char *tailindex;
120*10314Smckusick 
121*10314Smckusick 	tailindex = rindex(name, '/');
122*10314Smckusick 	if (tailindex == 0)
123*10314Smckusick 		return (NIL);
124*10314Smckusick 	*tailindex = '\0';
125*10314Smckusick 	ep = lookupname(name);
126*10314Smckusick 	*tailindex = '/';
127*10314Smckusick 	if (ep == NIL)
128*10314Smckusick 		return (NIL);
129*10314Smckusick 	if (ep->e_type != NODE)
130*10314Smckusick 		panic("%s is not a directory\n", name);
131*10314Smckusick 	return (ep);
132*10314Smckusick }
133*10314Smckusick 
134*10314Smckusick /*
135*10314Smckusick  * Determine the current pathname of a node or leaf
136*10314Smckusick  */
137*10314Smckusick char *
138*10314Smckusick myname(ep)
139*10314Smckusick 	register struct entry *ep;
140*10314Smckusick {
141*10314Smckusick 	register char *cp;
142*10314Smckusick 	static char namebuf[BUFSIZ];
143*10314Smckusick 
144*10314Smckusick 	for (cp = &namebuf[BUFSIZ - 2]; cp > &namebuf[ep->e_namlen]; ) {
145*10314Smckusick 		cp -= ep->e_namlen;
146*10314Smckusick 		bcopy(ep->e_name, cp, (long)ep->e_namlen);
147*10314Smckusick 		if (ep == lookupino(ROOTINO))
148*10314Smckusick 			return (cp);
149*10314Smckusick 		*(--cp) = '/';
150*10314Smckusick 		ep = ep->e_parent;
151*10314Smckusick 	}
152*10314Smckusick 	panic("%s: pathname too long\n", cp);
153*10314Smckusick 	return(cp);
154*10314Smckusick }
155*10314Smckusick 
156*10314Smckusick /*
157*10314Smckusick  * add an entry to the symbol table
158*10314Smckusick  */
159*10314Smckusick struct entry *
160*10314Smckusick addentry(name, inum, type)
161*10314Smckusick 	char *name;
162*10314Smckusick 	ino_t inum;
163*10314Smckusick 	int type;
164*10314Smckusick {
165*10314Smckusick 	register struct entry *np, *ep;
166*10314Smckusick 
167*10314Smckusick 	if (freelist != NIL) {
168*10314Smckusick 		np = freelist;
169*10314Smckusick 		freelist = np->e_sibling;
170*10314Smckusick 		bzero((char *)np, (long)sizeof(struct entry));
171*10314Smckusick 	} else {
172*10314Smckusick 		np = (struct entry *)calloc(1, sizeof(struct entry));
173*10314Smckusick 	}
174*10314Smckusick 	np->e_ino = inum;
175*10314Smckusick 	np->e_type = type & ~LINK;
176*10314Smckusick 	ep = lookupparent(name);
177*10314Smckusick 	if (ep == NIL) {
178*10314Smckusick 		if (inum != ROOTINO || lookupino(ROOTINO) != NIL)
179*10314Smckusick 			panic("bad name to addentry %s\n", name);
180*10314Smckusick 		np->e_name = savename(name);
181*10314Smckusick 		np->e_namlen = strlen(name);
182*10314Smckusick 		np->e_parent = np;
183*10314Smckusick 		addino(ROOTINO, np);
184*10314Smckusick 		return (np);
185*10314Smckusick 	}
186*10314Smckusick 	np->e_name = savename(rindex(name, '/') + 1);
187*10314Smckusick 	np->e_namlen = strlen(np->e_name);
188*10314Smckusick 	np->e_parent = ep;
189*10314Smckusick 	np->e_sibling = ep->e_entries;
190*10314Smckusick 	ep->e_entries = np;
191*10314Smckusick 	if (type & LINK) {
192*10314Smckusick 		ep = lookupino(inum);
193*10314Smckusick 		if (ep == NIL)
194*10314Smckusick 			panic("link to non-existant name\n");
195*10314Smckusick 		np->e_links = ep->e_links;
196*10314Smckusick 		ep->e_links = np;
197*10314Smckusick 	} else if (inum != 0) {
198*10314Smckusick 		if (lookupino(inum) != NIL)
199*10314Smckusick 			panic("duplicate entry\n");
200*10314Smckusick 		addino(inum, np);
201*10314Smckusick 	}
202*10314Smckusick 	return (np);
203*10314Smckusick }
204*10314Smckusick 
205*10314Smckusick /*
206*10314Smckusick  * delete an entry from the symbol table
207*10314Smckusick  */
208*10314Smckusick freeentry(ep)
209*10314Smckusick 	register struct entry *ep;
210*10314Smckusick {
211*10314Smckusick 	register struct entry *np;
212*10314Smckusick 
213*10314Smckusick 	np = lookupino(ep->e_ino);
214*10314Smckusick 	if (np == NIL)
215*10314Smckusick 		badentry(ep, "lookupino failed");
216*10314Smckusick 	if (ep->e_flags != REMOVED)
217*10314Smckusick 		badentry(ep, "not marked REMOVED");
218*10314Smckusick 	if (np->e_type == NODE) {
219*10314Smckusick 		if (np == ep && np->e_links != NIL)
220*10314Smckusick 			badentry(ep, "freeing referenced directory");
221*10314Smckusick 		if (ep->e_entries != NIL)
222*10314Smckusick 			badentry(ep, "freeing non-empty directory");
223*10314Smckusick 	}
224*10314Smckusick 	if (np == ep) {
225*10314Smckusick 		deleteino(ep->e_ino);
226*10314Smckusick 		addino(ep->e_ino, ep->e_links);
227*10314Smckusick 	} else {
228*10314Smckusick 		for (; np != NIL; np = np->e_links) {
229*10314Smckusick 			if (np->e_links == ep) {
230*10314Smckusick 				np->e_links = ep->e_links;
231*10314Smckusick 				break;
232*10314Smckusick 			}
233*10314Smckusick 		}
234*10314Smckusick 		if (np == NIL)
235*10314Smckusick 			badentry(ep, "link not found");
236*10314Smckusick 	}
237*10314Smckusick 	removeentry(ep);
238*10314Smckusick 	free(ep->e_name);
239*10314Smckusick 	ep->e_sibling = freelist;
240*10314Smckusick 	freelist = ep;
241*10314Smckusick }
242*10314Smckusick 
243*10314Smckusick /*
244*10314Smckusick  * Relocate an entry in the tree structure
245*10314Smckusick  */
246*10314Smckusick moveentry(ep, newname)
247*10314Smckusick 	register struct entry *ep;
248*10314Smckusick 	char *newname;
249*10314Smckusick {
250*10314Smckusick 	struct entry *np;
251*10314Smckusick 	char *cp;
252*10314Smckusick 	long len;
253*10314Smckusick 
254*10314Smckusick 	np = lookupparent(newname);
255*10314Smckusick 	if (np == NIL)
256*10314Smckusick 		badentry(ep, "cannot move ROOT");
257*10314Smckusick 	if (np != ep->e_parent) {
258*10314Smckusick 		removeentry(ep);
259*10314Smckusick 		ep->e_parent = np;
260*10314Smckusick 		ep->e_sibling = np->e_entries;
261*10314Smckusick 		np->e_entries = ep;
262*10314Smckusick 	}
263*10314Smckusick 	cp = rindex(newname, '/') + 1;
264*10314Smckusick 	len = strlen(cp);
265*10314Smckusick 	if (ep->e_flags & TMPNAME)
266*10314Smckusick 		ep->e_namlen--;
267*10314Smckusick 	if (ep->e_namlen >= len) {
268*10314Smckusick 		strcpy(ep->e_name, cp);
269*10314Smckusick 	} else {
270*10314Smckusick 		free(ep->e_name);
271*10314Smckusick 		ep->e_name = savename(cp);
272*10314Smckusick 	}
273*10314Smckusick 	ep->e_namlen = len;
274*10314Smckusick 	if (cp[len - 1] == TMPCHAR)
275*10314Smckusick 		ep->e_flags |= TMPNAME;
276*10314Smckusick 	else
277*10314Smckusick 		ep->e_flags &= ~TMPNAME;
278*10314Smckusick }
279*10314Smckusick 
280*10314Smckusick /*
281*10314Smckusick  * Remove an entry in the tree structure
282*10314Smckusick  */
283*10314Smckusick removeentry(ep)
284*10314Smckusick 	register struct entry *ep;
285*10314Smckusick {
286*10314Smckusick 	register struct entry *np;
287*10314Smckusick 
288*10314Smckusick 	np = ep->e_parent;
289*10314Smckusick 	if (np->e_entries == ep) {
290*10314Smckusick 		np->e_entries = ep->e_sibling;
291*10314Smckusick 	} else {
292*10314Smckusick 		for (np = np->e_entries; np != NIL; np = np->e_sibling) {
293*10314Smckusick 			if (np->e_sibling == ep) {
294*10314Smckusick 				np->e_sibling = ep->e_sibling;
295*10314Smckusick 				break;
296*10314Smckusick 			}
297*10314Smckusick 		}
298*10314Smckusick 		if (np == NIL)
299*10314Smckusick 			badentry(ep, "cannot find entry in parent list");
300*10314Smckusick 	}
301*10314Smckusick }
302*10314Smckusick 
303*10314Smckusick /*
304*10314Smckusick  * allocate space for a name
305*10314Smckusick  */
306*10314Smckusick char *
307*10314Smckusick savename(name)
308*10314Smckusick 	char *name;
309*10314Smckusick {
310*10314Smckusick 	long len;
311*10314Smckusick 	char *cp;
312*10314Smckusick 
313*10314Smckusick 	if (name == NULL)
314*10314Smckusick 		panic("bad name\n");
315*10314Smckusick 	len = strlen(name) + 2;
316*10314Smckusick 	len = (len + 3) & ~3;
317*10314Smckusick 	cp = malloc((unsigned)len);
318*10314Smckusick 	(void) strcpy(cp, name);
319*10314Smckusick 	return (cp);
320*10314Smckusick }
321*10314Smckusick 
322*10314Smckusick /*
323*10314Smckusick  * dump a snapshot of the symbol table
324*10314Smckusick  */
325*10314Smckusick dumpsymtable(filename, checkpt)
326*10314Smckusick 	char *filename;
327*10314Smckusick 	long checkpt;
328*10314Smckusick {
329*10314Smckusick 	register struct entry *ep;
330*10314Smckusick 	register ino_t i;
331*10314Smckusick 	struct entry *next;
332*10314Smckusick 	long mynum = 0, stroff = 0;
333*10314Smckusick 	FILE *fd;
334*10314Smckusick 	struct symtableheader hdr;
335*10314Smckusick 
336*10314Smckusick 	vprintf(stdout, "Check pointing the restore\n");
337*10314Smckusick 	if ((fd = fopen(filename, "w")) == NULL) {
338*10314Smckusick 		perror("fopen");
339*10314Smckusick 		panic("cannot create save file %s for symbol table\n",
340*10314Smckusick 			filename);
341*10314Smckusick 	}
342*10314Smckusick 	clearerr(fd);
343*10314Smckusick 	/*
344*10314Smckusick 	 * Assign indicies to each entry
345*10314Smckusick 	 * Write out the string entries
346*10314Smckusick 	 */
347*10314Smckusick 	for (i = ROOTINO; i < maxino; i++) {
348*10314Smckusick 		for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
349*10314Smckusick 			ep->e_index = mynum++;
350*10314Smckusick 			fwrite(ep->e_name, sizeof(char), (int)ep->e_namlen, fd);
351*10314Smckusick 			ep->e_name = (char *)stroff;
352*10314Smckusick 			stroff += ep->e_namlen;
353*10314Smckusick 		}
354*10314Smckusick 	}
355*10314Smckusick 	/*
356*10314Smckusick 	 * Convert entry pointers to indexes, and output
357*10314Smckusick 	 */
358*10314Smckusick 	for (i = 0; i < entrytblsize; i++) {
359*10314Smckusick 		if (entry[i] == NIL)
360*10314Smckusick 			continue;
361*10314Smckusick 		entry[i] = (struct entry *)entry[i]->e_index;
362*10314Smckusick 	}
363*10314Smckusick 	fwrite((char *)entry, sizeof(struct entry *), (int)entrytblsize, fd);
364*10314Smckusick 	/*
365*10314Smckusick 	 * Convert pointers to indexes, and output
366*10314Smckusick 	 */
367*10314Smckusick 	for (i = ROOTINO; i < maxino; i++) {
368*10314Smckusick 		for (ep = lookupino(i); ep != NIL; ep = next) {
369*10314Smckusick 			next = ep->e_links;
370*10314Smckusick 			ep->e_parent = (struct entry *)ep->e_parent->e_index;
371*10314Smckusick 			if (ep->e_links != NIL)
372*10314Smckusick 				ep->e_links =
373*10314Smckusick 					(struct entry *)ep->e_links->e_index;
374*10314Smckusick 			if (ep->e_sibling != NIL)
375*10314Smckusick 				ep->e_sibling =
376*10314Smckusick 					(struct entry *)ep->e_sibling->e_index;
377*10314Smckusick 			if (ep->e_entries != NIL)
378*10314Smckusick 				ep->e_entries =
379*10314Smckusick 					(struct entry *)ep->e_entries->e_index;
380*10314Smckusick 			if (ep->e_next != NIL)
381*10314Smckusick 				ep->e_next =
382*10314Smckusick 					(struct entry *)ep->e_next->e_index;
383*10314Smckusick 			fwrite((char *)ep, sizeof(struct entry), 1, fd);
384*10314Smckusick 		}
385*10314Smckusick 	}
386*10314Smckusick 	hdr.volno = checkpt;
387*10314Smckusick 	hdr.maxino = maxino;
388*10314Smckusick 	hdr.entrytblsize = entrytblsize;
389*10314Smckusick 	hdr.stringsize = stroff;
390*10314Smckusick 	hdr.dumptime = dumptime;
391*10314Smckusick 	hdr.dumpdate = dumpdate;
392*10314Smckusick 	fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd);
393*10314Smckusick 	if (ferror(fd)) {
394*10314Smckusick 		perror("fwrite");
395*10314Smckusick 		panic("output error to file %s writing symbol table\n",
396*10314Smckusick 			filename);
397*10314Smckusick 	}
398*10314Smckusick 	fclose(fd);
399*10314Smckusick }
400*10314Smckusick 
401*10314Smckusick /*
402*10314Smckusick  * Initialize a symbol table from a file
403*10314Smckusick  */
404*10314Smckusick initsymtable(filename)
405*10314Smckusick 	char *filename;
406*10314Smckusick {
407*10314Smckusick 	char *base;
408*10314Smckusick 	long tblsize;
409*10314Smckusick 	register struct entry *ep;
410*10314Smckusick 	struct entry *baseep, *lep;
411*10314Smckusick 	struct symtableheader hdr;
412*10314Smckusick 	struct stat stbuf;
413*10314Smckusick 	register long i;
414*10314Smckusick 	int fd;
415*10314Smckusick 
416*10314Smckusick 	vprintf(stdout, "Initialize symbol table.\n");
417*10314Smckusick 	if (filename == NULL) {
418*10314Smckusick 		entrytblsize = maxino / HASHFACTOR;
419*10314Smckusick 		entry = (struct entry **)
420*10314Smckusick 			calloc((unsigned)entrytblsize, sizeof(struct entry *));
421*10314Smckusick 		if (entry == (struct entry **)NIL)
422*10314Smckusick 			panic("no memory for entry table\n");
423*10314Smckusick 		(void)addentry(".", ROOTINO, NODE);
424*10314Smckusick 		return;
425*10314Smckusick 	}
426*10314Smckusick 	if ((fd = open(filename, 0)) < 0) {
427*10314Smckusick 		perror("open");
428*10314Smckusick 		panic("cannot open symbol table file %s\n", filename);
429*10314Smckusick 	}
430*10314Smckusick 	if (fstat(fd, &stbuf) < 0) {
431*10314Smckusick 		perror("stat");
432*10314Smckusick 		panic("cannot stat symbol table file %s\n", filename);
433*10314Smckusick 	}
434*10314Smckusick 	tblsize = stbuf.st_size - sizeof(struct symtableheader);
435*10314Smckusick 	base = malloc((unsigned)tblsize);
436*10314Smckusick 	if (base == NULL)
437*10314Smckusick 		panic("cannot allocate space for symbol table\n");
438*10314Smckusick 	if (read(fd, base, (int)tblsize) < 0 ||
439*10314Smckusick 	    read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) {
440*10314Smckusick 		perror("read");
441*10314Smckusick 		panic("cannot read symbol table file %s\n", filename);
442*10314Smckusick 	}
443*10314Smckusick 	switch (command) {
444*10314Smckusick 	case 'r':
445*10314Smckusick 		/*
446*10314Smckusick 		 * For normal continuation, insure that we are using
447*10314Smckusick 		 * the next incremental tape
448*10314Smckusick 		 */
449*10314Smckusick 		if (hdr.dumptime != dumpdate) {
450*10314Smckusick 			if (hdr.dumptime < dumpdate)
451*10314Smckusick 				fprintf(stderr, "Incremental tape too low\n");
452*10314Smckusick 			else
453*10314Smckusick 				fprintf(stderr, "Incremental tape too high\n");
454*10314Smckusick 			done(1);
455*10314Smckusick 		}
456*10314Smckusick 		break;
457*10314Smckusick 	case 'R':
458*10314Smckusick 		/*
459*10314Smckusick 		 * For restart, insure that we are using the same tape
460*10314Smckusick 		 */
461*10314Smckusick 		curfile.action = SKIP;
462*10314Smckusick 		dumptime = hdr.dumptime;
463*10314Smckusick 		dumpdate = hdr.dumpdate;
464*10314Smckusick 		getvol(hdr.volno);
465*10314Smckusick 		break;
466*10314Smckusick 	default:
467*10314Smckusick 		panic("initsymtable called from command %c\n", command);
468*10314Smckusick 		break;
469*10314Smckusick 	}
470*10314Smckusick 	maxino = hdr.maxino;
471*10314Smckusick 	entrytblsize = hdr.entrytblsize;
472*10314Smckusick 	entry = (struct entry **)(base + hdr.stringsize);
473*10314Smckusick 	baseep = (struct entry *)(&entry[entrytblsize]);
474*10314Smckusick 	lep = (struct entry *)(base + tblsize);
475*10314Smckusick 	for (i = 0; i < entrytblsize; i++) {
476*10314Smckusick 		if (entry[i] == NIL)
477*10314Smckusick 			continue;
478*10314Smckusick 		entry[i] = &baseep[(long)entry[i]];
479*10314Smckusick 	}
480*10314Smckusick 	for (ep = baseep; ep < lep; ep++) {
481*10314Smckusick 		ep->e_name = base + (long)ep->e_name;
482*10314Smckusick 		ep->e_parent = &baseep[(long)ep->e_parent];
483*10314Smckusick 		if (ep->e_sibling != NIL)
484*10314Smckusick 			ep->e_sibling = &baseep[(long)ep->e_sibling];
485*10314Smckusick 		if (ep->e_links != NIL)
486*10314Smckusick 			ep->e_links = &baseep[(long)ep->e_links];
487*10314Smckusick 		if (ep->e_entries != NIL)
488*10314Smckusick 			ep->e_entries = &baseep[(long)ep->e_entries];
489*10314Smckusick 		if (ep->e_next != NIL)
490*10314Smckusick 			ep->e_next = &baseep[(long)ep->e_next];
491*10314Smckusick 	}
492*10314Smckusick }
493