xref: /inferno-os/emu/port/devsnarf.c (revision e57c7e16a3789cd4de1a3c2560d49b1ee39cd10a)
1 /*
2  * host's snarf buffer
3  */
4 
5 #include "dat.h"
6 #include "fns.h"
7 #include "../port/error.h"
8 
9 enum{
10 	Qdir,
11 	Qsnarf,
12 
13 	Maxsnarf=	100*1024
14 };
15 
16 static
17 Dirtab snarftab[]={
18 	".",		{Qdir, 0, QTDIR},	0,	0555,
19 	"snarf",	{Qsnarf},			0,	0666,
20 };
21 
22 static QLock snarflock;	/* easiest to synchronise all access */
23 
24 static Chan*
25 snarfattach(char *spec)
26 {
27 	return devattach('^', spec);
28 }
29 
30 static Walkqid*
31 snarfwalk(Chan *c, Chan *nc, char **name, int nname)
32 {
33 	return devwalk(c, nc, name, nname, snarftab, nelem(snarftab), devgen);
34 }
35 
36 static int
37 snarfstat(Chan* c, uchar *db, int n)
38 {
39 	return devstat(c, db, n, snarftab, nelem(snarftab), devgen);
40 }
41 
42 static Chan*
43 snarfopen(Chan* c, int omode)
44 {
45 	c = devopen(c, omode, snarftab, nelem(snarftab), devgen);
46 	if(c->qid.path == Qsnarf){
47 		if(c->mode == ORDWR || c->mode == OWRITE){
48 			qlock(&snarflock);
49 			free(c->aux);
50 			c->aux = nil;
51 			qunlock(&snarflock);
52 		}
53 	}
54 	return c;
55 }
56 
57 static void
58 snarfclose(Chan* c)
59 {
60 	if((c->flag & COPEN) == 0)
61 		return;
62 	if(c->qid.path == Qsnarf){
63 		/* this must be the last reference: no need to lock */
64 		if(c->mode == ORDWR || c->mode == OWRITE){
65 			if(!waserror()){
66 				if(c->aux != nil)
67 					clipwrite(c->aux);
68 				poperror();
69 			}
70 		}
71 		free(c->aux);
72 	}
73 }
74 
75 static long
76 snarfread(Chan* c, void* a, long n, vlong offset)
77 {
78 	void *p;
79 
80 	switch((ulong)c->qid.path){
81 	case Qdir:
82 		return devdirread(c, a, n, snarftab, nelem(snarftab), devgen);
83 	case Qsnarf:
84 		qlock(&snarflock);
85 		if(waserror()){
86 			qunlock(&snarflock);
87 			nexterror();
88 		}
89 		if(offset == 0){
90 			p = c->aux;
91 			c->aux = nil;
92 			free(p);
93 			c->aux = clipread();
94 		}
95 		if(c->aux != nil)
96 			n = readstr(offset, a, n, c->aux);
97 		else
98 			n = 0;
99 		poperror();
100 		qunlock(&snarflock);
101 		break;
102 	default:
103 		n=0;
104 		break;
105 	}
106 	return n;
107 }
108 
109 static long
110 snarfwrite(Chan* c, void* va, long n, vlong offset)
111 {
112 	ulong l;
113 	char *p;
114 
115 	switch((ulong)c->qid.path){
116 	case Qsnarf:
117 		/* append only */
118 		USED(offset);	/* not */
119 		qlock(&snarflock);
120 		if(waserror()){
121 			qunlock(&snarflock);
122 			nexterror();
123 		}
124 		if(c->aux != nil)
125 			l = strlen(c->aux);
126 		else
127 			l = 0;
128 		if(l+n > Maxsnarf)
129 			error(Etoobig);
130 		c->aux = realloc(c->aux, l+n+1);
131 		if((p = c->aux) == nil)
132 			error(Enovmem);
133 		memmove(p+l, va, n);
134 		p[l+n] = 0;
135 		snarftab[1].qid.vers++;
136 		poperror();
137 		qunlock(&snarflock);
138 		break;
139 	default:
140 		error(Ebadusefd);
141 	}
142 	return n;
143 }
144 
145 Dev snarfdevtab = {
146 	'^',
147 	"snarf",
148 
149 	devinit,
150 	snarfattach,
151 	snarfwalk,
152 	snarfstat,
153 	snarfopen,
154 	devcreate,
155 	snarfclose,
156 	snarfread,
157 	devbread,
158 	snarfwrite,
159 	devbwrite,
160 	devremove,
161 	devwstat,
162 };
163