6 * Rather than reading /adm/users, which is a lot of work for
7 * a toy program, we assume all groups have the form
9 * meaning that each user is the leader of his own group.
14 OPERM = 0x3, /* mask of all permission types in open mode */
16 Maxsize = 512*1024*1024,
20 typedef struct Fid Fid;
21 typedef struct Ram Ram;
38 long parent; /* index in Ram array */
61 ulong path; /* incremented for each new file */
67 uchar mdata[IOHDRSZ+Maxfdata];
68 uchar rdata[Maxfdata]; /* buffer for data in reply */
69 uchar statbuf[STATMAX];
72 int messagesize = sizeof mdata;
75 uint ramstat(Ram*, uchar*, uint);
78 void *erealloc(void*, ulong);
82 int perm(Fid*, Ram*, int);
84 char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*),
85 *rattach(Fid*), *rwalk(Fid*),
86 *ropen(Fid*), *rcreate(Fid*),
87 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
88 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
90 char *(*fcalls[Tmax])(Fid*);
95 fcalls[Tversion]= rversion;
96 fcalls[Tflush]= rflush;
98 fcalls[Tattach]= rattach;
100 fcalls[Topen]= ropen;
101 fcalls[Tcreate]= rcreate;
102 fcalls[Tread]= rread;
103 fcalls[Twrite]= rwrite;
104 fcalls[Tclunk]= rclunk;
105 fcalls[Tremove]= rremove;
106 fcalls[Tstat]= rstat;
107 fcalls[Twstat]= rwstat;
110 char Eperm[] = "permission denied";
111 char Enotdir[] = "not a directory";
112 char Enoauth[] = "ramfs: authentication not required";
113 char Enotexist[] = "file does not exist";
114 char Einuse[] = "file in use";
115 char Eexist[] = "file exists";
116 char Eisdir[] = "file is a directory";
117 char Enotowner[] = "not owner";
118 char Eisopen[] = "file already open for I/O";
119 char Excl[] = "exclusive use file already open";
120 char Ename[] = "illegal name";
121 char Eversion[] = "unknown 9P version";
122 char Enotempty[] = "directory not empty";
123 char Ebadfid[] = "bad fid";
129 notifyf(void *a, char *s)
132 if(strncmp(s, "interrupt", 9) == 0)
138 main(int argc, char *argv[])
170 service = EARGF(usage());
178 error("pipe failed");
182 if(post9pservice(p[1], service, nil) < 0)
183 sysfatal("post9pservice %s: %r", service);
193 r->perm = DMDIR | 0775;
203 r->name = estrdup(".");
219 r->name = estrdup("file");
222 fmtinstall('F', fcallfmt);
223 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
231 close(p[0]); /* don't deadlock if child fails */
242 for(f = fids; f; f = f->next)
245 if(thdr.msize > sizeof mdata)
246 rhdr.msize = sizeof mdata;
248 rhdr.msize = thdr.msize;
249 messagesize = rhdr.msize;
250 if(strncmp(thdr.version, "9P2000", 6) != 0)
252 rhdr.version = "9P2000";
261 return "ramfs: no authentication required";
274 /* no authentication! */
280 rhdr.qid = f->ram->qid;
282 f->user = estrdup(thdr.uname);
285 if(strcmp(user, "none") == 0)
291 xclone(Fid *f, Fid **nf)
297 if(f->ram->busy == 0)
299 *nf = newfid(thdr.newfid);
304 (*nf)->user = f->user; /* no ref count; the leakage is minor */
324 if(thdr.newfid != thdr.fid){
325 err = xclone(f, &nf);
328 f = nf; /* walk the new fid */
333 for(i=0; i<thdr.nwname && i<MAXWELEM; i++){
334 if((fram->qid.type & QTDIR) == 0){
343 name = thdr.wname[i];
344 if(strcmp(name, ".") == 0){
347 rhdr.wqid[i] = fram->qid;
350 parent = &ram[fram->parent];
351 if(!perm(f, parent, Pexec)){
355 if(strcmp(name, "..") == 0){
359 for(r=ram; r < &ram[nram]; r++)
360 if(r->busy && r->parent==fram-ram && strcmp(name, r->name)==0){
366 if(i==0 && err == nil)
369 if(nf != nil && (err!=nil || rhdr.nwqid<thdr.nwname)){
370 /* clunk the new fid, which is the one we walked */
371 fprint(2, "f %d zero busy\n", f->fid);
375 if(rhdr.nwqid == thdr.nwname) /* update the fid after a successful walk */
398 if(r->qid.type & QTDIR){
405 /* can't remove root; must be able to write parent */
406 if(r->qid.path==0 || !perm(f, &ram[r->parent], Pwrite))
410 trunc = mode & OTRUNC;
412 if(mode==OWRITE || mode==ORDWR || trunc)
413 if(!perm(f, r, Pwrite))
415 if(mode==OREAD || mode==ORDWR)
416 if(!perm(f, r, Pread))
419 if(!perm(f, r, Pexec))
421 if(trunc && (r->perm&DMAPPEND)==0){
429 rhdr.iounit = messagesize-IOHDRSZ;
446 if(f->ram->busy == 0)
448 parent = f->ram - ram;
449 if((f->ram->qid.type&QTDIR) == 0)
451 /* must be able to write parent */
452 if(!perm(f, f->ram, Pwrite))
456 if(strcmp(name, ".")==0 || strcmp(name, "..")==0)
458 for(r=ram; r<&ram[nram]; r++)
459 if(r->busy && parent==r->parent)
460 if(strcmp((char*)name, r->name)==0)
462 for(r=ram; r->busy; r++)
463 if(r == &ram[Nram-1])
464 return "no free ram resources";
466 r->qid.path = ++path;
469 r->qid.type |= QTDIR;
472 r->name = estrdup(name);
474 r->group = f->ram->group;
475 r->muid = f->ram->muid;
477 prm = (prm&~0777) | (f->ram->perm&prm&0777);
479 prm = (prm&(~0777|0111)) | (f->ram->perm&prm&0666);
486 f->ram->mtime = r->atime;
489 rhdr.iounit = messagesize-IOHDRSZ;
491 if(thdr.mode & ORCLOSE)
507 if(f->ram->busy == 0)
514 if(cnt > messagesize) /* shouldn't happen, anyway */
516 if(f->ram->qid.type & QTDIR){
517 for(r=ram+1; off > 0; r++){
518 if(r->busy && r->parent==f->ram-ram)
519 off -= ramstat(r, statbuf, sizeof statbuf);
520 if(r == &ram[nram-1])
523 for(; r<&ram[nram] && n < cnt; r++){
524 if(!r->busy || r->parent!=f->ram-ram)
526 m = ramstat(r, buf+n, cnt-n);
531 rhdr.data = (char*)rdata;
542 rhdr.data = r->data+off;
560 if(r->perm & DMAPPEND)
563 if(r->qid.type & QTDIR)
565 if(off+cnt >= Maxsize) /* sanity check */
566 return "write too big";
567 if(off+cnt > r->ndata)
568 r->data = erealloc(r->data, off+cnt);
570 memset(r->data+r->ndata, 0, off-r->ndata);
571 if(off+cnt > r->ndata)
573 memmove(r->data+off, thdr.data, cnt);
583 long didx = dr - ram;
586 for(r=ram; r<&ram[nram]; r++)
587 if(r->busy && didx==r->parent)
595 if(r->qid.type & QTDIR && !emptydir(r))
602 memset(&r->qid, 0, sizeof r->qid);
617 e = realremove(f->ram);
618 fprint(2, "clunk fid %d busy=%d\n", f->fid, f->busy);
619 fprint(2, "f %d zero busy\n", f->fid);
633 fprint(2, "f %d zero busy\n", f->fid);
638 if(r->qid.path == 0 || !perm(f, &ram[r->parent], Pwrite))
640 ram[r->parent].mtime = time(0);
641 return realremove(r);
649 if(f->ram->busy == 0)
651 rhdr.nstat = ramstat(f->ram, statbuf, sizeof statbuf);
664 if(f->ram->busy == 0)
666 convM2D(thdr.stat, thdr.nstat, &dir, (char*)statbuf);
670 * To change length, must have write permission on file.
672 if(dir.length!=~0 && dir.length!=r->ndata){
673 if(!perm(f, r, Pwrite))
678 * To change name, must have write permission in parent
679 * and name must be unique.
681 if(dir.name[0]!='\0' && strcmp(dir.name, r->name)!=0){
682 if(!perm(f, &ram[r->parent], Pwrite))
684 for(s=ram; s<&ram[nram]; s++)
685 if(s->busy && s->parent==r->parent)
686 if(strcmp(dir.name, s->name)==0)
691 * To change mode, must be owner or group leader.
692 * Because of lack of users file, leader=>group itself.
694 if(dir.mode!=~0 && r->perm!=dir.mode){
695 if(strcmp(f->user, r->user) != 0)
696 if(strcmp(f->user, r->group) != 0)
701 * To change group, must be owner and member of new group,
702 * or leader of current group and leader of new group.
703 * Second case cannot happen, but we check anyway.
705 if(dir.gid[0]!='\0' && strcmp(r->group, dir.gid)!=0){
706 if(strcmp(f->user, r->user) == 0)
707 /* if(strcmp(f->user, dir.gid) == 0) */
709 if(strcmp(f->user, r->group) == 0)
710 if(strcmp(f->user, dir.gid) == 0)
718 dir.mode &= ~DMDIR; /* cannot change dir bit */
719 dir.mode |= r->perm&DMDIR;
722 if(dir.name[0] != '\0'){
724 r->name = estrdup(dir.name);
726 if(dir.gid[0] != '\0')
727 r->group = estrdup(dir.gid);
728 if(dir.length!=~0 && dir.length!=r->ndata){
729 r->data = erealloc(r->data, dir.length);
730 if(r->ndata < dir.length)
731 memset(r->data+r->ndata, 0, dir.length-r->ndata);
732 r->ndata = dir.length;
734 ram[r->parent].mtime = time(0);
739 ramstat(Ram *r, uchar *buf, uint nbuf)
747 dir.length = r->ndata;
751 dir.atime = r->atime;
752 dir.mtime = r->mtime;
753 n = convD2M(&dir, buf, nbuf);
765 for(f = fids; f; f = f->next)
768 else if(!ff && !f->busy)
774 f = emalloc(sizeof *f);
790 snprint(buf, sizeof buf, "/proc/%d/ctl", pid);
791 ctl = open(buf, OWRITE);
793 fprint(2, "can't protect ramfs\n");
795 fprint(ctl, "noswap\n");
796 fprint(ctl, "private\n");
803 * reading from a pipe or a network device
804 * will give an error after a few eof reads.
805 * however, we cannot tell the difference
806 * between a zero-length read and an interrupt
807 * on the processes writing to us,
808 * so we wait for the error.
810 n = read9pmsg(mfd[0], mdata, messagesize);
815 if(convM2S(mdata, n, &thdr) == 0)
819 fprint(2, "ramfs %d:<-%F\n", pid, &thdr);
821 if(!fcalls[thdr.type])
822 err = "bad fcall type";
824 err = (*fcalls[thdr.type])(newfid(thdr.fid));
829 rhdr.type = thdr.type + 1;
834 fprint(2, "ramfs %d:->%F\n", pid, &rhdr);/**/
835 n = convS2M(&rhdr, mdata, messagesize);
837 error("convS2M error on write");
838 if(write(mfd[1], mdata, n) != n)
839 error("mount write");
844 perm(Fid *f, Ram *r, int p)
846 if((p*Pother) & r->perm)
848 if(strcmp(f->user, r->group)==0 && ((p*Pgroup) & r->perm))
850 if(strcmp(f->user, r->user)==0 && ((p*Powner) & r->perm))
858 fprint(2, "%s: %s: %r\n", argv0, s);
869 error("out of memory");
875 erealloc(void *p, ulong n)
879 error("out of memory");
892 error("out of memory");
900 fprint(2, "usage: %s [-is] [-m mountpoint]\n", argv0);