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