ref: 8784d2d0ea623b3a6ea77ffb3559b2a6985ee5a5
parent: 4636a1e21adfe395c2afdce2145da497b913d1d3
author: aiju <[email protected]>
date: Sun Jul 24 18:12:01 EDT 2011
added devshr
--- /dev/null
+++ b/sys/src/9/port/devshr.c
@@ -1,0 +1,597 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+typedef struct Shr Shr;
+
+struct Shr
+{
+ Ref;
+ char *name;
+ char *owner;
+ ulong perm;
+ Shr *link;
+ ulong path;
+ Mhead umh; /* only lock and mount are used */
+ char *desc; /* contents of file; nil if invalid, rebuild if necessary */
+ QLock desclock;
+};
+
+static QLock shrlk;
+static Shr *shr;
+static int qidpath;
+static int mntid;
+
+static void
+shrdecref(Shr *sp)
+{
+ Mount *m, *mm;
+
+ if(decref(sp) != 0)
+ return;
+
+ for(m = sp->umh.mount; m != nil; m = mm) {
+ cclose(m->to);
+ mm = m->next;
+ free(m);
+ }
+ free(sp->owner);
+ free(sp->name);
+ free(sp);
+}
+
+static int
+shrgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
+{
+ Shr *sp;
+ Qid q;
+
+ if(s == DEVDOTDOT){
+ devdir(c, c->qid, "#σ", 0, eve, 0555, dp);
+ return 1;
+ }
+
+ qlock(&shrlk);
+ for(sp = shr; sp && s; sp = sp->link)
+ s--;
+
+ if(sp == 0) {
+ qunlock(&shrlk);
+ return -1;
+ }
+
+ mkqid(&q, sp->path, 0, c->dev ? QTFILE : QTDIR);
+ /* make sure name string continues to exist after we release lock */
+ kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
+ devdir(c, q, up->genbuf, 0, sp->owner, sp->perm & (c->dev ? ~0111 : ~0), dp);
+ qunlock(&shrlk);
+ return 1;
+}
+
+static void
+shrinit(void)
+{
+ qidpath = 1;
+}
+
+static Chan*
+shrattach(char *spec)
+{
+ Chan *c;
+
+ if(!(spec[0] == 'c' && spec[1] == 0 || spec[0] == 0))
+ error(Enoattach);
+
+ c = devattach(L'σ', spec);
+ if(spec[0] == 'c')
+ c->dev = 1;
+ else
+ c->dev = 0;
+ return c;
+}
+
+static Shr*
+shrlookup(char *name, ulong qidpath)
+{
+ Shr *sp;
+ for(sp = shr; sp; sp = sp->link)
+ if(sp->path == qidpath || (name && strcmp(sp->name, name) == 0))
+ return sp;
+ return nil;
+}
+
+static Walkqid*
+shrwalk(Chan *c, Chan *nc, char **name, int nname)
+{
+ Walkqid *wq, *wq2;
+ Shr *sp;
+ int alloc, j;
+ char *n;
+ Mount *f;
+
+ if(nname > 0)
+ isdir(c);
+
+ alloc = 0;
+ wq = smalloc(sizeof(Walkqid) + (nname - 1) * sizeof(Qid));
+ if(waserror()){
+ if(alloc && wq->clone != nil)
+ cclose(wq->clone);
+ free(wq);
+ return nil;
+ }
+ if(nc == nil){
+ nc = devclone(c);
+ nc->type = 0;
+ alloc = 1;
+ }
+ nc->aux = nil;
+ wq->clone = nc;
+ for(j = 0; j < nname; j++){
+ if(!(nc->qid.type & QTDIR)){
+ if(j == 0)
+ error(Enotdir);
+ kstrcpy(up->errstr, Enotdir, ERRMAX);
+ goto Done;
+ }
+ n = name[j];
+ if(n[0] == '.' && n[1] == 0)
+ USED(n);
+ else if(n[0] == '.' && n[1] == '.' && n[2] == 0){
+ if(nc->qid.path != 0)
+ nc->qid.path = 0;
+ nc->qid.type = QTDIR;
+ } else if(nc->qid.path == 0) {
+ qlock(&shrlk);
+ sp = shrlookup(n, -1);
+ if(sp != nil){
+ if(waserror()){
+ qunlock(&shrlk);
+ if(j == 0)
+ nexterror();
+ goto Done;
+ }
+ devpermcheck(sp->owner, sp->perm, OEXEC);
+ poperror();
+ mkqid(&nc->qid, sp->path, 0, c->dev ? QTFILE : QTDIR);
+ }
+ qunlock(&shrlk);
+ if(sp == nil)
+ goto Error;
+ } else {
+ qlock(&shrlk);
+ sp = shrlookup(nil, nc->qid.path);
+ if(sp != nil)
+ incref(sp);
+ qunlock(&shrlk);
+ if(sp == nil)
+ goto Error;
+ wq2 = nil;
+ rlock(&sp->umh.lock);
+ for(f = sp->umh.mount; f != nil && wq2 == nil; f = f->next) {
+ if(waserror())
+ continue;
+ wq2 = devtab[f->to->type]->walk(f->to, nil, name + j, nname - j);
+ poperror();
+ }
+ runlock(&sp->umh.lock);
+ shrdecref(sp);
+ if(wq2 == nil)
+ goto Error;
+ memmove(wq->qid + wq->nqid, wq2->qid, wq2->nqid);
+ wq->nqid += wq2->nqid;
+ if(alloc)
+ cclose(wq->clone);
+ wq->clone = wq2->clone;
+ free(wq2);
+ poperror();
+ return wq;
+ }
+ wq->qid[wq->nqid++] = nc->qid;
+ }
+
+ goto Done;
+Error:
+ if(j == 0)
+ error(Enonexist);
+ kstrcpy(up->errstr, Enonexist, ERRMAX);
+Done:
+ poperror();
+ if(wq->nqid < nname) {
+ if(alloc)
+ cclose(wq->clone);
+ wq->clone = nil;
+ } else if(wq->clone)
+ wq->clone->type = c->type;
+ return wq;
+}
+
+static int
+shrstat(Chan *c, uchar *db, int n)
+{
+ return devstat(c, db, n, 0, 0, shrgen);
+}
+
+static Chan*
+shropen(Chan *c, int omode)
+{
+ Shr *sp;
+
+ if(c->qid.type == QTDIR && omode != OREAD)
+ error(Eisdir);
+ if(c->qid.path != 0){
+ qlock(&shrlk);
+ if(waserror()){
+ qunlock(&shrlk);
+ nexterror();
+ }
+ sp = shrlookup(nil, c->qid.path);
+ if(sp == nil)
+ error(Enonexist);
+ if(c->qid.type == QTDIR)
+ c->umh = &sp->umh;
+ devpermcheck(sp->owner, sp->perm, openmode(omode));
+ qunlock(&shrlk);
+ poperror();
+ }
+ if(omode & ORCLOSE)
+ error(Eperm);
+ c->mode = openmode(omode);
+ c->flag |= COPEN;
+ c->offset = 0;
+ return c;
+}
+
+static void
+shrunioncreate(Chan *c, char *name, int omode, ulong perm)
+{
+ Shr *sp;
+ Mount *m;
+ Walkqid *wq;
+
+ error(Enocreate); /* code below is broken */
+
+ qlock(&shrlk);
+ sp = shrlookup(nil, c->qid.path);
+ if(sp != nil)
+ incref(sp);
+ qunlock(&shrlk);
+ if(sp == nil)
+ error(Enonexist);
+ if(waserror()){
+ shrdecref(sp);
+ nexterror();
+ }
+ for(m = sp->umh.mount; m != nil; m = m->next)
+ if(m->mflag & MCREATE)
+ break;
+ if(m == nil)
+ error(Enocreate);
+
+ wq = devtab[m->to->type]->walk(m->to, c, nil, 0);
+ if(wq == nil)
+ error(Egreg);
+ if(wq->clone != c){
+ cclose(wq->clone);
+ free(wq);
+ error(Egreg);
+ }
+ free(wq);
+ devtab[c->type]->create(c, name, omode, perm);
+ shrdecref(sp);
+ poperror();
+}
+
+static void
+shrcreate(Chan *c, char *name, int omode, ulong perm)
+{
+ char *sname;
+ Shr *sp;
+
+ if(c->qid.path != 0) {
+ shrunioncreate(c, name, omode, perm);
+ return;
+ }
+
+ if(c->dev != 1)
+ error(Eperm);
+
+ if(omode & OCEXEC) /* can't happen */
+ panic("someone broke namec");
+
+ sp = smalloc(sizeof *sp);
+ sname = smalloc(strlen(name)+1);
+
+ qlock(&shrlk);
+ if(waserror()){
+ free(sp);
+ free(sname);
+ qunlock(&shrlk);
+ nexterror();
+ }
+ if(sp == nil || sname == nil)
+ error(Enomem);
+ if(shrlookup(name, -1))
+ error(Eexist);
+
+ sp->path = qidpath++;
+ sp->link = shr;
+ strcpy(sname, name);
+ sp->name = sname;
+ incref(sp);
+ c->qid.type = QTFILE;
+ c->qid.path = sp->path;
+ shr = sp;
+ qunlock(&shrlk);
+ poperror();
+
+ kstrdup(&sp->owner, up->user);
+ sp->perm = (perm&0777) | ((perm&0444)>>2);
+
+ c->flag |= COPEN;
+ c->mode = OWRITE;
+}
+
+static void
+shrremove(Chan *c)
+{
+ Shr *sp, **l;
+
+ if(c->qid.path == 0)
+ error(Eperm);
+
+ qlock(&shrlk);
+ if(waserror()){
+ qunlock(&shrlk);
+ nexterror();
+ }
+ l = &shr;
+ for(sp = *l; sp; sp = sp->link) {
+ if(sp->path == c->qid.path)
+ break;
+
+ l = &sp->link;
+ }
+ if(sp == 0)
+ error(Enonexist);
+
+ if(strcmp(sp->owner, eve) == 0 && !iseve())
+ error(Eperm);
+ if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
+ error(Eperm);
+
+ *l = sp->link;
+ qunlock(&shrlk);
+ poperror();
+
+ shrdecref(sp);
+}
+
+static int
+shrwstat(Chan *c, uchar *dp, int n)
+{
+ char *strs;
+ Dir d;
+ Shr *sp;
+
+ if(c->qid.path == 0)
+ error(Eperm);
+
+ strs = nil;
+ qlock(&shrlk);
+ if(waserror()){
+ qunlock(&shrlk);
+ free(strs);
+ nexterror();
+ }
+
+ sp = shrlookup(nil, c->qid.path);
+ if(sp == 0)
+ error(Enonexist);
+
+ if(strcmp(sp->owner, up->user) != 0 && !iseve())
+ error(Eperm);
+
+ strs = smalloc(n);
+ n = convM2D(dp, n, &d, strs);
+ if(n == 0)
+ error(Eshortstat);
+ if(d.mode != ~0UL)
+ sp->perm = d.mode & 0777;
+ if(d.uid && *d.uid)
+ kstrdup(&sp->owner, d.uid);
+ if(d.name && *d.name && strcmp(sp->name, d.name) != 0) {
+ if(strchr(d.name, '/') != nil)
+ error(Ebadchar);
+ kstrdup(&sp->name, d.name);
+ }
+ qunlock(&shrlk);
+ free(strs);
+ poperror();
+ return n;
+}
+
+static void
+shrclose(Chan *c)
+{
+ c->umh = nil;
+ if(c->flag & CRCLOSE){
+ if(waserror())
+ return;
+ shrremove(c);
+ poperror();
+ }
+}
+
+static long
+shrread(Chan *c, void *va, long n, vlong off)
+{
+ Shr *sp;
+ long ret;
+ int nn;
+ Mount *f;
+ char *s, *e;
+
+ if(c->qid.path == 0)
+ return devdirread(c, va, n, 0, 0, shrgen);
+
+ if(c->qid.type & QTDIR)
+ return unionread(c, va, n);
+
+ qlock(&shrlk);
+ sp = shrlookup(nil, c->qid.path);
+ if(sp != nil)
+ incref(sp);
+ qunlock(&shrlk);
+ if(sp == nil)
+ error(Enonexist);
+ qlock(&sp->desclock);
+ if(sp->desc == nil){
+ nn = 0;
+ rlock(&sp->umh.lock);
+ for(f = sp->umh.mount; f != nil; f = f->next)
+ nn += 32 + strlen((char*)(f + 1));
+ s = sp->desc = smalloc(nn);
+ e = s + nn;
+ for(f = sp->umh.mount; f != nil; f = f->next)
+ s = seprint(s, e, "%lud %s %C %lud %lld\n", f->mountid, (char*)(f + 1), devtab[f->to->mchan->type]->dc, f->to->mchan->dev, f->to->qid.path);
+ runlock(&sp->umh.lock);
+ }
+ ret = readstr(off, va, n, sp->desc);
+ qunlock(&sp->desclock);
+ return ret;
+}
+
+static long
+shrwrite(Chan *c, void *va, long n, vlong)
+{
+ Shr *sp;
+ char *buf, *p, *desc, *aname;
+ int mode, fd;
+ Chan *bc, *c0;
+ Mount *m, *mm;
+ struct{
+ Chan *chan;
+ Chan *authchan;
+ char *spec;
+ int flags;
+ }bogus;
+
+ qlock(&shrlk);
+ sp = shrlookup(nil, c->qid.path);
+ if(sp == nil) {
+ qunlock(&shrlk);
+ error(Enonexist);
+ }
+ incref(sp);
+ qunlock(&shrlk);
+ if(waserror()){
+ shrdecref(sp);
+ nexterror();
+ }
+
+ buf = smalloc(n+1);
+ if(waserror()){
+ free(buf);
+ nexterror();
+ }
+ memmove(buf, va, n);
+ buf[n] = 0;
+
+ p = buf;
+ mode = 0;
+ for(; *p > ' '; p++)
+ switch(*p) {
+ case 'a': mode |= MAFTER; break;
+ case 'b': mode |= MBEFORE; break;
+ case 'c': mode |= MCREATE; break;
+ case 'C': mode |= MCACHE; break;
+ default: error(Ebadarg);
+ }
+
+ if((mode & (MAFTER|MBEFORE)) == 0 || (mode & (MAFTER|MBEFORE)) == (MAFTER|MBEFORE))
+ error(Ebadarg);
+ while(*p <= ' ')
+ p++;
+ if(*p == 0)
+ error(Ebadarg);
+ fd = strtol(p, &p, 10);
+ while(*p <= ' ' && *p != '\n')
+ p++;
+ if(*p != 0 && *p != '\n') {
+ desc = p;
+ p = strchr(desc, '\n');
+ if(p != nil)
+ *p = 0;
+ } else
+ desc = "";
+ aname = strchr(buf, '\n') + 1;
+ if(aname != nil && *aname == 0)
+ aname = nil;
+ if(strlen(desc) > 128)
+ error(Ebadarg);
+
+ bc = fdtochan(fd, ORDWR, 0, 1);
+ if(waserror()) {
+ cclose(bc);
+ nexterror();
+ }
+ bogus.flags = mode & MCACHE;
+ bogus.chan = bc;
+ bogus.authchan = nil;
+ bogus.spec = aname;
+ c0 = devtab[devno('M', 0)]->attach((char*)&bogus);
+ cclose(bc);
+ poperror();
+
+ m = smalloc(sizeof(Mount) + strlen(desc) + 1);
+ strcpy((char*)(m + 1), desc);
+ m->to = c0;
+ m->mflag = mode;
+ qlock(&shrlk);
+ m->mountid = ++mntid;
+ qunlock(&shrlk);
+ wlock(&sp->umh.lock);
+ if((mode & MAFTER) != 0 && sp->umh.mount != nil) {
+ for(mm = sp->umh.mount; mm->next != nil; mm = mm->next)
+ ;
+ mm->next = m;
+ } else {
+ m->next = sp->umh.mount;
+ sp->umh.mount = m;
+ }
+ wunlock(&sp->umh.lock);
+ qlock(&sp->desclock);
+ free(sp->desc);
+ sp->desc = nil;
+ qunlock(&sp->desclock);
+ shrdecref(sp);
+ free(buf);
+ poperror();
+ poperror();
+ return n;
+}
+
+Dev shrdevtab = {
+ L'σ',
+ "shr",
+
+ devreset,
+ shrinit,
+ devshutdown,
+ shrattach,
+ shrwalk,
+ shrstat,
+ shropen,
+ shrcreate,
+ shrclose,
+ shrread,
+ devbread,
+ shrwrite,
+ devbwrite,
+ shrremove,
+ shrwstat,
+};