symtab.c revision 40668
11558Srgrimes/*
21558Srgrimes * Copyright (c) 1983, 1993
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * Redistribution and use in source and binary forms, with or without
61558Srgrimes * modification, are permitted provided that the following conditions
71558Srgrimes * are met:
81558Srgrimes * 1. Redistributions of source code must retain the above copyright
91558Srgrimes *    notice, this list of conditions and the following disclaimer.
101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111558Srgrimes *    notice, this list of conditions and the following disclaimer in the
121558Srgrimes *    documentation and/or other materials provided with the distribution.
131558Srgrimes * 3. All advertising materials mentioning features or use of this software
141558Srgrimes *    must display the following acknowledgement:
151558Srgrimes *	This product includes software developed by the University of
161558Srgrimes *	California, Berkeley and its contributors.
171558Srgrimes * 4. Neither the name of the University nor the names of its contributors
181558Srgrimes *    may be used to endorse or promote products derived from this software
191558Srgrimes *    without specific prior written permission.
201558Srgrimes *
211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311558Srgrimes * SUCH DAMAGE.
321558Srgrimes */
331558Srgrimes
341558Srgrimes#ifndef lint
3537906Scharnier#if 0
3623685Speterstatic char sccsid[] = "@(#)symtab.c	8.3 (Berkeley) 4/28/95";
3737906Scharnier#endif
3837906Scharnierstatic const char rcsid[] =
3940668Sdima	"$Id: symtab.c,v 1.5 1998/07/28 06:20:13 charnier Exp $";
401558Srgrimes#endif /* not lint */
411558Srgrimes
421558Srgrimes/*
431558Srgrimes * These routines maintain the symbol table which tracks the state
441558Srgrimes * of the file system being restored. They provide lookup by either
451558Srgrimes * name or inode number. They also provide for creation, deletion,
461558Srgrimes * and renaming of entries. Because of the dynamic nature of pathnames,
471558Srgrimes * names should not be saved, but always constructed just before they
481558Srgrimes * are needed, by calling "myname".
491558Srgrimes */
501558Srgrimes
511558Srgrimes#include <sys/param.h>
521558Srgrimes#include <sys/stat.h>
531558Srgrimes
541558Srgrimes#include <ufs/ufs/dinode.h>
551558Srgrimes
561558Srgrimes#include <errno.h>
571558Srgrimes#include <fcntl.h>
581558Srgrimes#include <stdio.h>
591558Srgrimes#include <stdlib.h>
601558Srgrimes#include <string.h>
611558Srgrimes#include <unistd.h>
621558Srgrimes
631558Srgrimes#include "restore.h"
641558Srgrimes#include "extern.h"
651558Srgrimes
661558Srgrimes/*
671558Srgrimes * The following variables define the inode symbol table.
681558Srgrimes * The primary hash table is dynamically allocated based on
691558Srgrimes * the number of inodes in the file system (maxino), scaled by
701558Srgrimes * HASHFACTOR. The variable "entry" points to the hash table;
711558Srgrimes * the variable "entrytblsize" indicates its size (in entries).
721558Srgrimes */
731558Srgrimes#define HASHFACTOR 5
741558Srgrimesstatic struct entry **entry;
751558Srgrimesstatic long entrytblsize;
761558Srgrimes
771558Srgrimesstatic void		 addino __P((ino_t, struct entry *));
781558Srgrimesstatic struct entry	*lookupparent __P((char *));
791558Srgrimesstatic void		 removeentry __P((struct entry *));
801558Srgrimes
811558Srgrimes/*
821558Srgrimes * Look up an entry by inode number
831558Srgrimes */
841558Srgrimesstruct entry *
851558Srgrimeslookupino(inum)
861558Srgrimes	ino_t inum;
871558Srgrimes{
881558Srgrimes	register struct entry *ep;
891558Srgrimes
9023685Speter	if (inum < WINO || inum >= maxino)
911558Srgrimes		return (NULL);
921558Srgrimes	for (ep = entry[inum % entrytblsize]; ep != NULL; ep = ep->e_next)
931558Srgrimes		if (ep->e_ino == inum)
941558Srgrimes			return (ep);
951558Srgrimes	return (NULL);
961558Srgrimes}
971558Srgrimes
981558Srgrimes/*
991558Srgrimes * Add an entry into the entry table
1001558Srgrimes */
1011558Srgrimesstatic void
1021558Srgrimesaddino(inum, np)
1031558Srgrimes	ino_t inum;
1041558Srgrimes	struct entry *np;
1051558Srgrimes{
1061558Srgrimes	struct entry **epp;
1071558Srgrimes
10823685Speter	if (inum < WINO || inum >= maxino)
1091558Srgrimes		panic("addino: out of range %d\n", inum);
1101558Srgrimes	epp = &entry[inum % entrytblsize];
1111558Srgrimes	np->e_ino = inum;
1121558Srgrimes	np->e_next = *epp;
1131558Srgrimes	*epp = np;
1141558Srgrimes	if (dflag)
1151558Srgrimes		for (np = np->e_next; np != NULL; np = np->e_next)
1161558Srgrimes			if (np->e_ino == inum)
1171558Srgrimes				badentry(np, "duplicate inum");
1181558Srgrimes}
1191558Srgrimes
1201558Srgrimes/*
1211558Srgrimes * Delete an entry from the entry table
1221558Srgrimes */
1231558Srgrimesvoid
1241558Srgrimesdeleteino(inum)
1251558Srgrimes	ino_t inum;
1261558Srgrimes{
1271558Srgrimes	register struct entry *next;
1281558Srgrimes	struct entry **prev;
1291558Srgrimes
13023685Speter	if (inum < WINO || inum >= maxino)
1311558Srgrimes		panic("deleteino: out of range %d\n", inum);
1321558Srgrimes	prev = &entry[inum % entrytblsize];
1331558Srgrimes	for (next = *prev; next != NULL; next = next->e_next) {
1341558Srgrimes		if (next->e_ino == inum) {
1351558Srgrimes			next->e_ino = 0;
1361558Srgrimes			*prev = next->e_next;
1371558Srgrimes			return;
1381558Srgrimes		}
1391558Srgrimes		prev = &next->e_next;
1401558Srgrimes	}
1411558Srgrimes	panic("deleteino: %d not found\n", inum);
1421558Srgrimes}
1431558Srgrimes
1441558Srgrimes/*
1451558Srgrimes * Look up an entry by name
1461558Srgrimes */
1471558Srgrimesstruct entry *
1481558Srgrimeslookupname(name)
1491558Srgrimes	char *name;
1501558Srgrimes{
1511558Srgrimes	register struct entry *ep;
1521558Srgrimes	register char *np, *cp;
1531558Srgrimes	char buf[MAXPATHLEN];
1541558Srgrimes
1551558Srgrimes	cp = name;
1561558Srgrimes	for (ep = lookupino(ROOTINO); ep != NULL; ep = ep->e_entries) {
15722482Seivind		for (np = buf; *cp != '/' && *cp != '\0' &&
15822482Seivind				np < &buf[sizeof(buf)]; )
1591558Srgrimes			*np++ = *cp++;
16022482Seivind		if (np == &buf[sizeof(buf)])
16122482Seivind			break;
1621558Srgrimes		*np = '\0';
1631558Srgrimes		for ( ; ep != NULL; ep = ep->e_sibling)
1641558Srgrimes			if (strcmp(ep->e_name, buf) == 0)
1651558Srgrimes				break;
1661558Srgrimes		if (ep == NULL)
1671558Srgrimes			break;
1681558Srgrimes		if (*cp++ == '\0')
1691558Srgrimes			return (ep);
1701558Srgrimes	}
1711558Srgrimes	return (NULL);
1721558Srgrimes}
1731558Srgrimes
1741558Srgrimes/*
1751558Srgrimes * Look up the parent of a pathname
1761558Srgrimes */
1771558Srgrimesstatic struct entry *
1781558Srgrimeslookupparent(name)
1791558Srgrimes	char *name;
1801558Srgrimes{
1811558Srgrimes	struct entry *ep;
1821558Srgrimes	char *tailindex;
1831558Srgrimes
18423685Speter	tailindex = strrchr(name, '/');
1851558Srgrimes	if (tailindex == NULL)
1861558Srgrimes		return (NULL);
1871558Srgrimes	*tailindex = '\0';
1881558Srgrimes	ep = lookupname(name);
1891558Srgrimes	*tailindex = '/';
1901558Srgrimes	if (ep == NULL)
1911558Srgrimes		return (NULL);
1921558Srgrimes	if (ep->e_type != NODE)
1931558Srgrimes		panic("%s is not a directory\n", name);
1941558Srgrimes	return (ep);
1951558Srgrimes}
1961558Srgrimes
1971558Srgrimes/*
1981558Srgrimes * Determine the current pathname of a node or leaf
1991558Srgrimes */
2001558Srgrimeschar *
2011558Srgrimesmyname(ep)
2021558Srgrimes	register struct entry *ep;
2031558Srgrimes{
2041558Srgrimes	register char *cp;
2051558Srgrimes	static char namebuf[MAXPATHLEN];
2061558Srgrimes
2071558Srgrimes	for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) {
2081558Srgrimes		cp -= ep->e_namlen;
20923685Speter		memmove(cp, ep->e_name, (long)ep->e_namlen);
2101558Srgrimes		if (ep == lookupino(ROOTINO))
2111558Srgrimes			return (cp);
2121558Srgrimes		*(--cp) = '/';
2131558Srgrimes		ep = ep->e_parent;
2141558Srgrimes	}
2151558Srgrimes	panic("%s: pathname too long\n", cp);
2161558Srgrimes	return(cp);
2171558Srgrimes}
2181558Srgrimes
2191558Srgrimes/*
22037906Scharnier * Unused symbol table entries are linked together on a free list
2211558Srgrimes * headed by the following pointer.
2221558Srgrimes */
2231558Srgrimesstatic struct entry *freelist = NULL;
2241558Srgrimes
2251558Srgrimes/*
2261558Srgrimes * add an entry to the symbol table
2271558Srgrimes */
2281558Srgrimesstruct entry *
2291558Srgrimesaddentry(name, inum, type)
2301558Srgrimes	char *name;
2311558Srgrimes	ino_t inum;
2321558Srgrimes	int type;
2331558Srgrimes{
2341558Srgrimes	register struct entry *np, *ep;
2351558Srgrimes
2361558Srgrimes	if (freelist != NULL) {
2371558Srgrimes		np = freelist;
2381558Srgrimes		freelist = np->e_next;
23923685Speter		memset(np, 0, (long)sizeof(struct entry));
2401558Srgrimes	} else {
2411558Srgrimes		np = (struct entry *)calloc(1, sizeof(struct entry));
2421558Srgrimes		if (np == NULL)
2431558Srgrimes			panic("no memory to extend symbol table\n");
2441558Srgrimes	}
2451558Srgrimes	np->e_type = type & ~LINK;
2461558Srgrimes	ep = lookupparent(name);
2471558Srgrimes	if (ep == NULL) {
2481558Srgrimes		if (inum != ROOTINO || lookupino(ROOTINO) != NULL)
2491558Srgrimes			panic("bad name to addentry %s\n", name);
2501558Srgrimes		np->e_name = savename(name);
2511558Srgrimes		np->e_namlen = strlen(name);
2521558Srgrimes		np->e_parent = np;
2531558Srgrimes		addino(ROOTINO, np);
2541558Srgrimes		return (np);
2551558Srgrimes	}
25623685Speter	np->e_name = savename(strrchr(name, '/') + 1);
2571558Srgrimes	np->e_namlen = strlen(np->e_name);
2581558Srgrimes	np->e_parent = ep;
2591558Srgrimes	np->e_sibling = ep->e_entries;
2601558Srgrimes	ep->e_entries = np;
2611558Srgrimes	if (type & LINK) {
2621558Srgrimes		ep = lookupino(inum);
2631558Srgrimes		if (ep == NULL)
26437906Scharnier			panic("link to non-existent name\n");
2651558Srgrimes		np->e_ino = inum;
2661558Srgrimes		np->e_links = ep->e_links;
2671558Srgrimes		ep->e_links = np;
2681558Srgrimes	} else if (inum != 0) {
2691558Srgrimes		if (lookupino(inum) != NULL)
2701558Srgrimes			panic("duplicate entry\n");
2711558Srgrimes		addino(inum, np);
2721558Srgrimes	}
2731558Srgrimes	return (np);
2741558Srgrimes}
2751558Srgrimes
2761558Srgrimes/*
2771558Srgrimes * delete an entry from the symbol table
2781558Srgrimes */
2791558Srgrimesvoid
2801558Srgrimesfreeentry(ep)
2811558Srgrimes	register struct entry *ep;
2821558Srgrimes{
2831558Srgrimes	register struct entry *np;
2841558Srgrimes	ino_t inum;
2851558Srgrimes
2861558Srgrimes	if (ep->e_flags != REMOVED)
2871558Srgrimes		badentry(ep, "not marked REMOVED");
2881558Srgrimes	if (ep->e_type == NODE) {
2891558Srgrimes		if (ep->e_links != NULL)
2901558Srgrimes			badentry(ep, "freeing referenced directory");
2911558Srgrimes		if (ep->e_entries != NULL)
2921558Srgrimes			badentry(ep, "freeing non-empty directory");
2931558Srgrimes	}
2941558Srgrimes	if (ep->e_ino != 0) {
2951558Srgrimes		np = lookupino(ep->e_ino);
2961558Srgrimes		if (np == NULL)
2971558Srgrimes			badentry(ep, "lookupino failed");
2981558Srgrimes		if (np == ep) {
2991558Srgrimes			inum = ep->e_ino;
3001558Srgrimes			deleteino(inum);
3011558Srgrimes			if (ep->e_links != NULL)
3021558Srgrimes				addino(inum, ep->e_links);
3031558Srgrimes		} else {
3041558Srgrimes			for (; np != NULL; np = np->e_links) {
3051558Srgrimes				if (np->e_links == ep) {
3061558Srgrimes					np->e_links = ep->e_links;
3071558Srgrimes					break;
3081558Srgrimes				}
3091558Srgrimes			}
3101558Srgrimes			if (np == NULL)
3111558Srgrimes				badentry(ep, "link not found");
3121558Srgrimes		}
3131558Srgrimes	}
3141558Srgrimes	removeentry(ep);
3151558Srgrimes	freename(ep->e_name);
3161558Srgrimes	ep->e_next = freelist;
3171558Srgrimes	freelist = ep;
3181558Srgrimes}
3191558Srgrimes
3201558Srgrimes/*
3211558Srgrimes * Relocate an entry in the tree structure
3221558Srgrimes */
3231558Srgrimesvoid
3241558Srgrimesmoveentry(ep, newname)
3251558Srgrimes	register struct entry *ep;
3261558Srgrimes	char *newname;
3271558Srgrimes{
3281558Srgrimes	struct entry *np;
3291558Srgrimes	char *cp;
3301558Srgrimes
3311558Srgrimes	np = lookupparent(newname);
3321558Srgrimes	if (np == NULL)
3331558Srgrimes		badentry(ep, "cannot move ROOT");
3341558Srgrimes	if (np != ep->e_parent) {
3351558Srgrimes		removeentry(ep);
3361558Srgrimes		ep->e_parent = np;
3371558Srgrimes		ep->e_sibling = np->e_entries;
3381558Srgrimes		np->e_entries = ep;
3391558Srgrimes	}
34023685Speter	cp = strrchr(newname, '/') + 1;
3411558Srgrimes	freename(ep->e_name);
3421558Srgrimes	ep->e_name = savename(cp);
3431558Srgrimes	ep->e_namlen = strlen(cp);
3441558Srgrimes	if (strcmp(gentempname(ep), ep->e_name) == 0)
3451558Srgrimes		ep->e_flags |= TMPNAME;
3461558Srgrimes	else
3471558Srgrimes		ep->e_flags &= ~TMPNAME;
3481558Srgrimes}
3491558Srgrimes
3501558Srgrimes/*
3511558Srgrimes * Remove an entry in the tree structure
3521558Srgrimes */
3531558Srgrimesstatic void
3541558Srgrimesremoveentry(ep)
3551558Srgrimes	register struct entry *ep;
3561558Srgrimes{
3571558Srgrimes	register struct entry *np;
3581558Srgrimes
3591558Srgrimes	np = ep->e_parent;
3601558Srgrimes	if (np->e_entries == ep) {
3611558Srgrimes		np->e_entries = ep->e_sibling;
3621558Srgrimes	} else {
3631558Srgrimes		for (np = np->e_entries; np != NULL; np = np->e_sibling) {
3641558Srgrimes			if (np->e_sibling == ep) {
3651558Srgrimes				np->e_sibling = ep->e_sibling;
3661558Srgrimes				break;
3671558Srgrimes			}
3681558Srgrimes		}
3691558Srgrimes		if (np == NULL)
3701558Srgrimes			badentry(ep, "cannot find entry in parent list");
3711558Srgrimes	}
3721558Srgrimes}
3731558Srgrimes
3741558Srgrimes/*
3751558Srgrimes * Table of unused string entries, sorted by length.
3768871Srgrimes *
3771558Srgrimes * Entries are allocated in STRTBLINCR sized pieces so that names
3781558Srgrimes * of similar lengths can use the same entry. The value of STRTBLINCR
3791558Srgrimes * is chosen so that every entry has at least enough space to hold
3801558Srgrimes * a "struct strtbl" header. Thus every entry can be linked onto an
38137906Scharnier * appropriate free list.
3821558Srgrimes *
3831558Srgrimes * NB. The macro "allocsize" below assumes that "struct strhdr"
3841558Srgrimes *     has a size that is a power of two.
3851558Srgrimes */
3861558Srgrimesstruct strhdr {
3871558Srgrimes	struct strhdr *next;
3881558Srgrimes};
3891558Srgrimes
3901558Srgrimes#define STRTBLINCR	(sizeof(struct strhdr))
3911558Srgrimes#define allocsize(size)	(((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1))
3921558Srgrimes
3931558Srgrimesstatic struct strhdr strtblhdr[allocsize(NAME_MAX) / STRTBLINCR];
3941558Srgrimes
3951558Srgrimes/*
3961558Srgrimes * Allocate space for a name. It first looks to see if it already
3971558Srgrimes * has an appropriate sized entry, and if not allocates a new one.
3981558Srgrimes */
3991558Srgrimeschar *
4001558Srgrimessavename(name)
4011558Srgrimes	char *name;
4021558Srgrimes{
4031558Srgrimes	struct strhdr *np;
4041558Srgrimes	long len;
4051558Srgrimes	char *cp;
4061558Srgrimes
4071558Srgrimes	if (name == NULL)
4081558Srgrimes		panic("bad name\n");
4091558Srgrimes	len = strlen(name);
4101558Srgrimes	np = strtblhdr[len / STRTBLINCR].next;
4111558Srgrimes	if (np != NULL) {
4121558Srgrimes		strtblhdr[len / STRTBLINCR].next = np->next;
4131558Srgrimes		cp = (char *)np;
4141558Srgrimes	} else {
4151558Srgrimes		cp = malloc((unsigned)allocsize(len));
4161558Srgrimes		if (cp == NULL)
4171558Srgrimes			panic("no space for string table\n");
4181558Srgrimes	}
4191558Srgrimes	(void) strcpy(cp, name);
4201558Srgrimes	return (cp);
4211558Srgrimes}
4221558Srgrimes
4231558Srgrimes/*
4241558Srgrimes * Free space for a name. The resulting entry is linked onto the
4251558Srgrimes * appropriate free list.
4261558Srgrimes */
4271558Srgrimesvoid
4281558Srgrimesfreename(name)
4291558Srgrimes	char *name;
4301558Srgrimes{
4311558Srgrimes	struct strhdr *tp, *np;
4328871Srgrimes
4331558Srgrimes	tp = &strtblhdr[strlen(name) / STRTBLINCR];
4341558Srgrimes	np = (struct strhdr *)name;
4351558Srgrimes	np->next = tp->next;
4361558Srgrimes	tp->next = np;
4371558Srgrimes}
4381558Srgrimes
4391558Srgrimes/*
4401558Srgrimes * Useful quantities placed at the end of a dumped symbol table.
4411558Srgrimes */
4421558Srgrimesstruct symtableheader {
44340668Sdima	int32_t	volno;
44440668Sdima	int32_t	stringsize;
44540668Sdima	int32_t	entrytblsize;
4461558Srgrimes	time_t	dumptime;
4471558Srgrimes	time_t	dumpdate;
4481558Srgrimes	ino_t	maxino;
44940668Sdima	int32_t	ntrec;
4501558Srgrimes};
4511558Srgrimes
4521558Srgrimes/*
4531558Srgrimes * dump a snapshot of the symbol table
4541558Srgrimes */
4551558Srgrimesvoid
4561558Srgrimesdumpsymtable(filename, checkpt)
4571558Srgrimes	char *filename;
4581558Srgrimes	long checkpt;
4591558Srgrimes{
4601558Srgrimes	register struct entry *ep, *tep;
4611558Srgrimes	register ino_t i;
4621558Srgrimes	struct entry temp, *tentry;
4631558Srgrimes	long mynum = 1, stroff = 0;
4641558Srgrimes	FILE *fd;
4651558Srgrimes	struct symtableheader hdr;
4661558Srgrimes
4671558Srgrimes	vprintf(stdout, "Check pointing the restore\n");
4681558Srgrimes	if (Nflag)
4691558Srgrimes		return;
4701558Srgrimes	if ((fd = fopen(filename, "w")) == NULL) {
4711558Srgrimes		fprintf(stderr, "fopen: %s\n", strerror(errno));
4721558Srgrimes		panic("cannot create save file %s for symbol table\n",
4731558Srgrimes			filename);
4741558Srgrimes	}
4751558Srgrimes	clearerr(fd);
4761558Srgrimes	/*
47737906Scharnier	 * Assign indices to each entry
4781558Srgrimes	 * Write out the string entries
4791558Srgrimes	 */
48023685Speter	for (i = WINO; i <= maxino; i++) {
4811558Srgrimes		for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
4821558Srgrimes			ep->e_index = mynum++;
4831558Srgrimes			(void) fwrite(ep->e_name, sizeof(char),
4841558Srgrimes			       (int)allocsize(ep->e_namlen), fd);
4851558Srgrimes		}
4861558Srgrimes	}
4871558Srgrimes	/*
4881558Srgrimes	 * Convert pointers to indexes, and output
4891558Srgrimes	 */
4901558Srgrimes	tep = &temp;
4911558Srgrimes	stroff = 0;
49223685Speter	for (i = WINO; i <= maxino; i++) {
4931558Srgrimes		for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
49423685Speter			memmove(tep, ep, (long)sizeof(struct entry));
4951558Srgrimes			tep->e_name = (char *)stroff;
4961558Srgrimes			stroff += allocsize(ep->e_namlen);
4971558Srgrimes			tep->e_parent = (struct entry *)ep->e_parent->e_index;
4981558Srgrimes			if (ep->e_links != NULL)
4991558Srgrimes				tep->e_links =
5001558Srgrimes					(struct entry *)ep->e_links->e_index;
5011558Srgrimes			if (ep->e_sibling != NULL)
5021558Srgrimes				tep->e_sibling =
5031558Srgrimes					(struct entry *)ep->e_sibling->e_index;
5041558Srgrimes			if (ep->e_entries != NULL)
5051558Srgrimes				tep->e_entries =
5061558Srgrimes					(struct entry *)ep->e_entries->e_index;
5071558Srgrimes			if (ep->e_next != NULL)
5081558Srgrimes				tep->e_next =
5091558Srgrimes					(struct entry *)ep->e_next->e_index;
5101558Srgrimes			(void) fwrite((char *)tep, sizeof(struct entry), 1, fd);
5111558Srgrimes		}
5121558Srgrimes	}
5131558Srgrimes	/*
5141558Srgrimes	 * Convert entry pointers to indexes, and output
5151558Srgrimes	 */
5161558Srgrimes	for (i = 0; i < entrytblsize; i++) {
5171558Srgrimes		if (entry[i] == NULL)
5181558Srgrimes			tentry = NULL;
5191558Srgrimes		else
5201558Srgrimes			tentry = (struct entry *)entry[i]->e_index;
5211558Srgrimes		(void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd);
5221558Srgrimes	}
5231558Srgrimes	hdr.volno = checkpt;
5241558Srgrimes	hdr.maxino = maxino;
5251558Srgrimes	hdr.entrytblsize = entrytblsize;
5261558Srgrimes	hdr.stringsize = stroff;
5271558Srgrimes	hdr.dumptime = dumptime;
5281558Srgrimes	hdr.dumpdate = dumpdate;
5291558Srgrimes	hdr.ntrec = ntrec;
5301558Srgrimes	(void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd);
5311558Srgrimes	if (ferror(fd)) {
5321558Srgrimes		fprintf(stderr, "fwrite: %s\n", strerror(errno));
5331558Srgrimes		panic("output error to file %s writing symbol table\n",
5341558Srgrimes			filename);
5351558Srgrimes	}
5361558Srgrimes	(void) fclose(fd);
5371558Srgrimes}
5381558Srgrimes
5391558Srgrimes/*
5401558Srgrimes * Initialize a symbol table from a file
5411558Srgrimes */
5421558Srgrimesvoid
5431558Srgrimesinitsymtable(filename)
5441558Srgrimes	char *filename;
5451558Srgrimes{
5461558Srgrimes	char *base;
5471558Srgrimes	long tblsize;
5481558Srgrimes	register struct entry *ep;
5491558Srgrimes	struct entry *baseep, *lep;
5501558Srgrimes	struct symtableheader hdr;
5511558Srgrimes	struct stat stbuf;
5521558Srgrimes	register long i;
5531558Srgrimes	int fd;
5541558Srgrimes
5551558Srgrimes	vprintf(stdout, "Initialize symbol table.\n");
5561558Srgrimes	if (filename == NULL) {
5571558Srgrimes		entrytblsize = maxino / HASHFACTOR;
5581558Srgrimes		entry = (struct entry **)
5591558Srgrimes			calloc((unsigned)entrytblsize, sizeof(struct entry *));
5601558Srgrimes		if (entry == (struct entry **)NULL)
5611558Srgrimes			panic("no memory for entry table\n");
5621558Srgrimes		ep = addentry(".", ROOTINO, NODE);
5631558Srgrimes		ep->e_flags |= NEW;
5641558Srgrimes		return;
5651558Srgrimes	}
5661558Srgrimes	if ((fd = open(filename, O_RDONLY, 0)) < 0) {
5671558Srgrimes		fprintf(stderr, "open: %s\n", strerror(errno));
5681558Srgrimes		panic("cannot open symbol table file %s\n", filename);
5691558Srgrimes	}
5701558Srgrimes	if (fstat(fd, &stbuf) < 0) {
5711558Srgrimes		fprintf(stderr, "stat: %s\n", strerror(errno));
5721558Srgrimes		panic("cannot stat symbol table file %s\n", filename);
5731558Srgrimes	}
5741558Srgrimes	tblsize = stbuf.st_size - sizeof(struct symtableheader);
5751558Srgrimes	base = calloc(sizeof(char), (unsigned)tblsize);
5761558Srgrimes	if (base == NULL)
5771558Srgrimes		panic("cannot allocate space for symbol table\n");
5781558Srgrimes	if (read(fd, base, (int)tblsize) < 0 ||
5791558Srgrimes	    read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) {
5801558Srgrimes		fprintf(stderr, "read: %s\n", strerror(errno));
5811558Srgrimes		panic("cannot read symbol table file %s\n", filename);
5821558Srgrimes	}
5831558Srgrimes	switch (command) {
5841558Srgrimes	case 'r':
5851558Srgrimes		/*
5861558Srgrimes		 * For normal continuation, insure that we are using
5871558Srgrimes		 * the next incremental tape
5881558Srgrimes		 */
5891558Srgrimes		if (hdr.dumpdate != dumptime) {
5901558Srgrimes			if (hdr.dumpdate < dumptime)
5911558Srgrimes				fprintf(stderr, "Incremental tape too low\n");
5921558Srgrimes			else
5931558Srgrimes				fprintf(stderr, "Incremental tape too high\n");
5941558Srgrimes			done(1);
5951558Srgrimes		}
5961558Srgrimes		break;
5971558Srgrimes	case 'R':
5981558Srgrimes		/*
5991558Srgrimes		 * For restart, insure that we are using the same tape
6001558Srgrimes		 */
6011558Srgrimes		curfile.action = SKIP;
6021558Srgrimes		dumptime = hdr.dumptime;
6031558Srgrimes		dumpdate = hdr.dumpdate;
6041558Srgrimes		if (!bflag)
6051558Srgrimes			newtapebuf(hdr.ntrec);
6061558Srgrimes		getvol(hdr.volno);
6071558Srgrimes		break;
6081558Srgrimes	default:
6091558Srgrimes		panic("initsymtable called from command %c\n", command);
6101558Srgrimes		break;
6111558Srgrimes	}
6121558Srgrimes	maxino = hdr.maxino;
6131558Srgrimes	entrytblsize = hdr.entrytblsize;
6141558Srgrimes	entry = (struct entry **)
6151558Srgrimes		(base + tblsize - (entrytblsize * sizeof(struct entry *)));
6161558Srgrimes	baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry));
6171558Srgrimes	lep = (struct entry *)entry;
6181558Srgrimes	for (i = 0; i < entrytblsize; i++) {
6191558Srgrimes		if (entry[i] == NULL)
6201558Srgrimes			continue;
6211558Srgrimes		entry[i] = &baseep[(long)entry[i]];
6221558Srgrimes	}
6231558Srgrimes	for (ep = &baseep[1]; ep < lep; ep++) {
6241558Srgrimes		ep->e_name = base + (long)ep->e_name;
6251558Srgrimes		ep->e_parent = &baseep[(long)ep->e_parent];
6261558Srgrimes		if (ep->e_sibling != NULL)
6271558Srgrimes			ep->e_sibling = &baseep[(long)ep->e_sibling];
6281558Srgrimes		if (ep->e_links != NULL)
6291558Srgrimes			ep->e_links = &baseep[(long)ep->e_links];
6301558Srgrimes		if (ep->e_entries != NULL)
6311558Srgrimes			ep->e_entries = &baseep[(long)ep->e_entries];
6321558Srgrimes		if (ep->e_next != NULL)
6331558Srgrimes			ep->e_next = &baseep[(long)ep->e_next];
6341558Srgrimes	}
6351558Srgrimes}
636