1 /* Copyright ©2006 Kris Maglione <fbsdaemon at gmail dot com>
2 * See LICENSE file for license details.
3 */
4 #include "dat.h"
5 #include <assert.h>
6 #include <ctype.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <time.h>
12 #include "fns.h"
13
14
15 /* Datatypes: */
16 typedef struct Dirtab Dirtab;
17 struct Dirtab {
18 char *name;
19 uchar qtype;
20 uint type;
21 uint perm;
22 };
23
24 typedef struct FidLink FidLink;
25 struct FidLink {
26 FidLink *next;
27 Fid *fid;
28 };
29
30 typedef struct FileId FileId;
31 struct FileId {
32 FileId *next;
33 union {
34 void *ref;
35 char *buf;
36 Bar *bar;
37 Bar **bar_p;
38 View *view;
39 Client *client;
40 Ruleset *rule;
41 CTuple *col;
42 } p;
43 uint id;
44 uint index;
45 Dirtab tab;
46 ushort nref;
47 uchar volatil;
48 };
49
50 /* Constants */
51 enum { /* Dirs */
52 FsRoot, FsDClient, FsDClients, FsDBars,
53 FsDTag, FsDTags,
54 /* Files */
55 FsFBar, FsFCctl, FsFColRules, FsFClabel,
56 FsFCtags, FsFEvent, FsFKeys, FsFRctl,
57 FsFTagRules, FsFTctl, FsFTindex,
58 FsFprops
59 };
60
61 /* Error messages */
62 static char
63 Enoperm[] = "permission denied",
64 Enofile[] = "file not found",
65 Ebadvalue[] = "bad value",
66 Einterrupted[] = "interrupted";
67
68 /* Macros */
69 #define QID(t, i) (((vlong)((t)&0xFF)<<32)|((i)&0xFFFFFFFF))
70
71 /* Global Vars */
72 /***************/
73 FileId *free_fileid;
74 /* Pending, outgoing reads on /event */
75 Ixp9Req *peventread, *oeventread;
76 /* Fids for /event with pending reads */
77 FidLink *peventfid;
78
79 Ixp9Srv p9srv = {
80 .open= fs_open,
81 .walk= fs_walk,
82 .read= fs_read,
83 .stat= fs_stat,
84 .write= fs_write,
85 .clunk= fs_clunk,
86 .flush= fs_flush,
87 .attach=fs_attach,
88 .create=fs_create,
89 .remove=fs_remove,
90 .freefid=fs_freefid
91 };
92
93 /* ad-hoc file tree. Empty names ("") indicate dynamic entries to be filled
94 * in by lookup_file
95 */
96 static Dirtab
97 dirtab_root[]= {{".", QTDIR, FsRoot, 0500|DMDIR },
98 {"rbar", QTDIR, FsDBars, 0700|DMDIR },
99 {"lbar", QTDIR, FsDBars, 0700|DMDIR },
100 {"client", QTDIR, FsDClients, 0500|DMDIR },
101 {"tag", QTDIR, FsDTags, 0500|DMDIR },
102 {"ctl", QTAPPEND, FsFRctl, 0600|DMAPPEND },
103 {"colrules", QTFILE, FsFColRules, 0600 },
104 {"event", QTFILE, FsFEvent, 0600 },
105 {"keys", QTFILE, FsFKeys, 0600 },
106 {"tagrules", QTFILE, FsFTagRules, 0600 },
107 {nil}},
108 dirtab_clients[]={{".", QTDIR, FsDClients, 0500|DMDIR },
109 {"", QTDIR, FsDClient, 0500|DMDIR },
110 {nil}},
111 dirtab_client[]= {{".", QTDIR, FsDClient, 0500|DMDIR },
112 {"ctl", QTAPPEND, FsFCctl, 0600|DMAPPEND },
113 {"label", QTFILE, FsFClabel, 0600 },
114 {"tags", QTFILE, FsFCtags, 0600 },
115 {"props", QTFILE, FsFprops, 0400 },
116 {nil}},
117 dirtab_bars[]= {{".", QTDIR, FsDBars, 0700|DMDIR },
118 {"", QTFILE, FsFBar, 0600 },
119 {nil}},
120 dirtab_tags[]= {{".", QTDIR, FsDTags, 0500|DMDIR },
121 {"", QTDIR, FsDTag, 0500|DMDIR },
122 {nil}},
123 dirtab_tag[]= {{".", QTDIR, FsDTag, 0500|DMDIR },
124 {"ctl", QTAPPEND, FsFTctl, 0600|DMAPPEND },
125 {"index", QTFILE, FsFTindex, 0400 },
126 {nil}};
127 static Dirtab *dirtab[] = {
128 [FsRoot] = dirtab_root,
129 [FsDBars] = dirtab_bars,
130 [FsDClients] = dirtab_clients,
131 [FsDClient] = dirtab_client,
132 [FsDTags] = dirtab_tags,
133 [FsDTag] = dirtab_tag,
134 };
135
136 /* Utility Functions */
137 static FileId *
get_file(void)138 get_file(void) {
139 FileId *temp;
140 if(!free_fileid) {
141 uint i = 15;
142 temp = emallocz(sizeof(FileId) * i);
143 for(; i; i--) {
144 temp->next = free_fileid;
145 free_fileid = temp++;
146 }
147 }
148 temp = free_fileid;
149 free_fileid = temp->next;
150 temp->volatil = 0;
151 temp->nref = 1;
152 temp->next = nil;
153 return temp;
154 }
155
156 static void
free_file(FileId * f)157 free_file(FileId *f) {
158 if(--f->nref)
159 return;
160 free(f->tab.name);
161 f->next = free_fileid;
162 free_fileid = f;
163 }
164
165 /* Increase the reference counts of the FileId list */
166 static void
clone_files(FileId * f)167 clone_files(FileId *f) {
168 for(; f; f=f->next)
169 assert(f->nref++);
170 }
171
172 /* This should be moved to libixp */
173 static void
write_buf(Ixp9Req * r,char * buf,uint len)174 write_buf(Ixp9Req *r, char *buf, uint len) {
175 if(r->ifcall.offset >= len)
176 return;
177
178 len -= r->ifcall.offset;
179 if(len > r->ifcall.count)
180 len = r->ifcall.count;
181 r->ofcall.data = emalloc(len);
182 memcpy(r->ofcall.data, buf + r->ifcall.offset, len);
183 r->ofcall.count = len;
184 }
185
186 /* This should be moved to libixp */
187 static void
write_to_buf(Ixp9Req * r,void * buf,uint * len,uint max)188 write_to_buf(Ixp9Req *r, void *buf, uint *len, uint max) {
189 uint offset, count;
190
191 offset = (r->fid->omode&OAPPEND) ? *len : r->ifcall.offset;
192 if(offset > *len || r->ifcall.count == 0) {
193 r->ofcall.count = 0;
194 return;
195 }
196
197 count = r->ifcall.count;
198 if(max && (count > max - offset))
199 count = max - offset;
200
201 *len = offset + count;
202
203 if(max == 0) {
204 *(void **)buf = erealloc(*(void **)buf, *len + 1);
205 buf = *(void **)buf;
206 }
207
208 memcpy((uchar*)buf + offset, r->ifcall.data, count);
209 r->ofcall.count = count;
210 ((char *)buf)[offset+count] = '\0';
211 }
212
213 /* This should be moved to libixp */
214 static void
data_to_cstring(Ixp9Req * r)215 data_to_cstring(Ixp9Req *r) {
216 char *p;
217 uint i;
218
219 i = r->ifcall.count;
220 p = r->ifcall.data;
221 if(p[i - 1] == '\n')
222 i--;
223
224 r->ifcall.data = toutf8n(p, i);
225 assert(r->ifcall.data);
226 free(p);
227 }
228
229 typedef char* (*MsgFunc)(void*, IxpMsg*);
230
231 static char *
message(Ixp9Req * r,MsgFunc fn)232 message(Ixp9Req *r, MsgFunc fn) {
233 char *err, *s, *p, c;
234 FileId *f;
235 IxpMsg m;
236
237 f = r->fid->aux;
238
239 data_to_cstring(r);
240 s = r->ifcall.data;
241
242 err = nil;
243 c = *s;
244 while(c != '\0') {
245 while(*s == '\n')
246 s++;
247 p = s;
248 while(*p != '\0' && *p != '\n')
249 p++;
250 c = *p;
251 *p = '\0';
252
253 m = ixp_message((uchar*)s, p-s, 0);
254 s = fn(f->p.ref, &m);
255 if(s)
256 err = s;
257 s = p + 1;
258 }
259 return err;
260 }
261
262 static void
respond_event(Ixp9Req * r)263 respond_event(Ixp9Req *r) {
264 FileId *f = r->fid->aux;
265 if(f->p.buf) {
266 r->ofcall.data = (void *)f->p.buf;
267 r->ofcall.count = strlen(f->p.buf);
268 respond(r, nil);
269 f->p.buf = nil;
270 }else{
271 r->aux = peventread;
272 peventread = r;
273 }
274 }
275
276 void
write_event(char * format,...)277 write_event(char *format, ...) {
278 uint len, slen;
279 va_list ap;
280 FidLink *f;
281 FileId *fi;
282 Ixp9Req *req;
283
284 va_start(ap, format);
285 vsnprint(buffer, sizeof(buffer), format, ap);
286 va_end(ap);
287
288 len = strlen(buffer);
289 if(len == 0)
290 return;
291
292 for(f=peventfid; f; f=f->next) {
293 fi = f->fid->aux;
294
295 slen = 0;
296 if(fi->p.buf)
297 slen = strlen(fi->p.buf);
298 fi->p.buf = erealloc(fi->p.buf, slen + len + 1);
299 fi->p.buf[slen] = '\0';
300 strcat(fi->p.buf, buffer);
301 }
302 oeventread = peventread;
303 peventread = nil;
304 while((req = oeventread)) {
305 oeventread = oeventread->aux;
306 respond_event(req);
307 }
308 }
309
310 static void
dostat(Stat * s,uint len,FileId * f)311 dostat(Stat *s, uint len, FileId *f) {
312 s->type = 0;
313 s->dev = 0;
314 s->qid.path = QID(f->tab.type, f->id);
315 s->qid.version = 0;
316 s->qid.type = f->tab.qtype;
317 s->mode = f->tab.perm;
318 s->atime = time(nil);
319 s->mtime = time(nil);
320 s->length = len;
321 s->name = f->tab.name;
322 s->uid = user;
323 s->gid = user;
324 s->muid = user;
325 }
326
327 /* All lookups and directory organization should be performed through
328 * lookup_file, mostly through the dirtabs[] tree. */
329 static FileId *
lookup_file(FileId * parent,char * name)330 lookup_file(FileId *parent, char *name)
331 {
332 FileId *ret, *file, **last;
333 Dirtab *dir;
334 Client *c;
335 View *v;
336 Bar *b;
337 uint id;
338
339 if(!(parent->tab.perm & DMDIR))
340 return nil;
341 dir = dirtab[parent->tab.type];
342 last = &ret;
343 ret = nil;
344 for(; dir->name; dir++) {
345 /* Dynamic dirs */
346 if(!*dir->name) { /* strlen(dir->name) == 0 */
347 switch(parent->tab.type) {
348 case FsDClients:
349 if(!name || !strcmp(name, "sel")) {
350 if((c = selclient())) {
351 file = get_file();
352 *last = file;
353 last = &file->next;
354 file->volatil = True;
355 file->p.client = c;
356 file->id = c->w.w;
357 file->index = c->w.w;
358 file->tab = *dir;
359 file->tab.name = estrdup("sel");
360 }if(name) goto LastItem;
361 }
362 SET(id);
363 if(name) {
364 id = (uint)strtol(name, &name, 16);
365 if(*name) goto NextItem;
366 }
367 for(c=client; c; c=c->next) {
368 if(!name || c->w.w == id) {
369 file = get_file();
370 *last = file;
371 last = &file->next;
372 file->volatil = True;
373 file->p.client = c;
374 file->id = c->w.w;
375 file->index = c->w.w;
376 file->tab = *dir;
377 file->tab.name = smprint("%C", c);
378 assert(file->tab.name);
379 if(name) goto LastItem;
380 }
381 }
382 break;
383 case FsDTags:
384 if(!name || !strcmp(name, "sel")) {
385 if(screen->sel) {
386 file = get_file();
387 *last = file;
388 last = &file->next;
389 file->volatil = True;
390 file->p.view = screen->sel;
391 file->id = screen->sel->id;
392 file->tab = *dir;
393 file->tab.name = estrdup("sel");
394 }if(name) goto LastItem;
395 }
396 for(v=view; v; v=v->next) {
397 if(!name || !strcmp(name, v->name)) {
398 file = get_file();
399 *last = file;
400 last = &file->next;
401 file->volatil = True;
402 file->p.view = v;
403 file->id = v->id;
404 file->tab = *dir;
405 file->tab.name = estrdup(v->name);
406 if(name) goto LastItem;
407 }
408 }
409 break;
410 case FsDBars:
411 for(b=*parent->p.bar_p; b; b=b->next) {
412 if(!name || !strcmp(name, b->name)) {
413 file = get_file();
414 *last = file;
415 last = &file->next;
416 file->volatil = True;
417 file->p.bar = b;
418 file->id = b->id;
419 file->tab = *dir;
420 file->tab.name = estrdup(b->name);
421 if(name) goto LastItem;
422 }
423 }
424 break;
425 }
426 }else /* Static dirs */
427 if(!name || !strcmp(name, dir->name)) {
428 file = get_file();
429 *last = file;
430 last = &file->next;
431 file->id = 0;
432 file->p.ref = parent->p.ref;
433 file->index = parent->index;
434 file->tab = *dir;
435 file->tab.name = estrdup(file->tab.name);
436 /* Special considerations: */
437 switch(file->tab.type) {
438 case FsDBars:
439 if(!strcmp(file->tab.name, "lbar"))
440 file->p.bar_p = &screen[0].bar[BarLeft];
441 else
442 file->p.bar_p = &screen[0].bar[BarRight];
443 break;
444 case FsFColRules:
445 file->p.rule = &def.colrules;
446 break;
447 case FsFTagRules:
448 file->p.rule = &def.tagrules;
449 break;
450 }
451 if(name) goto LastItem;
452 }
453 NextItem:
454 continue;
455 }
456 LastItem:
457 *last = nil;
458 return ret;
459 }
460
461 static Bool
verify_file(FileId * f)462 verify_file(FileId *f) {
463 FileId *nf;
464 int ret;
465
466 if(!f->next)
467 return True;
468
469 ret = False;
470 if(verify_file(f->next)) {
471 nf = lookup_file(f->next, f->tab.name);
472 if(nf) {
473 if(!nf->volatil || nf->p.ref == f->p.ref)
474 ret = True;
475 free_file(nf);
476 }
477 }
478 return ret;
479 }
480
481 /* Service Functions */
482 void
fs_attach(Ixp9Req * r)483 fs_attach(Ixp9Req *r) {
484 FileId *f = get_file();
485 f->tab = dirtab[FsRoot][0];
486 f->tab.name = estrdup("/");
487 f->p.ref = nil;
488 r->fid->aux = f;
489 r->fid->qid.type = f->tab.qtype;
490 r->fid->qid.path = QID(f->tab.type, 0);
491 r->ofcall.qid = r->fid->qid;
492 respond(r, nil);
493 }
494
495 void
fs_walk(Ixp9Req * r)496 fs_walk(Ixp9Req *r) {
497 FileId *f, *nf;
498 int i;
499
500 f = r->fid->aux;
501 clone_files(f);
502 for(i=0; i < r->ifcall.nwname; i++) {
503 if(!strcmp(r->ifcall.wname[i], "..")) {
504 if(f->next) {
505 nf=f;
506 f=f->next;
507 free_file(nf);
508 }
509 }else{
510 nf = lookup_file(f, r->ifcall.wname[i]);
511 if(!nf)
512 break;
513 assert(!nf->next);
514 if(strcmp(r->ifcall.wname[i], ".")) {
515 nf->next = f;
516 f = nf;
517 }
518 }
519 r->ofcall.wqid[i].type = f->tab.qtype;
520 r->ofcall.wqid[i].path = QID(f->tab.type, f->id);
521 }
522 /* There should be a way to do this on freefid() */
523 if(i < r->ifcall.nwname) {
524 while((nf = f)) {
525 f=f->next;
526 free_file(nf);
527 }
528 respond(r, Enofile);
529 return;
530 }
531 /* Remove refs for r->fid if no new fid */
532 if(r->ifcall.fid == r->ifcall.newfid) {
533 nf = r->fid->aux;
534 r->fid->aux = f;
535 while((f = nf)) {
536 nf = nf->next;
537 free_file(f);
538 }
539 }else
540 r->newfid->aux = f;
541 r->ofcall.nwqid = i;
542 respond(r, nil);
543 }
544
545 static uint
fs_size(FileId * f)546 fs_size(FileId *f) {
547 switch(f->tab.type) {
548 default:
549 return 0;
550 case FsFColRules:
551 case FsFTagRules:
552 return f->p.rule->size;
553 case FsFKeys:
554 return def.keyssz;
555 case FsFCtags:
556 return strlen(f->p.client->tags);
557 case FsFClabel:
558 return strlen(f->p.client->name);
559 case FsFprops:
560 return strlen(f->p.client->props);
561 }
562 }
563
564 void
fs_stat(Ixp9Req * r)565 fs_stat(Ixp9Req *r) {
566 IxpMsg m;
567 Stat s;
568 int size;
569 uchar *buf;
570 FileId *f;
571
572 f = r->fid->aux;
573
574 if(!verify_file(f)) {
575 respond(r, Enofile);
576 return;
577 }
578
579 dostat(&s, fs_size(f), f);
580 r->ofcall.nstat = size = ixp_sizeof_stat(&s);
581 buf = emallocz(size);
582
583 m = ixp_message(buf, size, MsgPack);
584 ixp_pstat(&m, &s);
585
586 r->ofcall.stat = m.data;
587 respond(r, nil);
588 }
589
590 void
fs_read(Ixp9Req * r)591 fs_read(Ixp9Req *r) {
592 char *buf;
593 FileId *f, *tf;
594 int n, offset;
595 int size;
596
597 f = r->fid->aux;
598
599 if(!verify_file(f)) {
600 respond(r, Enofile);
601 return;
602 }
603
604 if(f->tab.perm & DMDIR && f->tab.perm & 0400) {
605 Stat s;
606 IxpMsg m;
607
608 offset = 0;
609 size = r->ifcall.count;
610 buf = emallocz(size);
611 m = ixp_message((uchar*)buf, size, MsgPack);
612
613 tf = f = lookup_file(f, nil);
614 /* Note: f->tab.name == "." so we skip it */
615 for(f=f->next; f; f=f->next) {
616 dostat(&s, fs_size(f), f);
617 n = ixp_sizeof_stat(&s);
618 if(offset >= r->ifcall.offset) {
619 if(size < n)
620 break;
621 ixp_pstat(&m, &s);
622 size -= n;
623 }
624 offset += n;
625 }
626 while((f = tf)) {
627 tf=tf->next;
628 free_file(f);
629 }
630 r->ofcall.count = r->ifcall.count - size;
631 r->ofcall.data = (char*)m.data;
632 respond(r, nil);
633 return;
634 }
635 else{
636 switch(f->tab.type) {
637 case FsFprops:
638 write_buf(r, f->p.client->props, strlen(f->p.client->props));
639 respond(r, nil);
640 return;
641 case FsFColRules:
642 case FsFTagRules:
643 write_buf(r, f->p.rule->string, f->p.rule->size);
644 respond(r, nil);
645 return;
646 case FsFKeys:
647 write_buf(r, def.keys, def.keyssz);
648 respond(r, nil);
649 return;
650 case FsFCtags:
651 write_buf(r, f->p.client->tags, strlen(f->p.client->tags));
652 respond(r, nil);
653 return;
654 case FsFClabel:
655 write_buf(r, f->p.client->name, strlen(f->p.client->name));
656 respond(r, nil);
657 return;
658 case FsFBar:
659 write_buf(r, f->p.bar->buf, strlen(f->p.bar->buf));
660 respond(r, nil);
661 return;
662 case FsFRctl:
663 buf = read_root_ctl();
664 write_buf(r, buf, strlen(buf));
665 respond(r, nil);
666 return;
667 case FsFCctl:
668 if(r->ifcall.offset) {
669 respond(r, nil);
670 return;
671 }
672 r->ofcall.data = smprint("%C", f->p.client);
673 r->ofcall.count = strlen(r->ofcall.data); /* will die if nil */
674 respond(r, nil);
675 return;
676 case FsFTindex:
677 buf = (char*)view_index(f->p.view);
678 n = strlen(buf);
679 write_buf(r, buf, n);
680 respond(r, nil);
681 return;
682 case FsFTctl:
683 buf = (char*)view_ctl(f->p.view);
684 n = strlen(buf);
685 write_buf(r, buf, n);
686 respond(r, nil);
687 return;
688 case FsFEvent:
689 respond_event(r);
690 return;
691 }
692 }
693 /*
694 * This is an assert because this should this should not be called if
695 * the file is not open for reading.
696 */
697 assert(!"Read called on an unreadable file");
698 }
699
700 void
fs_write(Ixp9Req * r)701 fs_write(Ixp9Req *r) {
702 FileId *f;
703 char *errstr;
704 uint i;
705
706 if(r->ifcall.count == 0) {
707 respond(r, nil);
708 return;
709 }
710 f = r->fid->aux;
711
712 if(!verify_file(f)) {
713 respond(r, Enofile);
714 return;
715 }
716
717 switch(f->tab.type) {
718 case FsFColRules:
719 case FsFTagRules:
720 write_to_buf(r, &f->p.rule->string, &f->p.rule->size, 0);
721 respond(r, nil);
722 return;
723 case FsFKeys:
724 write_to_buf(r, &def.keys, &def.keyssz, 0);
725 respond(r, nil);
726 return;
727 case FsFClabel:
728 data_to_cstring(r);
729 utfecpy(f->p.client->name, f->p.client->name+sizeof(client->name), r->ifcall.data);
730 draw_frame(f->p.client->sel);
731 update_class(f->p.client);
732 r->ofcall.count = r->ifcall.count;
733 respond(r, nil);
734 return;
735 case FsFCtags:
736 data_to_cstring(r);
737 apply_tags(f->p.client, r->ifcall.data);
738 r->ofcall.count = r->ifcall.count;
739 respond(r, nil);
740 return;
741 case FsFBar:
742 i = strlen(f->p.bar->buf);
743 write_to_buf(r, f->p.bar->buf, &i, 279);
744 r->ofcall.count = i - r->ifcall.offset;
745 respond(r, nil);
746 return;
747 case FsFCctl:
748 errstr = message(r, (MsgFunc)message_client);
749 r->ofcall.count = r->ifcall.count;
750 respond(r, errstr);
751 return;
752 case FsFTctl:
753 errstr = message(r, (MsgFunc)message_view);
754 r->ofcall.count = r->ifcall.count;
755 respond(r, errstr);
756 return;
757 case FsFRctl:
758 errstr = message(r, (MsgFunc)message_root);
759 r->ofcall.count = r->ifcall.count;
760 respond(r, errstr);
761 return;
762 case FsFEvent:
763 if(r->ifcall.data[r->ifcall.count-1] == '\n')
764 write_event("%.*s", r->ifcall.count, r->ifcall.data);
765 else
766 write_event("%.*s\n", r->ifcall.count, r->ifcall.data);
767 r->ofcall.count = r->ifcall.count;
768 respond(r, nil);
769 return;
770 }
771 /*
772 * This is an assert because this function should not be called if
773 * the file is not open for writing.
774 */
775 assert(!"Write called on an unwritable file");
776 }
777
778 void
fs_open(Ixp9Req * r)779 fs_open(Ixp9Req *r) {
780 FidLink *fl;
781 FileId *f = r->fid->aux;
782
783 if(!verify_file(f)) {
784 respond(r, Enofile);
785 return;
786 }
787
788 switch(f->tab.type) {
789 case FsFEvent:
790 fl = emallocz(sizeof(FidLink));
791 fl->fid = r->fid;
792 fl->next = peventfid;
793 peventfid = fl;
794 break;
795 }
796 if((r->ifcall.mode&3) == OEXEC) {
797 respond(r, Enoperm);
798 return;
799 }
800 if((r->ifcall.mode&3) != OREAD && !(f->tab.perm & 0200)) {
801 respond(r, Enoperm);
802 return;
803 }
804 if((r->ifcall.mode&3) != OWRITE && !(f->tab.perm & 0400)) {
805 respond(r, Enoperm);
806 return;
807 }
808 if((r->ifcall.mode&~(3|OAPPEND|OTRUNC))) {
809 respond(r, Enoperm);
810 return;
811 }
812 respond(r, nil);
813 }
814
815 void
fs_create(Ixp9Req * r)816 fs_create(Ixp9Req *r) {
817 FileId *f = r->fid->aux;
818
819 switch(f->tab.type) {
820 default:
821 respond(r, Enoperm);
822 return;
823 case FsDBars:
824 if(!strlen(r->ifcall.name)) {
825 respond(r, Ebadvalue);
826 return;
827 }
828 create_bar(f->p.bar_p, r->ifcall.name);
829 f = lookup_file(f, r->ifcall.name);
830 if(!f) {
831 respond(r, Enofile);
832 return;
833 }
834 r->ofcall.qid.type = f->tab.qtype;
835 r->ofcall.qid.path = QID(f->tab.type, f->id);
836 f->next = r->fid->aux;
837 r->fid->aux = f;
838 respond(r, nil);
839 break;
840 }
841 }
842
843 void
fs_remove(Ixp9Req * r)844 fs_remove(Ixp9Req *r) {
845 FileId *f = r->fid->aux;
846
847 if(!verify_file(f)) {
848 respond(r, Enofile);
849 return;
850 }
851
852
853 switch(f->tab.type) {
854 default:
855 respond(r, Enoperm);
856 return;
857 case FsFBar:
858 destroy_bar(f->next->p.bar_p, f->p.bar);
859 draw_bar(screen);
860 respond(r, nil);
861 break;
862 }
863 }
864
865 void
fs_clunk(Ixp9Req * r)866 fs_clunk(Ixp9Req *r) {
867 FidLink **fl, *ft;
868 FileId *f;
869 char *p, *q;
870 Client *c;
871 IxpMsg m;
872
873 f = r->fid->aux;
874 if(!verify_file(f)) {
875 respond(r, nil);
876 return;
877 }
878
879 switch(f->tab.type) {
880 case FsFColRules:
881 update_rules(&f->p.rule->rule, f->p.rule->string);
882 break;
883 case FsFTagRules:
884 update_rules(&f->p.rule->rule, f->p.rule->string);
885 for(c=client; c; c=c->next)
886 apply_rules(c);
887 update_views();
888 break;
889 case FsFKeys:
890 update_keys();
891 break;
892 case FsFBar:
893 p = toutf8(f->p.bar->buf);
894
895 m = ixp_message((uchar*)p, strlen(p), 0);
896 parse_colors(&m, &f->p.bar->col);
897
898 q = (char*)m.end-1;
899 while(q >= (char*)m.pos && *q == '\n')
900 *q-- = '\0';
901
902 q = f->p.bar->text;
903 utflcpy(q, (char*)m.pos, sizeof(((Bar*)0)->text));
904
905 free(p);
906
907 draw_bar(screen);
908 break;
909 case FsFEvent:
910 for(fl=&peventfid; *fl; fl=&(*fl)->next)
911 if((*fl)->fid == r->fid) {
912 ft = *fl;
913 *fl = (*fl)->next;
914 f = ft->fid->aux;
915 free(f->p.buf);
916 free(ft);
917 break;
918 }
919 break;
920 }
921 respond(r, nil);
922 }
923
924 void
fs_flush(Ixp9Req * r)925 fs_flush(Ixp9Req *r) {
926 Ixp9Req **i, **j;
927
928 for(i=&peventread; i != &oeventread; i=&oeventread)
929 for(j=i; *j; j=(Ixp9Req**)&(*j)->aux)
930 if(*j == r->oldreq) {
931 *j = (*j)->aux;
932 respond(r->oldreq, Einterrupted);
933 goto done;
934 }
935 done:
936 respond(r, nil);
937 }
938
939 void
fs_freefid(Fid * f)940 fs_freefid(Fid *f) {
941 FileId *id, *tid;
942
943 tid = f->aux;
944 while((id = tid)) {
945 tid = id->next;
946 free_file(id);
947 }
948 }
949