|
|
1.1 root 1: /*
2: * routines for creating and looking up internal files
3: *
4: * the internal file structure is a tree of Files.
5: * terminal nodes are regular files;
6: * their contents is in a real file outside.
7: * other nodes are directories;
8: * they exist only in our memory.
9: *
10: * directories are sorted lists;
11: * files are looked up by binary search.
12: */
13:
14: #include "faces.h"
15: #include "faceproto.h" /* for FROOT */
16: #include <stdio.h>
17: #include <sys/types.h>
18: #include <sys/stat.h>
19: #include "dirent.h" /* non-portable portable routines */
20:
21: static File *root;
22: static int nextino;
23:
24: #define DIRINIT 10
25: #define DIRCHUNK 100
26:
27: /*
28: * built-in directories
29: * every outside data file must be in one of these
30: */
31:
32: struct builtin {
33: char *ourname;
34: char *extname;
35: File *file;
36: time_t mtime;
37: } builtins[] = {
38: {"48x48x1", "/usr/jerq/icon/face48"},
39: {"48x48x2", "/usr/jerq/icon/48x48x2"},
40: {"512x512x8", "/t0/face/512x512x8"},
41: 0
42: };
43:
44: static time_t ptime, mtime;
45:
46: extern char *strchr();
47: extern File *falloc();
48:
49: /*
50: * remake the face tree
51: */
52:
53: maketree(pfile, mfile)
54: char *pfile, *mfile;
55: {
56: File *df, *f;
57: FILE *fp;
58: char *dir, *pers, *ref;
59: register struct builtin *bp;
60:
61: (void)newdata(pfile, mfile); /* store times */
62: if (root == NULL) {
63: nextino = FROOT;
64: root = newfile();
65: } else {
66: nextino = FROOT + 1;
67: freetree(root);
68: }
69: initdir(root, root);
70: for (bp = builtins; bp->ourname; bp++) {
71: f = newfile();
72: initdir(f, root);
73: filldir(f, bp->extname);
74: enterfile(root, bp->ourname, f);
75: bp->file = f;
76: }
77: if ((fp = fopen(pfile, "r")) == NULL)
78: log("%s: cannot open; no people\n", pfile);
79: else {
80: while (pcrack(fp, pfile, &dir, &pers, &ref)) {
81: if ((df = lookent(root, dir)) == NULL) {
82: df = newfile();
83: initdir(df, root);
84: enterfile(root, dir, df);
85: }
86: f = newfile(); /* make dir/pers */
87: if (enterfile(df, pers, f)) {
88: log("%s: %s/%s=%s: dup for %s/%s\n",
89: pfile, dir, pers, ref, dir, pers);
90: ffree(f);
91: continue;
92: }
93: initdir(f, df);
94: for (bp = builtins; bp->ourname; bp++)
95: if ((df = lookent(bp->file, ref)) != NULL)
96: enterfile(f, bp->ourname, df);
97: }
98: fclose(fp);
99: }
100: if ((fp = fopen(mfile, "r")) == NULL)
101: log("%s: cannot open; no machines\n", mfile);
102: else {
103: while (pcrack(fp, mfile, &dir, (char **)NULL, &ref)) {
104: if ((df = lookent(root, ref)) == NULL) {
105: log("%s: %s=%s: %s not found\n",
106: mfile, dir, ref, ref);
107: continue;
108: }
109: if ((f = enterfile(root, dir, df)) != NULL) {
110: if (f == df) {
111: log("%s: %s=%s: already true\n",
112: mfile, dir, ref);
113: continue;
114: }
115: uniondir(df, f, mfile, dir, ref);
116: }
117: }
118: fclose(fp);
119: }
120: }
121:
122: /*
123: * parse a line in people file or machine file
124: * fairly hackish
125: * people file: dir/person=realfile
126: * machine file: machdir=dir
127: * return 1 if a valid entry found,
128: * 0 if end of file
129: */
130:
131: pcrack(fp, fname, dirp, persp, refp)
132: FILE *fp;
133: char *fname;
134: char **dirp, **persp, **refp;
135: {
136: static char buf[100];
137: register char *p;
138:
139: again:
140: buf[sizeof(buf)-1] = 0;
141: if (fgets(buf, sizeof(buf), fp) == NULL)
142: return (0); /* EOF */
143: if (buf[sizeof(buf)-1]) {
144: buf[sizeof(buf)-1] = 0;
145: log("%s: line too long: %s ...\n", fname, buf);
146: return (0); /* too hard to recover for now */
147: }
148: if (buf[0] == '#' || buf[0] == '\n')
149: goto again; /* skip comments, empties */
150: p = buf;
151: *dirp = p;
152: if (persp) {
153: if ((p = strchr(p, '/')) == NULL) {
154: log("%s: missing /: %s", fname, buf);
155: goto again;
156: }
157: *p++ = 0;
158: *persp = p;
159: }
160: if ((p = strchr(p, '=')) == NULL) {
161: if (persp)
162: (*persp)[-1] = '/'; /* hack */
163: log("%s: missing =: %s", fname, buf);
164: goto again;
165: }
166: *p++ = 0;
167: *refp = p;
168: if ((p = strchr(p, '\n')) != NULL) /* fgets should promise this */
169: *p = 0;
170: return (1);
171: }
172:
173: /*
174: * see if the outside data has changed,
175: * and we should rebuild the tree
176: */
177:
178: newdata(pfile, mfile)
179: char *pfile, *mfile;
180: {
181: struct stat st;
182: int new;
183: register struct builtin *bp;
184:
185: new = 0;
186: for (bp = builtins; bp->ourname; bp++) {
187: if (stat(bp->extname, &st) < 0)
188: continue;
189: if (bp->mtime == 0)
190: bp->mtime = st.st_mtime;
191: if (bp->mtime < st.st_mtime) {
192: bp->mtime = st.st_mtime;
193: new = 1;
194: }
195: }
196: if (stat(pfile, &st) >= 0) {
197: if (ptime == 0)
198: ptime = st.st_mtime;
199: if (ptime < st.st_mtime) {
200: ptime = st.st_mtime;
201: new = 1;
202: }
203: }
204: if (stat(mfile, &st) >= 0) {
205: if (mtime == 0)
206: mtime = st.st_mtime;
207: if (mtime < st.st_mtime) {
208: mtime = st.st_mtime;
209: new = 1;
210: }
211: }
212: return (new);
213: }
214:
215: /*
216: * free a sub-tree
217: */
218: freetree(f)
219: register File *f;
220: {
221: register int i;
222: register File *nf;
223:
224: if (!isdir(f))
225: return;
226: for (i = 0; i < f->nfiles; i++) {
227: nf = f->dir[i].file;
228: if (nf == f /* probably "." */
229: || strcmp(f->dir[i].name, "..") == 0) {
230: nf->nlinks--;
231: continue;
232: }
233: if (isdir(nf))
234: freetree(nf);
235: if (--nf->nlinks > 0)
236: continue;
237: if (nf->data)
238: free(nf->data);
239: if (nf->dir)
240: free((char *)nf->dir);
241: ffree(nf);
242: }
243: if (f->data)
244: free(f->data);
245: f->data = NULL;
246: f->nfiles = 0; /* (but still allocated) */
247: }
248:
249: /*
250: * make a new file
251: */
252:
253: File *
254: newfile()
255: {
256: register File *f;
257:
258: f = falloc();
259: f->nlinks = 0; /* no entries yet */
260: f->ino = nextino++;
261: f->data = NULL;
262: f->dir = NULL;
263: return (f);
264: }
265:
266: /*
267: * init a directory:
268: * set up . and ..
269: */
270:
271: initdir(f, parent)
272: register File *f;
273: File *parent;
274: {
275: extern long time();
276:
277: if (f->dir == NULL) {
278: f->dir = (Dirent *)emalloc(DIRINIT*sizeof(Dirent));
279: f->nalloc = DIRINIT;
280: } else if (f->nalloc < 2)
281: panic("init badly formed dir\n");
282: if (f->data) {
283: free(f->data);
284: f->data = NULL;
285: }
286: f->nfiles = 2;
287: strcpy(f->dir[0].name, ".");
288: f->dir[0].file = f;
289: f->nlinks++;
290: strcpy(f->dir[1].name, "..");
291: f->dir[1].file = parent;
292: parent->nlinks++;
293: f->tc = time((long *)0);
294: f->ta = f->tc;
295: f->tm = f->tc;
296: }
297:
298: /*
299: * look up an entry in a directory
300: */
301:
302: File *
303: lookent(f, name)
304: File *f;
305: register char *name;
306: {
307: register Dirent *d;
308: register int i, cmp, u, l;
309:
310: if (!isdir(f))
311: return (NULL);
312: d = f->dir;
313: u = f->nfiles; /* first entry known to be too big */
314: l = 0; /* first entry known to be big enough */
315: while (u > l) {
316: i = (u + l)/2;
317: if ((cmp = name[0] - d[i].name[0]) == 0
318: && (cmp = strcmp(name, d[i].name)) == 0)
319: return (d[i].file);
320: else if (cmp < 0)
321: u = i;
322: else
323: l = i + 1;
324: }
325: return (NULL);
326: }
327:
328: /*
329: * enter newf in f with the given name
330: * if it is a new entry, return NULL
331: * if f already had name, return the old one, leave it in place
332: */
333:
334: File *
335: enterfile(f, name, newf)
336: File *f;
337: register char *name;
338: File *newf;
339: {
340: register Dirent *d;
341: register int i, cmp, u, l;
342:
343: if (!isdir(f))
344: panic("enter non-dir\n");
345: if (f->nalloc <= f->nfiles) { /* need more room */
346: f->nalloc += DIRCHUNK;
347: f->dir = (Dirent *)erealloc((char *)f->dir, f->nalloc*sizeof(Dirent));
348: }
349: d = f->dir;
350: u = f->nfiles; /* first entry known to be too big */
351: l = 0; /* first entry known to be big enough */
352: while (u > l) {
353: i = (u + l)/2;
354: if ((cmp = name[0] - d[i].name[0]) == 0
355: && (cmp = strcmp(name, d[i].name)) == 0)
356: return (d[i].file); /* unexpected */
357: else if (cmp < 0)
358: u = i;
359: else
360: l = i + 1;
361: }
362: /*
363: * not found; d[u] is too big
364: * insert before d[u]
365: */
366: for (i = f->nfiles; i > u; i--)
367: d[i] = d[i-1];
368: strncpy(d[i].name, name, DIRNSIZE);
369: d[i].file = newf;
370: f->nfiles++;
371: newf->nlinks++;
372: if (f->data) { /* invalid now */
373: free(f->data);
374: f->data = NULL;
375: }
376: return (NULL);
377: }
378:
379: /*
380: * look up a full pathname
381: */
382:
383: File *
384: lookfile(path)
385: register char *path;
386: {
387: File *f;
388: register char *sl;
389:
390: f = root;
391: for (;;) {
392: while (*path == '/')
393: path++;
394: if (*path == 0)
395: return (f);
396: if ((sl = strchr(path, '/')) != NULL)
397: *sl = 0; /* cheap hack */
398: f = lookent(f, path);
399: if (sl)
400: *sl = '/'; /* cheap hack returns */
401: if (f == NULL)
402: return (NULL);
403: if (sl == NULL)
404: return (f); /* no more slashes, so we're done */
405: path = sl + 1;
406: }
407: }
408:
409: /*
410: * link each entry from f to uf,
411: * fussing about duplicates
412: * --the string arguments are just for the log message
413: */
414:
415: uniondir(f, uf, mfile, dir, ref)
416: File *f, *uf;
417: char *mfile, *dir, *ref;
418: {
419: register int i;
420: register Dirent *dp;
421: register File *ef;
422:
423: dp = f->dir;
424: for (i = 0; i < f->nfiles; dp++, i++) {
425: if (dp->name[0] == '.'
426: && (strcmp(dp->name, ".") == 0 || strcmp(dp->name, "..") == 0))
427: continue;
428: if ((ef = enterfile(uf, dp->name, dp->file)) != NULL
429: && ef != dp->file) /* same file already there */
430: log("%s: %s=%s: file %s duplicate\n",
431: mfile, dir, ref, dp->name);
432: }
433: }
434:
435: /*
436: * copy directory entries from the outside
437: * to one of ours
438: * save many calls to enterfile, and many searches
439: * for files that don't exist, by building the directory
440: * here and sorting it
441: */
442:
443: static int
444: dircmp(a, b)
445: char *a, *b;
446: {
447: return (strncmp(((Dirent *)a)->name, ((Dirent *)b)->name, DIRNSIZE));
448: }
449:
450: filldir(f, realdir)
451: register File *f;
452: char *realdir;
453: {
454: DIR *fp;
455: register struct dirent *dp;
456: register Dirent *idp;
457: File *nf;
458: int rdlen;
459:
460: if ((fp = opendir(realdir)) == NULL) {
461: log("%s: can't opendir\n", realdir);
462: return;
463: }
464: rdlen = strlen(realdir);
465: idp = &f->dir[f->nfiles];
466: while ((dp = readdir(fp)) != NULL) {
467: if (dp->d_name[0] == '.'
468: && (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0))
469: continue;
470: nf = newfile();
471: if (f->nalloc <= f->nfiles) {
472: f->nalloc += DIRCHUNK;
473: f->dir = (Dirent *)erealloc((char *)f->dir, f->nalloc*sizeof(Dirent));
474: idp = &f->dir[f->nfiles]; /* realloc may move it */
475: }
476: strncpy(idp->name, dp->d_name, DIRNSIZE);
477: idp->file = nf;
478: idp++;
479: f->nfiles++;
480: nf->nlinks++;
481: nf->data = emalloc(rdlen+1+strlen(dp->d_name)+1);
482: strcpy(nf->data, realdir);
483: nf->data[rdlen] = '/';
484: strcpy(nf->data+rdlen+1, dp->d_name);
485: }
486: closedir(fp);
487: qsort((char *)f->dir, f->nfiles, sizeof(Dirent), dircmp);
488: }
489:
490: /*
491: * set up directory data to be sent to client
492: */
493: dirdata(f)
494: register File *f;
495: {
496: register int i;
497: register unsigned char *p;
498:
499: if (!isdir(f))
500: panic("dirdata not dir\n");
501: f->size = f->nfiles * FDLEN;
502: f->data = emalloc((int)f->size);
503: p = (unsigned char *)f->data;
504: for (i = 0; i < f->nfiles; i++) {
505: tofshort(p, FD_INO, f->dir[i].file->ino);
506: strncpy(p + FD_NAME, f->dir[i].name, FDLEN - FD_NAME);
507: p += FDLEN;
508: }
509: }
510:
511: /*
512: * manage storage for Files;
513: * cheap hack for speed, to cut malloc calls
514: * keep a free list of Files, linked on f->data
515: */
516:
517: static File *fflist;
518: #define FILECHUNK 100
519:
520: File *
521: falloc()
522: {
523: register File *f;
524: register int i;
525:
526: if ((f = fflist) != NULL) {
527: fflist = (File *)f->data;
528: return (f);
529: }
530: f = (File *)emalloc(FILECHUNK*sizeof(File));
531: for (i = 0; i < FILECHUNK-1; f++, i++) {
532: f->data = (char *)fflist;
533: fflist = f;
534: }
535: return (f);
536: }
537:
538: ffree(f)
539: File *f;
540: {
541: f->data = (char *)fflist;
542: fflist = f;
543: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.