#include <u.h>#include <libc.h>#include <fcall.h> /* * 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 open mode */ 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[Tmax])(Fid*); static voidinitfcalls(void){ fcalls[Tversion]= rversion; fcalls[Tflush]= rflush; fcalls[Tauth]= rauth; fcalls[Tattach]= rattach; fcalls[Twalk]= rwalk; fcalls[Topen]= ropen; fcalls[Tcreate]= rcreate; fcalls[Tread]= rread; fcalls[Twrite]= rwrite; fcalls[Tclunk]= rclunk; fcalls[Tremove]= rremove; fcalls[Tstat]= rstat; fcalls[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; voidnotifyf(void *a, char *s){ USED(a); if(strncmp(s, "interrupt", 9) == 0) noted(NCONT); noted(NDFLT);} voidmain(int argc, char *argv[]){ Ram *r; char *defmnt; int p[2]; int stdio = 0; char *service; initfcalls(); service = "ramfs"; defmnt = nil; ARGBEGIN{ case 'D': debug = 1; break; case 'i': defmnt = 0; stdio = 1; mfd[0] = 0; mfd[1] = 1; break; case 's': defmnt = nil; break; case 'm': defmnt = ARGF(); break; case 'p': private++; break; case 'S': defmnt = 0; service = EARGF(usage()); break; default: usage(); }ARGEND if(pipe(p) < 0) error("pipe failed"); if(!stdio){ mfd[0] = p[0]; mfd[1] = p[0]; if(post9pservice(p[1], service, nil) < 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); io(); 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*xclone(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 = xclone(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(name, r->name)==0){ 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 successful walk */ 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;Lines 1–500 of 896. Load more
#include <u.h> #include <libc.h> #include <fcall.h> /* * 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 open mode */ 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[Tmax])(Fid*); static void initfcalls(void) { fcalls[Tversion]= rversion; fcalls[Tflush]= rflush; fcalls[Tauth]= rauth; fcalls[Tattach]= rattach; fcalls[Twalk]= rwalk; fcalls[Topen]= ropen; fcalls[Tcreate]= rcreate; fcalls[Tread]= rread; fcalls[Twrite]= rwrite; fcalls[Tclunk]= rclunk; fcalls[Tremove]= rremove; fcalls[Tstat]= rstat; fcalls[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; initfcalls(); service = "ramfs"; defmnt = nil; ARGBEGIN{ case 'D': debug = 1; break; case 'i': defmnt = 0; stdio = 1; mfd[0] = 0; mfd[1] = 1; break; case 's': defmnt = nil; break; case 'm': defmnt = ARGF(); break; case 'p': private++; break; case 'S': defmnt = 0; service = EARGF(usage()); break; default: usage(); }ARGEND if(pipe(p) < 0) error("pipe failed"); if(!stdio){ mfd[0] = p[0]; mfd[1] = p[0]; if(post9pservice(p[1], service, nil) < 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); io(); 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* xclone(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 = xclone(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(name, r->name)==0){ 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 successful walk */ 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;