]> git.lizzy.rs Git - plan9front.git/commitdiff
added devshr
authoraiju <aiju@phicode.de>
Sun, 24 Jul 2011 20:12:01 +0000 (22:12 +0200)
committeraiju <aiju@phicode.de>
Sun, 24 Jul 2011 20:12:01 +0000 (22:12 +0200)
sys/src/9/port/devshr.c [new file with mode: 0644]

diff --git a/sys/src/9/port/devshr.c b/sys/src/9/port/devshr.c
new file mode 100644 (file)
index 0000000..ad57682
--- /dev/null
@@ -0,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,
+};