|
|
1.1 ! root 1: /* ! 2: * simple unix filesystem interface; ! 3: * access local files through system calls ! 4: */ ! 5: ! 6: #include <sys/types.h> ! 7: #include <sys/stat.h> ! 8: #include <stdio.h> ! 9: #include <errno.h> ! 10: #include <rf.h> ! 11: #include "zarf.h" ! 12: ! 13: extern int errno; ! 14: ! 15: static Rfile *rootf; ! 16: static int servuid, servgid; ! 17: ! 18: char rootname[200]; /* arbitrarily large */ ! 19: extern Namemap *exulist, *exglist; ! 20: ! 21: #define rfmode(m) (m) ! 22: #define fsmode(m) (m) ! 23: #define FSPERM 07777 /* just the permission bits */ ! 24: ! 25: static int clientdev(); ! 26: static int maxopen(); ! 27: static int samefile(); ! 28: ! 29: char *malloc(); ! 30: long lseek(); ! 31: ! 32: /* ! 33: * init: ! 34: * return the root ! 35: */ ! 36: ! 37: Rfile * ! 38: fsinit(argc, argv) ! 39: int argc; ! 40: char **argv; ! 41: { ! 42: register Rfile *f; ! 43: char *passwd = "/etc/passwd"; ! 44: char *group = "/etc/group"; ! 45: FILE *fp; ! 46: int foundex; ! 47: ! 48: foundex = 0; ! 49: while (--argc > 0) { ! 50: if (**++argv != '-') ! 51: continue; /* skip unknown args */ ! 52: switch (argv[0][1]) { ! 53: case 'd': ! 54: if (--argc <= 0) { ! 55: rflog("-d: missing arg\n"); ! 56: continue; ! 57: } ! 58: rfdebug = atoi(*++argv); ! 59: break; ! 60: ! 61: case 'p': ! 62: if (--argc <= 0) { ! 63: rflog("-p: missing arg\n"); ! 64: continue; ! 65: } ! 66: passwd = *++argv; ! 67: break; ! 68: ! 69: case 'g': ! 70: if (--argc <= 0) { ! 71: rflog("-g: missing arg\n"); ! 72: continue; ! 73: } ! 74: group = *++argv; ! 75: break; ! 76: ! 77: case 'r': ! 78: if (--argc <= 0) { ! 79: rflog("-r: missing arg\n"); ! 80: continue; ! 81: } ! 82: strcpy(rootname, *++argv); ! 83: break; ! 84: case 'e': ! 85: if (--argc <= 0) { ! 86: rflog("-e: missing arg\n"); ! 87: continue; ! 88: } ! 89: if (foundex == 0 && (fp = fopen(*++argv, "r")) != NULL) { ! 90: foundex = rdexcept(fp); ! 91: fclose(fp); ! 92: } ! 93: break; ! 94: ! 95: default: ! 96: rflog("unknown flag %s\n", *argv); ! 97: break; ! 98: } ! 99: } ! 100: rfuidmap = rfmkidmap(passwd, exulist); ! 101: rfgidmap = rfmkidmap(group, exglist); ! 102: if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL) ! 103: return (NULL); ! 104: if ((f->fs = malloc(sizeof(Fsfile))) == NULL) { ! 105: free((char *)f); ! 106: return (NULL); ! 107: } ! 108: if ((fsp(f)->name = malloc(strlen(rootname)+1)) == NULL) { ! 109: free(f->fs); ! 110: free((char *)f); ! 111: return (NULL); ! 112: } ! 113: if (rootname[0] == 0) ! 114: strcpy(rootname, "/"); ! 115: strcpy(fsp(f)->name, rootname); ! 116: fsp(f)->fd = -1; ! 117: fsp(f)->flags = WONTREAD|WONTWRITE|NOSTAT; ! 118: fsstat(f); ! 119: maxopen(f, 0); ! 120: rootf = f; ! 121: umask(0); ! 122: servuid = geteuid(); ! 123: servgid = getegid(); ! 124: setgid(servgid); /* to avoid inconsistencies */ ! 125: setuid(servuid); ! 126: return (f); ! 127: } ! 128: ! 129: Rfile * ! 130: fswalk(df, name) ! 131: Rfile *df; ! 132: char *name; ! 133: { ! 134: register Rfile *f; ! 135: char *nname; ! 136: ! 137: if (rfdebug) ! 138: rflog("walk %d,%ld '%s' '%s'\n", df->dev, df->ino, fsp(df)->name, name); ! 139: if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL) { ! 140: rflog("fswalk: no mem\n"); ! 141: fserrno = RFEINVAL; ! 142: return (NULL); ! 143: } ! 144: if ((f->fs = malloc(sizeof(Fsfile))) == NULL) { ! 145: free((char *)f); ! 146: rflog("fswalk: no mem\n"); ! 147: fserrno = RFEINVAL; ! 148: return (NULL); ! 149: } ! 150: if ((nname = malloc(strlen(fsp(df)->name) + strlen(name) + 2)) == NULL) { ! 151: free(f->fs); ! 152: free((char *)f); ! 153: rflog("fswalk: no mem\n"); ! 154: fserrno = RFEINVAL; ! 155: return (NULL); ! 156: } ! 157: fsp(f)->name = nname; ! 158: strcpy(nname, fsp(df)->name); ! 159: strcat(nname, "/"); ! 160: strcat(nname, name); ! 161: fsp(f)->fd = -1; ! 162: fsp(f)->flags = WONTREAD|WONTWRITE|NOSTAT; ! 163: if (fsstat(f) < 0) ! 164: goto bad; ! 165: /* ! 166: * hack to avoid hanging in open: ! 167: * don't open yet unless regular file (not device) ! 168: * and nonzero link count (not Research mounted stream) ! 169: * better not to defer open for ordinary files, ! 170: * in case someone unlinks the name we know ! 171: */ ! 172: if ((fsmode(f->mode) & S_IFMT) == S_IFREG && f->nlink != 0) ! 173: maxopen(f, 0); ! 174: if (df == rootf) { /* magic for . and .., mostly for pwd */ ! 175: #if NOTDEF ! 176: if (name[0] == 0 || strcmp(name, ".") == 0) { ! 177: close(fsp(f)->fd); ! 178: free(nname); ! 179: free(f->fs); ! 180: free((char *)f); ! 181: return (df); ! 182: } ! 183: #endif ! 184: if (strcmp(name, "..") == 0) { ! 185: close(fsp(f)->fd); ! 186: fserrno = 0; /* pseudo-error: popped out of root */ ! 187: goto bad; ! 188: } ! 189: } ! 190: return (f); ! 191: ! 192: bad: ! 193: free(nname); ! 194: free(f->fs); ! 195: free((char *)f); ! 196: return (NULL); ! 197: } ! 198: ! 199: Rfile * ! 200: fscreate(df, name, mode, uid, gid) ! 201: Rfile *df; ! 202: char *name; ! 203: int mode; ! 204: int uid, gid; ! 205: { ! 206: register Rfile *f; ! 207: char *nname; ! 208: ! 209: if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL) { ! 210: rflog("fscreate: no mem\n"); ! 211: fserrno = RFEINVAL; ! 212: return (NULL); ! 213: } ! 214: if ((f->fs = malloc(sizeof(Fsfile))) == NULL) { ! 215: free((char *)f); ! 216: rflog("fscreate: no mem\n"); ! 217: fserrno = RFEINVAL; ! 218: return (NULL); ! 219: } ! 220: if ((nname = malloc(strlen(fsp(df)->name) + strlen(name) + 2)) == NULL) { ! 221: free(f->fs); ! 222: free((char *)f); ! 223: rflog("fscreate: no mem\n"); ! 224: fserrno = RFEINVAL; ! 225: return (NULL); ! 226: } ! 227: fsp(f)->name = nname; ! 228: strcpy(nname, fsp(df)->name); ! 229: strcat(nname, "/"); ! 230: strcat(nname, name); ! 231: if ((fsp(f)->fd = creat(nname, fsmode(mode))) < 0) { ! 232: fserrno = errno; ! 233: goto bad; ! 234: } ! 235: fsp(f)->flags = WONTREAD|NOSTAT; ! 236: if (fsstat(f) < 0) { ! 237: rflog("fscreate: can't stat %s, err %d\n", nname, errno); ! 238: fserrno = RFEINVAL; ! 239: close(fsp(f)->fd); ! 240: goto bad; ! 241: } ! 242: if (uid != f->uid || gid != f->gid) { ! 243: if (chown(nname, uid, gid) >= 0) { ! 244: f->uid = uid; /* stat would be too slow */ ! 245: f->gid = gid; ! 246: } else if (servuid == 0) { /* if not root, ignore error */ ! 247: rflog("fscreate: can't set owner %s err %d\n", nname, errno); ! 248: fserrno = errno; ! 249: close(fsp(f)->fd); ! 250: goto bad; ! 251: } ! 252: } ! 253: return (f); ! 254: ! 255: bad: ! 256: free(nname); ! 257: free(f->fs); ! 258: free((char *)f); ! 259: return (NULL); ! 260: } ! 261: ! 262: int ! 263: fsmkdir(df, name, mode, uid, gid) ! 264: register Rfile *df; ! 265: char *name; ! 266: int mode; ! 267: int uid, gid; ! 268: { ! 269: char *nname; ! 270: struct stat st; ! 271: ! 272: if ((nname = malloc(strlen(fsp(df)->name) + strlen(name) + 2)) == NULL) { ! 273: rflog("fsmkdir: no mem\n"); ! 274: fserrno = RFEINVAL; ! 275: return (-1); ! 276: } ! 277: strcpy(nname, fsp(df)->name); ! 278: strcat(nname, "/"); ! 279: strcat(nname, name); ! 280: if (mkdir(nname, fsmode(mode)) < 0) { ! 281: fserrno = errno; ! 282: free(nname); ! 283: return (-1); ! 284: } ! 285: if (stat(nname, &st) < 0 ! 286: || (uid != st.st_uid || gid != st.st_gid) && chown(nname, uid, gid) < 0) { ! 287: rflog("fsmkdir: can't set owner %s err %d\n", nname, errno); ! 288: fserrno = errno; ! 289: rmdir(nname); /* maybe this will work */ ! 290: free(nname); ! 291: return (-1); ! 292: } ! 293: free(nname); ! 294: return (0); ! 295: } ! 296: ! 297: int ! 298: fsrmdir(df, name) ! 299: register Rfile *df; ! 300: char *name; ! 301: { ! 302: char *nname; ! 303: ! 304: if ((nname = malloc(strlen(fsp(df)->name) + strlen(name) + 2)) == NULL) { ! 305: rflog("fsrmdir: no mem\n"); ! 306: fserrno = RFEINVAL; ! 307: return (-1); ! 308: } ! 309: strcpy(nname, fsp(df)->name); ! 310: strcat(nname, "/"); ! 311: strcat(nname, name); ! 312: if (rmdir(nname) < 0) { ! 313: fserrno = errno; ! 314: free(nname); ! 315: return (-1); ! 316: } ! 317: free(nname); ! 318: return (0); ! 319: } ! 320: ! 321: int ! 322: fsdelete(df, name) ! 323: register Rfile *df; ! 324: char *name; ! 325: { ! 326: char *nname; ! 327: ! 328: if ((nname = malloc(strlen(fsp(df)->name) + strlen(name) + 2)) == NULL) { ! 329: rflog("fsdelete: no mem\n"); ! 330: fserrno = RFEINVAL; ! 331: return (-1); ! 332: } ! 333: strcpy(nname, fsp(df)->name); ! 334: strcat(nname, "/"); ! 335: strcat(nname, name); ! 336: if (unlink(nname) < 0) { ! 337: fserrno = errno; ! 338: free(nname); ! 339: return (-1); ! 340: } ! 341: free(nname); ! 342: return (0); ! 343: } ! 344: ! 345: int ! 346: fslink(df, name, f) ! 347: register Rfile *df, *f; ! 348: char *name; ! 349: { ! 350: char *nname; ! 351: ! 352: if ((nname = malloc(strlen(fsp(df)->name) + strlen(name) + 2)) == NULL) { ! 353: rflog("fslink: no mem\n"); ! 354: fserrno = RFEINVAL; ! 355: return (-1); ! 356: } ! 357: if (samefile(f) == 0) { ! 358: rflog("fslink: wrong file %s\n", fsp(f)->name); ! 359: fserrno = RFEINVAL; ! 360: return (-1); ! 361: } ! 362: strcpy(nname, fsp(df)->name); ! 363: strcat(nname, "/"); ! 364: strcat(nname, name); ! 365: if (link(fsp(f)->name, nname) < 0) { ! 366: fserrno = errno; ! 367: free(nname); ! 368: return (-1); ! 369: } ! 370: free(nname); ! 371: return (0); ! 372: } ! 373: ! 374: int ! 375: fsdone(f) ! 376: register Rfile *f; ! 377: { ! 378: ! 379: if (fsp(f)->flags & DIDDIR) ! 380: dodircleanup(f); ! 381: close(fsp(f)->fd); ! 382: free(fsp(f)->name); ! 383: free(f->fs); ! 384: free((char *)f); ! 385: return (0); ! 386: } ! 387: ! 388: /* ! 389: * this should really use fchmod and fchown, but ! 390: * (1) some systems don't have them; ! 391: * (2) there must be code to call chmod anyway, ! 392: * else how can we chmod a file in mode 0 if not super-user? ! 393: * (3) there's no futime anyway ! 394: * ! 395: * the test in front is to skip samefile (and perhaps a spurious ! 396: * error message) if nothing is really changing; ! 397: * usually this just means ta or tm is being updated to the ! 398: * value the local system has already stored after read or write ! 399: */ ! 400: ! 401: int ! 402: fsupdate(f, nf) ! 403: register Rfile *f, *nf; ! 404: { ! 405: long ft[2]; ! 406: int nfd; ! 407: int status; ! 408: ! 409: if ((fsmode(nf->mode)&FSPERM) == (fsmode(f->mode)&FSPERM) ! 410: && nf->uid == f->uid && nf->gid == f->gid ! 411: && nf->ta == f->ta && nf->tm == f->tm ! 412: && nf->size == f->size) ! 413: return (0); ! 414: if (samefile(f) == 0) { ! 415: rflog("fsupdate: wrong file %s\n", fsp(f)->name); ! 416: fserrno = RFEINVAL; ! 417: return (-1); ! 418: } ! 419: status = -1; ! 420: if ((fsmode(nf->mode)&FSPERM) != (fsmode(f->mode)&FSPERM)) { ! 421: if (chmod(fsp(f)->name, fsmode(nf->mode) & FSPERM) < 0) { ! 422: fserrno = errno; ! 423: goto out; ! 424: } ! 425: } ! 426: if (nf->ta || nf->tm) { ! 427: ft[0] = nf->ta; ! 428: ft[1] = nf->tm; ! 429: if (utime(fsp(f)->name, ft) < 0) { ! 430: fserrno = errno; ! 431: goto out; ! 432: } ! 433: } ! 434: if (f->uid != nf->uid || f->gid != nf->gid) { ! 435: if (chown(fsp(f)->name, nf->uid, nf->gid) < 0) { ! 436: fserrno = errno; ! 437: goto out; ! 438: } ! 439: } ! 440: if (f->size != nf->size && nf->size == 0) { ! 441: if ((nfd = creat(fsp(f)->name, 0)) < 0) { ! 442: fserrno = errno; ! 443: goto out; ! 444: } ! 445: close(nfd); ! 446: } ! 447: status = 0; ! 448: out: ! 449: fsstat(f); ! 450: return (status); ! 451: } ! 452: ! 453: fsstat(f) ! 454: register Rfile *f; ! 455: { ! 456: struct stat st; ! 457: ! 458: if (fsp(f)->fd >= 0 && fstat(fsp(f)->fd, &st) < 0) { ! 459: fserrno = errno; ! 460: return (-1); ! 461: } ! 462: else if (stat(fsp(f)->name, &st) < 0) { ! 463: fserrno = errno; ! 464: return (-1); ! 465: } ! 466: if (fsp(f)->flags & NOSTAT) ! 467: fsp(f)->flags &=~ NOSTAT; ! 468: else if (clientdev(st.st_dev) != f->dev || st.st_ino != f->ino) { ! 469: rflog("fsstat: wrong file %s\n", fsp(f)->name); ! 470: fserrno = RFEINVAL; ! 471: return (-1); ! 472: } ! 473: f->ino = st.st_ino; ! 474: f->dev = clientdev(st.st_dev); ! 475: f->mode = rfmode(st.st_mode); ! 476: switch(st.st_mode & S_IFMT) { ! 477: case S_IFDIR: ! 478: f->type = RFTDIR; ! 479: break; ! 480: ! 481: case S_IFCHR: ! 482: case S_IFBLK: ! 483: f->mode &=~ 07777; /* deny access to devices */ ! 484: /* fall through */ ! 485: case S_IFREG: ! 486: f->type = RFTREG; ! 487: break; ! 488: } ! 489: f->nlink = st.st_nlink; ! 490: f->uid = st.st_uid; ! 491: f->gid = st.st_gid; ! 492: f->size = st.st_size; ! 493: f->ta = st.st_atime; ! 494: f->tm = st.st_mtime; ! 495: f->tc = st.st_ctime; ! 496: return (0); ! 497: } ! 498: ! 499: int ! 500: fsread(f, off, buf, len) ! 501: register Rfile *f; ! 502: long off; ! 503: char *buf; ! 504: int len; ! 505: { ! 506: register int n; ! 507: ! 508: if (fsp(f)->flags & WONTREAD) ! 509: maxopen(f, 0); ! 510: if (fsp(f)->flags & CANTREAD) { ! 511: fserrno = RFEACCES; /* probably */ ! 512: return (-1); ! 513: } ! 514: lseek(fsp(f)->fd, off, 0); ! 515: if ((n = read(fsp(f)->fd, buf, len)) < 0) ! 516: fserrno = errno; ! 517: return (n); ! 518: } ! 519: ! 520: int ! 521: fsdirread(f, off, buf, len, offp) ! 522: register Rfile *f; ! 523: long off; ! 524: char *buf; ! 525: int len; ! 526: long *offp; ! 527: { ! 528: ! 529: if (fsp(f)->flags & WONTREAD) ! 530: maxopen(f, 0); ! 531: if (fsp(f)->flags & CANTREAD) { ! 532: fserrno = RFEACCES; /* probably */ ! 533: return (-1); ! 534: } ! 535: fsp(f)->flags |= DIDDIR; ! 536: return (dodirread(f, buf, len, off, offp)); ! 537: } ! 538: ! 539: int ! 540: fswrite(f, off, buf, len) ! 541: register Rfile *f; ! 542: long off; ! 543: char *buf; ! 544: int len; ! 545: { ! 546: register int n; ! 547: ! 548: if (fsp(f)->flags & WONTWRITE) ! 549: maxopen(f, 1); ! 550: if (fsp(f)->flags & CANTWRITE) { ! 551: fserrno = RFEACCES; ! 552: return (-1); ! 553: } ! 554: lseek(fsp(f)->fd, off, 0); ! 555: if ((n = write(fsp(f)->fd, buf, len)) < 0) ! 556: fserrno = errno; ! 557: else if (off + len > f->size) ! 558: f->size = off + len; /* should stat, but too slow */ ! 559: return (n); ! 560: } ! 561: ! 562: /* ! 563: * turn a client st_dev into an rf minor device ! 564: * exactly eight bits allowed ! 565: */ ! 566: ! 567: #define MAXDEVS 255 ! 568: ! 569: int maxdev = 0; ! 570: dev_t devtab[MAXDEVS]; ! 571: ! 572: static int ! 573: clientdev(d) ! 574: register dev_t d; ! 575: { ! 576: register int i; ! 577: ! 578: for (i = 0; i < maxdev; i++) ! 579: if (devtab[i] == d) ! 580: return (i); ! 581: if (i >= MAXDEVS) { ! 582: rflog("too many devs, can't map %x\n", d); ! 583: return (MAXDEVS); ! 584: } ! 585: devtab[i] = d; ! 586: maxdev = i + 1; ! 587: return (i); ! 588: } ! 589: ! 590: /* ! 591: * open a file as broadly as possible ! 592: * to avoid `text busy,' don't open for write ! 593: * unless specifically requested ! 594: * or unless file has no execute permissions (hack) ! 595: * directories usually have execute permissions (further hack) ! 596: */ ! 597: ! 598: #define ANYEXEC ((RFPEX<<RFPOWNER)|(RFPEX<<RFPGROUP)|(RFPEX<<RFPOTHER)) ! 599: ! 600: static int ! 601: maxopen(f, mustwrite) ! 602: register Rfile *f; ! 603: int mustwrite; ! 604: { ! 605: register Fsfile *fs; ! 606: int fd; ! 607: struct stat st; ! 608: register int flags; ! 609: ! 610: fd = -1; ! 611: fs = fsp(f); ! 612: flags = fs->flags; ! 613: if ((flags & (WONTREAD|WONTWRITE)) == 0) ! 614: return; ! 615: if ((flags & (CANTREAD|CANTWRITE)) == 0 ! 616: && mustwrite || (f->mode & ANYEXEC) == 0) { ! 617: if ((fd = open(fs->name, 2)) >= 0) ! 618: flags &=~ (WONTREAD|WONTWRITE); ! 619: } ! 620: if ((flags & (CANTREAD|WONTREAD)) == WONTREAD) { ! 621: flags &=~ WONTREAD; ! 622: if ((fd = open(fs->name, 0)) < 0) ! 623: flags |= CANTREAD; ! 624: } ! 625: if (mustwrite && (flags & (CANTWRITE|WONTWRITE)) == WONTWRITE) { ! 626: flags &=~ WONTWRITE; ! 627: if ((fd = open(fs->name, 1)) < 0) ! 628: flags |= CANTWRITE; ! 629: } ! 630: if (fd >= 0) { /* if we opened something */ ! 631: if ((flags & NOSTAT) == 0) { ! 632: if (fstat(fd, &st) < 0) { ! 633: rflog("maxopen: fstat %s err %d\n", fs->name, errno); ! 634: close(fd); ! 635: return; /* flags and fd unchanged */ ! 636: } else if (clientdev(st.st_dev) != f->dev || st.st_ino != f->ino) { ! 637: rflog("maxopen: wrong file %s\n", fs->name); ! 638: close(fd); ! 639: return; /* flags and fd unchanged */ ! 640: } ! 641: } ! 642: /* it's the same file, or we can't tell */ ! 643: fs->flags = flags; ! 644: if (fs->fd >= 0) ! 645: close(fs->fd); ! 646: fs->fd = fd; ! 647: } ! 648: } ! 649: ! 650: /* ! 651: * is this the same file we opened? ! 652: * call before operations that must use name rather than fd ! 653: */ ! 654: ! 655: static int ! 656: samefile(f) ! 657: register Rfile *f; ! 658: { ! 659: struct stat st; ! 660: ! 661: if (fsp(f)->flags & NOSTAT) ! 662: return (1); /* can't tell */ ! 663: if (stat(fsp(f)->name, &st) < 0) ! 664: return (0); ! 665: if (clientdev(st.st_dev) != f->dev || st.st_ino != f->ino) ! 666: return (0); ! 667: return (1); ! 668: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.