xref: /csrg-svn/sbin/restore/symtab.c (revision 11324)
110314Smckusick /* Copyright (c) 1983 Regents of the University of California */
210314Smckusick 
310314Smckusick #ifndef lint
4*11324Smckusick static char sccsid[] = "@(#)symtab.c	3.4	(Berkeley)	83/02/28";
510314Smckusick #endif
610314Smckusick 
710314Smckusick #include "restore.h"
810314Smckusick #include <sys/stat.h>
910314Smckusick 
1010314Smckusick struct symtableheader {
1110314Smckusick 	long	volno;
1210314Smckusick 	long	stringsize;
1311303Smckusick 	time_t	dumptime;
1411303Smckusick 	time_t	dumpdate;
1510314Smckusick 	ino_t	maxino;
1610314Smckusick };
1710314Smckusick 
1811129Smckusick struct entry *freelist = NIL;
1910314Smckusick 
2011129Smckusick #ifndef lookupino
2110314Smckusick /*
2210314Smckusick  * Look up an entry by inode number
2310314Smckusick  */
2410314Smckusick struct entry *
2510314Smckusick lookupino(inum)
2610314Smckusick 	ino_t inum;
2710314Smckusick {
2810314Smckusick 
2911129Smckusick 	return (entry[inum]);
3010314Smckusick }
3111129Smckusick #endif lookupino
3210314Smckusick 
3311129Smckusick #ifndef addino
3410314Smckusick /*
3510314Smckusick  * Add an entry into the entry table
3610314Smckusick  */
3710314Smckusick addino(inum, np)
3811129Smckusick 	long inum;
3910314Smckusick 	struct entry *np;
4010314Smckusick {
4110314Smckusick 
4211129Smckusick 	entry[inum] = np;
4310314Smckusick }
4411129Smckusick #endif addino
4510314Smckusick 
4611129Smckusick #ifndef deleteino
4710314Smckusick /*
4810314Smckusick  * Delete an entry from the entry table
4910314Smckusick  */
5010314Smckusick deleteino(inum)
5111129Smckusick 	long inum;
5210314Smckusick {
5310314Smckusick 
5411129Smckusick 	entry[inum] = NIL;
5510314Smckusick }
5611129Smckusick #endif deleteino
5710314Smckusick 
5810314Smckusick /*
5910314Smckusick  * Look up an entry by name
6010314Smckusick  */
6110314Smckusick struct entry *
6210314Smckusick lookupname(name)
6310314Smckusick 	char *name;
6410314Smckusick {
6510314Smckusick 	register struct entry *ep;
6610314Smckusick 	register char *np, *cp;
6710314Smckusick 	char buf[BUFSIZ];
6810314Smckusick 
6910314Smckusick 	cp = name;
7010314Smckusick 	for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) {
7110314Smckusick 		for (np = buf; *cp != '/' && *cp != '\0'; )
7210314Smckusick 			*np++ = *cp++;
7310314Smckusick 		*np = '\0';
7410314Smckusick 		for ( ; ep != NIL; ep = ep->e_sibling)
7510314Smckusick 			if (strcmp(ep->e_name, buf) == 0)
7610314Smckusick 				break;
7710314Smckusick 		if (ep == NIL)
7810314Smckusick 			break;
7911311Smckusick 		if (*cp++ == '\0')
8010314Smckusick 			return (ep);
8110314Smckusick 	}
8211311Smckusick 	return (NIL);
8310314Smckusick }
8410314Smckusick 
8510314Smckusick /*
8610314Smckusick  * Look up the parent of a pathname
8710314Smckusick  */
8810314Smckusick struct entry *
8910314Smckusick lookupparent(name)
9010314Smckusick 	char *name;
9110314Smckusick {
9210314Smckusick 	struct entry *ep;
9310314Smckusick 	char *tailindex;
9410314Smckusick 
9510314Smckusick 	tailindex = rindex(name, '/');
9610314Smckusick 	if (tailindex == 0)
9710314Smckusick 		return (NIL);
9810314Smckusick 	*tailindex = '\0';
9910314Smckusick 	ep = lookupname(name);
10011311Smckusick 	*tailindex = '/';
10110314Smckusick 	if (ep == NIL)
10210314Smckusick 		return (NIL);
10310314Smckusick 	if (ep->e_type != NODE)
10410314Smckusick 		panic("%s is not a directory\n", name);
10510314Smckusick 	return (ep);
10610314Smckusick }
10710314Smckusick 
10810314Smckusick /*
10910314Smckusick  * Determine the current pathname of a node or leaf
11010314Smckusick  */
11110314Smckusick char *
11210314Smckusick myname(ep)
11310314Smckusick 	register struct entry *ep;
11410314Smckusick {
11510314Smckusick 	register char *cp;
11610314Smckusick 	static char namebuf[BUFSIZ];
11710314Smckusick 
11810314Smckusick 	for (cp = &namebuf[BUFSIZ - 2]; cp > &namebuf[ep->e_namlen]; ) {
11910314Smckusick 		cp -= ep->e_namlen;
12010314Smckusick 		bcopy(ep->e_name, cp, (long)ep->e_namlen);
12110314Smckusick 		if (ep == lookupino(ROOTINO))
12210314Smckusick 			return (cp);
12310314Smckusick 		*(--cp) = '/';
12410314Smckusick 		ep = ep->e_parent;
12510314Smckusick 	}
12610314Smckusick 	panic("%s: pathname too long\n", cp);
12710314Smckusick 	return(cp);
12810314Smckusick }
12910314Smckusick 
13010314Smckusick /*
13110314Smckusick  * add an entry to the symbol table
13210314Smckusick  */
13310314Smckusick struct entry *
13410314Smckusick addentry(name, inum, type)
13510314Smckusick 	char *name;
13610314Smckusick 	ino_t inum;
13710314Smckusick 	int type;
13810314Smckusick {
13910314Smckusick 	register struct entry *np, *ep;
14010314Smckusick 
14110314Smckusick 	if (freelist != NIL) {
14210314Smckusick 		np = freelist;
14310314Smckusick 		freelist = np->e_sibling;
14410314Smckusick 		bzero((char *)np, (long)sizeof(struct entry));
14510314Smckusick 	} else {
14610314Smckusick 		np = (struct entry *)calloc(1, sizeof(struct entry));
14710314Smckusick 	}
14810314Smckusick 	np->e_ino = inum;
14910314Smckusick 	np->e_type = type & ~LINK;
15010314Smckusick 	ep = lookupparent(name);
15110314Smckusick 	if (ep == NIL) {
15210314Smckusick 		if (inum != ROOTINO || lookupino(ROOTINO) != NIL)
15310314Smckusick 			panic("bad name to addentry %s\n", name);
15410314Smckusick 		np->e_name = savename(name);
15510314Smckusick 		np->e_namlen = strlen(name);
15610314Smckusick 		np->e_parent = np;
15710314Smckusick 		addino(ROOTINO, np);
15810314Smckusick 		return (np);
15910314Smckusick 	}
16010314Smckusick 	np->e_name = savename(rindex(name, '/') + 1);
16110314Smckusick 	np->e_namlen = strlen(np->e_name);
16210314Smckusick 	np->e_parent = ep;
16310314Smckusick 	np->e_sibling = ep->e_entries;
16410314Smckusick 	ep->e_entries = np;
16510314Smckusick 	if (type & LINK) {
16610314Smckusick 		ep = lookupino(inum);
16710314Smckusick 		if (ep == NIL)
16810314Smckusick 			panic("link to non-existant name\n");
16910314Smckusick 		np->e_links = ep->e_links;
17010314Smckusick 		ep->e_links = np;
17110314Smckusick 	} else if (inum != 0) {
17210314Smckusick 		if (lookupino(inum) != NIL)
17310314Smckusick 			panic("duplicate entry\n");
17410314Smckusick 		addino(inum, np);
17510314Smckusick 	}
17610314Smckusick 	return (np);
17710314Smckusick }
17810314Smckusick 
17910314Smckusick /*
18010314Smckusick  * delete an entry from the symbol table
18110314Smckusick  */
18210314Smckusick freeentry(ep)
18310314Smckusick 	register struct entry *ep;
18410314Smckusick {
18510314Smckusick 	register struct entry *np;
18610314Smckusick 
18710314Smckusick 	np = lookupino(ep->e_ino);
18810314Smckusick 	if (np == NIL)
18910314Smckusick 		badentry(ep, "lookupino failed");
19010314Smckusick 	if (ep->e_flags != REMOVED)
19110314Smckusick 		badentry(ep, "not marked REMOVED");
19210314Smckusick 	if (np->e_type == NODE) {
19310314Smckusick 		if (np == ep && np->e_links != NIL)
19410314Smckusick 			badentry(ep, "freeing referenced directory");
19510314Smckusick 		if (ep->e_entries != NIL)
19610314Smckusick 			badentry(ep, "freeing non-empty directory");
19710314Smckusick 	}
19810314Smckusick 	if (np == ep) {
19910314Smckusick 		deleteino(ep->e_ino);
20010314Smckusick 		addino(ep->e_ino, ep->e_links);
20110314Smckusick 	} else {
20210314Smckusick 		for (; np != NIL; np = np->e_links) {
20310314Smckusick 			if (np->e_links == ep) {
20410314Smckusick 				np->e_links = ep->e_links;
20510314Smckusick 				break;
20610314Smckusick 			}
20710314Smckusick 		}
20810314Smckusick 		if (np == NIL)
20910314Smckusick 			badentry(ep, "link not found");
21010314Smckusick 	}
21110314Smckusick 	removeentry(ep);
21210314Smckusick 	free(ep->e_name);
21311129Smckusick 	if (ep->e_newname != NULL)
21411129Smckusick 		free(ep->e_newname);
21510314Smckusick 	ep->e_sibling = freelist;
21610314Smckusick 	freelist = ep;
21710314Smckusick }
21810314Smckusick 
21910314Smckusick /*
22011129Smckusick  * change the number associated with an entry
22111129Smckusick  */
22211129Smckusick renumber(ep, newinum)
22311129Smckusick 	struct entry *ep;
22411129Smckusick 	ino_t newinum;
22511129Smckusick {
22611129Smckusick 	register struct entry *np;
22711129Smckusick 
22811129Smckusick 	if (lookupino(newinum) != NIL)
22911129Smckusick 		badentry(ep, "renumber to active inum");
23011129Smckusick 	np = lookupino(ep->e_ino);
23111129Smckusick 	if (np == NIL)
23211129Smckusick 		badentry(ep, "lookupino failed");
23311129Smckusick 	deleteino(ep->e_ino);
23411129Smckusick 	addino(newinum, ep);
23511129Smckusick 	for (; np != NIL; np = np->e_links)
23611129Smckusick 		np->e_ino = newinum;
23711129Smckusick }
23811129Smckusick 
23911129Smckusick /*
24010314Smckusick  * Relocate an entry in the tree structure
24110314Smckusick  */
24210314Smckusick moveentry(ep, newname)
24310314Smckusick 	register struct entry *ep;
24410314Smckusick 	char *newname;
24510314Smckusick {
24610314Smckusick 	struct entry *np;
24710314Smckusick 	char *cp;
24810314Smckusick 	long len;
24910314Smckusick 
25010314Smckusick 	np = lookupparent(newname);
25110314Smckusick 	if (np == NIL)
25210314Smckusick 		badentry(ep, "cannot move ROOT");
25310314Smckusick 	if (np != ep->e_parent) {
25410314Smckusick 		removeentry(ep);
25510314Smckusick 		ep->e_parent = np;
25610314Smckusick 		ep->e_sibling = np->e_entries;
25710314Smckusick 		np->e_entries = ep;
25810314Smckusick 	}
25910314Smckusick 	cp = rindex(newname, '/') + 1;
26010314Smckusick 	len = strlen(cp);
26110314Smckusick 	if (ep->e_flags & TMPNAME)
26210314Smckusick 		ep->e_namlen--;
26310314Smckusick 	if (ep->e_namlen >= len) {
26410314Smckusick 		strcpy(ep->e_name, cp);
26510314Smckusick 	} else {
26610314Smckusick 		free(ep->e_name);
26710314Smckusick 		ep->e_name = savename(cp);
26810314Smckusick 	}
26910314Smckusick 	ep->e_namlen = len;
27010314Smckusick 	if (cp[len - 1] == TMPCHAR)
27110314Smckusick 		ep->e_flags |= TMPNAME;
27210314Smckusick 	else
27310314Smckusick 		ep->e_flags &= ~TMPNAME;
27410314Smckusick }
27510314Smckusick 
27610314Smckusick /*
27710314Smckusick  * Remove an entry in the tree structure
27810314Smckusick  */
27910314Smckusick removeentry(ep)
28010314Smckusick 	register struct entry *ep;
28110314Smckusick {
28210314Smckusick 	register struct entry *np;
28310314Smckusick 
28410314Smckusick 	np = ep->e_parent;
28510314Smckusick 	if (np->e_entries == ep) {
28610314Smckusick 		np->e_entries = ep->e_sibling;
28710314Smckusick 	} else {
28810314Smckusick 		for (np = np->e_entries; np != NIL; np = np->e_sibling) {
28910314Smckusick 			if (np->e_sibling == ep) {
29010314Smckusick 				np->e_sibling = ep->e_sibling;
29110314Smckusick 				break;
29210314Smckusick 			}
29310314Smckusick 		}
29410314Smckusick 		if (np == NIL)
29510314Smckusick 			badentry(ep, "cannot find entry in parent list");
29610314Smckusick 	}
29710314Smckusick }
29810314Smckusick 
29910314Smckusick /*
30010314Smckusick  * allocate space for a name
30110314Smckusick  */
30210314Smckusick char *
30310314Smckusick savename(name)
30410314Smckusick 	char *name;
30510314Smckusick {
30610314Smckusick 	long len;
30711311Smckusick 	char *cp;
30810314Smckusick 
30910314Smckusick 	if (name == NULL)
31010314Smckusick 		panic("bad name\n");
31110314Smckusick 	len = strlen(name) + 2;
31210314Smckusick 	len = (len + 3) & ~3;
31311311Smckusick 	cp = (char *)malloc((unsigned)len);
31411311Smckusick 	strcpy(cp, name);
31511311Smckusick 	return (cp);
31610314Smckusick }
31710314Smckusick 
31810314Smckusick /*
31910314Smckusick  * dump a snapshot of the symbol table
32010314Smckusick  */
32110314Smckusick dumpsymtable(filename, checkpt)
32210314Smckusick 	char *filename;
32310314Smckusick 	long checkpt;
32410314Smckusick {
32510314Smckusick 	register struct entry *ep;
32611129Smckusick 	register long i;
32710314Smckusick 	struct entry *next;
32810314Smckusick 	long mynum = 0, stroff = 0;
32910314Smckusick 	FILE *fd;
33010314Smckusick 	struct symtableheader hdr;
33110314Smckusick 
33210314Smckusick 	vprintf(stdout, "Check pointing the restore\n");
33310314Smckusick 	if ((fd = fopen(filename, "w")) == NULL) {
33410314Smckusick 		perror("fopen");
33510314Smckusick 		panic("cannot create save file %s for symbol table\n",
33610314Smckusick 			filename);
33710314Smckusick 	}
33810314Smckusick 	clearerr(fd);
33910314Smckusick 	/*
34010314Smckusick 	 * Assign indicies to each entry
34110314Smckusick 	 * Write out the string entries
34210314Smckusick 	 */
34310314Smckusick 	for (i = ROOTINO; i < maxino; i++) {
34410314Smckusick 		for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
34511129Smckusick 			ep->e_newname = (char *)mynum++;
34610314Smckusick 			fwrite(ep->e_name, sizeof(char), (int)ep->e_namlen, fd);
34710314Smckusick 			ep->e_name = (char *)stroff;
34810314Smckusick 			stroff += ep->e_namlen;
34910314Smckusick 		}
35010314Smckusick 	}
35110314Smckusick 	/*
35210314Smckusick 	 * Convert entry pointers to indexes, and output
35310314Smckusick 	 */
35411129Smckusick 	for (i = 0; i < maxino; i++) {
35510314Smckusick 		if (entry[i] == NIL)
35610314Smckusick 			continue;
35711129Smckusick 		entry[i] = (struct entry *)entry[i]->e_newname;
35810314Smckusick 	}
35911129Smckusick 	fwrite((char *)entry, sizeof(struct entry *), (int)maxino, fd);
36010314Smckusick 	/*
36110314Smckusick 	 * Convert pointers to indexes, and output
36210314Smckusick 	 */
36310314Smckusick 	for (i = ROOTINO; i < maxino; i++) {
36410314Smckusick 		for (ep = lookupino(i); ep != NIL; ep = next) {
36510314Smckusick 			next = ep->e_links;
36611129Smckusick 			ep->e_parent = (struct entry *)ep->e_parent->e_newname;
36711129Smckusick 			ep->e_links = (struct entry *)ep->e_links->e_newname;
36811129Smckusick 			ep->e_sibling =
36911129Smckusick 				(struct entry *)ep->e_sibling->e_newname;
37011129Smckusick 			ep->e_entries =
37111129Smckusick 				(struct entry *)ep->e_entries->e_newname;
37210314Smckusick 			fwrite((char *)ep, sizeof(struct entry), 1, fd);
37310314Smckusick 		}
37410314Smckusick 	}
37510314Smckusick 	hdr.volno = checkpt;
37610314Smckusick 	hdr.maxino = maxino;
37710314Smckusick 	hdr.stringsize = stroff;
37811303Smckusick 	hdr.dumptime = dumptime;
37911303Smckusick 	hdr.dumpdate = dumpdate;
38010314Smckusick 	fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd);
38110314Smckusick 	if (ferror(fd)) {
38210314Smckusick 		perror("fwrite");
38310314Smckusick 		panic("output error to file %s writing symbol table\n",
38410314Smckusick 			filename);
38510314Smckusick 	}
38610314Smckusick 	fclose(fd);
38710314Smckusick }
38810314Smckusick 
38910314Smckusick /*
39010314Smckusick  * Initialize a symbol table from a file
39110314Smckusick  */
39210314Smckusick initsymtable(filename)
39310314Smckusick 	char *filename;
39410314Smckusick {
39510314Smckusick 	char *base;
39610314Smckusick 	long tblsize;
39710314Smckusick 	register struct entry *ep;
39810314Smckusick 	struct entry *baseep, *lep;
39910314Smckusick 	struct symtableheader hdr;
40010314Smckusick 	struct stat stbuf;
40110314Smckusick 	register long i;
40210314Smckusick 	int fd;
40310314Smckusick 
40410314Smckusick 	vprintf(stdout, "Initialize symbol table.\n");
40510314Smckusick 	if ((fd = open(filename, 0)) < 0) {
40610314Smckusick 		perror("open");
40710314Smckusick 		panic("cannot open symbol table file %s\n", filename);
40810314Smckusick 	}
40910314Smckusick 	if (fstat(fd, &stbuf) < 0) {
41010314Smckusick 		perror("stat");
41110314Smckusick 		panic("cannot stat symbol table file %s\n", filename);
41210314Smckusick 	}
41310314Smckusick 	tblsize = stbuf.st_size - sizeof(struct symtableheader);
41411129Smckusick 	base = (char *)malloc((unsigned)tblsize);
41510314Smckusick 	if (base == NULL)
41610314Smckusick 		panic("cannot allocate space for symbol table\n");
41710314Smckusick 	if (read(fd, base, (int)tblsize) < 0 ||
41810314Smckusick 	    read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) {
41910314Smckusick 		perror("read");
42010314Smckusick 		panic("cannot read symbol table file %s\n", filename);
42110314Smckusick 	}
42211303Smckusick 	switch (command) {
42311303Smckusick 	case 'r':
42411303Smckusick 		/*
42511303Smckusick 		 * For normal continuation, insure that we are using
42611303Smckusick 		 * the next incremental tape
42711303Smckusick 		 */
42811303Smckusick 		if (hdr.dumptime != dumpdate) {
42911303Smckusick 			if (hdr.dumptime < dumpdate)
43011303Smckusick 				fprintf(stderr, "Incremental tape too low\n");
43111303Smckusick 			else
43211303Smckusick 				fprintf(stderr, "Incremental tape too high\n");
43311303Smckusick 			done(1);
43411303Smckusick 		}
43511303Smckusick 		break;
43611303Smckusick 	case 'R':
43711303Smckusick 		/*
43811303Smckusick 		 * For restart, insure that we are using the same tape
43911303Smckusick 		 */
440*11324Smckusick 		curfile.action = SKIP;
441*11324Smckusick 		dumptime = hdr.dumptime;
442*11324Smckusick 		dumpdate = hdr.dumpdate;
443*11324Smckusick 		getvol(hdr.volno);
44411303Smckusick 		break;
44511303Smckusick 	default:
44611303Smckusick 		panic("initsymtable called from command %c\n", command);
44711303Smckusick 		break;
44811303Smckusick 	}
44910314Smckusick 	maxino = hdr.maxino;
45010314Smckusick 	entry = (struct entry **)(base + hdr.stringsize);
45111129Smckusick 	baseep = (struct entry *)(&entry[maxino]);
45210314Smckusick 	lep = (struct entry *)(base + tblsize);
45311129Smckusick 	for (i = 0; i < maxino; i++) {
45410314Smckusick 		if (entry[i] == NIL)
45510314Smckusick 			continue;
45610314Smckusick 		entry[i] = &baseep[(long)entry[i]];
45710314Smckusick 	}
45810314Smckusick 	for (ep = baseep; ep < lep; ep++) {
45910314Smckusick 		ep->e_name = base + (long)ep->e_name;
46010314Smckusick 		ep->e_parent = &baseep[(long)ep->e_parent];
46111129Smckusick 		ep->e_sibling = &baseep[(long)ep->e_sibling];
46211129Smckusick 		ep->e_links = &baseep[(long)ep->e_links];
46311129Smckusick 		ep->e_entries = &baseep[(long)ep->e_entries];
46410314Smckusick 	}
46510314Smckusick }
466