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