| tramfs - plan9port - [fork] Plan 9 from user space | |
| git clone git://src.adamsgaard.dk/plan9port | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| commit 57ccfb9e8f51138c33ad5f58e14c0e54246cf5c4 | |
| parent b3994ec5c78e6c18885079b58abb7fb997899c3f | |
| Author: rsc <devnull@localhost> | |
| Date: Thu, 11 Dec 2003 17:50:50 +0000 | |
| ramfs | |
| Diffstat: | |
| A src/cmd/ramfs.c | 904 +++++++++++++++++++++++++++++… | |
| 1 file changed, 904 insertions(+), 0 deletions(-) | |
| --- | |
| diff --git a/src/cmd/ramfs.c b/src/cmd/ramfs.c | |
| t@@ -0,0 +1,904 @@ | |
| +#include <u.h> | |
| +#include <libc.h> | |
| +#include <fcall.h> | |
| + | |
| +int post9pservice(int, char*); | |
| + | |
| +/* | |
| + * Rather than reading /adm/users, which is a lot of work for | |
| + * a toy program, we assume all groups have the form | |
| + * NNN:user:user: | |
| + * meaning that each user is the leader of his own group. | |
| + */ | |
| + | |
| +enum | |
| +{ | |
| + OPERM = 0x3, /* mask of all permission types in … | |
| + Nram = 2048, | |
| + Maxsize = 512*1024*1024, | |
| + Maxfdata = 8192, | |
| +}; | |
| + | |
| +typedef struct Fid Fid; | |
| +typedef struct Ram Ram; | |
| + | |
| +struct Fid | |
| +{ | |
| + short busy; | |
| + short open; | |
| + short rclose; | |
| + int fid; | |
| + Fid *next; | |
| + char *user; | |
| + Ram *ram; | |
| +}; | |
| + | |
| +struct Ram | |
| +{ | |
| + short busy; | |
| + short open; | |
| + long parent; /* index in Ram array */ | |
| + Qid qid; | |
| + long perm; | |
| + char *name; | |
| + ulong atime; | |
| + ulong mtime; | |
| + char *user; | |
| + char *group; | |
| + char *muid; | |
| + char *data; | |
| + long ndata; | |
| +}; | |
| + | |
| +enum | |
| +{ | |
| + Pexec = 1, | |
| + Pwrite = 2, | |
| + Pread = 4, | |
| + Pother = 1, | |
| + Pgroup = 8, | |
| + Powner = 64, | |
| +}; | |
| + | |
| +ulong path; /* incremented for each new file */ | |
| +Fid *fids; | |
| +Ram ram[Nram]; | |
| +int nram; | |
| +int mfd[2]; | |
| +char *user; | |
| +uchar mdata[IOHDRSZ+Maxfdata]; | |
| +uchar rdata[Maxfdata]; /* buffer for data in reply */ | |
| +uchar statbuf[STATMAX]; | |
| +Fcall thdr; | |
| +Fcall rhdr; | |
| +int messagesize = sizeof mdata; | |
| + | |
| +Fid * newfid(int); | |
| +uint ramstat(Ram*, uchar*, uint); | |
| +void error(char*); | |
| +void io(void); | |
| +void *erealloc(void*, ulong); | |
| +void *emalloc(ulong); | |
| +char *estrdup(char*); | |
| +void usage(void); | |
| +int perm(Fid*, Ram*, int); | |
| + | |
| +char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*), | |
| + *rattach(Fid*), *rwalk(Fid*), | |
| + *ropen(Fid*), *rcreate(Fid*), | |
| + *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), | |
| + *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*); | |
| + | |
| +char *(*fcalls[])(Fid*) = { | |
| + [Tversion] rversion, | |
| + [Tflush] rflush, | |
| + [Tauth] rauth, | |
| + [Tattach] rattach, | |
| + [Twalk] rwalk, | |
| + [Topen] ropen, | |
| + [Tcreate] rcreate, | |
| + [Tread] rread, | |
| + [Twrite] rwrite, | |
| + [Tclunk] rclunk, | |
| + [Tremove] rremove, | |
| + [Tstat] rstat, | |
| + [Twstat] rwstat, | |
| +}; | |
| + | |
| +char Eperm[] = "permission denied"; | |
| +char Enotdir[] = "not a directory"; | |
| +char Enoauth[] = "ramfs: authentication not required"; | |
| +char Enotexist[] = "file does not exist"; | |
| +char Einuse[] = "file in use"; | |
| +char Eexist[] = "file exists"; | |
| +char Eisdir[] = "file is a directory"; | |
| +char Enotowner[] = "not owner"; | |
| +char Eisopen[] = "file already open for I/O"; | |
| +char Excl[] = "exclusive use file already open"; | |
| +char Ename[] = "illegal name"; | |
| +char Eversion[] = "unknown 9P version"; | |
| +char Enotempty[] = "directory not empty"; | |
| +char Ebadfid[] = "bad fid"; | |
| + | |
| +int debug; | |
| +int private; | |
| + | |
| +void | |
| +notifyf(void *a, char *s) | |
| +{ | |
| + USED(a); | |
| + if(strncmp(s, "interrupt", 9) == 0) | |
| + noted(NCONT); | |
| + noted(NDFLT); | |
| +} | |
| + | |
| +void | |
| +main(int argc, char *argv[]) | |
| +{ | |
| + Ram *r; | |
| + char *defmnt; | |
| + int p[2]; | |
| + int stdio = 0; | |
| + char *service; | |
| + | |
| + service = "ramfs"; | |
| + defmnt = "/tmp"; | |
| + ARGBEGIN{ | |
| + case 'D': | |
| + debug = 1; | |
| + break; | |
| + case 'i': | |
| + defmnt = 0; | |
| + stdio = 1; | |
| + mfd[0] = 0; | |
| + mfd[1] = 1; | |
| + break; | |
| + case 's': | |
| + defmnt = 0; | |
| + break; | |
| + case 'm': | |
| + defmnt = ARGF(); | |
| + break; | |
| + case 'p': | |
| + private++; | |
| + break; | |
| + case 'S': | |
| + defmnt = 0; | |
| + service = EARGF(usage()); | |
| + break; | |
| + default: | |
| + usage(); | |
| + }ARGEND | |
| + | |
| + if(defmnt) | |
| + sysfatal("cannot mount -- not on plan 9"); | |
| + | |
| + if(pipe(p) < 0) | |
| + error("pipe failed"); | |
| + if(!stdio){ | |
| + mfd[0] = p[0]; | |
| + mfd[1] = p[0]; | |
| + if(post9pservice(p[1], service) < 0) | |
| + sysfatal("post9pservice %s: %r", service); | |
| + } | |
| + | |
| + user = getuser(); | |
| + notify(notifyf); | |
| + nram = 2; | |
| + r = &ram[0]; | |
| + r->busy = 1; | |
| + r->data = 0; | |
| + r->ndata = 0; | |
| + r->perm = DMDIR | 0775; | |
| + r->qid.type = QTDIR; | |
| + r->qid.path = 0; | |
| + r->qid.vers = 0; | |
| + r->parent = 0; | |
| + r->user = user; | |
| + r->group = user; | |
| + r->muid = user; | |
| + r->atime = time(0); | |
| + r->mtime = r->atime; | |
| + r->name = estrdup("."); | |
| + | |
| + r = &ram[1]; | |
| + r->busy = 1; | |
| + r->data = 0; | |
| + r->ndata = 0; | |
| + r->perm = 0666; | |
| + r->qid.type = 0; | |
| + r->qid.path = 1; | |
| + r->qid.vers = 0; | |
| + r->parent = 0; | |
| + r->user = user; | |
| + r->group = user; | |
| + r->muid = user; | |
| + r->atime = time(0); | |
| + r->mtime = r->atime; | |
| + r->name = estrdup("file"); | |
| + | |
| + if(debug) | |
| + fmtinstall('F', fcallfmt); | |
| + switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){ | |
| + case -1: | |
| + error("fork"); | |
| + case 0: | |
| + close(p[1]); | |
| + io(); | |
| + break; | |
| + default: | |
| + close(p[0]); /* don't deadlock if child fails */ | |
| + } | |
| + exits(0); | |
| +} | |
| + | |
| +char* | |
| +rversion(Fid *x) | |
| +{ | |
| + Fid *f; | |
| + | |
| + USED(x); | |
| + for(f = fids; f; f = f->next) | |
| + if(f->busy) | |
| + rclunk(f); | |
| + if(thdr.msize > sizeof mdata) | |
| + rhdr.msize = sizeof mdata; | |
| + else | |
| + rhdr.msize = thdr.msize; | |
| + messagesize = rhdr.msize; | |
| + if(strncmp(thdr.version, "9P2000", 6) != 0) | |
| + return Eversion; | |
| + rhdr.version = "9P2000"; | |
| + return 0; | |
| +} | |
| + | |
| +char* | |
| +rauth(Fid *x) | |
| +{ | |
| + if(x->busy) | |
| + return Ebadfid; | |
| + return "ramfs: no authentication required"; | |
| +} | |
| + | |
| +char* | |
| +rflush(Fid *f) | |
| +{ | |
| + USED(f); | |
| + return 0; | |
| +} | |
| + | |
| +char* | |
| +rattach(Fid *f) | |
| +{ | |
| + /* no authentication! */ | |
| + if(f->busy) | |
| + return Ebadfid; | |
| + f->busy = 1; | |
| + f->rclose = 0; | |
| + f->ram = &ram[0]; | |
| + rhdr.qid = f->ram->qid; | |
| + if(thdr.uname[0]) | |
| + f->user = estrdup(thdr.uname); | |
| + else | |
| + f->user = "none"; | |
| + if(strcmp(user, "none") == 0) | |
| + user = f->user; | |
| + return 0; | |
| +} | |
| + | |
| +char* | |
| +clone(Fid *f, Fid **nf) | |
| +{ | |
| + if(!f->busy) | |
| + return Ebadfid; | |
| + if(f->open) | |
| + return Eisopen; | |
| + if(f->ram->busy == 0) | |
| + return Enotexist; | |
| + *nf = newfid(thdr.newfid); | |
| + (*nf)->busy = 1; | |
| + (*nf)->open = 0; | |
| + (*nf)->rclose = 0; | |
| + (*nf)->ram = f->ram; | |
| + (*nf)->user = f->user; /* no ref count; the leakage is minor */ | |
| + return 0; | |
| +} | |
| + | |
| +char* | |
| +rwalk(Fid *f) | |
| +{ | |
| + Ram *r, *fram; | |
| + char *name; | |
| + Ram *parent; | |
| + Fid *nf; | |
| + char *err; | |
| + ulong t; | |
| + int i; | |
| + | |
| + if(!f->busy) | |
| + return Ebadfid; | |
| + err = nil; | |
| + nf = nil; | |
| + rhdr.nwqid = 0; | |
| + if(thdr.newfid != thdr.fid){ | |
| + err = clone(f, &nf); | |
| + if(err) | |
| + return err; | |
| + f = nf; /* walk the new fid */ | |
| + } | |
| + fram = f->ram; | |
| + if(thdr.nwname > 0){ | |
| + t = time(0); | |
| + for(i=0; i<thdr.nwname && i<MAXWELEM; i++){ | |
| + if((fram->qid.type & QTDIR) == 0){ | |
| + err = Enotdir; | |
| + break; | |
| + } | |
| + if(fram->busy == 0){ | |
| + err = Enotexist; | |
| + break; | |
| + } | |
| + fram->atime = t; | |
| + name = thdr.wname[i]; | |
| + if(strcmp(name, ".") == 0){ | |
| + Found: | |
| + rhdr.nwqid++; | |
| + rhdr.wqid[i] = fram->qid; | |
| + continue; | |
| + } | |
| + parent = &ram[fram->parent]; | |
| + if(!perm(f, parent, Pexec)){ | |
| + err = Eperm; | |
| + break; | |
| + } | |
| + if(strcmp(name, "..") == 0){ | |
| + fram = parent; | |
| + goto Found; | |
| + } | |
| + for(r=ram; r < &ram[nram]; r++) | |
| + if(r->busy && r->parent==fram-ram && strcmp(na… | |
| + fram = r; | |
| + goto Found; | |
| + } | |
| + break; | |
| + } | |
| + if(i==0 && err == nil) | |
| + err = Enotexist; | |
| + } | |
| + if(nf != nil && (err!=nil || rhdr.nwqid<thdr.nwname)){ | |
| + /* clunk the new fid, which is the one we walked */ | |
| +fprint(2, "f %d zero busy\n", f->fid); | |
| + f->busy = 0; | |
| + f->ram = nil; | |
| + } | |
| + if(rhdr.nwqid == thdr.nwname) /* update the fid after a success… | |
| + f->ram = fram; | |
| + assert(f->busy); | |
| + return err; | |
| +} | |
| + | |
| +char * | |
| +ropen(Fid *f) | |
| +{ | |
| + Ram *r; | |
| + int mode, trunc; | |
| + | |
| + if(!f->busy) | |
| + return Ebadfid; | |
| + if(f->open) | |
| + return Eisopen; | |
| + r = f->ram; | |
| + if(r->busy == 0) | |
| + return Enotexist; | |
| + if(r->perm & DMEXCL) | |
| + if(r->open) | |
| + return Excl; | |
| + mode = thdr.mode; | |
| + if(r->qid.type & QTDIR){ | |
| + if(mode != OREAD) | |
| + return Eperm; | |
| + rhdr.qid = r->qid; | |
| + return 0; | |
| + } | |
| + if(mode & ORCLOSE){ | |
| + /* can't remove root; must be able to write parent */ | |
| + if(r->qid.path==0 || !perm(f, &ram[r->parent], Pwrite)) | |
| + return Eperm; | |
| + f->rclose = 1; | |
| + } | |
| + trunc = mode & OTRUNC; | |
| + mode &= OPERM; | |
| + if(mode==OWRITE || mode==ORDWR || trunc) | |
| + if(!perm(f, r, Pwrite)) | |
| + return Eperm; | |
| + if(mode==OREAD || mode==ORDWR) | |
| + if(!perm(f, r, Pread)) | |
| + return Eperm; | |
| + if(mode==OEXEC) | |
| + if(!perm(f, r, Pexec)) | |
| + return Eperm; | |
| + if(trunc && (r->perm&DMAPPEND)==0){ | |
| + r->ndata = 0; | |
| + if(r->data) | |
| + free(r->data); | |
| + r->data = 0; | |
| + r->qid.vers++; | |
| + } | |
| + rhdr.qid = r->qid; | |
| + rhdr.iounit = messagesize-IOHDRSZ; | |
| + f->open = 1; | |
| + r->open++; | |
| + return 0; | |
| +} | |
| + | |
| +char * | |
| +rcreate(Fid *f) | |
| +{ | |
| + Ram *r; | |
| + char *name; | |
| + long parent, prm; | |
| + | |
| + if(!f->busy) | |
| + return Ebadfid; | |
| + if(f->open) | |
| + return Eisopen; | |
| + if(f->ram->busy == 0) | |
| + return Enotexist; | |
| + parent = f->ram - ram; | |
| + if((f->ram->qid.type&QTDIR) == 0) | |
| + return Enotdir; | |
| + /* must be able to write parent */ | |
| + if(!perm(f, f->ram, Pwrite)) | |
| + return Eperm; | |
| + prm = thdr.perm; | |
| + name = thdr.name; | |
| + if(strcmp(name, ".")==0 || strcmp(name, "..")==0) | |
| + return Ename; | |
| + for(r=ram; r<&ram[nram]; r++) | |
| + if(r->busy && parent==r->parent) | |
| + if(strcmp((char*)name, r->name)==0) | |
| + return Einuse; | |
| + for(r=ram; r->busy; r++) | |
| + if(r == &ram[Nram-1]) | |
| + return "no free ram resources"; | |
| + r->busy = 1; | |
| + r->qid.path = ++path; | |
| + r->qid.vers = 0; | |
| + if(prm & DMDIR) | |
| + r->qid.type |= QTDIR; | |
| + r->parent = parent; | |
| + free(r->name); | |
| + r->name = estrdup(name); | |
| + r->user = f->user; | |
| + r->group = f->ram->group; | |
| + r->muid = f->ram->muid; | |
| + if(prm & DMDIR) | |
| + prm = (prm&~0777) | (f->ram->perm&prm&0777); | |
| + else | |
| + prm = (prm&(~0777|0111)) | (f->ram->perm&prm&0666); | |
| + r->perm = prm; | |
| + r->ndata = 0; | |
| + if(r-ram >= nram) | |
| + nram = r - ram + 1; | |
| + r->atime = time(0); | |
| + r->mtime = r->atime; | |
| + f->ram->mtime = r->atime; | |
| + f->ram = r; | |
| + rhdr.qid = r->qid; | |
| + rhdr.iounit = messagesize-IOHDRSZ; | |
| + f->open = 1; | |
| + if(thdr.mode & ORCLOSE) | |
| + f->rclose = 1; | |
| + r->open++; | |
| + return 0; | |
| +} | |
| + | |
| +char* | |
| +rread(Fid *f) | |
| +{ | |
| + Ram *r; | |
| + uchar *buf; | |
| + long off; | |
| + int n, m, cnt; | |
| + | |
| + if(!f->busy) | |
| + return Ebadfid; | |
| + if(f->ram->busy == 0) | |
| + return Enotexist; | |
| + n = 0; | |
| + rhdr.count = 0; | |
| + off = thdr.offset; | |
| + buf = rdata; | |
| + cnt = thdr.count; | |
| + if(cnt > messagesize) /* shouldn't happen, anyway */ | |
| + cnt = messagesize; | |
| + if(f->ram->qid.type & QTDIR){ | |
| + for(r=ram+1; off > 0; r++){ | |
| + if(r->busy && r->parent==f->ram-ram) | |
| + off -= ramstat(r, statbuf, sizeof statbuf); | |
| + if(r == &ram[nram-1]) | |
| + return 0; | |
| + } | |
| + for(; r<&ram[nram] && n < cnt; r++){ | |
| + if(!r->busy || r->parent!=f->ram-ram) | |
| + continue; | |
| + m = ramstat(r, buf+n, cnt-n); | |
| + if(m == 0) | |
| + break; | |
| + n += m; | |
| + } | |
| + rhdr.data = (char*)rdata; | |
| + rhdr.count = n; | |
| + return 0; | |
| + } | |
| + r = f->ram; | |
| + if(off >= r->ndata) | |
| + return 0; | |
| + r->atime = time(0); | |
| + n = cnt; | |
| + if(off+n > r->ndata) | |
| + n = r->ndata - off; | |
| + rhdr.data = r->data+off; | |
| + rhdr.count = n; | |
| + return 0; | |
| +} | |
| + | |
| +char* | |
| +rwrite(Fid *f) | |
| +{ | |
| + Ram *r; | |
| + ulong off; | |
| + int cnt; | |
| + | |
| + r = f->ram; | |
| + if(!f->busy) | |
| + return Ebadfid; | |
| + if(r->busy == 0) | |
| + return Enotexist; | |
| + off = thdr.offset; | |
| + if(r->perm & DMAPPEND) | |
| + off = r->ndata; | |
| + cnt = thdr.count; | |
| + if(r->qid.type & QTDIR) | |
| + return Eisdir; | |
| + if(off+cnt >= Maxsize) /* sanity check */ | |
| + return "write too big"; | |
| + if(off+cnt > r->ndata) | |
| + r->data = erealloc(r->data, off+cnt); | |
| + if(off > r->ndata) | |
| + memset(r->data+r->ndata, 0, off-r->ndata); | |
| + if(off+cnt > r->ndata) | |
| + r->ndata = off+cnt; | |
| + memmove(r->data+off, thdr.data, cnt); | |
| + r->qid.vers++; | |
| + r->mtime = time(0); | |
| + rhdr.count = cnt; | |
| + return 0; | |
| +} | |
| + | |
| +static int | |
| +emptydir(Ram *dr) | |
| +{ | |
| + long didx = dr - ram; | |
| + Ram *r; | |
| + | |
| + for(r=ram; r<&ram[nram]; r++) | |
| + if(r->busy && didx==r->parent) | |
| + return 0; | |
| + return 1; | |
| +} | |
| + | |
| +char * | |
| +realremove(Ram *r) | |
| +{ | |
| + if(r->qid.type & QTDIR && !emptydir(r)) | |
| + return Enotempty; | |
| + r->ndata = 0; | |
| + if(r->data) | |
| + free(r->data); | |
| + r->data = 0; | |
| + r->parent = 0; | |
| + memset(&r->qid, 0, sizeof r->qid); | |
| + free(r->name); | |
| + r->name = nil; | |
| + r->busy = 0; | |
| + return nil; | |
| +} | |
| + | |
| +char * | |
| +rclunk(Fid *f) | |
| +{ | |
| + char *e = nil; | |
| + | |
| + if(f->open) | |
| + f->ram->open--; | |
| + if(f->rclose) | |
| + e = realremove(f->ram); | |
| +fprint(2, "clunk fid %d busy=%d\n", f->fid, f->busy); | |
| +fprint(2, "f %d zero busy\n", f->fid); | |
| + f->busy = 0; | |
| + f->open = 0; | |
| + f->ram = 0; | |
| + return e; | |
| +} | |
| + | |
| +char * | |
| +rremove(Fid *f) | |
| +{ | |
| + Ram *r; | |
| + | |
| + if(f->open) | |
| + f->ram->open--; | |
| +fprint(2, "f %d zero busy\n", f->fid); | |
| + f->busy = 0; | |
| + f->open = 0; | |
| + r = f->ram; | |
| + f->ram = 0; | |
| + if(r->qid.path == 0 || !perm(f, &ram[r->parent], Pwrite)) | |
| + return Eperm; | |
| + ram[r->parent].mtime = time(0); | |
| + return realremove(r); | |
| +} | |
| + | |
| +char * | |
| +rstat(Fid *f) | |
| +{ | |
| + if(!f->busy) | |
| + return Ebadfid; | |
| + if(f->ram->busy == 0) | |
| + return Enotexist; | |
| + rhdr.nstat = ramstat(f->ram, statbuf, sizeof statbuf); | |
| + rhdr.stat = statbuf; | |
| + return 0; | |
| +} | |
| + | |
| +char * | |
| +rwstat(Fid *f) | |
| +{ | |
| + Ram *r, *s; | |
| + Dir dir; | |
| + | |
| + if(!f->busy) | |
| + return Ebadfid; | |
| + if(f->ram->busy == 0) | |
| + return Enotexist; | |
| + convM2D(thdr.stat, thdr.nstat, &dir, (char*)statbuf); | |
| + r = f->ram; | |
| + | |
| + /* | |
| + * To change length, must have write permission on file. | |
| + */ | |
| + if(dir.length!=~0 && dir.length!=r->ndata){ | |
| + if(!perm(f, r, Pwrite)) | |
| + return Eperm; | |
| + } | |
| + | |
| + /* | |
| + * To change name, must have write permission in parent | |
| + * and name must be unique. | |
| + */ | |
| + if(dir.name[0]!='\0' && strcmp(dir.name, r->name)!=0){ | |
| + if(!perm(f, &ram[r->parent], Pwrite)) | |
| + return Eperm; | |
| + for(s=ram; s<&ram[nram]; s++) | |
| + if(s->busy && s->parent==r->parent) | |
| + if(strcmp(dir.name, s->name)==0) | |
| + return Eexist; | |
| + } | |
| + | |
| + /* | |
| + * To change mode, must be owner or group leader. | |
| + * Because of lack of users file, leader=>group itself. | |
| + */ | |
| + if(dir.mode!=~0 && r->perm!=dir.mode){ | |
| + if(strcmp(f->user, r->user) != 0) | |
| + if(strcmp(f->user, r->group) != 0) | |
| + return Enotowner; | |
| + } | |
| + | |
| + /* | |
| + * To change group, must be owner and member of new group, | |
| + * or leader of current group and leader of new group. | |
| + * Second case cannot happen, but we check anyway. | |
| + */ | |
| + if(dir.gid[0]!='\0' && strcmp(r->group, dir.gid)!=0){ | |
| + if(strcmp(f->user, r->user) == 0) | |
| + // if(strcmp(f->user, dir.gid) == 0) | |
| + goto ok; | |
| + if(strcmp(f->user, r->group) == 0) | |
| + if(strcmp(f->user, dir.gid) == 0) | |
| + goto ok; | |
| + return Enotowner; | |
| + ok:; | |
| + } | |
| + | |
| + /* all ok; do it */ | |
| + if(dir.mode != ~0){ | |
| + dir.mode &= ~DMDIR; /* cannot change dir bit */ | |
| + dir.mode |= r->perm&DMDIR; | |
| + r->perm = dir.mode; | |
| + } | |
| + if(dir.name[0] != '\0'){ | |
| + free(r->name); | |
| + r->name = estrdup(dir.name); | |
| + } | |
| + if(dir.gid[0] != '\0') | |
| + r->group = estrdup(dir.gid); | |
| + if(dir.length!=~0 && dir.length!=r->ndata){ | |
| + r->data = erealloc(r->data, dir.length); | |
| + if(r->ndata < dir.length) | |
| + memset(r->data+r->ndata, 0, dir.length-r->ndata); | |
| + r->ndata = dir.length; | |
| + } | |
| + ram[r->parent].mtime = time(0); | |
| + return 0; | |
| +} | |
| + | |
| +uint | |
| +ramstat(Ram *r, uchar *buf, uint nbuf) | |
| +{ | |
| + int n; | |
| + Dir dir; | |
| + | |
| + dir.name = r->name; | |
| + dir.qid = r->qid; | |
| + dir.mode = r->perm; | |
| + dir.length = r->ndata; | |
| + dir.uid = r->user; | |
| + dir.gid = r->group; | |
| + dir.muid = r->muid; | |
| + dir.atime = r->atime; | |
| + dir.mtime = r->mtime; | |
| + n = convD2M(&dir, buf, nbuf); | |
| + if(n > 2) | |
| + return n; | |
| + return 0; | |
| +} | |
| + | |
| +Fid * | |
| +newfid(int fid) | |
| +{ | |
| + Fid *f, *ff; | |
| + | |
| + ff = 0; | |
| + for(f = fids; f; f = f->next) | |
| + if(f->fid == fid){ | |
| +fprint(2, "got fid %d busy=%d\n", fid, f->busy); | |
| + return f; | |
| + } | |
| + else if(!ff && !f->busy) | |
| + ff = f; | |
| + if(ff){ | |
| + ff->fid = fid; | |
| + return ff; | |
| + } | |
| + f = emalloc(sizeof *f); | |
| + f->ram = nil; | |
| + f->fid = fid; | |
| + f->next = fids; | |
| + fids = f; | |
| + return f; | |
| +} | |
| + | |
| +void | |
| +io(void) | |
| +{ | |
| + char *err, buf[20]; | |
| + int n, pid, ctl; | |
| + | |
| + pid = getpid(); | |
| + if(private){ | |
| + snprint(buf, sizeof buf, "/proc/%d/ctl", pid); | |
| + ctl = open(buf, OWRITE); | |
| + if(ctl < 0){ | |
| + fprint(2, "can't protect ramfs\n"); | |
| + }else{ | |
| + fprint(ctl, "noswap\n"); | |
| + fprint(ctl, "private\n"); | |
| + close(ctl); | |
| + } | |
| + } | |
| + | |
| + for(;;){ | |
| + /* | |
| + * reading from a pipe or a network device | |
| + * will give an error after a few eof reads. | |
| + * however, we cannot tell the difference | |
| + * between a zero-length read and an interrupt | |
| + * on the processes writing to us, | |
| + * so we wait for the error. | |
| + */ | |
| + n = read9pmsg(mfd[0], mdata, messagesize); | |
| + if(n < 0) | |
| + error("mount read"); | |
| + if(n == 0) | |
| + error("mount eof"); | |
| + if(convM2S(mdata, n, &thdr) == 0) | |
| + continue; | |
| + | |
| + if(debug) | |
| + fprint(2, "ramfs %d:<-%F\n", pid, &thdr); | |
| + | |
| + if(!fcalls[thdr.type]) | |
| + err = "bad fcall type"; | |
| + else | |
| + err = (*fcalls[thdr.type])(newfid(thdr.fid)); | |
| + if(err){ | |
| + rhdr.type = Rerror; | |
| + rhdr.ename = err; | |
| + }else{ | |
| + rhdr.type = thdr.type + 1; | |
| + rhdr.fid = thdr.fid; | |
| + } | |
| + rhdr.tag = thdr.tag; | |
| + if(debug) | |
| + fprint(2, "ramfs %d:->%F\n", pid, &rhdr);/**/ | |
| + n = convS2M(&rhdr, mdata, messagesize); | |
| + if(n == 0) | |
| + error("convS2M error on write"); | |
| + if(write(mfd[1], mdata, n) != n) | |
| + error("mount write"); | |
| + } | |
| +} | |
| + | |
| +int | |
| +perm(Fid *f, Ram *r, int p) | |
| +{ | |
| + if((p*Pother) & r->perm) | |
| + return 1; | |
| + if(strcmp(f->user, r->group)==0 && ((p*Pgroup) & r->perm)) | |
| + return 1; | |
| + if(strcmp(f->user, r->user)==0 && ((p*Powner) & r->perm)) | |
| + return 1; | |
| + return 0; | |
| +} | |
| + | |
| +void | |
| +error(char *s) | |
| +{ | |
| + fprint(2, "%s: %s: %r\n", argv0, s); | |
| + exits(s); | |
| +} | |
| + | |
| +void * | |
| +emalloc(ulong n) | |
| +{ | |
| + void *p; | |
| + | |
| + p = malloc(n); | |
| + if(!p) | |
| + error("out of memory"); | |
| + memset(p, 0, n); | |
| + return p; | |
| +} | |
| + | |
| +void * | |
| +erealloc(void *p, ulong n) | |
| +{ | |
| + p = realloc(p, n); | |
| + if(!p) | |
| + error("out of memory"); | |
| + return p; | |
| +} | |
| + | |
| +char * | |
| +estrdup(char *q) | |
| +{ | |
| + char *p; | |
| + int n; | |
| + | |
| + n = strlen(q)+1; | |
| + p = malloc(n); | |
| + if(!p) | |
| + error("out of memory"); | |
| + memmove(p, q, n); | |
| + return p; | |
| +} | |
| + | |
| +void | |
| +usage(void) | |
| +{ | |
| + fprint(2, "usage: %s [-is] [-m mountpoint]\n", argv0); | |
| + exits("usage"); | |
| +} | |
| + |