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