ref: 3866717cbb020199d58171c1c0cdd7382a74ee82
dir: /emu/port/devsnarf.c/
/*
* 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()){
if(c->aux != nil)
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,
};