123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829 |
- #include "dat.h"
- #include "fns.h"
- #include "error.h"
- #include "interp.h"
- #include <isa.h>
- #include "runt.h"
- typedef struct SrvFile SrvFile;
- typedef struct Pending Pending;
- /* request pending to a server, in case a server vanishes */
- struct Pending
- {
- Pending* next;
- Pending* prev;
- int fid;
- Channel* rc;
- Channel* wc;
- };
- struct SrvFile
- {
- char* name;
- char* user;
- ulong perm;
- Qid qid;
- int ref;
- /* root directory */
- char* spec;
- SrvFile* devlist;
- SrvFile* entry;
- /* file */
- int opens;
- int flags;
- vlong length;
- Channel* read;
- Channel* write;
- SrvFile* dir; /* parent directory */
- Pending waitlist; /* pending requests from client opens */
- };
- enum
- {
- SORCLOSE = (1<<0),
- SRDCLOSE = (1<<1),
- SWRCLOSE = (1<<2),
- SREMOVED = (1<<3),
- };
- typedef struct SrvDev SrvDev;
- struct SrvDev
- {
- Type* Rread;
- Type* Rwrite;
- QLock l;
- ulong pathgen;
- SrvFile* devices;
- };
- static SrvDev dev;
- void freechan(Heap*, int);
- static void freerdchan(Heap*, int);
- static void freewrchan(Heap*, int);
- static void delwaiting(Pending*);
- Type *Trdchan;
- Type *Twrchan;
- static int
- srvgen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp)
- {
- SrvFile *f;
- USED(name);
- USED(tab);
- USED(ntab);
- if(s == DEVDOTDOT){
- devdir(c, c->qid, "#s", 0, eve, 0555, dp);
- return 1;
- }
- f = c->aux;
- if((c->qid.type & QTDIR) == 0){
- if(s > 0)
- return -1;
- devdir(c, f->qid, f->name, f->length, f->user, f->perm, dp);
- return 1;
- }
- for(f = f->entry; f != nil; f = f->entry){
- if(s-- == 0)
- break;
- }
- if(f == nil)
- return -1;
- devdir(c, f->qid, f->name, f->length, f->user, f->perm, dp);
- return 1;
- }
- static void
- srvinit(void)
- {
- static uchar rmap[] = Sys_Rread_map;
- static uchar wmap[] = Sys_Rwrite_map;
- Trdchan = dtype(freerdchan, sizeof(Channel), Tchannel.map, Tchannel.np);
- Twrchan = dtype(freewrchan, sizeof(Channel), Tchannel.map, Tchannel.np);
- dev.pathgen = 1;
- dev.Rread = dtype(freeheap, Sys_Rread_size, rmap, sizeof(rmap));
- dev.Rwrite = dtype(freeheap, Sys_Rwrite_size, wmap, sizeof(wmap));
- }
- static int
- srvcanattach(SrvFile *d)
- {
- if(strcmp(d->user, up->env->user) == 0)
- return 1;
- /*
- * Need write permission in other to allow attaches if
- * we are not the owner
- */
- if(d->perm & 2)
- return 1;
- return 0;
- }
- static Chan*
- srvattach(char *spec)
- {
- Chan *c;
- SrvFile *d;
- char srvname[16];
- qlock(&dev.l);
- if(waserror()){
- qunlock(&dev.l);
- nexterror();
- }
- if(spec[0] != '\0'){
- for(d = dev.devices; d != nil; d = d->devlist){
- if(strcmp(spec, d->spec) == 0){
- if(!srvcanattach(d))
- error(Eperm);
- c = devattach('s', spec);
- c->aux = d;
- c->qid = d->qid;
- d->ref++;
- poperror();
- qunlock(&dev.l);
- return c;
- }
- }
- }
- d = malloc(sizeof(SrvFile));
- if(d == nil)
- error(Enomem);
- d->ref = 1;
- kstrdup(&d->spec, spec);
- kstrdup(&d->user, up->env->user);
- snprint(srvname, sizeof(srvname), "srv%ld", up->env->pgrp->pgrpid);
- kstrdup(&d->name, srvname);
- d->perm = DMDIR|0770;
- mkqid(&d->qid, dev.pathgen++, 0, QTDIR);
- d->devlist = dev.devices;
- dev.devices = d;
- poperror();
- qunlock(&dev.l);
- c = devattach('s', spec);
- c->aux = d;
- c->qid = d->qid;
- return c;
- }
- static Walkqid*
- srvwalk(Chan *c, Chan *nc, char **name, int nname)
- {
- SrvFile *d, *pd;
- Walkqid *w;
- pd = c->aux;
- qlock(&dev.l);
- if(waserror()){
- qunlock(&dev.l);
- nexterror();
- }
- w = devwalk(c, nc, name, nname, nil, 0, srvgen);
- if(w != nil && w->clone != nil){
- if(nname != 0){
- for(d = pd->entry; d != nil; d = d->entry)
- if(d->qid.path == w->clone->qid.path)
- break;
- if(d == nil)
- panic("srvwalk");
- if(w->clone == c)
- pd->ref--;
- }else
- d = pd;
- w->clone->aux = d;
- d->ref++;
- }
- poperror();
- qunlock(&dev.l);
- return w;
- }
- static int
- srvstat(Chan *c, uchar *db, int n)
- {
- qlock(&dev.l);
- if(waserror()){
- qunlock(&dev.l);
- nexterror();
- }
- n = devstat(c, db, n, 0, 0, srvgen);
- poperror();
- qunlock(&dev.l);
- return n;
- }
- static Chan*
- srvopen(Chan *c, int omode)
- {
- SrvFile *sf;
- openmode(omode); /* check it */
- if(c->qid.type & QTDIR){
- if(omode != OREAD)
- error(Eisdir);
- c->mode = omode;
- c->flag |= COPEN;
- c->offset = 0;
- return c;
- }
- sf = c->aux;
- qlock(&dev.l);
- if(waserror()){
- qunlock(&dev.l);
- nexterror();
- }
- devpermcheck(sf->user, sf->perm, omode);
- if(omode&ORCLOSE && strcmp(sf->user, up->env->user) != 0)
- error(Eperm);
- if(sf->perm & DMEXCL && sf->opens != 0)
- error(Einuse);
- sf->opens++;
- if(omode&ORCLOSE)
- sf->flags |= SORCLOSE;
- poperror();
- qunlock(&dev.l);
- c->offset = 0;
- c->flag |= COPEN;
- c->mode = openmode(omode);
- return c;
- }
- static int
- srvwstat(Chan *c, uchar *dp, int n)
- {
- Dir *d;
- SrvFile *sf, *f;
- sf = c->aux;
- if(strcmp(up->env->user, sf->user) != 0)
- error(Eperm);
- d = smalloc(sizeof(*d)+n);
- if(waserror()){
- free(d);
- nexterror();
- }
- n = convM2D(dp, n, d, (char*)&d[1]);
- if(n == 0)
- error(Eshortstat);
- if(!emptystr(d->name)){
- if(sf->dir == nil)
- error(Eperm);
- validwstatname(d->name);
- qlock(&dev.l);
- for(f = sf->dir; f != nil; f = f->entry)
- if(strcmp(f->name, d->name) == 0){
- qunlock(&dev.l);
- error(Eexist);
- }
- kstrdup(&sf->name, d->name);
- qunlock(&dev.l);
- }
- if(d->mode != ~0UL)
- sf->perm = d->mode & (DMEXCL|DMAPPEND|0777);
- if(d->length != (vlong)-1)
- sf->length = d->length;
- poperror();
- free(d);
- return n;
- }
- static void
- srvputdir(SrvFile *dir)
- {
- SrvFile **l, *d;
- dir->ref--;
- if(dir->ref != 0)
- return;
- for(l = &dev.devices; (d = *l) != nil; l = &d->devlist)
- if(d == dir){
- *l = d->devlist;
- break;
- }
- free(dir->spec);
- free(dir->user);
- free(dir->name);
- free(dir);
- }
- static void
- srvunblock(SrvFile *sf, int fid)
- {
- Channel *d;
- Sys_FileIO_read rreq;
- Sys_FileIO_write wreq;
- acquire();
- if(waserror()){
- release();
- nexterror();
- }
- d = sf->read;
- if(d != H){
- rreq.t0 = 0;
- rreq.t1 = 0;
- rreq.t2 = fid;
- rreq.t3 = H;
- csendalt(d, &rreq, d->mid.t, -1);
- }
- d = sf->write;
- if(d != H){
- wreq.t0 = 0;
- wreq.t1 = H;
- wreq.t2 = fid;
- wreq.t3 = H;
- csendalt(d, &wreq, d->mid.t, -1);
- }
- poperror();
- release();
- }
- static void
- srvcancelreqs(SrvFile *sf)
- {
- Pending *w, *ws;
- Sys_Rread rreply;
- Sys_Rwrite wreply;
- acquire();
- ws = &sf->waitlist;
- while((w = ws->next) != ws){
- delwaiting(w);
- if(waserror() == 0){
- if(w->rc != nil){
- rreply.t0 = H;
- rreply.t1 = c2string(Ehungup, strlen(Ehungup));
- csend(w->rc, &rreply);
- }
- if(w->wc != nil){
- wreply.t0 = 0;
- wreply.t1 = c2string(Ehungup, strlen(Ehungup));
- csend(w->wc, &wreply);
- }
- poperror();
- }
- }
- release();
- }
- static void
- srvdelete(SrvFile *sf)
- {
- SrvFile *f, **l;
- if((sf->flags & SREMOVED) == 0){
- for(l = &sf->dir->entry; (f = *l) != nil; l = &f->entry){
- if(sf == f){
- *l = f->entry;
- break;
- }
- }
- sf->ref--;
- sf->flags |= SREMOVED;
- }
- }
- static void
- srvchkref(SrvFile *sf)
- {
- if(sf->ref != 0)
- return;
- if(sf->dir != nil)
- srvputdir(sf->dir);
- free(sf->user);
- free(sf->name);
- free(sf);
- }
- static void
- srvfree(SrvFile *sf, int flag)
- {
- sf->flags |= flag;
- if((sf->flags & (SRDCLOSE | SWRCLOSE)) == (SRDCLOSE | SWRCLOSE)){
- sf->ref--;
- srvdelete(sf);
- /* no further requests can arrive; return error to pending requests */
- srvcancelreqs(sf);
- srvchkref(sf);
- }
- }
- static void
- freerdchan(Heap *h, int swept)
- {
- SrvFile *sf;
- release();
- qlock(&dev.l);
- sf = H2D(Channel*, h)->aux;
- sf->read = H;
- srvfree(sf, SRDCLOSE);
- qunlock(&dev.l);
- acquire();
- freechan(h, swept);
- }
- static void
- freewrchan(Heap *h, int swept)
- {
- SrvFile *sf;
- release();
- qlock(&dev.l);
- sf = H2D(Channel*, h)->aux;
- sf->write = H;
- srvfree(sf, SWRCLOSE);
- qunlock(&dev.l);
- acquire();
- freechan(h, swept);
- }
- static void
- srvclunk(Chan *c, int remove)
- {
- int opens, noperm;
- SrvFile *sf;
- sf = c->aux;
- qlock(&dev.l);
- if(c->qid.type & QTDIR){
- srvputdir(sf);
- qunlock(&dev.l);
- if(remove)
- error(Eperm);
- return;
- }
- opens = 0;
- if(c->flag & COPEN){
- opens = sf->opens--;
- if(sf->read != H || sf->write != H)
- srvunblock(sf, c->fid);
- }
- sf->ref--;
- if(opens == 1){
- if(sf->flags & SORCLOSE)
- remove = 1;
- }
- noperm = 0;
- if(remove && strcmp(sf->dir->user, up->env->user) != 0){
- noperm = 1;
- remove = 0;
- }
- if(remove)
- srvdelete(sf);
- srvchkref(sf);
- qunlock(&dev.l);
- if(noperm)
- error(Eperm);
- }
- static void
- srvclose(Chan *c)
- {
- srvclunk(c, 0);
- }
- static void
- srvremove(Chan *c)
- {
- srvclunk(c, 1);
- }
- static void
- addwaiting(SrvFile *sp, Pending *w)
- {
- Pending *sw;
- sw = &sp->waitlist;
- w->next = sw;
- w->prev = sw->prev;
- sw->prev->next = w;
- sw->prev = w;
- }
- static void
- delwaiting(Pending *w)
- {
- w->next->prev = w->prev;
- w->prev->next = w->next;
- }
- static long
- srvread(Chan *c, void *va, long count, vlong offset)
- {
- int l;
- Heap * volatile h;
- Array *a;
- SrvFile *sp;
- Channel *rc;
- Channel *rd;
- Pending wait;
- Sys_Rread * volatile r;
- Sys_FileIO_read req;
- if(c->qid.type & QTDIR){
- qlock(&dev.l);
- if(waserror()){
- qunlock(&dev.l);
- nexterror();
- }
- l = devdirread(c, va, count, 0, 0, srvgen);
- poperror();
- qunlock(&dev.l);
- return l;
- }
- sp = c->aux;
- acquire();
- if(waserror()){
- release();
- nexterror();
- }
- rd = sp->read;
- if(rd == H)
- error(Ehungup);
- rc = cnewc(dev.Rread, movtmp, 1);
- ptradd(D2H(rc));
- if(waserror()){
- ptrdel(D2H(rc));
- destroy(rc);
- nexterror();
- }
- req.t0 = offset;
- req.t1 = count;
- req.t2 = c->fid;
- req.t3 = rc;
- csend(rd, &req);
- h = heap(dev.Rread);
- r = H2D(Sys_Rread *, h);
- ptradd(h);
- if(waserror()){
- ptrdel(h);
- destroy(r);
- nexterror();
- }
- wait.fid = c->fid;
- wait.rc = rc;
- wait.wc = nil;
- addwaiting(sp, &wait);
- if(waserror()){
- delwaiting(&wait);
- nexterror();
- }
- crecv(rc, r);
- poperror();
- delwaiting(&wait);
- if(r->t1 != H)
- error(string2c(r->t1));
- a = r->t0;
- l = 0;
- if(a != H){
- l = a->len;
- if(l > count)
- l = count;
- memmove(va, a->data, l);
- }
- poperror();
- ptrdel(h);
- destroy(r);
- poperror();
- ptrdel(D2H(rc));
- destroy(rc);
- poperror();
- release();
- return l;
- }
- static long
- srvwrite(Chan *c, void *va, long count, vlong offset)
- {
- long l;
- Heap * volatile h;
- SrvFile *sp;
- Channel *wc;
- Channel *wr;
- Pending wait;
- Sys_Rwrite * volatile w;
- Sys_FileIO_write req;
- if(c->qid.type & QTDIR)
- error(Eperm);
- acquire();
- if(waserror()){
- release();
- nexterror();
- }
- sp = c->aux;
- wr = sp->write;
- if(wr == H)
- error(Ehungup);
- wc = cnewc(dev.Rwrite, movtmp, 1);
- ptradd(D2H(wc));
- if(waserror()){
- ptrdel(D2H(wc));
- destroy(wc);
- nexterror();
- }
- req.t0 = offset;
- req.t1 = mem2array(va, count);
- req.t2 = c->fid;
- req.t3 = wc;
- ptradd(D2H(req.t1));
- if(waserror()){
- ptrdel(D2H(req.t1));
- destroy(req.t1);
- nexterror();
- }
- csend(wr, &req);
- poperror();
- ptrdel(D2H(req.t1));
- destroy(req.t1);
- h = heap(dev.Rwrite);
- w = H2D(Sys_Rwrite *, h);
- ptradd(h);
- if(waserror()){
- ptrdel(h);
- destroy(w);
- nexterror();
- }
- wait.fid = c->fid;
- wait.rc = nil;
- wait.wc = wc;
- addwaiting(sp, &wait);
- if(waserror()){
- delwaiting(&wait);
- nexterror();
- }
- crecv(wc, w);
- poperror();
- delwaiting(&wait);
- if(w->t1 != H)
- error(string2c(w->t1));
- poperror();
- ptrdel(h);
- l = w->t0;
- destroy(w);
- poperror();
- ptrdel(D2H(wc));
- destroy(wc);
- poperror();
- release();
- if(l < 0)
- l = 0;
- return l;
- }
- static void
- srvretype(Channel *c, SrvFile *f, Type *t)
- {
- Heap *h;
- h = D2H(c);
- freetype(h->t);
- h->t = t;
- t->ref++;
- c->aux = f;
- }
- int
- srvf2c(char *dir, char *file, Sys_FileIO *io)
- {
- SrvFile *s, *f;
- volatile struct { Chan *c; } c;
- c.c = nil;
- if(waserror()){
- cclose(c.c);
- return -1;
- }
- if(strchr(file, '/') != nil || strlen(file) >= 64 || strcmp(file, ".") == 0 || strcmp(file, "..") == 0)
- error(Efilename);
- c.c = namec(dir, Aaccess, 0, 0);
- if((c.c->qid.type&QTDIR) == 0 || devtab[c.c->type]->dc != 's')
- error("directory not a srv device");
- s = c.c->aux;
- qlock(&dev.l);
- if(waserror()){
- qunlock(&dev.l);
- nexterror();
- }
- for(f = s->entry; f != nil; f = f->entry){
- if(strcmp(f->name, file) == 0)
- error(Eexist);
- }
- f = malloc(sizeof(SrvFile));
- if(f == nil)
- error(Enomem);
- srvretype(io->read, f, Trdchan);
- srvretype(io->write, f, Twrchan);
- f->read = io->read;
- f->write = io->write;
-
- f->waitlist.next = &f->waitlist;
- f->waitlist.prev = &f->waitlist;
- kstrdup(&f->name, file);
- kstrdup(&f->user, up->env->user);
- f->perm = 0666 & (~0666 | (s->perm & 0666));
- f->length = 0;
- f->ref = 2;
- mkqid(&f->qid, dev.pathgen++, 0, QTFILE);
- f->entry = s->entry;
- s->entry = f;
- s->ref++;
- f->dir = s;
- poperror();
- qunlock(&dev.l);
- cclose(c.c);
- poperror();
- return 0;
- }
- Dev srvdevtab = {
- 's',
- "srv",
- srvinit,
- srvattach,
- srvwalk,
- srvstat,
- srvopen,
- devcreate,
- srvclose,
- srvread,
- devbread,
- srvwrite,
- devbwrite,
- srvremove,
- srvwstat
- };
|