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