1 #include <lib9.h>
2 #include <styx.h>
3 #include "styxserver.h"
4 #include "styxaux.h"
5
6 #define MAXSTAT 512
7 #define EMSGLEN 256 /* %r */
8
9 #define TABSZ 32 /* power of 2 */
10
11 static unsigned long boottime;
12 static char* eve = "inferno";
13 static int Debug = 0;
14
15 char Enomem[] = "out of memory";
16 char Eperm[] = "permission denied";
17 char Enodev[] = "no free devices";
18 char Ehungup[] = "write to hungup channel";
19 char Eexist[] = "file exists";
20 char Enonexist[] = "file does not exist";
21 char Ebadcmd[] = "bad command";
22 char Ebadarg[] = "bad arg in system call";
23 char Enofid[] = "no such fid";
24 char Enotdir[] = "not a directory";
25 char Eopen[] = "already open";
26 char Ebadfid[] = "bad fid";
27
28 /* client state */
29 enum{
30 CDISC = 01,
31 CNREAD = 02,
32 CRECV = 04,
33 };
34
35 typedef struct Walkqid Walkqid;
36
37 struct Fid
38 {
39 Client *client;
40 Fid *next;
41 short fid;
42 ushort open;
43 ushort mode; /* read/write */
44 ulong offset; /* in file */
45 int dri; /* dirread index */
46 Qid qid;
47 };
48
49 struct Walkqid
50 {
51 Fid *clone;
52 int nqid;
53 Qid qid[1];
54 };
55
56 #define ASSERT(A,B) styxassert((int)A,B)
57
58 static int hash(Path);
59 static void deletefids(Client *);
60
61 static void
styxfatal(char * fmt,...)62 styxfatal(char *fmt, ...)
63 {
64 char buf[1024], *out;
65 va_list arg;
66 out = seprint(buf, buf+sizeof(buf), "Fatal error: ");
67 va_start(arg, fmt);
68 out = vseprint(out, buf+sizeof(buf), fmt, arg);
69 va_end(arg);
70 write(2, buf, out-buf);
71 styxexit(1);
72 }
73
74 static void
styxassert(int vtrue,char * reason)75 styxassert(int vtrue, char *reason)
76 {
77 if(!vtrue)
78 styxfatal("assertion failed: %s\n", reason);
79 }
80
81 void *
styxmalloc(int bytes)82 styxmalloc(int bytes)
83 {
84 char *m = malloc(bytes);
85 if(m == nil)
86 styxfatal(Enomem);
87 memset(m, 0, bytes);
88 return m;
89 }
90
91 void
styxfree(void * p)92 styxfree(void *p)
93 {
94 free(p);
95 }
96
97 void
styxdebug()98 styxdebug()
99 {
100 Debug = 1;
101 }
102
103 static Client *
newclient(Styxserver * server,int fd)104 newclient(Styxserver *server, int fd)
105 {
106 Client *c = (Client *)styxmalloc(sizeof(Client));
107
108 if(Debug)
109 fprint(2, "New client at %lux\n", (ulong)c);
110 c->server = server;
111 c->fd = fd;
112 c->nread = 0;
113 c->nc = 0;
114 c->state = 0;
115 c->fids = nil;
116 c->uname = strdup(eve);
117 c->aname = strdup("");
118 c->next = server->clients;
119 server->clients = c;
120 if(server->ops->newclient)
121 server->ops->newclient(c);
122 return c;
123 }
124
125 static void
freeclient(Client * c)126 freeclient(Client *c)
127 {
128 Client **p;
129 Styxserver *server;
130
131 if(Debug)
132 fprint(2, "Freeing client at %lux\n", (ulong)c);
133 server = c->server;
134 if(server->ops->freeclient)
135 server->ops->freeclient(c);
136 for(p = &server->clients; *p; p = &(*p)->next)
137 if(*p == c){
138 styxclosesocket(c->fd);
139 *p = c->next;
140 deletefids(c);
141 free(c->uname);
142 free(c->aname);
143 styxfree(c);
144 return;
145 }
146 }
147
148 static int
nbread(Client * c,int nr)149 nbread(Client *c, int nr)
150 {
151 int nb;
152
153 if(c->state&CDISC)
154 return -1;
155 nb = styxrecv(c->server, c->fd, c->msg + c->nread, nr, 0);
156 if(nb <= 0){
157 c->nread = 0;
158 c->state |= CDISC;
159 return -1;
160 }
161 c->nread += nb;
162 return 0;
163 }
164
165 static int
rd(Client * c,Fcall * r)166 rd(Client *c, Fcall *r)
167 {
168 if(c->nc > 0){ /* last convM2S consumed nc bytes */
169 c->nread -= c->nc;
170 if((int)c->nread < 0){
171 r->ename = "negative size in rd";
172 return -1;
173 }
174 memmove(c->msg, c->msg+c->nc, c->nread);
175 c->nc = 0;
176 }
177 if(c->state&CRECV){
178 if(nbread(c, MSGMAX - c->nread) != 0){
179 r->ename = "unexpected EOF";
180 return -1;
181 }
182 c->state &= ~CRECV;
183 }
184 c->nc = convM2S((uchar*)(c->msg), c->nread, r);
185 if(c->nc < 0){
186 r->ename = "bad message format";
187 return -1;
188 }
189 if(c->nc == 0 && c->nread > 0){
190 c->nread = 0;
191 c->state &= ~CNREAD;
192 return 0;
193 }
194 if(c->nread > c->nc)
195 c->state |= CNREAD;
196 else
197 c->state &= ~CNREAD;
198 if(c->nc == 0)
199 return 0;
200 /* fprint(2, "rd: %F\n", r); */
201 return 1;
202 }
203
204 static int
wr(Client * c,Fcall * r)205 wr(Client *c, Fcall *r)
206 {
207 int n;
208 char buf[MSGMAX];
209
210 n = convS2M(r, (uchar*)buf, sizeof(buf));
211 if(n < 0){
212 r->ename = "bad message type in wr";
213 return -1;
214 }
215 /* fprint(2, "wr: %F\n", r); */
216 return styxsend(c->server, c->fd, buf, n, 0);
217 }
218
219 static void
sremove(Styxserver * server,Styxfile * f)220 sremove(Styxserver *server, Styxfile *f)
221 {
222 Styxfile *s, *next, **p;
223
224 if(f == nil)
225 return;
226 if(Debug)
227 fprint(2, "Remove file %s Qid=%llx\n", f->d.name, f->d.qid.path);
228 if(f->d.qid.type&QTDIR)
229 for(s = f->child; s != nil; s = next){
230 next = s->sibling;
231 sremove(server, s);
232 }
233 for(p = &server->ftab[hash(f->d.qid.path)]; *p; p = &(*p)->next)
234 if(*p == f){
235 *p = f->next;
236 break;
237 }
238 for(p = &f->parent->child; *p; p = &(*p)->sibling)
239 if(*p == f){
240 *p = f->sibling;
241 break;
242 }
243 styxfree(f->d.name);
244 styxfree(f->d.uid);
245 styxfree(f->d.gid);
246 styxfree(f);
247 }
248
249 int
styxrmfile(Styxserver * server,Path qid)250 styxrmfile(Styxserver *server, Path qid)
251 {
252 Styxfile *f;
253
254 f = styxfindfile(server, qid);
255 if(f != nil){
256 if(f->parent == nil)
257 return -1;
258 sremove(server, f);
259 return 0;
260 }
261 return -1;
262 }
263
264 static void
incref(Styxfile * f)265 incref(Styxfile *f)
266 {
267 if(f != nil)
268 f->ref++;
269 }
270
271 static void
decref(Styxfile * f)272 decref(Styxfile *f)
273 {
274 if(f != nil)
275 --f->ref;
276 }
277
278 static void
increff(Fid * f)279 increff(Fid *f)
280 {
281 incref(styxfindfile(f->client->server, f->qid.path));
282 }
283
284 static void
decreff(Fid * f)285 decreff(Fid *f)
286 {
287 decref(styxfindfile(f->client->server, f->qid.path));
288 }
289
290 static void
incopen(Fid * f)291 incopen(Fid *f)
292 {
293 Styxfile *file;
294
295 if(f->open && (file = styxfindfile(f->client->server, f->qid.path)) != nil)
296 file->open++;
297 }
298
299 static void
decopen(Fid * f)300 decopen(Fid *f)
301 {
302 Styxfile *file;
303
304 if(f->open && (file = styxfindfile(f->client->server, f->qid.path)) != nil)
305 file->open--;
306 }
307
308 int
styxperm(Styxfile * f,char * uid,int mode)309 styxperm(Styxfile *f, char *uid, int mode)
310 {
311 int m, p;
312
313 p = 0;
314 switch(mode&3){
315 case OREAD: p = AREAD; break;
316 case OWRITE: p = AWRITE; break;
317 case ORDWR: p = AREAD+AWRITE; break;
318 case OEXEC: p = AEXEC; break;
319 }
320 if(mode&OTRUNC)
321 p |= AWRITE;
322 m = f->d.mode&7;
323 if((p&m) == p)
324 return 1;
325 if(strcmp(f->d.uid, uid) == 0){
326 m |= (f->d.mode>>6)&7;
327 if((p&m) == p)
328 return 1;
329 }
330 if(strcmp(f->d.gid, uid) == 0){
331 m |= (f->d.mode>>3)&7;
332 if((p&m) == p)
333 return 1;
334 }
335 return 0;
336 }
337
338 static int
hash(Path path)339 hash(Path path)
340 {
341 return path&(TABSZ-1);
342 }
343
344 Styxfile *
styxfindfile(Styxserver * server,Path path)345 styxfindfile(Styxserver *server, Path path)
346 {
347 Styxfile *f;
348
349 for(f = server->ftab[hash(path)]; f != nil; f = f->next){
350 if(f->d.qid.path == path)
351 return f;
352 }
353 return nil;
354 }
355
356 static Fid *
findfid(Client * c,short fid)357 findfid(Client *c, short fid)
358 {
359 Fid *f;
360 for(f = c->fids; f && f->fid != fid; f = f->next)
361 ;
362 return f;
363 }
364
365 static void
deletefid(Client * c,Fid * d)366 deletefid(Client *c, Fid *d)
367 {
368 /* TODO: end any outstanding reads on this fid */
369 Fid **f;
370
371 for(f = &c->fids; *f; f = &(*f)->next)
372 if(*f == d){
373 decreff(d);
374 decopen(d);
375 *f = d->next;
376 styxfree(d);
377 return;
378 }
379 }
380
381 static void
deletefids(Client * c)382 deletefids(Client *c)
383 {
384 Fid *f, *g;
385
386 for(f = c->fids; f; f = g){
387 decreff(f);
388 decopen(f);
389 g = f->next;
390 styxfree(f);
391 }
392 }
393
394 Fid *
newfid(Client * c,short fid,Qid qid)395 newfid(Client *c, short fid, Qid qid){
396 Fid *f;
397
398 f = styxmalloc(sizeof(Fid));
399 ASSERT(f, "newfid");
400 f->client = c;
401 f->fid = fid;
402 f->open = 0;
403 f->dri = 0;
404 f->qid = qid;
405 f->next = c->fids;
406 c->fids = f;
407 increff(f);
408 return f;
409 }
410
411 static void
flushtag(int oldtag)412 flushtag(int oldtag)
413 {
414 USED(oldtag);
415 }
416
417 int
eqqid(Qid a,Qid b)418 eqqid(Qid a, Qid b)
419 {
420 return a.path == b.path && a.vers == b.vers;
421 }
422
423 static Fid *
fidclone(Fid * old,short fid)424 fidclone(Fid *old, short fid)
425 {
426 Fid *new;
427
428 new = newfid(old->client, fid, old->qid);
429 return new;
430 }
431
432 static Walkqid*
devwalk(Client * c,Styxfile * file,Fid * fp,Fid * nfp,char ** name,int nname,char ** err)433 devwalk(Client *c, Styxfile *file, Fid *fp, Fid *nfp, char **name, int nname, char **err)
434 {
435 Styxserver *server;
436 long j;
437 Walkqid *wq;
438 char *n;
439 Styxfile *p, *f;
440 Styxops *ops;
441 Qid qid;
442
443 *err = nil;
444 server = c->server;
445 ops = server->ops;
446
447 wq = styxmalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
448 wq->nqid = 0;
449
450 p = file;
451 qid = p != nil ? p->d.qid : fp->qid;
452 for(j = 0; j < nname; j++){
453 if(!(qid.type&QTDIR)){
454 if(j == 0)
455 styxfatal("devwalk error");
456 *err = Enotdir;
457 goto Done;
458 }
459 if(p != nil && !styxperm(p, c->uname, OEXEC)){
460 *err = Eperm;
461 goto Done;
462 }
463 n = name[j];
464 if(strcmp(n, ".") == 0){
465 Accept:
466 wq->qid[wq->nqid++] = nfp->qid;
467 continue;
468 }
469 if(p != nil && strcmp(n, "..") == 0 && p->parent){
470 decref(p);
471 nfp->qid.path = p->parent->d.qid.path;
472 nfp->qid.type = p->parent->d.qid.type;
473 nfp->qid.vers = 0;
474 incref(p->parent);
475 p = p->parent;
476 qid = p->d.qid;
477 goto Accept;
478 }
479
480 if(ops->walk != nil){
481 char *e;
482
483 e = ops->walk(&qid, n);
484 if(e == nil){
485 decreff(nfp);
486 nfp->qid = qid;
487 increff(nfp);
488 p = styxfindfile(server, qid.path);
489 if(server->needfile && p == nil)
490 goto Done;
491 qid = p != nil ? p->d.qid : nfp->qid;
492 goto Accept;
493 }
494 }
495
496 if(p != nil)
497 for(f = p->child; f != nil; f = f->sibling){
498 if(strcmp(n, f->d.name) == 0){
499 decref(p);
500 nfp->qid.path = f->d.qid.path;
501 nfp->qid.type = f->d.qid.type;
502 nfp->qid.vers = 0;
503 incref(f);
504 p = f;
505 qid = p->d.qid;
506 goto Accept;
507 }
508 }
509 if(j == 0 && *err == nil)
510 *err = Enonexist;
511 goto Done;
512 }
513 Done:
514 if(*err != nil){
515 styxfree(wq);
516 return nil;
517 }
518 return wq;
519 }
520
521 static long
devdirread(Fid * fp,Styxfile * file,char * d,long n)522 devdirread(Fid *fp, Styxfile *file, char *d, long n)
523 {
524 long dsz, m;
525 Styxfile *f;
526 int i;
527
528 struct{
529 Dir d;
530 char slop[100]; /* TO DO */
531 }dir;
532
533 f = file->child;
534 for(i = 0; i < fp->dri; i++)
535 if(f == 0)
536 return 0;
537 else
538 f = f->sibling;
539 for(m = 0; m < n; fp->dri++){
540 if(f == nil)
541 break;
542 dir.d = f->d;
543 dsz = convD2M(&dir.d, (uchar*)d, n-m);
544 m += dsz;
545 d += dsz;
546 f = f->sibling;
547 }
548
549 return m;
550 }
551
552 static char*
nilconv(char * s)553 nilconv(char *s)
554 {
555 if(s != nil && s[0] == '\0')
556 return nil;
557 return s;
558 }
559
560 static Styxfile *
newfile(Styxserver * server,Styxfile * parent,int isdir,Path qid,char * name,int mode,char * owner)561 newfile(Styxserver *server, Styxfile *parent, int isdir, Path qid, char *name, int mode, char *owner)
562 {
563 Styxfile *file;
564 Dir d;
565 int h;
566
567 if(qid == -1)
568 qid = server->qidgen++;
569 file = styxfindfile(server, qid);
570 if(file != nil)
571 return nil;
572 if(parent != nil){
573 for(file = parent->child; file != nil; file = file->sibling)
574 if(strcmp(name, file->d.name) == 0)
575 return nil;
576 }
577 file = (Styxfile *)styxmalloc(sizeof(Styxfile));
578 file->parent = parent;
579 file->child = nil;
580 h = hash(qid);
581 file->next = server->ftab[h];
582 server->ftab[h] = file;
583 if(parent){
584 file->sibling = parent->child;
585 parent->child = file;
586 }else
587 file->sibling = nil;
588
589 d.type = 'X';
590 d.dev = 'x';
591 d.qid.path = qid;
592 d.qid.type = 0;
593 d.qid.vers = 0;
594 d.mode = mode;
595 d.atime = time(0);
596 d.mtime = boottime;
597 d.length = 0;
598 d.name = strdup(name);
599 d.uid = strdup(owner);
600 d.gid = strdup(eve);
601 d.muid = "";
602
603 if(isdir){
604 d.qid.type |= QTDIR;
605 d.mode |= DMDIR;
606 }
607 else{
608 d.qid.type &= ~QTDIR;
609 d.mode &= ~DMDIR;
610 }
611
612 file->d = d;
613 file->ref = 0;
614 file->open = 0;
615 if(Debug)
616 fprint(2, "New file %s Qid=%llx\n", name, qid);
617 return file;
618 }
619
620 static void
run(Client * c)621 run(Client *c)
622 {
623 Fcall f;
624 Fid *fp, *nfp;
625 int i, open, mode;
626 char ebuf[EMSGLEN];
627 Walkqid *wq;
628 Styxfile *file;
629 Dir dir;
630 Qid qid;
631 Styxops *ops;
632 char strs[128];
633
634 ebuf[0] = 0;
635 if(rd(c, &f) <= 0)
636 return;
637 if(f.type == Tflush){
638 flushtag(f.oldtag);
639 f.type = Rflush;
640 wr(c, &f);
641 return;
642 }
643 ops = c->server->ops;
644 file = nil;
645 fp = findfid(c, f.fid);
646 if(f.type != Tversion && f.type != Tauth && f.type != Tattach){
647 if(fp == nil){
648 f.type = Rerror;
649 f.ename = Enofid;
650 wr(c, &f);
651 return;
652 }
653 else{
654 file = styxfindfile(c->server, fp->qid.path);
655 if(c->server->needfile && file == nil){
656 f.type = Rerror;
657 f.ename = Enonexist;
658 wr(c, &f);
659 return;
660 }
661 }
662 }
663 /* if(fp == nil) fprint(2, "fid not found for %d\n", f.fid); */
664 switch(f.type){
665 case Twalk:
666 if(Debug){
667 fprint(2, "Twalk %d %d", f.fid, f.newfid);
668 for(i = 0; i < f.nwname; i++)
669 fprint(2, " %s", f.wname[i]);
670 fprint(2, "\n");
671 }
672 nfp = findfid(c, f.newfid);
673 f.type = Rerror;
674 if(nfp){
675 deletefid(c, nfp);
676 nfp = nil;
677 }
678 if(nfp){
679 f.ename = "fid in use";
680 if(Debug) fprint(2, "walk: %s\n", f.ename);
681 wr(c, &f);
682 break;
683 }else if(fp->open){
684 f.ename = "can't clone";
685 wr(c, &f);
686 break;
687 }
688 if(f.newfid != f.fid)
689 nfp = fidclone(fp, f.newfid);
690 else
691 nfp = fp;
692 if((wq = devwalk(c, file, fp, nfp, f.wname, f.nwname, &f.ename)) == nil){
693 if(nfp != fp)
694 deletefid(c, nfp);
695 f.type = Rerror;
696 }else{
697 if(nfp != fp){
698 if(wq->nqid != f.nwname)
699 deletefid(c, nfp);
700 }
701 f.type = Rwalk;
702 f.nwqid = wq->nqid;
703 for(i = 0; i < wq->nqid; i++)
704 f.wqid[i] = wq->qid[i];
705 styxfree(wq);
706 }
707 wr(c, &f);
708 break;
709 case Topen:
710 if(Debug)
711 fprint(2, "Topen %d\n", f.fid);
712 f.ename = nil;
713 if(fp->open)
714 f.ename = Eopen;
715 else if((fp->qid.type&QTDIR) && (f.mode&(OWRITE|OTRUNC|ORCLOSE)))
716 f.ename = Eperm;
717 else if(file != nil && !styxperm(file, c->uname, f.mode))
718 f.ename = Eperm;
719 else if((f.mode&ORCLOSE) && file != nil && file->parent != nil && !styxperm(file->parent, c->uname, OWRITE))
720 f.ename = Eperm;
721 if(f.ename != nil){
722 f.type = Rerror;
723 wr(c, &f);
724 break;
725 }
726 f.ename = Enonexist;
727 decreff(fp);
728 if(ops->open == nil || (f.ename = ops->open(&fp->qid, f.mode)) == nil){
729 f.type = Ropen;
730 f.qid = fp->qid;
731 fp->mode = f.mode;
732 fp->open = 1;
733 fp->offset = 0;
734 incopen(fp);
735 }
736 else
737 f.type = Rerror;
738 increff(fp);
739 wr(c, &f);
740 break;
741 case Tcreate:
742 if(Debug)
743 fprint(2, "Tcreate %d %s\n", f.fid, f.name);
744 f.ename = nil;
745 if(fp->open)
746 f.ename = Eopen;
747 else if(!(fp->qid.type&QTDIR))
748 f.ename = Enotdir;
749 else if((f.perm&DMDIR) && (f.mode&(OWRITE|OTRUNC|ORCLOSE)))
750 f.ename = Eperm;
751 else if(file != nil && !styxperm(file, c->uname, OWRITE))
752 f.ename = Eperm;
753 if(f.ename != nil){
754 f.type = Rerror;
755 wr(c, &f);
756 break;
757 }
758 f.ename = Eperm;
759 decreff(fp);
760 if(file != nil){
761 if(f.perm&DMDIR)
762 f.perm = (f.perm&~0777) | (file->d.mode&f.perm&0777) | DMDIR;
763 else
764 f.perm = (f.perm&(~0777|0111)) | (file->d.mode&f.perm&0666);
765 }
766 if(ops->create && (f.ename = ops->create(&fp->qid, f.name, f.perm, f.mode)) == nil){
767 f.type = Rcreate;
768 f.qid = fp->qid;
769 fp->mode = f.mode;
770 fp->open = 1;
771 fp->offset = 0;
772 incopen(fp);
773 }
774 else
775 f.type = Rerror;
776 increff(fp);
777 wr(c, &f);
778 break;
779 case Tread:
780 if(Debug)
781 fprint(2, "Tread %d\n", f.fid);
782 if(!fp->open){
783 f.type = Rerror;
784 f.ename = Ebadfid;
785 wr(c, &f);
786 break;
787 }
788 if(fp->qid.type&QTDIR || (file != nil && file->d.qid.type&QTDIR)){
789 f.type = Rread;
790 if(file == nil){
791 f.ename = Eperm;
792 if(ops->read && (f.ename = ops->read(fp->qid, c->data, (ulong*)(&f.count), fp->dri)) == nil){
793 f.data = c->data;
794 }
795 else
796 f.type = Rerror;
797 }
798 else{
799 f.count = devdirread(fp, file, c->data, f.count);
800 f.data = c->data;
801 }
802 }else{
803 f.ename = Eperm;
804 f.type = Rerror;
805 if(ops->read && (f.ename = ops->read(fp->qid, c->data, (ulong*)(&f.count), f.offset)) == nil){
806 f.type = Rread;
807 f.data = c->data;
808 }
809 }
810 wr(c, &f);
811 break;
812 case Twrite:
813 if(Debug)
814 fprint(2, "Twrite %d\n", f.fid);
815 if(!fp->open){
816 f.type = Rerror;
817 f.ename = Ebadfid;
818 wr(c, &f);
819 break;
820 }
821 f.ename = Eperm;
822 f.type = Rerror;
823 if(ops->write && (f.ename = ops->write(fp->qid, f.data, (ulong*)(&f.count), f.offset)) == nil){
824 f.type = Rwrite;
825 }
826 wr(c, &f);
827 break;
828 case Tclunk:
829 if(Debug)
830 fprint(2, "Tclunk %d\n", f.fid);
831 open = fp->open;
832 mode = fp->mode;
833 qid = fp->qid;
834 deletefid(c, fp);
835 f.type = Rclunk;
836 if(open && ops->close && (f.ename = ops->close(qid, mode)) != nil)
837 f.type = Rerror;
838 wr(c, &f);
839 break;
840 case Tremove:
841 if(Debug)
842 fprint(2, "Tremove %d\n", f.fid);
843 if(file != nil && file->parent != nil && !styxperm(file->parent, c->uname, OWRITE)){
844 f.type = Rerror;
845 f.ename = Eperm;
846 deletefid(c, fp);
847 wr(c, &f);
848 break;
849 }
850 f.ename = Eperm;
851 if(ops->remove && (f.ename = ops->remove(fp->qid)) == nil)
852 f.type = Rremove;
853 else
854 f.type = Rerror;
855 deletefid(c, fp);
856 wr(c, &f);
857 break;
858 case Tstat:
859 if(Debug)
860 fprint(2, "Tstat %d qid=%llx\n", f.fid, fp->qid.path);
861 f.stat = styxmalloc(MAXSTAT);
862 f.ename = "stat error";
863 if(ops->stat == nil && file != nil){
864 f.type = Rstat;
865 f.nstat = convD2M(&file->d, f.stat, MAXSTAT);
866 }
867 else if(ops->stat && (f.ename = ops->stat(fp->qid, &dir)) == nil){
868 f.type = Rstat;
869 f.nstat = convD2M(&dir, f.stat, MAXSTAT);
870 }
871 else
872 f.type = Rerror;
873 wr(c, &f);
874 styxfree(f.stat);
875 break;
876 case Twstat:
877 if(Debug)
878 fprint(2, "Twstat %d\n", f.fid);
879 f.ename = Eperm;
880 convM2D(f.stat, f.nstat, &dir, strs);
881 dir.name = nilconv(dir.name);
882 dir.uid = nilconv(dir.uid);
883 dir.gid = nilconv(dir.gid);
884 dir.muid = nilconv(dir.muid);
885 if(ops->wstat && (f.ename = ops->wstat(fp->qid, &dir)) == nil)
886 f.type = Rwstat;
887 else
888 f.type = Rerror;
889 wr(c, &f);
890 break;
891 case Tversion:
892 if(Debug)
893 fprint(2, "Tversion\n");
894 f.type = Rversion;
895 f.tag = NOTAG;
896 wr(c, &f);
897 break;
898 case Tauth:
899 if(Debug)
900 fprint(2, "Tauth\n");
901 f.type = Rauth;
902 wr(c, &f);
903 break;
904 case Tattach:
905 if(Debug)
906 fprint(2, "Tattach %d %s %s\n", f.fid, f.uname[0] ? f.uname : c->uname, f.aname[0]? f.aname: c->aname);
907 if(fp){
908 f.type = Rerror;
909 f.ename = "fid in use";
910 }else{
911 Qid q;
912
913 if(f.uname[0]){
914 free(c->uname);
915 c->uname = strdup(f.uname);
916 }
917 if(f.aname[0]){
918 free(c->aname);
919 c->aname = strdup(f.aname);
920 }
921 q.path = Qroot;
922 q.type = QTDIR;
923 q.vers = 0;
924 fp = newfid(c, f.fid, q);
925 f.type = Rattach;
926 f.fid = fp->fid;
927 f.qid = q;
928 if(ops->attach && (f.ename = ops->attach(c->uname, c->aname)) != nil)
929 f.type = Rerror;
930 }
931 wr(c, &f);
932 break;
933 }
934 }
935
936 char *
styxinit(Styxserver * server,Styxops * ops,char * port,int perm,int needfile)937 styxinit(Styxserver *server, Styxops *ops, char *port, int perm, int needfile)
938 {
939 int i;
940
941 if(Debug)
942 fprint(2, "Initialising Styx server on port %s\n", port);
943 if(perm == -1)
944 perm = 0555;
945 server->ops = ops;
946 server->clients = nil;
947 server->root = nil;
948 server->ftab = (Styxfile**)malloc(TABSZ*sizeof(Styxfile*));
949 for(i = 0; i < TABSZ; i++)
950 server->ftab[i] = nil;
951 server->qidgen = Qroot+1;
952 if(styxinitsocket() < 0)
953 return "styxinitsocket failed";
954 server->connfd = styxannounce(server, port);
955 if(server->connfd < 0)
956 return "can't announce on network port";
957 styxinitwait(server);
958 server->root = newfile(server, nil, 1, Qroot, "/", perm|DMDIR, eve);
959 server->needfile = needfile;
960 return nil;
961 }
962
963 char*
styxend(Styxserver * server)964 styxend(Styxserver *server)
965 {
966 USED(server);
967 styxendsocket();
968 return nil;
969 }
970
971 char *
styxwait(Styxserver * server)972 styxwait(Styxserver *server)
973 {
974 return styxwaitmsg(server);
975 }
976
977 char *
styxprocess(Styxserver * server)978 styxprocess(Styxserver *server)
979 {
980 Client *c;
981 int s;
982
983 if(styxnewcall(server)){
984 s = styxaccept(server);
985 if(s >= 0){
986 newclient(server, s);
987 styxnewclient(server, s);
988 }
989 }
990 for(c = server->clients; c != nil; ){
991 Client *next = c->next;
992
993 server->curc = c;
994 if(c->fd >= 0 && styxnewmsg(server, c->fd))
995 c->state |= CRECV;
996 if(c->state&(CNREAD|CRECV)){
997 if(c->state&CDISC){
998 styxfreeclient(server, c->fd);
999 freeclient(c);
1000 }else
1001 do
1002 run(c);
1003 while(c->state&CNREAD);
1004 }
1005 c = next;
1006 }
1007
1008 return nil;
1009 }
1010
1011 Client*
styxclient(Styxserver * server)1012 styxclient(Styxserver *server)
1013 {
1014 return server->curc;
1015 }
1016
1017 Styxfile*
styxaddfile(Styxserver * server,Path pqid,Path qid,char * name,int mode,char * owner)1018 styxaddfile(Styxserver *server, Path pqid, Path qid, char *name, int mode, char *owner)
1019 {
1020 Styxfile *f, *parent;
1021
1022 parent = styxfindfile(server, pqid);
1023 if(parent == nil || (parent->d.qid.type&QTDIR) == 0)
1024 return nil;
1025 f = newfile(server, parent, 0, qid, name, mode, owner);
1026 return f;
1027 }
1028
1029 Styxfile*
styxadddir(Styxserver * server,Path pqid,Path qid,char * name,int mode,char * owner)1030 styxadddir(Styxserver *server, Path pqid, Path qid, char *name, int mode, char *owner)
1031 {
1032 Styxfile *f, *parent;
1033
1034 parent = styxfindfile(server, pqid);
1035 if(parent == nil || (parent->d.qid.type&QTDIR) == 0)
1036 return nil;
1037 f = newfile(server, parent, 1, qid, name, mode|DMDIR, owner);
1038 return f;
1039 }
1040
1041 long
styxreadstr(ulong off,char * buf,ulong n,char * str)1042 styxreadstr(ulong off, char *buf, ulong n, char *str)
1043 {
1044 int size;
1045
1046 size = strlen(str);
1047 if(off >= size)
1048 return 0;
1049 if(off+n > size)
1050 n = size-off;
1051 memmove(buf, str+off, n);
1052 return n;
1053 }
1054
1055 Qid
styxqid(int path,int isdir)1056 styxqid(int path, int isdir)
1057 {
1058 Qid q;
1059
1060 q.path = path;
1061 q.vers = 0;
1062 if(isdir)
1063 q.type = QTDIR;
1064 else
1065 q.type = 0;
1066 return q;
1067 }
1068
1069 void
styxsetowner(char * name)1070 styxsetowner(char *name)
1071 {
1072 eve = name;
1073 }
1074