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 int12 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 int26 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)101 {102 while(attr){103 if(strcmp(attr->name, name) == 0)104 return attr->value;105 attr = attr->next;106 }107 return nil;108 }110 char*111 plumbpack(Plumbmsg *m, int *np)112 {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;126 }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;145 }147 int148 plumbsend(int fd, Plumbmsg *m)149 {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;159 }161 static int162 plumbline(char **linep, char *buf, int i, int n, int *bad)163 {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';181 }182 *linep = p;183 i++;184 }185 return i;186 }188 void189 plumbfree(Plumbmsg *m)190 {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);202 }203 free(m->data);204 free(m);205 }207 Plumbattr*208 plumbunpackattr(char *p)209 {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;232 }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;250 }251 }252 }else{253 if(c==' ' || c=='\t')254 break;255 if(c == '\''){256 quoting = 1;257 continue;258 }259 }260 *v++ = c;261 }262 a->value = malloc(v-attrbuf+1);263 if(a->value == nil){264 free(a->name);265 free(a);266 break;267 }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 else274 prev->next = a;275 prev = a;276 p = q;277 }278 return attr;279 }281 Plumbattr*282 plumbaddattr(Plumbattr *attr, Plumbattr *new)283 {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;293 }295 Plumbattr*296 plumbdelattr(Plumbattr *attr, char *name)297 {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;305 }306 if(l == nil)307 return nil;308 if(prev)309 prev->next = l->next;310 else311 attr = l->next;312 free(l->name);313 free(l->value);314 free(l);315 return attr;316 }318 Plumbmsg*319 plumbunpackpartial(char *buf, int n, int *morep)320 {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);345 }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';356 }357 }358 if(bad){359 plumbfree(m);360 m = nil;361 }362 return m;363 }365 Plumbmsg*366 plumbunpack(char *buf, int n)367 {368 return plumbunpackpartial(buf, n, nil);369 }371 Plumbmsg*372 plumbrecv(int fd)373 {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);392 }393 }394 free(buf);395 return m;396 }