Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <fcall.h>
4 #include <fs.h>
5 #include "plumb.h"
7 static char attrbuf[4096];
9 char *home;
11 int
12 plumbopen(char *name, int omode)
13 {
14 Fsys *fs;
15 int fd;
17 fs = nsmount("plumb", "");
18 if(fs == nil)
19 return -1;
20 fd = fsopenfd(fs, name, omode);
21 fsunmount(fs);
22 return fd;
23 }
25 static int
26 Strlen(char *s)
27 {
28 if(s == nil)
29 return 0;
30 return strlen(s);
31 }
33 static char*
34 Strcpy(char *s, char *t)
35 {
36 if(t == nil)
37 return s;
38 return strcpy(s, t) + strlen(t);
39 }
41 /* quote attribute value, if necessary */
42 static char*
43 quote(char *s)
44 {
45 char *t;
46 int c;
48 if(s == nil){
49 attrbuf[0] = '\0';
50 return attrbuf;
51 }
52 if(strpbrk(s, " '=\t") == nil)
53 return s;
54 t = attrbuf;
55 *t++ = '\'';
56 while(t < attrbuf+sizeof attrbuf-2){
57 c = *s++;
58 if(c == '\0')
59 break;
60 *t++ = c;
61 if(c == '\'')
62 *t++ = c;
63 }
64 *t++ = '\'';
65 *t = '\0';
66 return attrbuf;
67 }
69 char*
70 plumbpackattr(Plumbattr *attr)
71 {
72 int n;
73 Plumbattr *a;
74 char *s, *t;
76 if(attr == nil)
77 return nil;
78 n = 0;
79 for(a=attr; a!=nil; a=a->next)
80 n += Strlen(a->name) + 1 + Strlen(quote(a->value)) + 1;
81 s = malloc(n);
82 if(s == nil)
83 return nil;
84 t = s;
85 *t = '\0';
86 for(a=attr; a!=nil; a=a->next){
87 if(t != s)
88 *t++ = ' ';
89 strcpy(t, a->name);
90 strcat(t, "=");
91 strcat(t, quote(a->value));
92 t += strlen(t);
93 }
94 if(t > s+n)
95 abort();
96 return s;
97 }
99 char*
100 plumblookup(Plumbattr *attr, char *name)
102 while(attr){
103 if(strcmp(attr->name, name) == 0)
104 return attr->value;
105 attr = attr->next;
107 return nil;
110 char*
111 plumbpack(Plumbmsg *m, int *np)
113 int n, ndata;
114 char *buf, *p, *attr;
116 ndata = m->ndata;
117 if(ndata < 0)
118 ndata = Strlen(m->data);
119 attr = plumbpackattr(m->attr);
120 n = Strlen(m->src)+1 + Strlen(m->dst)+1 + Strlen(m->wdir)+1 +
121 Strlen(m->type)+1 + Strlen(attr)+1 + 16 + ndata;
122 buf = malloc(n+1); /* +1 for '\0' */
123 if(buf == nil){
124 free(attr);
125 return nil;
127 p = Strcpy(buf, m->src);
128 *p++ = '\n';
129 p = Strcpy(p, m->dst);
130 *p++ = '\n';
131 p = Strcpy(p, m->wdir);
132 *p++ = '\n';
133 p = Strcpy(p, m->type);
134 *p++ = '\n';
135 p = Strcpy(p, attr);
136 *p++ = '\n';
137 p += sprint(p, "%d\n", ndata);
138 memmove(p, m->data, ndata);
139 *np = (p-buf)+ndata;
140 buf[*np] = '\0'; /* null terminate just in case */
141 if(*np >= n+1)
142 abort();
143 free(attr);
144 return buf;
147 int
148 plumbsend(int fd, Plumbmsg *m)
150 char *buf;
151 int n;
153 buf = plumbpack(m, &n);
154 if(buf == nil)
155 return -1;
156 n = write(fd, buf, n);
157 free(buf);
158 return n;
161 static int
162 plumbline(char **linep, char *buf, int i, int n, int *bad)
164 int starti;
165 char *p;
167 if(*bad)
168 return i;
169 starti = i;
170 while(i<n && buf[i]!='\n')
171 i++;
172 if(i == n)
173 *bad = 1;
174 else{
175 p = malloc((i-starti) + 1);
176 if(p == nil)
177 *bad = 1;
178 else{
179 memmove(p, buf+starti, i-starti);
180 p[i-starti] = '\0';
182 *linep = p;
183 i++;
185 return i;
188 void
189 plumbfree(Plumbmsg *m)
191 Plumbattr *a, *next;
193 free(m->src);
194 free(m->dst);
195 free(m->wdir);
196 free(m->type);
197 for(a=m->attr; a!=nil; a=next){
198 next = a->next;
199 free(a->name);
200 free(a->value);
201 free(a);
203 free(m->data);
204 free(m);
207 Plumbattr*
208 plumbunpackattr(char *p)
210 Plumbattr *attr, *prev, *a;
211 char *q, *v;
212 int c, quoting;
214 attr = prev = nil;
215 while(*p!='\0' && *p!='\n'){
216 while(*p==' ' || *p=='\t')
217 p++;
218 if(*p == '\0')
219 break;
220 for(q=p; *q!='\0' && *q!='\n' && *q!=' ' && *q!='\t'; q++)
221 if(*q == '=')
222 break;
223 if(*q != '=')
224 break; /* malformed attribute */
225 a = malloc(sizeof(Plumbattr));
226 if(a == nil)
227 break;
228 a->name = malloc(q-p+1);
229 if(a->name == nil){
230 free(a);
231 break;
233 memmove(a->name, p, q-p);
234 a->name[q-p] = '\0';
235 /* process quotes in value */
236 q++; /* skip '=' */
237 v = attrbuf;
238 quoting = 0;
239 while(*q!='\0' && *q!='\n'){
240 if(v >= attrbuf+sizeof attrbuf)
241 break;
242 c = *q++;
243 if(quoting){
244 if(c == '\''){
245 if(*q == '\'')
246 q++;
247 else{
248 quoting = 0;
249 continue;
252 }else{
253 if(c==' ' || c=='\t')
254 break;
255 if(c == '\''){
256 quoting = 1;
257 continue;
260 *v++ = c;
262 a->value = malloc(v-attrbuf+1);
263 if(a->value == nil){
264 free(a->name);
265 free(a);
266 break;
268 memmove(a->value, attrbuf, v-attrbuf);
269 a->value[v-attrbuf] = '\0';
270 a->next = nil;
271 if(prev == nil)
272 attr = a;
273 else
274 prev->next = a;
275 prev = a;
276 p = q;
278 return attr;
281 Plumbattr*
282 plumbaddattr(Plumbattr *attr, Plumbattr *new)
284 Plumbattr *l;
286 l = attr;
287 if(l == nil)
288 return new;
289 while(l->next != nil)
290 l = l->next;
291 l->next = new;
292 return attr;
295 Plumbattr*
296 plumbdelattr(Plumbattr *attr, char *name)
298 Plumbattr *l, *prev;
300 prev = nil;
301 for(l=attr; l!=nil; l=l->next){
302 if(strcmp(name, l->name) == 0)
303 break;
304 prev = l;
306 if(l == nil)
307 return nil;
308 if(prev)
309 prev->next = l->next;
310 else
311 attr = l->next;
312 free(l->name);
313 free(l->value);
314 free(l);
315 return attr;
318 Plumbmsg*
319 plumbunpackpartial(char *buf, int n, int *morep)
321 Plumbmsg *m;
322 int i, bad;
323 char *ntext, *attr;
325 m = malloc(sizeof(Plumbmsg));
326 if(m == nil)
327 return nil;
328 memset(m, 0, sizeof(Plumbmsg));
329 if(morep != nil)
330 *morep = 0;
331 bad = 0;
332 i = plumbline(&m->src, buf, 0, n, &bad);
333 i = plumbline(&m->dst, buf, i, n, &bad);
334 i = plumbline(&m->wdir, buf, i, n, &bad);
335 i = plumbline(&m->type, buf, i, n, &bad);
336 i = plumbline(&attr, buf, i, n, &bad);
337 m->attr = plumbunpackattr(attr);
338 free(attr);
339 i = plumbline(&ntext, buf, i, n, &bad);
340 m->ndata = atoi(ntext);
341 if(m->ndata != n-i){
342 bad = 1;
343 if(morep!=nil && m->ndata>n-i)
344 *morep = m->ndata - (n-i);
346 free(ntext);
347 if(!bad){
348 m->data = malloc(n-i+1); /* +1 for '\0' */
349 if(m->data == nil)
350 bad = 1;
351 else{
352 memmove(m->data, buf+i, m->ndata);
353 m->ndata = n-i;
354 /* null-terminate in case it's text */
355 m->data[m->ndata] = '\0';
358 if(bad){
359 plumbfree(m);
360 m = nil;
362 return m;
365 Plumbmsg*
366 plumbunpack(char *buf, int n)
368 return plumbunpackpartial(buf, n, nil);
371 Plumbmsg*
372 plumbrecv(int fd)
374 char *buf;
375 Plumbmsg *m;
376 int n, more;
378 buf = malloc(8192);
379 if(buf == nil)
380 return nil;
381 n = read(fd, buf, 8192);
382 m = nil;
383 if(n > 0){
384 m = plumbunpackpartial(buf, n, &more);
385 if(m==nil && more>0){
386 /* we now know how many more bytes to read for complete message */
387 buf = realloc(buf, n+more);
388 if(buf == nil)
389 return nil;
390 if(readn(fd, buf+n, more) == more)
391 m = plumbunpackpartial(buf, n+more, nil);
394 free(buf);
395 return m;