13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 3*219b2ee8SDavid du Colombier #include <auth.h> 43e12c5d1SDavid du Colombier #include <fcall.h> 53e12c5d1SDavid du Colombier 63e12c5d1SDavid du Colombier /* 73e12c5d1SDavid du Colombier * Rather than reading /adm/users, which is a lot of work for 83e12c5d1SDavid du Colombier * a toy program, we assume all groups have the form 93e12c5d1SDavid du Colombier * NNN:user:user: 103e12c5d1SDavid du Colombier * meaning that each user is the leader of his own group. 113e12c5d1SDavid du Colombier */ 123e12c5d1SDavid du Colombier 133e12c5d1SDavid du Colombier enum 143e12c5d1SDavid du Colombier { 153e12c5d1SDavid du Colombier OPERM = 0x3, /* mask of all permission types in open mode */ 163e12c5d1SDavid du Colombier Nram = 512, 173e12c5d1SDavid du Colombier }; 183e12c5d1SDavid du Colombier 193e12c5d1SDavid du Colombier typedef struct Fid Fid; 203e12c5d1SDavid du Colombier typedef struct Ram Ram; 213e12c5d1SDavid du Colombier 223e12c5d1SDavid du Colombier struct Fid 233e12c5d1SDavid du Colombier { 243e12c5d1SDavid du Colombier short busy; 253e12c5d1SDavid du Colombier short open; 263e12c5d1SDavid du Colombier short rclose; 273e12c5d1SDavid du Colombier int fid; 283e12c5d1SDavid du Colombier Fid *next; 293e12c5d1SDavid du Colombier char *user; 303e12c5d1SDavid du Colombier Ram *ram; 313e12c5d1SDavid du Colombier }; 323e12c5d1SDavid du Colombier 333e12c5d1SDavid du Colombier struct Ram 343e12c5d1SDavid du Colombier { 353e12c5d1SDavid du Colombier short busy; 363e12c5d1SDavid du Colombier short open; 373e12c5d1SDavid du Colombier long parent; /* index in Ram array */ 383e12c5d1SDavid du Colombier Qid qid; 393e12c5d1SDavid du Colombier long perm; 403e12c5d1SDavid du Colombier char name[NAMELEN]; 413e12c5d1SDavid du Colombier ulong atime; 423e12c5d1SDavid du Colombier ulong mtime; 433e12c5d1SDavid du Colombier char *user; 443e12c5d1SDavid du Colombier char *group; 453e12c5d1SDavid du Colombier char *data; 463e12c5d1SDavid du Colombier long ndata; 473e12c5d1SDavid du Colombier }; 483e12c5d1SDavid du Colombier 493e12c5d1SDavid du Colombier enum 503e12c5d1SDavid du Colombier { 513e12c5d1SDavid du Colombier Pexec = 1, 523e12c5d1SDavid du Colombier Pwrite = 2, 533e12c5d1SDavid du Colombier Pread = 4, 543e12c5d1SDavid du Colombier Pother = 1, 553e12c5d1SDavid du Colombier Pgroup = 8, 563e12c5d1SDavid du Colombier Powner = 64, 573e12c5d1SDavid du Colombier }; 583e12c5d1SDavid du Colombier 593e12c5d1SDavid du Colombier ulong path; /* incremented for each new file */ 603e12c5d1SDavid du Colombier Fid *fids; 613e12c5d1SDavid du Colombier Ram ram[Nram]; 623e12c5d1SDavid du Colombier int nram; 633e12c5d1SDavid du Colombier int mfd[2]; 643e12c5d1SDavid du Colombier char user[NAMELEN]; 653e12c5d1SDavid du Colombier char mdata[MAXMSG+MAXFDATA]; 663e12c5d1SDavid du Colombier Fcall rhdr; 673e12c5d1SDavid du Colombier Fcall thdr; 683e12c5d1SDavid du Colombier 693e12c5d1SDavid du Colombier Fid * newfid(int); 703e12c5d1SDavid du Colombier void ramstat(Ram*, char*); 713e12c5d1SDavid du Colombier void error(char*); 723e12c5d1SDavid du Colombier void io(void); 733e12c5d1SDavid du Colombier void *erealloc(void*, ulong); 743e12c5d1SDavid du Colombier void *emalloc(ulong); 753e12c5d1SDavid du Colombier void usage(void); 763e12c5d1SDavid du Colombier int perm(Fid*, Ram*, int); 773e12c5d1SDavid du Colombier 783e12c5d1SDavid du Colombier char *rflush(Fid*), *rnop(Fid*), *rsession(Fid*), 793e12c5d1SDavid du Colombier *rattach(Fid*), *rclone(Fid*), *rwalk(Fid*), 803e12c5d1SDavid du Colombier *rclwalk(Fid*), *ropen(Fid*), *rcreate(Fid*), 813e12c5d1SDavid du Colombier *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), 82*219b2ee8SDavid du Colombier *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*); 833e12c5d1SDavid du Colombier 843e12c5d1SDavid du Colombier char *(*fcalls[])(Fid*) = { 853e12c5d1SDavid du Colombier [Tflush] rflush, 863e12c5d1SDavid du Colombier [Tsession] rsession, 873e12c5d1SDavid du Colombier [Tnop] rnop, 883e12c5d1SDavid du Colombier [Tattach] rattach, 893e12c5d1SDavid du Colombier [Tclone] rclone, 903e12c5d1SDavid du Colombier [Twalk] rwalk, 913e12c5d1SDavid du Colombier [Tclwalk] rclwalk, 923e12c5d1SDavid du Colombier [Topen] ropen, 933e12c5d1SDavid du Colombier [Tcreate] rcreate, 943e12c5d1SDavid du Colombier [Tread] rread, 953e12c5d1SDavid du Colombier [Twrite] rwrite, 963e12c5d1SDavid du Colombier [Tclunk] rclunk, 973e12c5d1SDavid du Colombier [Tremove] rremove, 983e12c5d1SDavid du Colombier [Tstat] rstat, 993e12c5d1SDavid du Colombier [Twstat] rwstat, 1003e12c5d1SDavid du Colombier }; 1013e12c5d1SDavid du Colombier 1023e12c5d1SDavid du Colombier char Eperm[] = "permission denied"; 1033e12c5d1SDavid du Colombier char Enotdir[] = "not a directory"; 1043e12c5d1SDavid du Colombier char Enoauth[] = "no authentication in ramfs"; 1053e12c5d1SDavid du Colombier char Enotexist[] = "file does not exist"; 1063e12c5d1SDavid du Colombier char Einuse[] = "file in use"; 1073e12c5d1SDavid du Colombier char Eexist[] = "file exists"; 1083e12c5d1SDavid du Colombier char Enotowner[] = "not owner"; 1093e12c5d1SDavid du Colombier char Eisopen[] = "file already open for I/O"; 1103e12c5d1SDavid du Colombier char Excl[] = "exclusive use file already open"; 1113e12c5d1SDavid du Colombier char Ename[] = "illegal name"; 1123e12c5d1SDavid du Colombier 113*219b2ee8SDavid du Colombier int debug; 114*219b2ee8SDavid du Colombier 1153e12c5d1SDavid du Colombier void 1163e12c5d1SDavid du Colombier notifyf(void *a, char *s) 1173e12c5d1SDavid du Colombier { 1183e12c5d1SDavid du Colombier USED(a); 1193e12c5d1SDavid du Colombier if(strncmp(s, "interrupt", 9) == 0) 1203e12c5d1SDavid du Colombier noted(NCONT); 1213e12c5d1SDavid du Colombier noted(NDFLT); 1223e12c5d1SDavid du Colombier } 1233e12c5d1SDavid du Colombier 1243e12c5d1SDavid du Colombier void 1253e12c5d1SDavid du Colombier main(int argc, char *argv[]) 1263e12c5d1SDavid du Colombier { 1273e12c5d1SDavid du Colombier Ram *r; 1283e12c5d1SDavid du Colombier char *defmnt; 1293e12c5d1SDavid du Colombier int p[2]; 1303e12c5d1SDavid du Colombier char buf[12]; 1313e12c5d1SDavid du Colombier int fd; 1323e12c5d1SDavid du Colombier int stdio = 0; 1333e12c5d1SDavid du Colombier 1343e12c5d1SDavid du Colombier defmnt = "/tmp"; 1353e12c5d1SDavid du Colombier ARGBEGIN{ 136*219b2ee8SDavid du Colombier case 'd': 137*219b2ee8SDavid du Colombier debug = 1; 138*219b2ee8SDavid du Colombier break; 1393e12c5d1SDavid du Colombier case 'i': 1403e12c5d1SDavid du Colombier defmnt = 0; 1413e12c5d1SDavid du Colombier stdio = 1; 1423e12c5d1SDavid du Colombier mfd[0] = 0; 1433e12c5d1SDavid du Colombier mfd[1] = 1; 1443e12c5d1SDavid du Colombier break; 1453e12c5d1SDavid du Colombier case 's': 1463e12c5d1SDavid du Colombier defmnt = 0; 1473e12c5d1SDavid du Colombier break; 1483e12c5d1SDavid du Colombier case 'm': 1493e12c5d1SDavid du Colombier defmnt = ARGF(); 1503e12c5d1SDavid du Colombier break; 1513e12c5d1SDavid du Colombier default: 1523e12c5d1SDavid du Colombier usage(); 1533e12c5d1SDavid du Colombier }ARGEND 1543e12c5d1SDavid du Colombier 1553e12c5d1SDavid du Colombier if(pipe(p) < 0) 1563e12c5d1SDavid du Colombier error("pipe failed"); 1573e12c5d1SDavid du Colombier if(!stdio){ 1583e12c5d1SDavid du Colombier mfd[0] = p[0]; 1593e12c5d1SDavid du Colombier mfd[1] = p[0]; 1603e12c5d1SDavid du Colombier if(defmnt == 0){ 1613e12c5d1SDavid du Colombier fd = create("#s/ramfs", OWRITE, 0666); 1623e12c5d1SDavid du Colombier if(fd < 0) 1633e12c5d1SDavid du Colombier error("create of /srv/ramfs failed"); 1643e12c5d1SDavid du Colombier sprint(buf, "%d", p[1]); 1653e12c5d1SDavid du Colombier if(write(fd, buf, strlen(buf)) < 0) 1663e12c5d1SDavid du Colombier error("writing /srv/ramfs"); 1673e12c5d1SDavid du Colombier } 1683e12c5d1SDavid du Colombier } 1693e12c5d1SDavid du Colombier 1703e12c5d1SDavid du Colombier notify(notifyf); 1713e12c5d1SDavid du Colombier nram = 1; 1723e12c5d1SDavid du Colombier r = &ram[0]; 1733e12c5d1SDavid du Colombier r->busy = 1; 1743e12c5d1SDavid du Colombier r->data = 0; 1753e12c5d1SDavid du Colombier r->ndata = 0; 1763e12c5d1SDavid du Colombier r->perm = CHDIR | 0775; 1773e12c5d1SDavid du Colombier r->qid.path = CHDIR; 1783e12c5d1SDavid du Colombier r->qid.vers = 0; 1793e12c5d1SDavid du Colombier r->parent = 0; 1803e12c5d1SDavid du Colombier r->user = user; 1813e12c5d1SDavid du Colombier r->group = user; 1823e12c5d1SDavid du Colombier r->atime = time(0); 1833e12c5d1SDavid du Colombier r->mtime = r->atime; 1843e12c5d1SDavid du Colombier strcpy(r->name, "."); 1853e12c5d1SDavid du Colombier strcpy(user, getuser()); 1863e12c5d1SDavid du Colombier 187*219b2ee8SDavid du Colombier if(debug) 188*219b2ee8SDavid du Colombier fmtinstall('F', fcallconv); 1893e12c5d1SDavid du Colombier switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){ 1903e12c5d1SDavid du Colombier case -1: 1913e12c5d1SDavid du Colombier error("fork"); 1923e12c5d1SDavid du Colombier case 0: 1933e12c5d1SDavid du Colombier close(p[1]); 1943e12c5d1SDavid du Colombier io(); 1953e12c5d1SDavid du Colombier break; 1963e12c5d1SDavid du Colombier default: 1973e12c5d1SDavid du Colombier close(p[0]); /* don't deadlock if child fails */ 198*219b2ee8SDavid du Colombier if(defmnt && mount(p[1], defmnt, MREPL|MCREATE, "") < 0) 1993e12c5d1SDavid du Colombier error("mount failed"); 2003e12c5d1SDavid du Colombier } 2013e12c5d1SDavid du Colombier exits(0); 2023e12c5d1SDavid du Colombier } 2033e12c5d1SDavid du Colombier 2043e12c5d1SDavid du Colombier char* 2053e12c5d1SDavid du Colombier rnop(Fid *f) 2063e12c5d1SDavid du Colombier { 2073e12c5d1SDavid du Colombier USED(f); 2083e12c5d1SDavid du Colombier return 0; 2093e12c5d1SDavid du Colombier } 2103e12c5d1SDavid du Colombier 2113e12c5d1SDavid du Colombier char* 2123e12c5d1SDavid du Colombier rsession(Fid *unused) 2133e12c5d1SDavid du Colombier { 2143e12c5d1SDavid du Colombier Fid *f; 2153e12c5d1SDavid du Colombier 2163e12c5d1SDavid du Colombier USED(unused); 2173e12c5d1SDavid du Colombier 2183e12c5d1SDavid du Colombier for(f = fids; f; f = f->next) 2193e12c5d1SDavid du Colombier if(f->busy) 2203e12c5d1SDavid du Colombier rclunk(f); 221*219b2ee8SDavid du Colombier memset(thdr.authid, 0, sizeof(thdr.authid)); 222*219b2ee8SDavid du Colombier memset(thdr.authdom, 0, sizeof(thdr.authdom)); 223*219b2ee8SDavid du Colombier memset(thdr.chal, 0, sizeof(thdr.chal)); 2243e12c5d1SDavid du Colombier return 0; 2253e12c5d1SDavid du Colombier } 2263e12c5d1SDavid du Colombier 2273e12c5d1SDavid du Colombier char* 2283e12c5d1SDavid du Colombier rflush(Fid *f) 2293e12c5d1SDavid du Colombier { 2303e12c5d1SDavid du Colombier USED(f); 2313e12c5d1SDavid du Colombier return 0; 2323e12c5d1SDavid du Colombier } 2333e12c5d1SDavid du Colombier 2343e12c5d1SDavid du Colombier char* 2353e12c5d1SDavid du Colombier rattach(Fid *f) 2363e12c5d1SDavid du Colombier { 2373e12c5d1SDavid du Colombier /* no authentication! */ 2383e12c5d1SDavid du Colombier f->busy = 1; 2393e12c5d1SDavid du Colombier f->rclose = 0; 2403e12c5d1SDavid du Colombier f->ram = &ram[0]; 2413e12c5d1SDavid du Colombier thdr.qid = f->ram->qid; 2423e12c5d1SDavid du Colombier if(rhdr.uname[0]) 2433e12c5d1SDavid du Colombier f->user = strdup(rhdr.uname); 2443e12c5d1SDavid du Colombier else 2453e12c5d1SDavid du Colombier f->user = "none"; 2463e12c5d1SDavid du Colombier return 0; 2473e12c5d1SDavid du Colombier } 2483e12c5d1SDavid du Colombier 2493e12c5d1SDavid du Colombier char* 2503e12c5d1SDavid du Colombier rclone(Fid *f) 2513e12c5d1SDavid du Colombier { 2523e12c5d1SDavid du Colombier Fid *nf; 2533e12c5d1SDavid du Colombier 2543e12c5d1SDavid du Colombier if(f->open) 2553e12c5d1SDavid du Colombier return Eisopen; 2563e12c5d1SDavid du Colombier if(f->ram->busy == 0) 2573e12c5d1SDavid du Colombier return Enotexist; 2583e12c5d1SDavid du Colombier nf = newfid(rhdr.newfid); 2593e12c5d1SDavid du Colombier nf->busy = 1; 2603e12c5d1SDavid du Colombier nf->open = 0; 2613e12c5d1SDavid du Colombier nf->rclose = 0; 2623e12c5d1SDavid du Colombier nf->ram = f->ram; 2633e12c5d1SDavid du Colombier nf->user = f->user; /* no ref count; the leakage is minor */ 2643e12c5d1SDavid du Colombier return 0; 2653e12c5d1SDavid du Colombier } 2663e12c5d1SDavid du Colombier 2673e12c5d1SDavid du Colombier char* 2683e12c5d1SDavid du Colombier rwalk(Fid *f) 2693e12c5d1SDavid du Colombier { 2703e12c5d1SDavid du Colombier Ram *r; 2713e12c5d1SDavid du Colombier char *name; 2723e12c5d1SDavid du Colombier Ram *parent; 2733e12c5d1SDavid du Colombier 2743e12c5d1SDavid du Colombier if((f->ram->qid.path & CHDIR) == 0) 2753e12c5d1SDavid du Colombier return Enotdir; 2763e12c5d1SDavid du Colombier if(f->ram->busy == 0) 2773e12c5d1SDavid du Colombier return Enotexist; 2783e12c5d1SDavid du Colombier f->ram->atime = time(0); 2793e12c5d1SDavid du Colombier name = rhdr.name; 2803e12c5d1SDavid du Colombier if(strcmp(name, ".") == 0){ 2813e12c5d1SDavid du Colombier thdr.qid = f->ram->qid; 2823e12c5d1SDavid du Colombier return 0; 2833e12c5d1SDavid du Colombier } 2843e12c5d1SDavid du Colombier parent = &ram[f->ram->parent]; 2853e12c5d1SDavid du Colombier if(!perm(f, parent, Pexec)) 2863e12c5d1SDavid du Colombier return Eperm; 2873e12c5d1SDavid du Colombier if(strcmp(name, "..") == 0){ 2883e12c5d1SDavid du Colombier f->ram = parent; 2893e12c5d1SDavid du Colombier thdr.qid = f->ram->qid; 2903e12c5d1SDavid du Colombier return 0; 2913e12c5d1SDavid du Colombier } 2923e12c5d1SDavid du Colombier for(r=ram; r < &ram[nram]; r++) 2933e12c5d1SDavid du Colombier if(r->busy && r->parent==f->ram-ram && strcmp(name, r->name)==0){ 2943e12c5d1SDavid du Colombier thdr.qid = r->qid; 2953e12c5d1SDavid du Colombier f->ram = r; 2963e12c5d1SDavid du Colombier return 0; 2973e12c5d1SDavid du Colombier } 2983e12c5d1SDavid du Colombier return Enotexist; 2993e12c5d1SDavid du Colombier } 3003e12c5d1SDavid du Colombier 3013e12c5d1SDavid du Colombier char * 3023e12c5d1SDavid du Colombier rclwalk(Fid *f) 3033e12c5d1SDavid du Colombier { 3043e12c5d1SDavid du Colombier Fid *nf; 3053e12c5d1SDavid du Colombier char *err; 3063e12c5d1SDavid du Colombier 3073e12c5d1SDavid du Colombier nf = newfid(rhdr.newfid); 3083e12c5d1SDavid du Colombier nf->busy = 1; 3093e12c5d1SDavid du Colombier nf->rclose = 0; 3103e12c5d1SDavid du Colombier nf->ram = f->ram; 3113e12c5d1SDavid du Colombier nf->user = f->user; 3123e12c5d1SDavid du Colombier if(err = rwalk(nf)) 3133e12c5d1SDavid du Colombier rclunk(nf); 3143e12c5d1SDavid du Colombier return err; 3153e12c5d1SDavid du Colombier } 3163e12c5d1SDavid du Colombier 3173e12c5d1SDavid du Colombier char * 3183e12c5d1SDavid du Colombier ropen(Fid *f) 3193e12c5d1SDavid du Colombier { 3203e12c5d1SDavid du Colombier Ram *r; 3213e12c5d1SDavid du Colombier int mode, trunc; 3223e12c5d1SDavid du Colombier 3233e12c5d1SDavid du Colombier if(f->open) 3243e12c5d1SDavid du Colombier return Eisopen; 3253e12c5d1SDavid du Colombier r = f->ram; 3263e12c5d1SDavid du Colombier if(r->busy == 0) 3273e12c5d1SDavid du Colombier return Enotexist; 3283e12c5d1SDavid du Colombier if(r->perm & CHEXCL) 3293e12c5d1SDavid du Colombier if(r->open) 3303e12c5d1SDavid du Colombier return Excl; 3313e12c5d1SDavid du Colombier mode = rhdr.mode; 3323e12c5d1SDavid du Colombier if(r->qid.path & CHDIR){ 3333e12c5d1SDavid du Colombier if(mode != OREAD) 3343e12c5d1SDavid du Colombier return Eperm; 3353e12c5d1SDavid du Colombier thdr.qid = r->qid; 3363e12c5d1SDavid du Colombier return 0; 3373e12c5d1SDavid du Colombier } 3383e12c5d1SDavid du Colombier if(mode & ORCLOSE){ 3393e12c5d1SDavid du Colombier /* must be able to write parent */ 3403e12c5d1SDavid du Colombier if(!perm(f, &ram[r->parent], Pwrite)) 3413e12c5d1SDavid du Colombier return Eperm; 3423e12c5d1SDavid du Colombier f->rclose = 1; 3433e12c5d1SDavid du Colombier } 3443e12c5d1SDavid du Colombier trunc = mode & OTRUNC; 3453e12c5d1SDavid du Colombier mode &= OPERM; 3463e12c5d1SDavid du Colombier if(mode==OWRITE || mode==ORDWR || trunc) 3473e12c5d1SDavid du Colombier if(!perm(f, r, Pwrite)) 3483e12c5d1SDavid du Colombier return Eperm; 3493e12c5d1SDavid du Colombier if(mode==OREAD || mode==ORDWR) 3503e12c5d1SDavid du Colombier if(!perm(f, r, Pread)) 3513e12c5d1SDavid du Colombier return Eperm; 3523e12c5d1SDavid du Colombier if(mode==OEXEC) 3533e12c5d1SDavid du Colombier if(!perm(f, r, Pexec)) 3543e12c5d1SDavid du Colombier return Eperm; 3553e12c5d1SDavid du Colombier if(trunc && (r->perm&CHAPPEND)==0){ 3563e12c5d1SDavid du Colombier r->ndata = 0; 3573e12c5d1SDavid du Colombier if(r->data) 3583e12c5d1SDavid du Colombier free(r->data); 3593e12c5d1SDavid du Colombier r->data = 0; 3603e12c5d1SDavid du Colombier r->qid.vers++; 3613e12c5d1SDavid du Colombier } 3623e12c5d1SDavid du Colombier thdr.qid = r->qid; 3633e12c5d1SDavid du Colombier f->open = 1; 3643e12c5d1SDavid du Colombier r->open++; 3653e12c5d1SDavid du Colombier return 0; 3663e12c5d1SDavid du Colombier } 3673e12c5d1SDavid du Colombier 3683e12c5d1SDavid du Colombier char * 3693e12c5d1SDavid du Colombier rcreate(Fid *f) 3703e12c5d1SDavid du Colombier { 3713e12c5d1SDavid du Colombier Ram *r; 3723e12c5d1SDavid du Colombier char *name; 3733e12c5d1SDavid du Colombier long parent, prm; 3743e12c5d1SDavid du Colombier 3753e12c5d1SDavid du Colombier if(f->open) 3763e12c5d1SDavid du Colombier return Eisopen; 3773e12c5d1SDavid du Colombier if(f->ram->busy == 0) 3783e12c5d1SDavid du Colombier return Enotexist; 3793e12c5d1SDavid du Colombier parent = f->ram - ram; 3803e12c5d1SDavid du Colombier if((f->ram->qid.path&CHDIR) == 0) 3813e12c5d1SDavid du Colombier return Enotdir; 3823e12c5d1SDavid du Colombier /* must be able to write parent */ 3833e12c5d1SDavid du Colombier if(!perm(f, f->ram, Pwrite)) 3843e12c5d1SDavid du Colombier return Eperm; 3853e12c5d1SDavid du Colombier prm = rhdr.perm; 3863e12c5d1SDavid du Colombier name = rhdr.name; 3873e12c5d1SDavid du Colombier if(strcmp(name, ".")==0 || strcmp(name, "..")==0) 3883e12c5d1SDavid du Colombier return Ename; 3893e12c5d1SDavid du Colombier for(r=ram; r<&ram[nram]; r++) 3903e12c5d1SDavid du Colombier if(r->busy && parent==r->parent) 3913e12c5d1SDavid du Colombier if(strcmp((char*)name, r->name)==0) 3923e12c5d1SDavid du Colombier return Einuse; 3933e12c5d1SDavid du Colombier for(r=ram; r->busy; r++) 3943e12c5d1SDavid du Colombier if(r == &ram[Nram-1]) 3953e12c5d1SDavid du Colombier return "no free ram resources"; 3963e12c5d1SDavid du Colombier r->busy = 1; 3973e12c5d1SDavid du Colombier r->qid.path = ++path; 3983e12c5d1SDavid du Colombier r->qid.vers = 0; 3993e12c5d1SDavid du Colombier if(prm & CHDIR) 4003e12c5d1SDavid du Colombier r->qid.path |= CHDIR; 4013e12c5d1SDavid du Colombier r->parent = parent; 4023e12c5d1SDavid du Colombier strcpy(r->name, (char*)name); 4033e12c5d1SDavid du Colombier r->user = f->user; 4043e12c5d1SDavid du Colombier r->group = f->ram->group; 4053e12c5d1SDavid du Colombier if(prm & CHDIR) 4063e12c5d1SDavid du Colombier prm = (prm&~0777) | (f->ram->perm&prm&0777); 4073e12c5d1SDavid du Colombier else 4083e12c5d1SDavid du Colombier prm = (prm&(~0777|0111)) | (f->ram->perm&prm&0666); 4093e12c5d1SDavid du Colombier r->perm = prm; 4103e12c5d1SDavid du Colombier r->ndata = 0; 4113e12c5d1SDavid du Colombier if(r-ram >= nram) 4123e12c5d1SDavid du Colombier nram = r - ram + 1; 4133e12c5d1SDavid du Colombier r->atime = time(0); 4143e12c5d1SDavid du Colombier r->mtime = r->atime; 4153e12c5d1SDavid du Colombier f->ram->mtime = r->atime; 4163e12c5d1SDavid du Colombier f->ram = r; 4173e12c5d1SDavid du Colombier thdr.qid = r->qid; 4183e12c5d1SDavid du Colombier f->open = 1; 4193e12c5d1SDavid du Colombier r->open++; 4203e12c5d1SDavid du Colombier return 0; 4213e12c5d1SDavid du Colombier } 4223e12c5d1SDavid du Colombier 4233e12c5d1SDavid du Colombier char* 4243e12c5d1SDavid du Colombier rread(Fid *f) 4253e12c5d1SDavid du Colombier { 4263e12c5d1SDavid du Colombier Ram *r; 4273e12c5d1SDavid du Colombier char *buf; 4283e12c5d1SDavid du Colombier long off; 4293e12c5d1SDavid du Colombier int n, cnt; 4303e12c5d1SDavid du Colombier 4313e12c5d1SDavid du Colombier if(f->ram->busy == 0) 4323e12c5d1SDavid du Colombier return Enotexist; 4333e12c5d1SDavid du Colombier n = 0; 4343e12c5d1SDavid du Colombier thdr.count = 0; 4353e12c5d1SDavid du Colombier off = rhdr.offset; 4363e12c5d1SDavid du Colombier buf = thdr.data; 437*219b2ee8SDavid du Colombier cnt = rhdr.count; 4383e12c5d1SDavid du Colombier if(f->ram->qid.path & CHDIR){ 439*219b2ee8SDavid du Colombier cnt = (rhdr.count/DIRLEN)*DIRLEN; 440*219b2ee8SDavid du Colombier if(off%DIRLEN) 4413e12c5d1SDavid du Colombier return "i/o error"; 4423e12c5d1SDavid du Colombier for(r=ram+1; off; r++){ 4433e12c5d1SDavid du Colombier if(r->busy && r->parent==f->ram-ram) 4443e12c5d1SDavid du Colombier off -= DIRLEN; 4453e12c5d1SDavid du Colombier if(r == &ram[nram-1]) 4463e12c5d1SDavid du Colombier return 0; 4473e12c5d1SDavid du Colombier } 4483e12c5d1SDavid du Colombier for(; r<&ram[nram] && n < cnt; r++){ 4493e12c5d1SDavid du Colombier if(!r->busy || r->parent!=f->ram-ram) 4503e12c5d1SDavid du Colombier continue; 4513e12c5d1SDavid du Colombier ramstat(r, buf+n); 4523e12c5d1SDavid du Colombier n += DIRLEN; 4533e12c5d1SDavid du Colombier } 4543e12c5d1SDavid du Colombier thdr.count = n; 4553e12c5d1SDavid du Colombier return 0; 4563e12c5d1SDavid du Colombier } 4573e12c5d1SDavid du Colombier r = f->ram; 4583e12c5d1SDavid du Colombier if(off >= r->ndata) 4593e12c5d1SDavid du Colombier return 0; 4603e12c5d1SDavid du Colombier r->atime = time(0); 4613e12c5d1SDavid du Colombier n = cnt; 4623e12c5d1SDavid du Colombier if(off+n > r->ndata) 4633e12c5d1SDavid du Colombier n = r->ndata - off; 4643e12c5d1SDavid du Colombier thdr.data = r->data+off; 4653e12c5d1SDavid du Colombier thdr.count = n; 4663e12c5d1SDavid du Colombier return 0; 4673e12c5d1SDavid du Colombier } 4683e12c5d1SDavid du Colombier 4693e12c5d1SDavid du Colombier char* 4703e12c5d1SDavid du Colombier rwrite(Fid *f) 4713e12c5d1SDavid du Colombier { 4723e12c5d1SDavid du Colombier Ram *r; 4733e12c5d1SDavid du Colombier ulong off; 4743e12c5d1SDavid du Colombier int cnt; 4753e12c5d1SDavid du Colombier 4763e12c5d1SDavid du Colombier r = f->ram; 4773e12c5d1SDavid du Colombier if(r->busy == 0) 4783e12c5d1SDavid du Colombier return Enotexist; 4793e12c5d1SDavid du Colombier off = rhdr.offset; 4803e12c5d1SDavid du Colombier if(r->perm & CHAPPEND) 4813e12c5d1SDavid du Colombier off = r->ndata; 4823e12c5d1SDavid du Colombier cnt = rhdr.count; 4833e12c5d1SDavid du Colombier if(r->qid.path & CHDIR) 4843e12c5d1SDavid du Colombier return "file is a directory"; 4853e12c5d1SDavid du Colombier if(off > 100*1024*1024) /* sanity check */ 4863e12c5d1SDavid du Colombier return "write too big"; 4873e12c5d1SDavid du Colombier if(off+cnt > r->ndata) 4883e12c5d1SDavid du Colombier r->data = erealloc(r->data, off+cnt); 4893e12c5d1SDavid du Colombier if(off > r->ndata) 4903e12c5d1SDavid du Colombier memset(r->data+r->ndata, 0, off-r->ndata); 4913e12c5d1SDavid du Colombier if(off+cnt > r->ndata) 4923e12c5d1SDavid du Colombier r->ndata = off+cnt; 4933e12c5d1SDavid du Colombier memmove(r->data+off, rhdr.data, cnt); 4943e12c5d1SDavid du Colombier r->qid.vers++; 4953e12c5d1SDavid du Colombier r->mtime = time(0); 4963e12c5d1SDavid du Colombier thdr.count = cnt; 4973e12c5d1SDavid du Colombier return 0; 4983e12c5d1SDavid du Colombier } 4993e12c5d1SDavid du Colombier 5003e12c5d1SDavid du Colombier void 5013e12c5d1SDavid du Colombier realremove(Ram *r) 5023e12c5d1SDavid du Colombier { 5033e12c5d1SDavid du Colombier r->ndata = 0; 5043e12c5d1SDavid du Colombier if(r->data) 5053e12c5d1SDavid du Colombier free(r->data); 5063e12c5d1SDavid du Colombier r->data = 0; 5073e12c5d1SDavid du Colombier r->parent = 0; 5083e12c5d1SDavid du Colombier r->qid = (Qid){0, 0}; 5093e12c5d1SDavid du Colombier r->name[0] = 0; 5103e12c5d1SDavid du Colombier r->busy = 0; 5113e12c5d1SDavid du Colombier } 5123e12c5d1SDavid du Colombier 5133e12c5d1SDavid du Colombier char * 5143e12c5d1SDavid du Colombier rclunk(Fid *f) 5153e12c5d1SDavid du Colombier { 5163e12c5d1SDavid du Colombier if(f->open) 5173e12c5d1SDavid du Colombier f->ram->open--; 5183e12c5d1SDavid du Colombier if(f->rclose) 5193e12c5d1SDavid du Colombier realremove(f->ram); 5203e12c5d1SDavid du Colombier f->busy = 0; 5213e12c5d1SDavid du Colombier f->open = 0; 5223e12c5d1SDavid du Colombier f->ram = 0; 5233e12c5d1SDavid du Colombier return 0; 5243e12c5d1SDavid du Colombier } 5253e12c5d1SDavid du Colombier 5263e12c5d1SDavid du Colombier char * 5273e12c5d1SDavid du Colombier rremove(Fid *f) 5283e12c5d1SDavid du Colombier { 5293e12c5d1SDavid du Colombier Ram *r; 5303e12c5d1SDavid du Colombier 5313e12c5d1SDavid du Colombier if(f->open) 5323e12c5d1SDavid du Colombier f->ram->open--; 5333e12c5d1SDavid du Colombier f->busy = 0; 5343e12c5d1SDavid du Colombier f->open = 0; 5353e12c5d1SDavid du Colombier r = f->ram; 5363e12c5d1SDavid du Colombier f->ram = 0; 5373e12c5d1SDavid du Colombier if(!perm(f, &ram[r->parent], Pwrite)) 5383e12c5d1SDavid du Colombier return Eperm; 5393e12c5d1SDavid du Colombier ram[r->parent].mtime = time(0); 5403e12c5d1SDavid du Colombier realremove(r); 5413e12c5d1SDavid du Colombier return 0; 5423e12c5d1SDavid du Colombier } 5433e12c5d1SDavid du Colombier 5443e12c5d1SDavid du Colombier char * 5453e12c5d1SDavid du Colombier rstat(Fid *f) 5463e12c5d1SDavid du Colombier { 5473e12c5d1SDavid du Colombier if(f->ram->busy == 0) 5483e12c5d1SDavid du Colombier return Enotexist; 5493e12c5d1SDavid du Colombier ramstat(f->ram, thdr.stat); 5503e12c5d1SDavid du Colombier return 0; 5513e12c5d1SDavid du Colombier } 5523e12c5d1SDavid du Colombier 5533e12c5d1SDavid du Colombier char * 5543e12c5d1SDavid du Colombier rwstat(Fid *f) 5553e12c5d1SDavid du Colombier { 5563e12c5d1SDavid du Colombier Ram *r, *s; 5573e12c5d1SDavid du Colombier Dir dir; 5583e12c5d1SDavid du Colombier 5593e12c5d1SDavid du Colombier if(f->ram->busy == 0) 5603e12c5d1SDavid du Colombier return Enotexist; 5613e12c5d1SDavid du Colombier convM2D(rhdr.stat, &dir); 5623e12c5d1SDavid du Colombier r = f->ram; 5633e12c5d1SDavid du Colombier 5643e12c5d1SDavid du Colombier /* 5653e12c5d1SDavid du Colombier * To change name, must have write permission in parent 5663e12c5d1SDavid du Colombier * and name must be unique. 5673e12c5d1SDavid du Colombier */ 5683e12c5d1SDavid du Colombier if(strcmp(dir.name, r->name) != 0){ 5693e12c5d1SDavid du Colombier if(!perm(f, &ram[r->parent], Pwrite)) 5703e12c5d1SDavid du Colombier return Eperm; 5713e12c5d1SDavid du Colombier for(s=ram; s<&ram[nram]; s++) 5723e12c5d1SDavid du Colombier if(s->busy && s->parent==r->parent) 5733e12c5d1SDavid du Colombier if(strcmp(dir.name, s->name)==0) 5743e12c5d1SDavid du Colombier return Eexist; 5753e12c5d1SDavid du Colombier } 5763e12c5d1SDavid du Colombier 5773e12c5d1SDavid du Colombier /* 5783e12c5d1SDavid du Colombier * To change mode, must be owner or group leader to change mode. 5793e12c5d1SDavid du Colombier * Because of lack of users file, leader=>group itself. 5803e12c5d1SDavid du Colombier */ 5813e12c5d1SDavid du Colombier if(r->perm != dir.mode){ 5823e12c5d1SDavid du Colombier if(strcmp(f->user, r->user) != 0) 5833e12c5d1SDavid du Colombier if(strcmp(f->user, r->group) != 0) 5843e12c5d1SDavid du Colombier return Enotowner; 5853e12c5d1SDavid du Colombier } 5863e12c5d1SDavid du Colombier 5873e12c5d1SDavid du Colombier /* 5883e12c5d1SDavid du Colombier * To change group, must be owner and member of new group, 5893e12c5d1SDavid du Colombier * or leader of current group and leader of new group. 5903e12c5d1SDavid du Colombier * Second case cannot happen, but we check anyway. 5913e12c5d1SDavid du Colombier */ 5923e12c5d1SDavid du Colombier if(strcmp(r->group, dir.gid) != 0){ 5933e12c5d1SDavid du Colombier if(strcmp(f->user, r->user) == 0) 5943e12c5d1SDavid du Colombier if(strcmp(f->user, dir.gid) == 0) 5953e12c5d1SDavid du Colombier goto ok; 5963e12c5d1SDavid du Colombier if(strcmp(f->user, r->group) == 0) 5973e12c5d1SDavid du Colombier if(strcmp(f->user, dir.gid) == 0) 5983e12c5d1SDavid du Colombier goto ok; 5993e12c5d1SDavid du Colombier return Enotowner; 6003e12c5d1SDavid du Colombier ok:; 6013e12c5d1SDavid du Colombier } 6023e12c5d1SDavid du Colombier 6033e12c5d1SDavid du Colombier /* all ok; do it */ 6043e12c5d1SDavid du Colombier dir.mode &= ~CHDIR; /* cannot change dir bit */ 6053e12c5d1SDavid du Colombier dir.mode |= r->perm&CHDIR; 6063e12c5d1SDavid du Colombier r->perm = dir.mode; 6073e12c5d1SDavid du Colombier memmove(r->name, dir.name, NAMELEN); 6083e12c5d1SDavid du Colombier r->group = strdup(dir.gid); 6093e12c5d1SDavid du Colombier ram[r->parent].mtime = time(0); 6103e12c5d1SDavid du Colombier return 0; 6113e12c5d1SDavid du Colombier } 6123e12c5d1SDavid du Colombier 6133e12c5d1SDavid du Colombier void 6143e12c5d1SDavid du Colombier ramstat(Ram *r, char *buf) 6153e12c5d1SDavid du Colombier { 6163e12c5d1SDavid du Colombier Dir dir; 6173e12c5d1SDavid du Colombier 6183e12c5d1SDavid du Colombier memmove(dir.name, r->name, NAMELEN); 6193e12c5d1SDavid du Colombier dir.qid = r->qid; 6203e12c5d1SDavid du Colombier dir.mode = r->perm; 6213e12c5d1SDavid du Colombier dir.length = r->ndata; 6223e12c5d1SDavid du Colombier dir.hlength = 0; 6233e12c5d1SDavid du Colombier strcpy(dir.uid, r->user); 6243e12c5d1SDavid du Colombier strcpy(dir.gid, r->group); 6253e12c5d1SDavid du Colombier dir.atime = r->atime; 6263e12c5d1SDavid du Colombier dir.mtime = r->mtime; 6273e12c5d1SDavid du Colombier convD2M(&dir, buf); 6283e12c5d1SDavid du Colombier } 6293e12c5d1SDavid du Colombier 6303e12c5d1SDavid du Colombier Fid * 6313e12c5d1SDavid du Colombier newfid(int fid) 6323e12c5d1SDavid du Colombier { 6333e12c5d1SDavid du Colombier Fid *f, *ff; 6343e12c5d1SDavid du Colombier 6353e12c5d1SDavid du Colombier ff = 0; 6363e12c5d1SDavid du Colombier for(f = fids; f; f = f->next) 6373e12c5d1SDavid du Colombier if(f->fid == fid) 6383e12c5d1SDavid du Colombier return f; 6393e12c5d1SDavid du Colombier else if(!ff && !f->busy) 6403e12c5d1SDavid du Colombier ff = f; 6413e12c5d1SDavid du Colombier if(ff){ 6423e12c5d1SDavid du Colombier ff->fid = fid; 6433e12c5d1SDavid du Colombier return ff; 6443e12c5d1SDavid du Colombier } 6453e12c5d1SDavid du Colombier f = emalloc(sizeof *f); 6463e12c5d1SDavid du Colombier f->ram = 0; 6473e12c5d1SDavid du Colombier f->fid = fid; 6483e12c5d1SDavid du Colombier f->next = fids; 6493e12c5d1SDavid du Colombier fids = f; 6503e12c5d1SDavid du Colombier return f; 6513e12c5d1SDavid du Colombier } 6523e12c5d1SDavid du Colombier 6533e12c5d1SDavid du Colombier void 6543e12c5d1SDavid du Colombier io(void) 6553e12c5d1SDavid du Colombier { 6563e12c5d1SDavid du Colombier char *err; 6573e12c5d1SDavid du Colombier int n; 6583e12c5d1SDavid du Colombier 6593e12c5d1SDavid du Colombier for(;;){ 6603e12c5d1SDavid du Colombier /* 6613e12c5d1SDavid du Colombier * reading from a pipe or a network device 6623e12c5d1SDavid du Colombier * will give an error after a few eof reads 6633e12c5d1SDavid du Colombier * however, we cannot tell the difference 6643e12c5d1SDavid du Colombier * between a zero-length read and an interrupt 6653e12c5d1SDavid du Colombier * on the processes writing to us, 6663e12c5d1SDavid du Colombier * so we wait for the error 6673e12c5d1SDavid du Colombier */ 6683e12c5d1SDavid du Colombier n = read(mfd[0], mdata, sizeof mdata); 6693e12c5d1SDavid du Colombier if(n == 0) 6703e12c5d1SDavid du Colombier continue; 6713e12c5d1SDavid du Colombier if(n < 0) 6723e12c5d1SDavid du Colombier error("mount read"); 6733e12c5d1SDavid du Colombier if(convM2S(mdata, &rhdr, n) == 0) 6743e12c5d1SDavid du Colombier continue; 6753e12c5d1SDavid du Colombier 676*219b2ee8SDavid du Colombier if(debug) 677*219b2ee8SDavid du Colombier fprint(2, "ramfs:<-%F\n", &rhdr); 6783e12c5d1SDavid du Colombier 6793e12c5d1SDavid du Colombier thdr.data = mdata + MAXMSG; 6803e12c5d1SDavid du Colombier if(!fcalls[rhdr.type]) 6813e12c5d1SDavid du Colombier err = "bad fcall type"; 6823e12c5d1SDavid du Colombier else 6833e12c5d1SDavid du Colombier err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); 6843e12c5d1SDavid du Colombier if(err){ 6853e12c5d1SDavid du Colombier thdr.type = Rerror; 6863e12c5d1SDavid du Colombier strncpy(thdr.ename, err, ERRLEN); 6873e12c5d1SDavid du Colombier }else{ 6883e12c5d1SDavid du Colombier thdr.type = rhdr.type + 1; 6893e12c5d1SDavid du Colombier thdr.fid = rhdr.fid; 6903e12c5d1SDavid du Colombier } 6913e12c5d1SDavid du Colombier thdr.tag = rhdr.tag; 692*219b2ee8SDavid du Colombier if(debug) 693*219b2ee8SDavid du Colombier fprint(2, "ramfs:->%F\n", &thdr);/**/ 6943e12c5d1SDavid du Colombier n = convS2M(&thdr, mdata); 6953e12c5d1SDavid du Colombier if(write(mfd[1], mdata, n) != n) 6963e12c5d1SDavid du Colombier error("mount write"); 6973e12c5d1SDavid du Colombier } 6983e12c5d1SDavid du Colombier } 6993e12c5d1SDavid du Colombier 7003e12c5d1SDavid du Colombier int 7013e12c5d1SDavid du Colombier perm(Fid *f, Ram *r, int p) 7023e12c5d1SDavid du Colombier { 7033e12c5d1SDavid du Colombier if((p*Pother) & r->perm) 7043e12c5d1SDavid du Colombier return 1; 7053e12c5d1SDavid du Colombier if(strcmp(f->user, r->group)==0 && ((p*Pgroup) & r->perm)) 7063e12c5d1SDavid du Colombier return 1; 7073e12c5d1SDavid du Colombier if(strcmp(f->user, r->user)==0 && ((p*Powner) & r->perm)) 7083e12c5d1SDavid du Colombier return 1; 7093e12c5d1SDavid du Colombier return 0; 7103e12c5d1SDavid du Colombier } 7113e12c5d1SDavid du Colombier 7123e12c5d1SDavid du Colombier void 7133e12c5d1SDavid du Colombier error(char *s) 7143e12c5d1SDavid du Colombier { 715*219b2ee8SDavid du Colombier fprint(2, "%s: %s: %r\n", argv0, s); 7163e12c5d1SDavid du Colombier exits(s); 7173e12c5d1SDavid du Colombier } 7183e12c5d1SDavid du Colombier 7193e12c5d1SDavid du Colombier void * 7203e12c5d1SDavid du Colombier emalloc(ulong n) 7213e12c5d1SDavid du Colombier { 7223e12c5d1SDavid du Colombier void *p; 7233e12c5d1SDavid du Colombier 7243e12c5d1SDavid du Colombier p = malloc(n); 7253e12c5d1SDavid du Colombier if(!p) 7263e12c5d1SDavid du Colombier error("out of memory"); 7273e12c5d1SDavid du Colombier return p; 7283e12c5d1SDavid du Colombier } 7293e12c5d1SDavid du Colombier 7303e12c5d1SDavid du Colombier void * 7313e12c5d1SDavid du Colombier erealloc(void *p, ulong n) 7323e12c5d1SDavid du Colombier { 7333e12c5d1SDavid du Colombier p = realloc(p, n); 7343e12c5d1SDavid du Colombier if(!p) 7353e12c5d1SDavid du Colombier error("out of memory"); 7363e12c5d1SDavid du Colombier return p; 7373e12c5d1SDavid du Colombier } 7383e12c5d1SDavid du Colombier 7393e12c5d1SDavid du Colombier void 7403e12c5d1SDavid du Colombier usage(void) 7413e12c5d1SDavid du Colombier { 7423e12c5d1SDavid du Colombier fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0); 7433e12c5d1SDavid du Colombier exits("usage"); 7443e12c5d1SDavid du Colombier } 745