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