ref: f31e1f4e4272beae2bc8a40ee2d5fb5a3061a3d3
dir: /sys/src/9/port/devskel.c/
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "netif.h" typedef struct Skel Skel; struct Skel { int ref; QLock lk; char name[KNAMELEN]; char mode; }; struct { QLock lk; ulong path; } skelalloc; enum{ Qroot, Qdir, Qskel, }; static Chan* skelattach(char *spec) { Chan *c; Skel *f; uvlong path; c = devattach('z', spec); f = smalloc(sizeof *f); if(spec != nil && spec[0] != '\0' && strchr("de", spec[0]) != nil) f->mode = spec[0]; else f->mode = 'f'; f->ref = 1; qlock(&skelalloc.lk); path = skelalloc.path++; qunlock(&skelalloc.lk); mkqid(&c->qid, NETQID(path, Qroot), 0, QTDIR); c->aux = f; return c; } static int step(Chan *c, Dir *dp, int direction) { Skel *f; Qid qid; ulong perm; uvlong path; char *name; perm = 0555|DMDIR; path = NETTYPE(c->qid.path); f = c->aux; name = f->name; path += direction; if(!f->name[0] && path != Qroot) return -1; switch(path){ case Qroot: mkqid(&qid, Qroot, 0, QTDIR); name = "#z"; break; case Qdir: mkqid(&qid, Qdir, 0, QTDIR); break; case Qskel: switch(f->mode){ case 'd': mkqid(&qid, Qskel, 0, QTDIR); break; case 'f': default: mkqid(&qid, Qskel, 0, QTFILE); perm = 0666; break; } break; default: return -1; } qid.path = NETQID(NETID(c->qid.path), qid.path); devdir(c, qid, name, 0, eve, perm, dp); return 1; } static int skelgen(Chan *c, char *name, Dirtab *, int, int s, Dir *dp) { Skel *f; f = c->aux; //First walk away from root if(name && !f->name[0] && f->mode != 'e' && NETTYPE(c->qid.path) == Qroot) utfecpy(f->name, &f->name[sizeof f->name-1], name); if(s != DEVDOTDOT) s++; return step(c, dp, s); } static Walkqid* skelwalk(Chan *c, Chan *nc, char **name, int nname) { Walkqid *wq; Skel *f; f = c->aux; qlock(&f->lk); if(waserror()){ qunlock(&f->lk); nexterror(); } wq = devwalk(c, nc, name, nname, nil, 0, skelgen); if(wq != nil && wq->clone != nil && wq->clone != c){ if(f->ref <= 0) panic("devskel ref"); f->ref++; } qunlock(&f->lk); poperror(); return wq; } static Chan* skelopen(Chan *c, int omode) { if(!(c->qid.type & QTDIR)) error(Eperm); if(omode != OREAD) error(Ebadarg); c->mode = omode; c->flag |= COPEN; c->offset = 0; return c; } static void skelclose(Chan *c) { Skel *f; f = c->aux; qlock(&f->lk); f->ref--; if(f->ref == 0){ qunlock(&f->lk); free(f); } else qunlock(&f->lk); } static long skelread(Chan *c, void *va, long n, vlong) { Skel *f; long nout; if(!(c->qid.type & QTDIR)) error(Eperm); f = c->aux; qlock(&f->lk); if(waserror()){ qunlock(&f->lk); nexterror(); } nout = devdirread(c, va, n, nil, 0, skelgen); qunlock(&f->lk); poperror(); return nout; } static long skelwrite(Chan *, void *, long, vlong) { error(Eperm); return 0; } static int skelstat(Chan *c, uchar *db, int n) { Skel *f; Dir dir; f = c->aux; qlock(&f->lk); step(c, &dir, 0); qunlock(&f->lk); n = convD2M(&dir, db, n); if(n < BIT16SZ) error(Eshortstat); return n; } Dev skeldevtab = { 'z', "skel", devreset, devinit, devshutdown, skelattach, skelwalk, skelstat, skelopen, devcreate, skelclose, skelread, devbread, skelwrite, devbwrite, devremove, devwstat, };