#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/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 intsrvgen(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 voidsrvinit(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 intsrvcanattach(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 intsrvstat(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 intsrvwstat(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 voidsrvputdir(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 voidsrvunblock(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 voidsrvcancelreqs(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 voidsrvdelete(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 voidsrvchkref(SrvFile *sf){ if(sf->ref != 0) return; if(sf->dir != nil) srvputdir(sf->dir); free(sf->user); free(sf->name); free(sf);} static voidsrvfree(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 voidfreerdchan(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 voidfreewrchan(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 voidsrvclunk(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)Lines 1–500 of 834. Load more
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/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)