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