From 2277c5d7bbe1f9595fad512d8f790708473a9bf1 Mon Sep 17 00:00:00 2001 From: rsc Date: Sun, 21 Mar 2004 04:33:13 +0000 Subject: Small tweaks Lots of new code imported. --- src/lib9p/_post.c | 77 +++++ src/lib9p/dirread.c | 40 +++ src/lib9p/fid.c | 81 +++++ src/lib9p/file.c | 372 +++++++++++++++++++++++ src/lib9p/ftest.c | 29 ++ src/lib9p/intmap.c | 166 +++++++++++ src/lib9p/mem.c | 49 +++ src/lib9p/mkfile | 20 ++ src/lib9p/parse.c | 115 ++++++++ src/lib9p/post.c | 24 ++ src/lib9p/post.h | 13 + src/lib9p/ramfs.c | 163 ++++++++++ src/lib9p/req.c | 112 +++++++ src/lib9p/srv.c | 837 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib9p/tpost.c | 18 ++ src/lib9p/uid.c | 34 +++ src/lib9p/util.c | 25 ++ 17 files changed, 2175 insertions(+) create mode 100644 src/lib9p/_post.c create mode 100644 src/lib9p/dirread.c create mode 100644 src/lib9p/fid.c create mode 100644 src/lib9p/file.c create mode 100644 src/lib9p/ftest.c create mode 100644 src/lib9p/intmap.c create mode 100644 src/lib9p/mem.c create mode 100644 src/lib9p/mkfile create mode 100644 src/lib9p/parse.c create mode 100644 src/lib9p/post.c create mode 100644 src/lib9p/post.h create mode 100644 src/lib9p/ramfs.c create mode 100644 src/lib9p/req.c create mode 100644 src/lib9p/srv.c create mode 100644 src/lib9p/tpost.c create mode 100644 src/lib9p/uid.c create mode 100644 src/lib9p/util.c (limited to 'src/lib9p') diff --git a/src/lib9p/_post.c b/src/lib9p/_post.c new file mode 100644 index 00000000..e8313be1 --- /dev/null +++ b/src/lib9p/_post.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include <9p.h> +#include +#include "post.h" + +Postcrud* +_post1(Srv *s, char *name, char *mtpt, int flag) +{ + Postcrud *p; + + p = emalloc9p(sizeof *p); + if(!s->nopipe){ + if(pipe(p->fd) < 0) + sysfatal("pipe: %r"); + s->infd = s->outfd = p->fd[1]; + s->srvfd = p->fd[0]; + } + if(name) + if(postfd(name, s->srvfd) < 0) + sysfatal("postfd %s: %r", name); + p->s = s; + p->mtpt = mtpt; + p->flag = flag; + return p; +} + +void +_post2(void *v) +{ + Srv *s; + + s = v; + rfork(RFNOTEG); + if(!s->leavefdsopen){ + rendezvous((ulong)s, 0); + close(s->srvfd); + } + srv(s); +} + +void +_post3(Postcrud *p) +{ + /* + * Normally the server is posting as the last thing it does + * before exiting, so the correct thing to do is drop into + * a different fd space and close the 9P server half of the + * pipe before trying to mount the kernel half. This way, + * if the file server dies, we don't have a ref to the 9P server + * half of the pipe. Then killing the other procs will drop + * all the refs on the 9P server half, and the mount will fail. + * Otherwise the mount hangs forever. + * + * Libthread in general and acme win in particular make + * it hard to make this fd bookkeeping work out properly, + * so leaveinfdopen is a flag that win sets to opt out of this + * safety net. + */ + if(!p->s->leavefdsopen){ + rfork(RFFDG); + rendezvous((ulong)p->s, 0); + close(p->s->infd); + if(p->s->infd != p->s->outfd) + close(p->s->outfd); + } + + if(p->mtpt){ + if(amount(p->s->srvfd, p->mtpt, p->flag, "") == -1) + sysfatal("mount %s: %r", p->mtpt); + }else + close(p->s->srvfd); + free(p); +} + diff --git a/src/lib9p/dirread.c b/src/lib9p/dirread.c new file mode 100644 index 00000000..7fb88305 --- /dev/null +++ b/src/lib9p/dirread.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include <9p.h> + +void +dirread9p(Req *r, Dirgen *gen, void *aux) +{ + int start; + uchar *p, *ep; + uint rv; + Dir d; + + if(r->ifcall.offset == 0) + start = 0; + else + start = r->fid->dirindex; + + p = (uchar*)r->ofcall.data; + ep = p+r->ifcall.count; + + while(p < ep){ + memset(&d, 0, sizeof d); + if((*gen)(start, &d, aux) < 0) + break; + rv = convD2M(&d, p, ep-p); + free(d.name); + free(d.muid); + free(d.uid); + free(d.gid); + if(rv <= BIT16SZ) + break; + p += rv; + start++; + } + r->fid->dirindex = start; + r->ofcall.count = p - (uchar*)r->ofcall.data; +} diff --git a/src/lib9p/fid.c b/src/lib9p/fid.c new file mode 100644 index 00000000..2393f1c4 --- /dev/null +++ b/src/lib9p/fid.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include "9p.h" + +static void +incfidref(void *v) +{ + Fid *f; + + f = v; + if(f) + incref(&f->ref); +} + +Fidpool* +allocfidpool(void (*destroy)(Fid*)) +{ + Fidpool *f; + + f = emalloc9p(sizeof *f); + f->map = allocmap(incfidref); + f->destroy = destroy; + return f; +} + +void +freefidpool(Fidpool *p) +{ + freemap(p->map, (void(*)(void*))p->destroy); + free(p); +} + +Fid* +allocfid(Fidpool *pool, ulong fid) +{ + Fid *f; + + f = emalloc9p(sizeof *f); + f->fid = fid; + f->omode = -1; + f->pool = pool; + + incfidref(f); + incfidref(f); + if(caninsertkey(pool->map, fid, f) == 0){ + closefid(f); + return nil; + } + + return f; +} + +Fid* +lookupfid(Fidpool *pool, ulong fid) +{ + return lookupkey(pool->map, fid); +} + +void +closefid(Fid *f) +{ + if(decref(&f->ref) == 0) { + if(f->rdir) + closedirfile(f->rdir); + if(f->pool->destroy) + f->pool->destroy(f); + if(f->file) + closefile(f->file); + free(f->uid); + free(f); + } +} + +Fid* +removefid(Fidpool *pool, ulong fid) +{ + return deletekey(pool->map, fid); +} diff --git a/src/lib9p/file.c b/src/lib9p/file.c new file mode 100644 index 00000000..79a8a11d --- /dev/null +++ b/src/lib9p/file.c @@ -0,0 +1,372 @@ +#include +#include +#include +#include +#include +#include <9p.h> + +/* + * To avoid deadlock, the following rules must be followed. + * Always lock child then parent, never parent then child. + * If holding the free file lock, do not lock any Files. + */ +struct Filelist { + File *f; + Filelist *link; +}; + +static QLock filelk; +static File *freefilelist; + +static File* +allocfile(void) +{ + int i, a; + File *f; + enum { N = 16 }; + + qlock(&filelk); + if(freefilelist == nil){ + f = emalloc9p(N*sizeof(*f)); + for(i=0; iaux; + qunlock(&filelk); + + a = f->allocd; + memset(f, 0, sizeof *f); + f->allocd = a; + return f; +} + +static void +freefile(File *f) +{ + Filelist *fl, *flnext; + + for(fl=f->filelist; fl; fl=flnext){ + flnext = fl->link; + assert(fl->f == nil); + free(fl); + } + + free(f->dir.name); + free(f->dir.uid); + free(f->dir.gid); + free(f->dir.muid); + qlock(&filelk); + assert(f->ref.ref == 0); + f->aux = freefilelist; + freefilelist = f; + qunlock(&filelk); +} + +void +closefile(File *f) +{ + if(decref(&f->ref) == 0){ + f->tree->destroy(f); + freefile(f); + } +} + +static void +nop(File *f) +{ + USED(f); +} + +int +removefile(File *f) +{ + File *fp; + Filelist *fl; + + fp = f->parent; + if(fp == nil){ + werrstr("no parent"); + closefile(f); + return -1; + } + + if(fp == f){ + werrstr("cannot remove root"); + closefile(f); + return -1; + } + + wlock(&fp->rwlock); + wlock(&f->rwlock); + if(f->nchild != 0){ + werrstr("has children"); + wunlock(&f->rwlock); + wunlock(&fp->rwlock); + closefile(f); + return -1; + } + + if(f->parent != fp){ + werrstr("parent changed underfoot"); + wunlock(&f->rwlock); + wunlock(&fp->rwlock); + closefile(f); + return -1; + } + + for(fl=fp->filelist; fl; fl=fl->link) + if(fl->f == f) + break; + assert(fl != nil && fl->f == f); + + fl->f = nil; + fp->nchild--; + f->parent = nil; + wunlock(&fp->rwlock); + wunlock(&f->rwlock); + + closefile(fp); /* reference from child */ + closefile(f); /* reference from tree */ + closefile(f); + return 0; +} + +File* +createfile(File *fp, char *name, char *uid, ulong perm, void *aux) +{ + File *f; + Filelist *fl, *freel; + Tree *t; + + if((fp->dir.qid.type&QTDIR) == 0){ + werrstr("create in non-directory"); + return nil; + } + + freel = nil; + wlock(&fp->rwlock); + for(fl=fp->filelist; fl; fl=fl->link){ + if(fl->f == nil) + freel = fl; + else if(strcmp(fl->f->dir.name, name) == 0){ + wunlock(&fp->rwlock); + werrstr("file already exists"); + return nil; + } + } + + if(freel == nil){ + freel = emalloc9p(sizeof *freel); + freel->link = fp->filelist; + fp->filelist = freel; + } + + f = allocfile(); + f->dir.name = estrdup9p(name); + f->dir.uid = estrdup9p(uid ? uid : fp->dir.uid); + f->dir.gid = estrdup9p(fp->dir.gid); + f->dir.muid = estrdup9p(uid ? uid : "unknown"); + f->aux = aux; + f->dir.mode = perm; + + t = fp->tree; + lock(&t->genlock); + f->dir.qid.path = t->qidgen++; + unlock(&t->genlock); + if(perm & DMDIR) + f->dir.qid.type |= QTDIR; + if(perm & DMAPPEND) + f->dir.qid.type |= QTAPPEND; + if(perm & DMEXCL) + f->dir.qid.type |= QTEXCL; + + f->dir.mode = perm; + f->dir.atime = f->dir.mtime = time(0); + f->dir.length = 0; + f->parent = fp; + incref(&fp->ref); + f->tree = fp->tree; + + incref(&f->ref); /* being returned */ + incref(&f->ref); /* for the tree */ + freel->f = f; + fp->nchild++; + wunlock(&fp->rwlock); + + return f; +} + +static File* +walkfile1(File *dir, char *elem) +{ + File *fp; + Filelist *fl; + + rlock(&dir->rwlock); + if(strcmp(elem, "..") == 0){ + fp = dir->parent; + incref(&fp->ref); + runlock(&dir->rwlock); + closefile(dir); + return fp; + } + + fp = nil; + for(fl=dir->filelist; fl; fl=fl->link) + if(fl->f && strcmp(fl->f->dir.name, elem)==0){ + fp = fl->f; + incref(&fp->ref); + break; + } + + runlock(&dir->rwlock); + closefile(dir); + return fp; +} + +File* +walkfile(File *f, char *path) +{ + char *os, *s, *nexts; + File *nf; + + if(strchr(path, '/') == nil) + return walkfile1(f, path); /* avoid malloc */ + + os = s = estrdup9p(path); + incref(&f->ref); + for(; *s; s=nexts){ + if(nexts = strchr(s, '/')) + *nexts++ = '\0'; + else + nexts = s+strlen(s); + nf = walkfile1(f, s); + decref(&f->ref); + f = nf; + if(f == nil) + break; + } + free(os); + return f; +} + +Tree* +alloctree(char *uid, char *gid, ulong mode, void (*destroy)(File*)) +{ + char *muid; + Tree *t; + File *f; + + t = emalloc9p(sizeof *t); + f = allocfile(); + f->dir.name = estrdup9p("/"); + if(uid == nil){ + if(uid = getuser()) + uid = estrdup9p(uid); + } + if(uid == nil) + uid = estrdup9p("none"); + else + uid = estrdup9p(uid); + + if(gid == nil) + gid = estrdup9p(uid); + else + gid = estrdup9p(gid); + + muid = estrdup9p(uid); + + f->dir.qid = (Qid){0, 0, QTDIR}; + f->dir.length = 0; + f->dir.atime = f->dir.mtime = time(0); + f->dir.mode = DMDIR | mode; + f->tree = t; + f->parent = f; + f->dir.uid = uid; + f->dir.gid = gid; + f->dir.muid = muid; + + incref(&f->ref); + t->root = f; + t->qidgen = 0; + t->dirqidgen = 1; + if(destroy == nil) + destroy = nop; + t->destroy = destroy; + + return t; +} + +static void +_freefiles(File *f) +{ + Filelist *fl, *flnext; + + for(fl=f->filelist; fl; fl=flnext){ + flnext = fl->link; + _freefiles(fl->f); + free(fl); + } + + f->tree->destroy(f); + freefile(f); +} + +void +freetree(Tree *t) +{ + _freefiles(t->root); + free(t); +} + +struct Readdir { + Filelist *fl; +}; + +Readdir* +opendirfile(File *dir) +{ + Readdir *r; + + rlock(&dir->rwlock); + if((dir->dir.mode & DMDIR)==0){ + runlock(&dir->rwlock); + return nil; + } + r = emalloc9p(sizeof(*r)); + + /* + * This reference won't go away while we're using it + * since we are dir->rdir. + */ + r->fl = dir->filelist; + runlock(&dir->rwlock); + return r; +} + +long +readdirfile(Readdir *r, uchar *buf, long n) +{ + long x, m; + Filelist *fl; + + for(fl=r->fl, m=0; fl && m+2<=n; fl=fl->link, m+=x){ + if(fl->f == nil) + x = 0; + else if((x=convD2M(&fl->f->dir, buf+m, n-m)) <= BIT16SZ) + break; + } + r->fl = fl; + return m; +} + +void +closedirfile(Readdir *r) +{ + free(r); +} diff --git a/src/lib9p/ftest.c b/src/lib9p/ftest.c new file mode 100644 index 00000000..6692b7f1 --- /dev/null +++ b/src/lib9p/ftest.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include "9p.h" + +void +main(void) +{ + Tree *t; + File *hello, *goodbye, *world; + + t = mktree(); + + hello = fcreate(t->root, "hello", CHDIR|0777); + assert(hello != nil); + + goodbye = fcreate(t->root, "goodbye", CHDIR|0777); + assert(goodbye != nil); + + world = fcreate(hello, "world", 0666); + assert(world != nil); + world = fcreate(goodbye, "world", 0666); + assert(world != nil); + fdump(t->root, 0); + + fremove(world); + fdump(t->root, 0); +} diff --git a/src/lib9p/intmap.c b/src/lib9p/intmap.c new file mode 100644 index 00000000..48695675 --- /dev/null +++ b/src/lib9p/intmap.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include +#include <9p.h> + +enum { + NHASH = 128 +}; + +typedef struct Intlist Intlist; +struct Intlist +{ + ulong id; + void* aux; + Intlist* link; +}; + +struct Intmap +{ + RWLock rwlock; + Intlist* hash[NHASH]; + void (*inc)(void*); +}; + +static ulong +hashid(ulong id) +{ + return id%NHASH; +} + +static void +nop(void *v) +{ + USED(v); +} + +Intmap* +allocmap(void (*inc)(void*)) +{ + Intmap *m; + + m = emalloc9p(sizeof(*m)); + if(inc == nil) + inc = nop; + m->inc = inc; + return m; +} + +void +freemap(Intmap *map, void (*destroy)(void*)) +{ + int i; + Intlist *p, *nlink; + + if(destroy == nil) + destroy = nop; + for(i=0; ihash[i]; p; p=nlink){ + nlink = p->link; + destroy(p->aux); + free(p); + } + } + + free(map); +} + +static Intlist** +llookup(Intmap *map, ulong id) +{ + Intlist **lf; + + for(lf=&map->hash[hashid(id)]; *lf; lf=&(*lf)->link) + if((*lf)->id == id) + break; + return lf; +} + +/* + * The RWlock is used as expected except that we allow + * inc() to be called while holding it. This is because we're + * locking changes to the tree structure, not to the references. + * Inc() is expected to have its own locking. + */ +void* +lookupkey(Intmap *map, ulong id) +{ + Intlist *f; + void *v; + + rlock(&map->rwlock); + if(f = *llookup(map, id)){ + v = f->aux; + map->inc(v); + }else + v = nil; + runlock(&map->rwlock); + return v; +} + +void* +insertkey(Intmap *map, ulong id, void *v) +{ + Intlist *f; + void *ov; + ulong h; + + wlock(&map->rwlock); + if(f = *llookup(map, id)){ + /* no decrement for ov because we're returning it */ + ov = f->aux; + f->aux = v; + }else{ + f = emalloc9p(sizeof(*f)); + f->id = id; + f->aux = v; + h = hashid(id); + f->link = map->hash[h]; + map->hash[h] = f; + ov = nil; + } + wunlock(&map->rwlock); + return ov; +} + +int +caninsertkey(Intmap *map, ulong id, void *v) +{ + Intlist *f; + int rv; + ulong h; + + wlock(&map->rwlock); + if(*llookup(map, id)) + rv = 0; + else{ + f = emalloc9p(sizeof *f); + f->id = id; + f->aux = v; + h = hashid(id); + f->link = map->hash[h]; + map->hash[h] = f; + rv = 1; + } + wunlock(&map->rwlock); + return rv; +} + +void* +deletekey(Intmap *map, ulong id) +{ + Intlist **lf, *f; + void *ov; + + wlock(&map->rwlock); + if(f = *(lf = llookup(map, id))){ + ov = f->aux; + *lf = f->link; + free(f); + }else + ov = nil; + wunlock(&map->rwlock); + return ov; +} diff --git a/src/lib9p/mem.c b/src/lib9p/mem.c new file mode 100644 index 00000000..b4414951 --- /dev/null +++ b/src/lib9p/mem.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include +#include "9p.h" + +void* +emalloc9p(ulong sz) +{ + void *v; + + if((v = malloc(sz)) == nil) { + fprint(2, "out of memory allocating %lud\n", sz); + exits("mem"); + } + memset(v, 0, sz); + setmalloctag(v, getcallerpc(&sz)); + return v; +} + +void* +erealloc9p(void *v, ulong sz) +{ + void *nv; + + if((nv = realloc(v, sz)) == nil) { + fprint(2, "out of memory allocating %lud\n", sz); + exits("mem"); + } + if(v == nil) + setmalloctag(nv, getcallerpc(&v)); + setrealloctag(nv, getcallerpc(&v)); + return nv; +} + +char* +estrdup9p(char *s) +{ + char *t; + + if((t = strdup(s)) == nil) { + fprint(2, "out of memory in strdup(%.10s)\n", s); + exits("mem"); + } + setmalloctag(t, getcallerpc(&s)); + return t; +} + diff --git a/src/lib9p/mkfile b/src/lib9p/mkfile new file mode 100644 index 00000000..17a10a3c --- /dev/null +++ b/src/lib9p/mkfile @@ -0,0 +1,20 @@ +PLAN9=../.. +<$PLAN9/src/mkhdr + +LIB=lib9p.a +OFILES=\ + _post.$O\ + dirread.$O\ + fid.$O\ + file.$O\ + intmap.$O\ + mem.$O\ + req.$O\ + parse.$O\ + post.$O\ + srv.$O\ + tpost.$O\ + uid.$O\ + util.$O\ + +<$PLAN9/src/mksyslib diff --git a/src/lib9p/parse.c b/src/lib9p/parse.c new file mode 100644 index 00000000..753ae79d --- /dev/null +++ b/src/lib9p/parse.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include <9p.h> + +/* + * Generous estimate of number of fields, including terminal nil pointer + */ +static int +ncmdfield(char *p, int n) +{ + int white, nwhite; + char *ep; + int nf; + + if(p == nil) + return 1; + + nf = 0; + ep = p+n; + white = 1; /* first text will start field */ + while(p < ep){ + nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0); /* UTF is irrelevant */ + if(white && !nwhite) /* beginning of field */ + nf++; + white = nwhite; + } + return nf+1; /* +1 for nil */ +} + +/* + * parse a command written to a device + */ +Cmdbuf* +parsecmd(char *p, int n) +{ + Cmdbuf *cb; + int nf; + char *sp; + + nf = ncmdfield(p, n); + + /* allocate Cmdbuf plus string pointers plus copy of string including \0 */ + sp = emalloc9p(sizeof(*cb) + nf * sizeof(char*) + n + 1); + cb = (Cmdbuf*)sp; + cb->f = (char**)(&cb[1]); + cb->buf = (char*)(&cb->f[nf]); + + memmove(cb->buf, p, n); + + /* dump new line and null terminate */ + if(n > 0 && cb->buf[n-1] == '\n') + n--; + cb->buf[n] = '\0'; + + cb->nf = tokenize(cb->buf, cb->f, nf-1); + cb->f[cb->nf] = nil; + + return cb; +} + +/* + * Reconstruct original message, for error diagnostic + */ +void +respondcmderror(Req *r, Cmdbuf *cb, char *fmt, ...) +{ + int i; + va_list arg; + char *p, *e; + char err[ERRMAX]; + + e = err+ERRMAX-10; + va_start(arg, fmt); + p = vseprint(err, e, fmt, arg); + va_end(arg); + p = seprint(p, e, ": \""); + for(i=0; inf; i++){ + if(i > 0) + p = seprint(p, e, " "); + p = seprint(p, e, "%q", cb->f[i]); + } + strcpy(p, "\""); + respond(r, err); +} + +/* + * Look up entry in table + */ +Cmdtab* +lookupcmd(Cmdbuf *cb, Cmdtab *ctab, int nctab) +{ + int i; + Cmdtab *ct; + + if(cb->nf == 0){ + werrstr("empty control message"); + return nil; + } + + for(ct = ctab, i=0; icmd, "*") !=0) /* wildcard always matches */ + if(strcmp(ct->cmd, cb->f[0]) != 0) + continue; + if(ct->narg != 0 && ct->narg != cb->nf){ + werrstr("bad # args to command"); + return nil; + } + return ct; + } + + werrstr("unknown control message"); + return nil; +} diff --git a/src/lib9p/post.c b/src/lib9p/post.c new file mode 100644 index 00000000..09296a88 --- /dev/null +++ b/src/lib9p/post.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#include <9p.h> +#include "post.h" + +void +postmountsrv(Srv *s, char *name, char *mtpt, int flag) +{ + Postcrud *p; + + p = _post1(s, name, mtpt, flag); + switch(rfork(RFPROC|RFNOTEG|RFNAMEG|RFMEM)){ + case -1: + sysfatal("rfork: %r"); + case 0: + _post2(s); + exits(nil); + default: + _post3(p); + } +} + diff --git a/src/lib9p/post.h b/src/lib9p/post.h new file mode 100644 index 00000000..069a7ce7 --- /dev/null +++ b/src/lib9p/post.h @@ -0,0 +1,13 @@ +typedef struct Postcrud Postcrud; +struct Postcrud +{ + int fd[2]; + Srv *s; + char *name; + char *mtpt; + int flag; +}; + +Postcrud *_post1(Srv*, char*, char*, int); +void _post2(void*); +void _post3(Postcrud*); diff --git a/src/lib9p/ramfs.c b/src/lib9p/ramfs.c new file mode 100644 index 00000000..a2f0b3d7 --- /dev/null +++ b/src/lib9p/ramfs.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include <9p.h> + +static char Ebad[] = "something bad happened"; +static char Enomem[] = "no memory"; + +typedef struct Ramfile Ramfile; +struct Ramfile { + char *data; + int ndata; +}; + +void +fsread(Req *r) +{ + Ramfile *rf; + vlong offset; + long count; + + rf = r->fid->file->aux; + offset = r->ifcall.offset; + count = r->ifcall.count; + +//print("read %ld %lld\n", *count, offset); + if(offset >= rf->ndata){ + r->ofcall.count = 0; + respond(r, nil); + return; + } + + if(offset+count >= rf->ndata) + count = rf->ndata - offset; + + memmove(r->ofcall.data, rf->data+offset, count); + r->ofcall.count = count; + respond(r, nil); +} + +void +fswrite(Req *r) +{ + void *v; + Ramfile *rf; + vlong offset; + long count; + + rf = r->fid->file->aux; + offset = r->ifcall.offset; + count = r->ifcall.count; + + if(offset+count >= rf->ndata){ + v = realloc(rf->data, offset+count); + if(v == nil){ + respond(r, Enomem); + return; + } + rf->data = v; + rf->ndata = offset+count; + r->fid->file->length = rf->ndata; + } + memmove(rf->data+offset, r->ifcall.data, count); + r->ofcall.count = count; + respond(r, nil); +} + +void +fscreate(Req *r) +{ + Ramfile *rf; + File *f; + + if(f = createfile(r->fid->file, r->ifcall.name, r->fid->uid, r->ifcall.perm, nil)){ + rf = emalloc9p(sizeof *rf); + f->aux = rf; + r->fid->file = f; + r->ofcall.qid = f->qid; + respond(r, nil); + return; + } + respond(r, Ebad); +} + +void +fsopen(Req *r) +{ + Ramfile *rf; + + rf = r->fid->file->aux; + + if(rf && (r->ifcall.mode&OTRUNC)){ + rf->ndata = 0; + r->fid->file->length = 0; + } + + respond(r, nil); +} + +void +fsdestroyfile(File *f) +{ + Ramfile *rf; + +//fprint(2, "clunk\n"); + rf = f->aux; + if(rf){ + free(rf->data); + free(rf); + } +} + +Srv fs = { + .open= fsopen, + .read= fsread, + .write= fswrite, + .create= fscreate, +}; + +void +usage(void) +{ + fprint(2, "usage: ramfs [-D] [-s srvname] [-m mtpt]\n"); + exits("usage"); +} + +void +main(int argc, char **argv) +{ + char *srvname = nil; + char *mtpt = nil; + Qid q; + + fs.tree = alloctree(nil, nil, DMDIR|0777, fsdestroyfile); + q = fs.tree->root->qid; + + ARGBEGIN{ + case 'D': + chatty9p++; + break; + case 's': + srvname = EARGF(usage()); + break; + case 'm': + mtpt = EARGF(usage()); + break; + default: + usage(); + }ARGEND; + + if(argc) + usage(); + + if(chatty9p) + fprint(2, "ramsrv.nopipe %d srvname %s mtpt %s\n", fs.nopipe, srvname, mtpt); + if(srvname == nil && mtpt == nil) + sysfatal("you should at least specify a -s or -m option"); + + postmountsrv(&fs, srvname, mtpt, MREPL|MCREATE); + exits(0); +} diff --git a/src/lib9p/req.c b/src/lib9p/req.c new file mode 100644 index 00000000..8e1aaab5 --- /dev/null +++ b/src/lib9p/req.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include +#include <9p.h> + +static void +increqref(void *v) +{ + Req *r; + + r = v; + if(r){ +if(chatty9p > 1) + fprint(2, "increfreq %p %ld\n", r, r->ref.ref); + incref(&r->ref); + } +} + +Reqpool* +allocreqpool(void (*destroy)(Req*)) +{ + Reqpool *f; + + f = emalloc9p(sizeof *f); + f->map = allocmap(increqref); + f->destroy = destroy; + return f; +} + +void +freereqpool(Reqpool *p) +{ + freemap(p->map, (void(*)(void*))p->destroy); + free(p); +} + +Req* +allocreq(Reqpool *pool, ulong tag) +{ + Req *r; + + r = emalloc9p(sizeof *r); + r->tag = tag; + r->pool = pool; + + increqref(r); + increqref(r); + if(caninsertkey(pool->map, tag, r) == 0){ + closereq(r); + return nil; + } + + return r; +} + +Req* +lookupreq(Reqpool *pool, ulong tag) +{ +if(chatty9p > 1) + fprint(2, "lookupreq %lud\n", tag); + return lookupkey(pool->map, tag); +} + +void +closereq(Req *r) +{ + int i; + + if(r == nil) + return; + +if(chatty9p > 1) + fprint(2, "closereq %p %ld\n", r, r->ref.ref); + + if(decref(&r->ref) == 0){ + if(r->fid) + closefid(r->fid); + if(r->newfid) + closefid(r->newfid); + if(r->afid) + closefid(r->afid); + if(r->oldreq) + closereq(r->oldreq); + for(i=0; inflush; i++) + respond(r->flush[i], nil); + free(r->flush); + switch(r->ifcall.type){ + case Tstat: + free(r->ofcall.stat); + free(r->d.name); + free(r->d.uid); + free(r->d.gid); + free(r->d.muid); + break; + } + if(r->pool->destroy) + r->pool->destroy(r); + free(r->buf); + free(r->rbuf); + free(r); + } +} + +Req* +removereq(Reqpool *pool, ulong tag) +{ +if(chatty9p > 1) + fprint(2, "removereq %lud\n", tag); + return deletekey(pool->map, tag); +} diff --git a/src/lib9p/srv.c b/src/lib9p/srv.c new file mode 100644 index 00000000..c5262f4c --- /dev/null +++ b/src/lib9p/srv.c @@ -0,0 +1,837 @@ +#include +#include +#include +#include +#include +#include <9p.h> + +// static char Ebadattach[] = "unknown specifier in attach"; +static char Ebadoffset[] = "bad offset"; +// static char Ebadcount[] = "bad count"; +static char Ebotch[] = "9P protocol botch"; +static char Ecreatenondir[] = "create in non-directory"; +static char Edupfid[] = "duplicate fid"; +static char Eduptag[] = "duplicate tag"; +static char Eisdir[] = "is a directory"; +static char Enocreate[] = "create prohibited"; +// static char Enomem[] = "out of memory"; +static char Enoremove[] = "remove prohibited"; +static char Enostat[] = "stat prohibited"; +static char Enotfound[] = "file not found"; +// static char Enowrite[] = "write prohibited"; +static char Enowstat[] = "wstat prohibited"; +static char Eperm[] = "permission denied"; +static char Eunknownfid[] = "unknown fid"; +static char Ebaddir[] = "bad directory in wstat"; +static char Ewalknodir[] = "walk in non-directory"; + +static void +setfcallerror(Fcall *f, char *err) +{ + f->ename = err; + f->type = Rerror; +} + +static void +changemsize(Srv *srv, int msize) +{ + if(srv->rbuf && srv->wbuf && srv->msize == msize) + return; + qlock(&srv->rlock); + qlock(&srv->wlock); + srv->msize = msize; + free(srv->rbuf); + free(srv->wbuf); + srv->rbuf = emalloc9p(msize); + srv->wbuf = emalloc9p(msize); + qunlock(&srv->rlock); + qunlock(&srv->wlock); +} + +static Req* +getreq(Srv *s) +{ + long n; + uchar *buf; + Fcall f; + Req *r; + + qlock(&s->rlock); + if((n = read9pmsg(s->infd, s->rbuf, s->msize)) <= 0){ + qunlock(&s->rlock); + return nil; + } + + buf = emalloc9p(n); + memmove(buf, s->rbuf, n); + qunlock(&s->rlock); + + if(convM2S(buf, n, &f) != n){ + free(buf); + return nil; + } + + if((r=allocreq(s->rpool, f.tag)) == nil){ /* duplicate tag: cons up a fake Req */ + r = emalloc9p(sizeof *r); + incref(&r->ref); + r->tag = f.tag; + r->ifcall = f; + r->error = Eduptag; + r->buf = buf; + r->responded = 0; + r->type = 0; + r->srv = s; + r->pool = nil; +if(chatty9p) + fprint(2, "<-%d- %F: dup tag\n", s->infd, &f); + return r; + } + + r->srv = s; + r->responded = 0; + r->buf = buf; + r->ifcall = f; + memset(&r->ofcall, 0, sizeof r->ofcall); + r->type = r->ifcall.type; + +if(chatty9p) + if(r->error) + fprint(2, "<-%d- %F: %s\n", s->infd, &r->ifcall, r->error); + else + fprint(2, "<-%d- %F\n", s->infd, &r->ifcall); + + return r; +} + +static void +filewalk(Req *r) +{ + int i; + File *f; + + f = r->fid->file; + assert(f != nil); + + incref(&f->ref); + for(i=0; iifcall.nwname; i++) + if(f = walkfile(f, r->ifcall.wname[i])) + r->ofcall.wqid[i] = f->dir.qid; + else + break; + + r->ofcall.nwqid = i; + if(f){ + r->newfid->file = f; + r->newfid->qid = r->newfid->file->dir.qid; + } + respond(r, nil); +} + +void +walkandclone(Req *r, char *(*walk1)(Fid*, char*, void*), char *(*clone)(Fid*, Fid*, void*), void *arg) +{ + int i; + char *e; + + if(r->fid == r->newfid && r->ifcall.nwname > 1){ + respond(r, "lib9p: unused documented feature not implemented"); + return; + } + + if(r->fid != r->newfid){ + r->newfid->qid = r->fid->qid; + if(clone && (e = clone(r->fid, r->newfid, arg))){ + respond(r, e); + return; + } + } + + e = nil; + for(i=0; iifcall.nwname; i++){ + if(e = walk1(r->newfid, r->ifcall.wname[i], arg)) + break; + r->ofcall.wqid[i] = r->newfid->qid; + } + + r->ofcall.nwqid = i; + if(e && i==0) + respond(r, e); + else + respond(r, nil); +} + +static void +sversion(Srv *srv, Req *r) +{ + USED(srv); + + if(strncmp(r->ifcall.version, "9P", 2) != 0){ + r->ofcall.version = "unknown"; + respond(r, nil); + return; + } + + r->ofcall.version = "9P2000"; + r->ofcall.msize = r->ifcall.msize; + respond(r, nil); +} +static void +rversion(Req *r, char *error) +{ + assert(error == nil); + changemsize(r->srv, r->ofcall.msize); +} + +static void +sauth(Srv *srv, Req *r) +{ + char e[ERRMAX]; + + if((r->afid = allocfid(srv->fpool, r->ifcall.afid)) == nil){ + respond(r, Edupfid); + return; + } + if(srv->auth) + srv->auth(r); + else{ + snprint(e, sizeof e, "%s: authentication not required", argv0); + respond(r, e); + } +} +static void +rauth(Req *r, char *error) +{ + if(error && r->afid) + closefid(removefid(r->srv->fpool, r->afid->fid)); +} + +static void +sattach(Srv *srv, Req *r) +{ + if((r->fid = allocfid(srv->fpool, r->ifcall.fid)) == nil){ + respond(r, Edupfid); + return; + } + r->afid = nil; + if(r->ifcall.afid != NOFID && (r->afid = lookupfid(srv->fpool, r->ifcall.afid)) == nil){ + respond(r, Eunknownfid); + return; + } + r->fid->uid = estrdup9p(r->ifcall.uname); + if(srv->tree){ + r->fid->file = srv->tree->root; + /* BUG? incref(r->fid->file) ??? */ + r->ofcall.qid = r->fid->file->dir.qid; + r->fid->qid = r->ofcall.qid; + } + if(srv->attach) + srv->attach(r); + else + respond(r, nil); + return; +} +static void +rattach(Req *r, char *error) +{ + if(error && r->fid) + closefid(removefid(r->srv->fpool, r->fid->fid)); +} + +static void +sflush(Srv *srv, Req *r) +{ + r->oldreq = lookupreq(srv->rpool, r->ifcall.oldtag); + if(r->oldreq == nil || r->oldreq == r) + respond(r, nil); + else if(srv->flush) + srv->flush(r); + else + respond(r, nil); +} +static int +rflush(Req *r, char *error) +{ + Req *or; + + assert(error == nil); + or = r->oldreq; + if(or){ + qlock(&or->lk); + if(or->responded == 0){ + or->flush = erealloc9p(or->flush, (or->nflush+1)*sizeof(or->flush[0])); + or->flush[or->nflush++] = r; + qunlock(&or->lk); + return -1; /* delay response until or is responded */ + } + qunlock(&or->lk); + closereq(or); + } + r->oldreq = nil; + return 0; +} + +static char* +oldwalk1(Fid *fid, char *name, void *arg) +{ + char *e; + Qid qid; + Srv *srv; + + srv = arg; + e = srv->walk1(fid, name, &qid); + if(e) + return e; + fid->qid = qid; + return nil; +} + +static char* +oldclone(Fid *fid, Fid *newfid, void *arg) +{ + Srv *srv; + + srv = arg; + if(srv->clone == nil) + return nil; + return srv->clone(fid, newfid); +} + +static void +swalk(Srv *srv, Req *r) +{ + if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ + respond(r, Eunknownfid); + return; + } + if(r->fid->omode != -1){ + respond(r, "cannot clone open fid"); + return; + } + if(r->ifcall.nwname && !(r->fid->qid.type&QTDIR)){ + respond(r, Ewalknodir); + return; + } + if(r->ifcall.fid != r->ifcall.newfid){ + if((r->newfid = allocfid(srv->fpool, r->ifcall.newfid)) == nil){ + respond(r, Edupfid); + return; + } + r->newfid->uid = estrdup9p(r->fid->uid); + }else{ + incref(&r->fid->ref); + r->newfid = r->fid; + } + if(r->fid->file){ + filewalk(r); + }else if(srv->walk1) + walkandclone(r, oldwalk1, oldclone, srv); + else if(srv->walk) + srv->walk(r); + else + sysfatal("no walk function, no file trees"); +} +static void +rwalk(Req *r, char *error) +{ + if(error || r->ofcall.nwqid < r->ifcall.nwname){ + if(r->ifcall.fid != r->ifcall.newfid && r->newfid) + closefid(removefid(r->srv->fpool, r->newfid->fid)); + if (r->ofcall.nwqid==0){ + if(error==nil && r->ifcall.nwname!=0) + r->error = Enotfound; + }else + r->error = nil; // No error on partial walks + }else{ + if(r->ofcall.nwqid == 0){ + /* Just a clone */ + r->newfid->qid = r->fid->qid; + }else{ + /* if file trees are in use, filewalk took care of the rest */ + r->newfid->qid = r->ofcall.wqid[r->ofcall.nwqid-1]; + } + } +} + +static void +sopen(Srv *srv, Req *r) +{ + int p; + + if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ + respond(r, Eunknownfid); + return; + } + if(r->fid->omode != -1){ + respond(r, Ebotch); + return; + } + if((r->fid->qid.type&QTDIR) && (r->ifcall.mode&~ORCLOSE) != OREAD){ + respond(r, Eisdir); + return; + } + r->ofcall.qid = r->fid->qid; + switch(r->ifcall.mode&3){ + default: + assert(0); + case OREAD: + p = AREAD; + break; + case OWRITE: + p = AWRITE; + break; + case ORDWR: + p = AREAD|AWRITE; + break; + case OEXEC: + p = AEXEC; + break; + } + if(r->ifcall.mode&OTRUNC) + p |= AWRITE; + if((r->fid->qid.type&QTDIR) && p!=AREAD){ + respond(r, Eperm); + return; + } + if(r->fid->file){ + if(!hasperm(r->fid->file, r->fid->uid, p)){ + respond(r, Eperm); + return; + } + /* BUG RACE */ + if((r->ifcall.mode&ORCLOSE) + && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){ + respond(r, Eperm); + return; + } + r->ofcall.qid = r->fid->file->dir.qid; + if((r->ofcall.qid.type&QTDIR) + && (r->fid->rdir = opendirfile(r->fid->file)) == nil){ + respond(r, "opendirfile failed"); + return; + } + } + if(srv->open) + srv->open(r); + else + respond(r, nil); +} +static void +ropen(Req *r, char *error) +{ + char errbuf[ERRMAX]; + if(error) + return; + if(chatty9p){ + snprint(errbuf, sizeof errbuf, "fid mode is 0x%ux\n", r->ifcall.mode); + write(2, errbuf, strlen(errbuf)); + } + r->fid->omode = r->ifcall.mode; + r->fid->qid = r->ofcall.qid; + if(r->ofcall.qid.type&QTDIR) + r->fid->diroffset = 0; +} + +static void +screate(Srv *srv, Req *r) +{ + if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil) + respond(r, Eunknownfid); + else if(r->fid->omode != -1) + respond(r, Ebotch); + else if(!(r->fid->qid.type&QTDIR)) + respond(r, Ecreatenondir); + else if(r->fid->file && !hasperm(r->fid->file, r->fid->uid, AWRITE)) + respond(r, Eperm); + else if(srv->create) + srv->create(r); + else + respond(r, Enocreate); +} +static void +rcreate(Req *r, char *error) +{ + if(error) + return; + r->fid->omode = r->ifcall.mode; + r->fid->qid = r->ofcall.qid; +} + +static void +sread(Srv *srv, Req *r) +{ + int o; + + if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ + respond(r, Eunknownfid); + return; + } + if(r->ifcall.count < 0){ + respond(r, Ebotch); + return; + } + if(r->ifcall.offset < 0 + || ((r->fid->qid.type&QTDIR) && r->ifcall.offset != 0 && r->ifcall.offset != r->fid->diroffset)){ + respond(r, Ebadoffset); + return; + } + + if(r->ifcall.count > srv->msize - IOHDRSZ) + r->ifcall.count = srv->msize - IOHDRSZ; + r->rbuf = emalloc9p(r->ifcall.count); + r->ofcall.data = r->rbuf; + o = r->fid->omode & 3; + if(o != OREAD && o != ORDWR && o != OEXEC){ + respond(r, Ebotch); + return; + } + if((r->fid->qid.type&QTDIR) && r->fid->file){ + r->ofcall.count = readdirfile(r->fid->rdir, r->rbuf, r->ifcall.count); + respond(r, nil); + return; + } + if(srv->read) + srv->read(r); + else + respond(r, "no srv->read"); +} +static void +rread(Req *r, char *error) +{ + if(error==nil && (r->fid->qid.type&QTDIR)) + r->fid->diroffset += r->ofcall.count; +} + +static void +swrite(Srv *srv, Req *r) +{ + int o; + char e[ERRMAX]; + + if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ + respond(r, Eunknownfid); + return; + } + if(r->ifcall.count < 0){ + respond(r, Ebotch); + return; + } + if(r->ifcall.offset < 0){ + respond(r, Ebotch); + return; + } + if(r->ifcall.count > srv->msize - IOHDRSZ) + r->ifcall.count = srv->msize - IOHDRSZ; + o = r->fid->omode & 3; + if(o != OWRITE && o != ORDWR){ + snprint(e, sizeof e, "write on fid with open mode 0x%ux", r->fid->omode); + respond(r, e); + return; + } + if(srv->write) + srv->write(r); + else + respond(r, "no srv->write"); +} +static void +rwrite(Req *r, char *error) +{ + if(error) + return; + if(r->fid->file) + r->fid->file->dir.qid.vers++; +} + +static void +sclunk(Srv *srv, Req *r) +{ + if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil) + respond(r, Eunknownfid); + else + respond(r, nil); +} +static void +rclunk(Req *r, char *msg) +{ + USED(r); + USED(msg); +} + +static void +sremove(Srv *srv, Req *r) +{ + if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil){ + respond(r, Eunknownfid); + return; + } + /* BUG RACE */ + if(r->fid->file && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){ + respond(r, Eperm); + return; + } + if(srv->remove) + srv->remove(r); + else + respond(r, r->fid->file ? nil : Enoremove); +} +static void +rremove(Req *r, char *error, char *errbuf) +{ + if(error) + return; + if(r->fid->file){ + if(removefile(r->fid->file) < 0){ + snprint(errbuf, ERRMAX, "remove %s: %r", + r->fid->file->dir.name); + r->error = errbuf; + } + r->fid->file = nil; + } +} + +static void +sstat(Srv *srv, Req *r) +{ + if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ + respond(r, Eunknownfid); + return; + } + if(r->fid->file){ + r->d = r->fid->file->dir; + if(r->d.name) + r->d.name = estrdup9p(r->d.name); + if(r->d.uid) + r->d.uid = estrdup9p(r->d.uid); + if(r->d.gid) + r->d.gid = estrdup9p(r->d.gid); + if(r->d.muid) + r->d.muid = estrdup9p(r->d.muid); + } + if(srv->stat) + srv->stat(r); + else if(r->fid->file) + respond(r, nil); + else + respond(r, Enostat); +} +static void +rstat(Req *r, char *error) +{ + int n; + uchar *statbuf; + uchar tmp[BIT16SZ]; + + if(error) + return; + if(convD2M(&r->d, tmp, BIT16SZ) != BIT16SZ){ + r->error = "convD2M(_,_,BIT16SZ) did not return BIT16SZ"; + return; + } + n = GBIT16(tmp)+BIT16SZ; + statbuf = emalloc9p(n); + if(statbuf == nil){ + r->error = "out of memory"; + return; + } + r->ofcall.nstat = convD2M(&r->d, statbuf, n); + r->ofcall.stat = statbuf; /* freed in closereq */ + if(r->ofcall.nstat <= BIT16SZ){ + r->error = "convD2M fails"; + free(statbuf); + return; + } +} + +static void +swstat(Srv *srv, Req *r) +{ + if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ + respond(r, Eunknownfid); + return; + } + if(srv->wstat == nil){ + respond(r, Enowstat); + return; + } + if(convM2D(r->ifcall.stat, r->ifcall.nstat, &r->d, (char*)r->ifcall.stat) != r->ifcall.nstat){ + respond(r, Ebaddir); + return; + } + if((ushort)~r->d.type){ + respond(r, "wstat -- attempt to change type"); + return; + } + if((uint)~r->d.dev){ + respond(r, "wstat -- attempt to change dev"); + return; + } + if((uchar)~r->d.qid.type || (ulong)~r->d.qid.vers || (uvlong)~r->d.qid.path){ + respond(r, "wstat -- attempt to change qid"); + return; + } + if(r->d.muid && r->d.muid[0]){ + respond(r, "wstat -- attempt to change muid"); + return; + } + if((ulong)~r->d.mode && ((r->d.mode&DMDIR)>>24) != (r->fid->qid.type&QTDIR)){ + respond(r, "wstat -- attempt to change DMDIR bit"); + return; + } + srv->wstat(r); +} +static void +rwstat(Req *r, char *msg) +{ + USED(r); + USED(msg); +} + +void +srv(Srv *srv) +{ + Req *r; + + fmtinstall('D', dirfmt); + fmtinstall('F', fcallfmt); + + if(srv->fpool == nil) + srv->fpool = allocfidpool(srv->destroyfid); + if(srv->rpool == nil) + srv->rpool = allocreqpool(srv->destroyreq); + if(srv->msize == 0) + srv->msize = 8192+IOHDRSZ; + + changemsize(srv, srv->msize); + + srv->fpool->srv = srv; + srv->rpool->srv = srv; + + while(r = getreq(srv)){ + if(r->error){ + respond(r, r->error); + continue; + } + switch(r->ifcall.type){ + default: + respond(r, "unknown message"); + break; + case Tversion: sversion(srv, r); break; + case Tauth: sauth(srv, r); break; + case Tattach: sattach(srv, r); break; + case Tflush: sflush(srv, r); break; + case Twalk: swalk(srv, r); break; + case Topen: sopen(srv, r); break; + case Tcreate: screate(srv, r); break; + case Tread: sread(srv, r); break; + case Twrite: swrite(srv, r); break; + case Tclunk: sclunk(srv, r); break; + case Tremove: sremove(srv, r); break; + case Tstat: sstat(srv, r); break; + case Twstat: swstat(srv, r); break; + } + } + + if(srv->end) + srv->end(srv); +} + +void +respond(Req *r, char *error) +{ + int i, m, n; + char errbuf[ERRMAX]; + Srv *srv; + + srv = r->srv; + assert(srv != nil); + + assert(r->responded == 0); + r->error = error; + + switch(r->ifcall.type){ + default: + assert(0); + /* + * Flush is special. If the handler says so, we return + * without further processing. Respond will be called + * again once it is safe. + */ + case Tflush: + if(rflush(r, error)<0) + return; + break; + case Tversion: rversion(r, error); break; + case Tauth: rauth(r, error); break; + case Tattach: rattach(r, error); break; + case Twalk: rwalk(r, error); break; + case Topen: ropen(r, error); break; + case Tcreate: rcreate(r, error); break; + case Tread: rread(r, error); break; + case Twrite: rwrite(r, error); break; + case Tclunk: rclunk(r, error); break; + case Tremove: rremove(r, error, errbuf); break; + case Tstat: rstat(r, error); break; + case Twstat: rwstat(r, error); break; + } + + r->ofcall.tag = r->ifcall.tag; + r->ofcall.type = r->ifcall.type+1; + if(r->error) + setfcallerror(&r->ofcall, r->error); + +if(chatty9p) + fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall); + + qlock(&srv->wlock); + n = convS2M(&r->ofcall, srv->wbuf, srv->msize); + if(n <= 0){ + fprint(2, "n = %d %F\n", n, &r->ofcall); + abort(); + } + assert(n > 2); + if(r->pool) /* not a fake */ + closereq(removereq(r->pool, r->ifcall.tag)); + m = write(srv->outfd, srv->wbuf, n); + if(m != n) + sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd); + qunlock(&srv->wlock); + + qlock(&r->lk); /* no one will add flushes now */ + r->responded = 1; + qunlock(&r->lk); + + for(i=0; inflush; i++) + respond(r->flush[i], nil); + free(r->flush); + + if(r->pool) + closereq(r); + else + free(r); +} + +int +postfd(char *name, int pfd) +{ + int fd; + char buf[80]; + + snprint(buf, sizeof buf, "/srv/%s", name); + if(chatty9p) + fprint(2, "postfd %s\n", buf); + fd = create(buf, OWRITE|ORCLOSE|OCEXEC, 0600); + if(fd < 0){ + if(chatty9p) + fprint(2, "create fails: %r\n"); + return -1; + } + if(fprint(fd, "%d", pfd) < 0){ + if(chatty9p) + fprint(2, "write fails: %r\n"); + close(fd); + return -1; + } + if(chatty9p) + fprint(2, "postfd successful\n"); + return 0; +} + diff --git a/src/lib9p/tpost.c b/src/lib9p/tpost.c new file mode 100644 index 00000000..68da19a7 --- /dev/null +++ b/src/lib9p/tpost.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include <9p.h> +#include "post.h" + +void +threadpostmountsrv(Srv *s, char *name, char *mtpt, int flag) +{ + Postcrud *p; + + p = _post1(s, name, mtpt, flag); + if(procrfork(_post2, s, 32*1024, RFNAMEG|RFNOTEG) < 0) + sysfatal("procrfork: %r"); + _post3(p); +} + diff --git a/src/lib9p/uid.c b/src/lib9p/uid.c new file mode 100644 index 00000000..84b98bde --- /dev/null +++ b/src/lib9p/uid.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include <9p.h> + +/* + * simplistic permission checking. assume that + * each user is the leader of her own group. + */ +int +hasperm(File *f, char *uid, int p) +{ + int m; + + m = f->dir.mode & 7; /* other */ + if((p & m) == p) + return 1; + + if(strcmp(f->dir.uid, uid) == 0) { + m |= (f->dir.mode>>6) & 7; + if((p & m) == p) + return 1; + } + + if(strcmp(f->dir.gid, uid) == 0) { + m |= (f->dir.mode>>3) & 7; + if((p & m) == p) + return 1; + } + + return 0; +} diff --git a/src/lib9p/util.c b/src/lib9p/util.c new file mode 100644 index 00000000..17588a95 --- /dev/null +++ b/src/lib9p/util.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include +#include "9p.h" + +void +readbuf(Req *r, void *s, long n) +{ + r->ofcall.count = r->ifcall.count; + if(r->ifcall.offset >= n){ + r->ofcall.count = 0; + return; + } + if(r->ifcall.offset+r->ofcall.count > n) + r->ofcall.count = n - r->ifcall.offset; + memmove(r->ofcall.data, (char*)s+r->ifcall.offset, r->ofcall.count); +} + +void +readstr(Req *r, char *s) +{ + readbuf(r, s, strlen(s)); +} -- cgit v1.2.3