diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /emu/port/devsnarf.c | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'emu/port/devsnarf.c')
| -rw-r--r-- | emu/port/devsnarf.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/emu/port/devsnarf.c b/emu/port/devsnarf.c new file mode 100644 index 00000000..4778c130 --- /dev/null +++ b/emu/port/devsnarf.c @@ -0,0 +1,161 @@ +/* + * host's snarf buffer + */ + +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +enum{ + Qdir, + Qsnarf, + + Maxsnarf= 100*1024 +}; + +static +Dirtab snarftab[]={ + ".", {Qdir, 0, QTDIR}, 0, 0555, + "snarf", {Qsnarf}, 0, 0666, +}; + +static QLock snarflock; /* easiest to synchronise all access */ + +static Chan* +snarfattach(char *spec) +{ + return devattach('^', spec); +} + +static Walkqid* +snarfwalk(Chan *c, Chan *nc, char **name, int nname) +{ + return devwalk(c, nc, name, nname, snarftab, nelem(snarftab), devgen); +} + +static int +snarfstat(Chan* c, uchar *db, int n) +{ + return devstat(c, db, n, snarftab, nelem(snarftab), devgen); +} + +static Chan* +snarfopen(Chan* c, int omode) +{ + c = devopen(c, omode, snarftab, nelem(snarftab), devgen); + if(c->qid.path == Qsnarf){ + if(c->mode == ORDWR || c->mode == OWRITE){ + qlock(&snarflock); + free(c->aux); + c->aux = nil; + qunlock(&snarflock); + } + } + return c; +} + +static void +snarfclose(Chan* c) +{ + if((c->flag & COPEN) == 0) + return; + if(c->qid.path == Qsnarf){ + /* this must be the last reference: no need to lock */ + if(c->mode == ORDWR || c->mode == OWRITE){ + if(!waserror()){ + clipwrite(c->aux); + poperror(); + } + } + free(c->aux); + } +} + +static long +snarfread(Chan* c, void* a, long n, vlong offset) +{ + void *p; + + switch((ulong)c->qid.path){ + case Qdir: + return devdirread(c, a, n, snarftab, nelem(snarftab), devgen); + case Qsnarf: + qlock(&snarflock); + if(waserror()){ + qunlock(&snarflock); + nexterror(); + } + if(offset == 0){ + p = c->aux; + c->aux = nil; + free(p); + c->aux = clipread(); + } + if(c->aux != nil) + n = readstr(offset, a, n, c->aux); + else + n = 0; + poperror(); + qunlock(&snarflock); + break; + default: + n=0; + break; + } + return n; +} + +static long +snarfwrite(Chan* c, void* va, long n, vlong offset) +{ + ulong l; + char *p; + + switch((ulong)c->qid.path){ + case Qsnarf: + /* append only */ + USED(offset); /* not */ + qlock(&snarflock); + if(waserror()){ + qunlock(&snarflock); + nexterror(); + } + if(c->aux != nil) + l = strlen(c->aux); + else + l = 0; + if(l+n > Maxsnarf) + error(Etoobig); + c->aux = realloc(c->aux, l+n+1); + if((p = c->aux) == nil) + error(Enovmem); + memmove(p+l, va, n); + p[l+n] = 0; + snarftab[1].qid.vers++; + poperror(); + qunlock(&snarflock); + break; + default: + error(Ebadusefd); + } + return n; +} + +Dev snarfdevtab = { + '^', + "snarf", + + devinit, + snarfattach, + snarfwalk, + snarfstat, + snarfopen, + devcreate, + snarfclose, + snarfread, + devbread, + snarfwrite, + devbwrite, + devremove, + devwstat, +}; |
