1*b7041c07Sderaadt /* $OpenBSD: symtab.c,v 1.24 2021/10/24 21:24:22 deraadt Exp $ */
2a916033eSmillert /* $NetBSD: symtab.c,v 1.10 1997/03/19 08:42:54 lukem Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*
5df930be7Sderaadt * Copyright (c) 1983, 1993
6df930be7Sderaadt * The Regents of the University of California. All rights reserved.
7df930be7Sderaadt *
8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt * modification, are permitted provided that the following conditions
10df930be7Sderaadt * are met:
11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt * documentation and/or other materials provided with the distribution.
161ef0d710Smillert * 3. Neither the name of the University nor the names of its contributors
17df930be7Sderaadt * may be used to endorse or promote products derived from this software
18df930be7Sderaadt * without specific prior written permission.
19df930be7Sderaadt *
20df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df930be7Sderaadt * SUCH DAMAGE.
31df930be7Sderaadt */
32df930be7Sderaadt
33df930be7Sderaadt /*
34df930be7Sderaadt * These routines maintain the symbol table which tracks the state
35df930be7Sderaadt * of the file system being restored. They provide lookup by either
36df930be7Sderaadt * name or inode number. They also provide for creation, deletion,
37df930be7Sderaadt * and renaming of entries. Because of the dynamic nature of pathnames,
38df930be7Sderaadt * names should not be saved, but always constructed just before they
39df930be7Sderaadt * are needed, by calling "myname".
40df930be7Sderaadt */
41df930be7Sderaadt
42df930be7Sderaadt #include <sys/stat.h>
43df930be7Sderaadt
44df930be7Sderaadt #include <ufs/ufs/dinode.h>
45df930be7Sderaadt
46a916033eSmillert #include <err.h>
47df930be7Sderaadt #include <fcntl.h>
48df930be7Sderaadt #include <stdio.h>
49df930be7Sderaadt #include <stdlib.h>
50df930be7Sderaadt #include <string.h>
51df930be7Sderaadt #include <unistd.h>
52b9fc9a72Sderaadt #include <limits.h>
53df930be7Sderaadt
54df930be7Sderaadt #include "restore.h"
55df930be7Sderaadt #include "extern.h"
56df930be7Sderaadt
57df930be7Sderaadt /*
58df930be7Sderaadt * The following variables define the inode symbol table.
59df930be7Sderaadt * The primary hash table is dynamically allocated based on
60df930be7Sderaadt * the number of inodes in the file system (maxino), scaled by
61df930be7Sderaadt * HASHFACTOR. The variable "entry" points to the hash table;
62df930be7Sderaadt * the variable "entrytblsize" indicates its size (in entries).
63df930be7Sderaadt */
64df930be7Sderaadt #define HASHFACTOR 5
65df930be7Sderaadt static struct entry **entry;
66df930be7Sderaadt static long entrytblsize;
67df930be7Sderaadt
68c72b5b24Smillert static void addino(ino_t, struct entry *);
69c72b5b24Smillert static struct entry *lookupparent(char *);
70c72b5b24Smillert static void removeentry(struct entry *);
71df930be7Sderaadt
72df930be7Sderaadt /*
73df930be7Sderaadt * Look up an entry by inode number
74df930be7Sderaadt */
75df930be7Sderaadt struct entry *
lookupino(ino_t inum)764e95fccfSderaadt lookupino(ino_t inum)
77df930be7Sderaadt {
78e073c79dSmpech struct entry *ep;
79df930be7Sderaadt
8001344d76Smillert if (inum < ROOTINO || inum >= maxino)
81df930be7Sderaadt return (NULL);
82df930be7Sderaadt for (ep = entry[inum % entrytblsize]; ep != NULL; ep = ep->e_next)
83df930be7Sderaadt if (ep->e_ino == inum)
84df930be7Sderaadt return (ep);
85df930be7Sderaadt return (NULL);
86df930be7Sderaadt }
87df930be7Sderaadt
88df930be7Sderaadt /*
89df930be7Sderaadt * Add an entry into the entry table
90df930be7Sderaadt */
91df930be7Sderaadt static void
addino(ino_t inum,struct entry * np)924e95fccfSderaadt addino(ino_t inum, struct entry *np)
93df930be7Sderaadt {
94df930be7Sderaadt struct entry **epp;
95df930be7Sderaadt
9601344d76Smillert if (inum < ROOTINO || inum >= maxino)
973b92bd08Sderaadt panic("addino: out of range %llu\n",
983b92bd08Sderaadt (unsigned long long)inum);
99df930be7Sderaadt epp = &entry[inum % entrytblsize];
100df930be7Sderaadt np->e_ino = inum;
101df930be7Sderaadt np->e_next = *epp;
102df930be7Sderaadt *epp = np;
103df930be7Sderaadt if (dflag)
104df930be7Sderaadt for (np = np->e_next; np != NULL; np = np->e_next)
105df930be7Sderaadt if (np->e_ino == inum)
106df930be7Sderaadt badentry(np, "duplicate inum");
107df930be7Sderaadt }
108df930be7Sderaadt
109df930be7Sderaadt /*
110df930be7Sderaadt * Delete an entry from the entry table
111df930be7Sderaadt */
112df930be7Sderaadt void
deleteino(ino_t inum)1134e95fccfSderaadt deleteino(ino_t inum)
114df930be7Sderaadt {
115e073c79dSmpech struct entry *next;
116df930be7Sderaadt struct entry **prev;
117df930be7Sderaadt
11801344d76Smillert if (inum < ROOTINO || inum >= maxino)
1193b92bd08Sderaadt panic("deleteino: out of range %llu\n",
1203b92bd08Sderaadt (unsigned long long)inum);
121df930be7Sderaadt prev = &entry[inum % entrytblsize];
122df930be7Sderaadt for (next = *prev; next != NULL; next = next->e_next) {
123df930be7Sderaadt if (next->e_ino == inum) {
124df930be7Sderaadt next->e_ino = 0;
125df930be7Sderaadt *prev = next->e_next;
126df930be7Sderaadt return;
127df930be7Sderaadt }
128df930be7Sderaadt prev = &next->e_next;
129df930be7Sderaadt }
1303b92bd08Sderaadt panic("deleteino: %llu not found\n", (unsigned long long)inum);
131df930be7Sderaadt }
132df930be7Sderaadt
133df930be7Sderaadt /*
134df930be7Sderaadt * Look up an entry by name
135df930be7Sderaadt */
136df930be7Sderaadt struct entry *
lookupname(char * name)1374e95fccfSderaadt lookupname(char *name)
138df930be7Sderaadt {
139e073c79dSmpech struct entry *ep;
140e073c79dSmpech char *np, *cp;
141b9fc9a72Sderaadt char buf[PATH_MAX];
142df930be7Sderaadt
143df930be7Sderaadt cp = name;
144df930be7Sderaadt for (ep = lookupino(ROOTINO); ep != NULL; ep = ep->e_entries) {
145c34257a4Sderaadt for (np = buf;
146c34257a4Sderaadt *cp != '/' && *cp != '\0' && np < &buf[sizeof(buf)]; )
147df930be7Sderaadt *np++ = *cp++;
148c34257a4Sderaadt if (np == &buf[sizeof(buf)])
149c34257a4Sderaadt break;
150df930be7Sderaadt *np = '\0';
151df930be7Sderaadt for ( ; ep != NULL; ep = ep->e_sibling)
152df930be7Sderaadt if (strcmp(ep->e_name, buf) == 0)
153df930be7Sderaadt break;
154df930be7Sderaadt if (ep == NULL)
155df930be7Sderaadt break;
156df930be7Sderaadt if (*cp++ == '\0')
157df930be7Sderaadt return (ep);
158df930be7Sderaadt }
159df930be7Sderaadt return (NULL);
160df930be7Sderaadt }
161df930be7Sderaadt
162df930be7Sderaadt /*
163df930be7Sderaadt * Look up the parent of a pathname
164df930be7Sderaadt */
165df930be7Sderaadt static struct entry *
lookupparent(char * name)1664e95fccfSderaadt lookupparent(char *name)
167df930be7Sderaadt {
168df930be7Sderaadt struct entry *ep;
169df930be7Sderaadt char *tailindex;
170df930be7Sderaadt
171df930be7Sderaadt tailindex = strrchr(name, '/');
172df930be7Sderaadt if (tailindex == NULL)
173df930be7Sderaadt return (NULL);
174df930be7Sderaadt *tailindex = '\0';
175df930be7Sderaadt ep = lookupname(name);
176df930be7Sderaadt *tailindex = '/';
177df930be7Sderaadt if (ep == NULL)
178df930be7Sderaadt return (NULL);
179df930be7Sderaadt if (ep->e_type != NODE)
180df930be7Sderaadt panic("%s is not a directory\n", name);
181df930be7Sderaadt return (ep);
182df930be7Sderaadt }
183df930be7Sderaadt
184df930be7Sderaadt /*
185df930be7Sderaadt * Determine the current pathname of a node or leaf
186df930be7Sderaadt */
187df930be7Sderaadt char *
myname(struct entry * ep)1884e95fccfSderaadt myname(struct entry *ep)
189df930be7Sderaadt {
190e073c79dSmpech char *cp;
191b9fc9a72Sderaadt static char namebuf[PATH_MAX];
192df930be7Sderaadt
193b9fc9a72Sderaadt for (cp = &namebuf[PATH_MAX - 2]; cp > &namebuf[ep->e_namlen]; ) {
194df930be7Sderaadt cp -= ep->e_namlen;
19534278641Stedu memcpy(cp, ep->e_name, ep->e_namlen);
196df930be7Sderaadt if (ep == lookupino(ROOTINO))
197df930be7Sderaadt return (cp);
198df930be7Sderaadt *(--cp) = '/';
199df930be7Sderaadt ep = ep->e_parent;
200df930be7Sderaadt }
201df930be7Sderaadt panic("%s: pathname too long\n", cp);
202df930be7Sderaadt return(cp);
203df930be7Sderaadt }
204df930be7Sderaadt
205df930be7Sderaadt /*
206df930be7Sderaadt * Unused symbol table entries are linked together on a freelist
207df930be7Sderaadt * headed by the following pointer.
208df930be7Sderaadt */
209df930be7Sderaadt static struct entry *freelist = NULL;
210df930be7Sderaadt
211df930be7Sderaadt /*
212df930be7Sderaadt * add an entry to the symbol table
213df930be7Sderaadt */
214df930be7Sderaadt struct entry *
addentry(char * name,ino_t inum,int type)2154e95fccfSderaadt addentry(char *name, ino_t inum, int type)
216df930be7Sderaadt {
217e073c79dSmpech struct entry *np, *ep;
218df930be7Sderaadt
219df930be7Sderaadt if (freelist != NULL) {
220df930be7Sderaadt np = freelist;
221df930be7Sderaadt freelist = np->e_next;
22234278641Stedu memset(np, 0, sizeof(struct entry));
223df930be7Sderaadt } else {
22434278641Stedu np = calloc(1, sizeof(struct entry));
225df930be7Sderaadt if (np == NULL)
226df930be7Sderaadt panic("no memory to extend symbol table\n");
227df930be7Sderaadt }
228df930be7Sderaadt np->e_type = type & ~LINK;
229df930be7Sderaadt ep = lookupparent(name);
230df930be7Sderaadt if (ep == NULL) {
231df930be7Sderaadt if (inum != ROOTINO || lookupino(ROOTINO) != NULL)
232df930be7Sderaadt panic("bad name to addentry %s\n", name);
233df930be7Sderaadt np->e_name = savename(name);
234df930be7Sderaadt np->e_namlen = strlen(name);
235df930be7Sderaadt np->e_parent = np;
236df930be7Sderaadt addino(ROOTINO, np);
237df930be7Sderaadt return (np);
238df930be7Sderaadt }
239df930be7Sderaadt np->e_name = savename(strrchr(name, '/') + 1);
240df930be7Sderaadt np->e_namlen = strlen(np->e_name);
241df930be7Sderaadt np->e_parent = ep;
242df930be7Sderaadt np->e_sibling = ep->e_entries;
243df930be7Sderaadt ep->e_entries = np;
244df930be7Sderaadt if (type & LINK) {
245df930be7Sderaadt ep = lookupino(inum);
246df930be7Sderaadt if (ep == NULL)
2476957a4a4Sjmc panic("link to non-existent name\n");
248df930be7Sderaadt np->e_ino = inum;
249df930be7Sderaadt np->e_links = ep->e_links;
250df930be7Sderaadt ep->e_links = np;
251df930be7Sderaadt } else if (inum != 0) {
252df930be7Sderaadt if (lookupino(inum) != NULL)
253df930be7Sderaadt panic("duplicate entry\n");
254df930be7Sderaadt addino(inum, np);
255df930be7Sderaadt }
256df930be7Sderaadt return (np);
257df930be7Sderaadt }
258df930be7Sderaadt
259df930be7Sderaadt /*
260df930be7Sderaadt * delete an entry from the symbol table
261df930be7Sderaadt */
262df930be7Sderaadt void
freeentry(struct entry * ep)2634e95fccfSderaadt freeentry(struct entry *ep)
264df930be7Sderaadt {
265e073c79dSmpech struct entry *np;
266df930be7Sderaadt ino_t inum;
267df930be7Sderaadt
268df930be7Sderaadt if (ep->e_flags != REMOVED)
269df930be7Sderaadt badentry(ep, "not marked REMOVED");
270df930be7Sderaadt if (ep->e_type == NODE) {
271df930be7Sderaadt if (ep->e_links != NULL)
272df930be7Sderaadt badentry(ep, "freeing referenced directory");
273df930be7Sderaadt if (ep->e_entries != NULL)
274df930be7Sderaadt badentry(ep, "freeing non-empty directory");
275df930be7Sderaadt }
276df930be7Sderaadt if (ep->e_ino != 0) {
277df930be7Sderaadt np = lookupino(ep->e_ino);
278df930be7Sderaadt if (np == NULL)
279df930be7Sderaadt badentry(ep, "lookupino failed");
280df930be7Sderaadt if (np == ep) {
281df930be7Sderaadt inum = ep->e_ino;
282df930be7Sderaadt deleteino(inum);
283df930be7Sderaadt if (ep->e_links != NULL)
284df930be7Sderaadt addino(inum, ep->e_links);
285df930be7Sderaadt } else {
286df930be7Sderaadt for (; np != NULL; np = np->e_links) {
287df930be7Sderaadt if (np->e_links == ep) {
288df930be7Sderaadt np->e_links = ep->e_links;
289df930be7Sderaadt break;
290df930be7Sderaadt }
291df930be7Sderaadt }
292df930be7Sderaadt if (np == NULL)
293df930be7Sderaadt badentry(ep, "link not found");
294df930be7Sderaadt }
295df930be7Sderaadt }
296df930be7Sderaadt removeentry(ep);
297df930be7Sderaadt freename(ep->e_name);
298df930be7Sderaadt ep->e_next = freelist;
299df930be7Sderaadt freelist = ep;
300df930be7Sderaadt }
301df930be7Sderaadt
302df930be7Sderaadt /*
303df930be7Sderaadt * Relocate an entry in the tree structure
304df930be7Sderaadt */
305df930be7Sderaadt void
moveentry(struct entry * ep,char * newname)3064e95fccfSderaadt moveentry(struct entry *ep, char *newname)
307df930be7Sderaadt {
308df930be7Sderaadt struct entry *np;
309df930be7Sderaadt char *cp;
310df930be7Sderaadt
311df930be7Sderaadt np = lookupparent(newname);
312df930be7Sderaadt if (np == NULL)
313df930be7Sderaadt badentry(ep, "cannot move ROOT");
314df930be7Sderaadt if (np != ep->e_parent) {
315df930be7Sderaadt removeentry(ep);
316df930be7Sderaadt ep->e_parent = np;
317df930be7Sderaadt ep->e_sibling = np->e_entries;
318df930be7Sderaadt np->e_entries = ep;
319df930be7Sderaadt }
320df930be7Sderaadt cp = strrchr(newname, '/') + 1;
321df930be7Sderaadt freename(ep->e_name);
322df930be7Sderaadt ep->e_name = savename(cp);
323df930be7Sderaadt ep->e_namlen = strlen(cp);
324df930be7Sderaadt if (strcmp(gentempname(ep), ep->e_name) == 0)
325df930be7Sderaadt ep->e_flags |= TMPNAME;
326df930be7Sderaadt else
327df930be7Sderaadt ep->e_flags &= ~TMPNAME;
328df930be7Sderaadt }
329df930be7Sderaadt
330df930be7Sderaadt /*
331df930be7Sderaadt * Remove an entry in the tree structure
332df930be7Sderaadt */
333df930be7Sderaadt static void
removeentry(struct entry * ep)3344e95fccfSderaadt removeentry(struct entry *ep)
335df930be7Sderaadt {
336e073c79dSmpech struct entry *np;
337df930be7Sderaadt
338df930be7Sderaadt np = ep->e_parent;
339df930be7Sderaadt if (np->e_entries == ep) {
340df930be7Sderaadt np->e_entries = ep->e_sibling;
341df930be7Sderaadt } else {
342df930be7Sderaadt for (np = np->e_entries; np != NULL; np = np->e_sibling) {
343df930be7Sderaadt if (np->e_sibling == ep) {
344df930be7Sderaadt np->e_sibling = ep->e_sibling;
345df930be7Sderaadt break;
346df930be7Sderaadt }
347df930be7Sderaadt }
348df930be7Sderaadt if (np == NULL)
349df930be7Sderaadt badentry(ep, "cannot find entry in parent list");
350df930be7Sderaadt }
351df930be7Sderaadt }
352df930be7Sderaadt
353df930be7Sderaadt /*
354df930be7Sderaadt * Table of unused string entries, sorted by length.
355df930be7Sderaadt *
356df930be7Sderaadt * Entries are allocated in STRTBLINCR sized pieces so that names
357df930be7Sderaadt * of similar lengths can use the same entry. The value of STRTBLINCR
358df930be7Sderaadt * is chosen so that every entry has at least enough space to hold
359df930be7Sderaadt * a "struct strtbl" header. Thus every entry can be linked onto an
360df930be7Sderaadt * apprpriate free list.
361df930be7Sderaadt *
362df930be7Sderaadt * NB. The macro "allocsize" below assumes that "struct strhdr"
363df930be7Sderaadt * has a size that is a power of two.
364df930be7Sderaadt */
365df930be7Sderaadt struct strhdr {
366df930be7Sderaadt struct strhdr *next;
367df930be7Sderaadt };
368df930be7Sderaadt
369df930be7Sderaadt #define STRTBLINCR (sizeof(struct strhdr))
370df930be7Sderaadt #define allocsize(size) (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1))
371df930be7Sderaadt
372df930be7Sderaadt static struct strhdr strtblhdr[allocsize(NAME_MAX) / STRTBLINCR];
373df930be7Sderaadt
374df930be7Sderaadt /*
375df930be7Sderaadt * Allocate space for a name. It first looks to see if it already
376df930be7Sderaadt * has an appropriate sized entry, and if not allocates a new one.
377df930be7Sderaadt */
378df930be7Sderaadt char *
savename(char * name)3794e95fccfSderaadt savename(char *name)
380df930be7Sderaadt {
381df930be7Sderaadt struct strhdr *np;
382df930be7Sderaadt long len;
383df930be7Sderaadt char *cp;
384df930be7Sderaadt
385df930be7Sderaadt if (name == NULL)
386df930be7Sderaadt panic("bad name\n");
387df930be7Sderaadt len = strlen(name);
388df930be7Sderaadt np = strtblhdr[len / STRTBLINCR].next;
389df930be7Sderaadt if (np != NULL) {
390df930be7Sderaadt strtblhdr[len / STRTBLINCR].next = np->next;
391df930be7Sderaadt cp = (char *)np;
392df930be7Sderaadt } else {
39334278641Stedu cp = malloc(allocsize(len));
394df930be7Sderaadt if (cp == NULL)
395df930be7Sderaadt panic("no space for string table\n");
396df930be7Sderaadt }
397952cad2dSderaadt (void)strlcpy(cp, name, len + 1);
398df930be7Sderaadt return (cp);
399df930be7Sderaadt }
400df930be7Sderaadt
401df930be7Sderaadt /*
402df930be7Sderaadt * Free space for a name. The resulting entry is linked onto the
403df930be7Sderaadt * appropriate free list.
404df930be7Sderaadt */
405df930be7Sderaadt void
freename(char * name)4064e95fccfSderaadt freename(char *name)
407df930be7Sderaadt {
408df930be7Sderaadt struct strhdr *tp, *np;
409df930be7Sderaadt
410df930be7Sderaadt tp = &strtblhdr[strlen(name) / STRTBLINCR];
411df930be7Sderaadt np = (struct strhdr *)name;
412df930be7Sderaadt np->next = tp->next;
413df930be7Sderaadt tp->next = np;
414df930be7Sderaadt }
415df930be7Sderaadt
416df930be7Sderaadt /*
417df930be7Sderaadt * Useful quantities placed at the end of a dumped symbol table.
418df930be7Sderaadt */
419df930be7Sderaadt struct symtableheader {
420d739c122Sderaadt int32_t volno;
421d739c122Sderaadt int32_t stringsize;
422d739c122Sderaadt int32_t entrytblsize;
423df930be7Sderaadt time_t dumptime;
424df930be7Sderaadt time_t dumpdate;
425df930be7Sderaadt ino_t maxino;
426d739c122Sderaadt int32_t ntrec;
427df930be7Sderaadt };
428df930be7Sderaadt
429df930be7Sderaadt /*
430df930be7Sderaadt * dump a snapshot of the symbol table
431df930be7Sderaadt */
432df930be7Sderaadt void
dumpsymtable(char * filename,long checkpt)4334e95fccfSderaadt dumpsymtable(char *filename, long checkpt)
434df930be7Sderaadt {
435e073c79dSmpech struct entry *ep, *tep;
436e073c79dSmpech ino_t i;
437df930be7Sderaadt struct entry temp, *tentry;
438df930be7Sderaadt long mynum = 1, stroff = 0;
43910d9ecc2Sderaadt FILE *fp;
440df930be7Sderaadt struct symtableheader hdr;
441df930be7Sderaadt
442a916033eSmillert Vprintf(stdout, "Check pointing the restore\n");
443df930be7Sderaadt if (Nflag)
444df930be7Sderaadt return;
44510d9ecc2Sderaadt if ((fp = fopen(filename, "w")) == NULL) {
446a916033eSmillert warn("fopen");
447df930be7Sderaadt panic("cannot create save file %s for symbol table\n",
448df930be7Sderaadt filename);
449df930be7Sderaadt }
45010d9ecc2Sderaadt clearerr(fp);
451df930be7Sderaadt /*
452cb354146Smiod * Assign indices to each entry
453df930be7Sderaadt * Write out the string entries
454df930be7Sderaadt */
45501344d76Smillert for (i = ROOTINO; i <= maxino; i++) {
456df930be7Sderaadt for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
457df930be7Sderaadt ep->e_index = mynum++;
458df930be7Sderaadt (void)fwrite(ep->e_name, sizeof(char),
45910d9ecc2Sderaadt (int)allocsize(ep->e_namlen), fp);
460df930be7Sderaadt }
461df930be7Sderaadt }
462df930be7Sderaadt /*
463df930be7Sderaadt * Convert pointers to indexes, and output
464df930be7Sderaadt */
465df930be7Sderaadt tep = &temp;
466df930be7Sderaadt stroff = 0;
46701344d76Smillert for (i = ROOTINO; i <= maxino; i++) {
468df930be7Sderaadt for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
46934278641Stedu memcpy(tep, ep, sizeof(struct entry));
470df930be7Sderaadt tep->e_name = (char *)stroff;
471df930be7Sderaadt stroff += allocsize(ep->e_namlen);
472df930be7Sderaadt tep->e_parent = (struct entry *)ep->e_parent->e_index;
473df930be7Sderaadt if (ep->e_links != NULL)
474df930be7Sderaadt tep->e_links =
475df930be7Sderaadt (struct entry *)ep->e_links->e_index;
476df930be7Sderaadt if (ep->e_sibling != NULL)
477df930be7Sderaadt tep->e_sibling =
478df930be7Sderaadt (struct entry *)ep->e_sibling->e_index;
479df930be7Sderaadt if (ep->e_entries != NULL)
480df930be7Sderaadt tep->e_entries =
481df930be7Sderaadt (struct entry *)ep->e_entries->e_index;
482df930be7Sderaadt if (ep->e_next != NULL)
483df930be7Sderaadt tep->e_next =
484df930be7Sderaadt (struct entry *)ep->e_next->e_index;
48510d9ecc2Sderaadt (void)fwrite((char *)tep, sizeof(struct entry), 1, fp);
486df930be7Sderaadt }
487df930be7Sderaadt }
488df930be7Sderaadt /*
489df930be7Sderaadt * Convert entry pointers to indexes, and output
490df930be7Sderaadt */
491df930be7Sderaadt for (i = 0; i < entrytblsize; i++) {
492df930be7Sderaadt if (entry[i] == NULL)
493df930be7Sderaadt tentry = NULL;
494df930be7Sderaadt else
495df930be7Sderaadt tentry = (struct entry *)entry[i]->e_index;
49610d9ecc2Sderaadt (void)fwrite((char *)&tentry, sizeof(struct entry *), 1, fp);
497df930be7Sderaadt }
498df930be7Sderaadt hdr.volno = checkpt;
499df930be7Sderaadt hdr.maxino = maxino;
500df930be7Sderaadt hdr.entrytblsize = entrytblsize;
501df930be7Sderaadt hdr.stringsize = stroff;
502df930be7Sderaadt hdr.dumptime = dumptime;
503df930be7Sderaadt hdr.dumpdate = dumpdate;
504df930be7Sderaadt hdr.ntrec = ntrec;
50510d9ecc2Sderaadt (void)fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fp);
50610d9ecc2Sderaadt if (ferror(fp)) {
507a916033eSmillert warn("fwrite");
508df930be7Sderaadt panic("output error to file %s writing symbol table\n",
509df930be7Sderaadt filename);
510df930be7Sderaadt }
51110d9ecc2Sderaadt (void)fclose(fp);
512df930be7Sderaadt }
513df930be7Sderaadt
514df930be7Sderaadt /*
515df930be7Sderaadt * Initialize a symbol table from a file
516df930be7Sderaadt */
517df930be7Sderaadt void
initsymtable(char * filename)5184e95fccfSderaadt initsymtable(char *filename)
519df930be7Sderaadt {
520df930be7Sderaadt char *base;
521df930be7Sderaadt long tblsize;
522e073c79dSmpech struct entry *ep;
523df930be7Sderaadt struct entry *baseep, *lep;
524df930be7Sderaadt struct symtableheader hdr;
525df930be7Sderaadt struct stat stbuf;
526e073c79dSmpech long i;
527df930be7Sderaadt int fd;
528df930be7Sderaadt
529a916033eSmillert Vprintf(stdout, "Initialize symbol table.\n");
530df930be7Sderaadt if (filename == NULL) {
531df930be7Sderaadt entrytblsize = maxino / HASHFACTOR;
53234278641Stedu entry = calloc(entrytblsize, sizeof(struct entry *));
53334278641Stedu if (entry == NULL)
534df930be7Sderaadt panic("no memory for entry table\n");
535df930be7Sderaadt ep = addentry(".", ROOTINO, NODE);
536df930be7Sderaadt ep->e_flags |= NEW;
537df930be7Sderaadt return;
538df930be7Sderaadt }
539*b7041c07Sderaadt if ((fd = open(filename, O_RDONLY)) == -1) {
540a916033eSmillert warn("open");
541df930be7Sderaadt panic("cannot open symbol table file %s\n", filename);
542df930be7Sderaadt }
543df69c215Sderaadt if (fstat(fd, &stbuf) == -1) {
544a916033eSmillert warn("stat");
545df930be7Sderaadt panic("cannot stat symbol table file %s\n", filename);
546df930be7Sderaadt }
547df930be7Sderaadt tblsize = stbuf.st_size - sizeof(struct symtableheader);
54834278641Stedu base = calloc(tblsize, sizeof(char));
549df930be7Sderaadt if (base == NULL)
550df930be7Sderaadt panic("cannot allocate space for symbol table\n");
551df69c215Sderaadt if (read(fd, base, tblsize) == -1 ||
552df69c215Sderaadt read(fd, &hdr, sizeof(struct symtableheader)) == -1) {
553a916033eSmillert warn("read");
554df930be7Sderaadt panic("cannot read symbol table file %s\n", filename);
555df930be7Sderaadt }
556ecb8696cSderaadt close(fd);
557df930be7Sderaadt switch (command) {
558df930be7Sderaadt case 'r':
559df930be7Sderaadt /*
560df930be7Sderaadt * For normal continuation, insure that we are using
561df930be7Sderaadt * the next incremental tape
562df930be7Sderaadt */
563a916033eSmillert if (hdr.dumpdate != dumptime)
564a916033eSmillert errx(1, "Incremental tape too %s",
565a916033eSmillert (hdr.dumpdate < dumptime) ? "low" : "high");
566df930be7Sderaadt break;
567df930be7Sderaadt case 'R':
568df930be7Sderaadt /*
569df930be7Sderaadt * For restart, insure that we are using the same tape
570df930be7Sderaadt */
571df930be7Sderaadt curfile.action = SKIP;
572df930be7Sderaadt dumptime = hdr.dumptime;
573df930be7Sderaadt dumpdate = hdr.dumpdate;
574df930be7Sderaadt if (!bflag)
575df930be7Sderaadt newtapebuf(hdr.ntrec);
576df930be7Sderaadt getvol(hdr.volno);
577df930be7Sderaadt break;
578df930be7Sderaadt default:
579df930be7Sderaadt panic("initsymtable called from command %c\n", command);
580df930be7Sderaadt break;
581df930be7Sderaadt }
582df930be7Sderaadt maxino = hdr.maxino;
583df930be7Sderaadt entrytblsize = hdr.entrytblsize;
584df930be7Sderaadt entry = (struct entry **)
585df930be7Sderaadt (base + tblsize - (entrytblsize * sizeof(struct entry *)));
586df930be7Sderaadt baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry));
587df930be7Sderaadt lep = (struct entry *)entry;
588df930be7Sderaadt for (i = 0; i < entrytblsize; i++) {
589df930be7Sderaadt if (entry[i] == NULL)
590df930be7Sderaadt continue;
591df930be7Sderaadt entry[i] = &baseep[(long)entry[i]];
592df930be7Sderaadt }
593df930be7Sderaadt for (ep = &baseep[1]; ep < lep; ep++) {
594df930be7Sderaadt ep->e_name = base + (long)ep->e_name;
595df930be7Sderaadt ep->e_parent = &baseep[(long)ep->e_parent];
596df930be7Sderaadt if (ep->e_sibling != NULL)
597df930be7Sderaadt ep->e_sibling = &baseep[(long)ep->e_sibling];
598df930be7Sderaadt if (ep->e_links != NULL)
599df930be7Sderaadt ep->e_links = &baseep[(long)ep->e_links];
600df930be7Sderaadt if (ep->e_entries != NULL)
601df930be7Sderaadt ep->e_entries = &baseep[(long)ep->e_entries];
602df930be7Sderaadt if (ep->e_next != NULL)
603df930be7Sderaadt ep->e_next = &baseep[(long)ep->e_next];
604df930be7Sderaadt }
605df930be7Sderaadt }
606