|
|
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.