]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devshr.c
mouse: fix cursor redraw to prevent screen blanking (thanks erik)
[plan9front.git] / sys / src / 9 / port / devshr.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "../port/error.h"
7
8 enum {
9         Qroot,
10         Qcroot,
11         Qshr,
12         Qcshr,
13         Qcmpt,
14 };
15
16 typedef struct Ent Ent;
17 typedef struct Shr Shr;
18 typedef struct Mpt Mpt;
19 typedef struct Sch Sch;
20
21 struct Ent
22 {
23         Ref;
24         int     id;
25         char    *name;
26         char    *owner;
27         ulong   perm;
28 };
29
30 struct Shr
31 {
32         Ent;
33         Mhead   umh;
34         Shr     *next;
35 };
36
37 struct Mpt
38 {
39         Ent;
40         Mount   m;
41 };
42
43 struct Sch
44 {
45         int     level;
46
47         Shr     *shr;
48         Mpt     *mpt;
49
50         Chan    *chan;
51 };
52
53 static QLock    shrslk;
54 static Shr      *shrs;
55
56 static int      shrid;
57 static int      mptid;
58
59 static Mpt*
60 tompt(Mount *m)
61 {
62         return (Mpt*)((char*)m - (char*)&((Mpt*)0)->m);
63 }
64
65 static Sch*
66 tosch(Chan *c)
67 {
68         Sch *sch;
69
70         if(c == nil)
71                 error("nil chan");
72         sch = c->aux;
73         if(sch == nil)
74                 error("nil chan aux");
75         if(sch->chan != c)
76                 error("bad chan");
77         return sch;
78 }
79
80 static void
81 shrinit(void)
82 {
83         shrid = 1;
84         mptid = 1;
85 }
86
87 static void
88 putmpt(Mpt *mpt)
89 {
90         if(decref(mpt))
91                 return;
92         if(mpt->m.to)
93                 cclose(mpt->m.to);
94         free(mpt->name);
95         free(mpt->owner);
96         free(mpt);
97 }
98
99 static void
100 putshr(Shr *shr)
101 {
102         if(decref(shr))
103                 return;
104         free(shr->name);
105         free(shr->owner);
106         free(shr);
107 }
108
109 static Qid
110 shrqid(int level, int id)
111 {
112         Qid q;
113
114         q.type = (level == Qcmpt) ? QTFILE : QTDIR;
115         q.path = (uvlong)id<<4 | level;
116         q.vers = 0;
117         return q;
118 }
119
120 static Chan*
121 shrattach(char *spec)
122 {
123         Sch *sch;
124         Chan *c;
125         
126         if(!(spec[0] == 'c' && spec[1] == 0 || spec[0] == 0))
127                 error(Enoattach);
128         c = devattach(L'σ', spec);
129
130         sch = smalloc(sizeof(*sch));
131         sch->level = spec[0] == 'c' ? Qcroot : Qroot;
132         sch->mpt = nil;
133         sch->shr = nil;
134         sch->chan = c;
135         c->aux = sch;
136         c->qid = shrqid(sch->level, 0);
137
138         return c;
139 }
140
141 static Chan*
142 shrclone(Chan *c)
143 {
144         Chan *nc;
145         Sch *sch, *och;
146
147         och = tosch(c);
148         nc = devclone(c);
149         sch = smalloc(sizeof(*sch));
150         memmove(sch, och, sizeof(*sch));
151         if(sch->shr)
152                 incref(sch->shr);
153         if(sch->mpt)
154                 incref(sch->mpt);
155         sch->chan = nc;
156         nc->aux = sch;
157         return nc;
158 }
159
160 static void
161 shrclunk(Chan *c)
162 {
163         Sch *sch;
164
165         sch = tosch(c);
166         c->aux = nil;
167         sch->chan = nil;
168         if(sch->mpt)
169                 putmpt(sch->mpt);
170         if(sch->shr)
171                 putshr(sch->shr);
172         free(sch);      
173 }
174
175 static Walkqid*
176 shrwalk(Chan *c, Chan *nc, char **name, int nname)
177 {
178         Walkqid *wq, *wq2;
179         int alloc, j;
180         char *nam;
181         Sch *sch;
182         Shr *shr;
183         Mpt *mpt;
184         Mount *m;
185         Mhead *h;
186         
187         alloc = 0;
188         if(nc == nil){
189                 nc = shrclone(c);
190                 alloc = 1;
191         }
192         wq = smalloc(sizeof(Walkqid) + (nname - 1) * sizeof(Qid));
193         wq->nqid = 0;
194         wq->clone = nc;
195         if(waserror()){
196                 if(alloc)
197                         cclose(wq->clone);
198                 if(wq->nqid > 0)
199                         wq->clone = nil;
200                 else {
201                         free(wq);
202                         wq = nil;
203                 }
204                 return wq;
205         }
206         sch = tosch(nc);
207         for(j = 0; j < nname; j++){
208                 if(nc->qid.type != QTDIR)
209                         error(Enotdir);
210
211                 nam = name[j];
212                 if(nam[0] == '.' && nam[1] == 0) {
213                         /* nop */
214                 } else if(nam[0] == '.' && nam[1] == '.' && nam[2] == 0) {
215                         switch(sch->level){
216                         default:
217                                 error(Egreg);
218                         case Qshr:
219                                 nc->qid = shrqid(sch->level = Qroot, 0);
220                                 break;
221                         case Qcshr:
222                                 nc->qid = shrqid(sch->level = Qcroot, 0);
223                                 break;
224                         }
225                         putshr(sch->shr);
226                         sch->shr = nil;
227                 } else if(sch->level == Qcroot || sch->level == Qroot) {
228                         qlock(&shrslk);
229                         for(shr = shrs; shr; shr = shr->next)
230                                 if(strcmp(nam, shr->name) == 0){
231                                         incref(shr);
232                                         break;
233                                 }
234                         qunlock(&shrslk);
235                         if(shr == nil)
236                                 error(Enonexist);
237                         sch->level = sch->level == Qcroot ? Qcshr : Qshr;
238                         sch->shr = shr;
239                         nc->qid = shrqid(sch->level, shr->id);
240                 } else if(sch->level == Qcshr) {
241                         mpt = nil;
242                         shr = sch->shr;
243                         h = &shr->umh;
244                         rlock(&h->lock);
245                         for(m = h->mount; m; m = m->next){
246                                 mpt = tompt(m);
247                                 if(strcmp(nam, mpt->name) == 0){
248                                         incref(mpt);
249                                         break;
250                                 }
251                         }
252                         runlock(&h->lock);
253                         if(m == nil)
254                                 error(Enonexist);
255                         sch->mpt = mpt;
256                         nc->qid = shrqid(sch->level = Qcmpt, mpt->id);
257                 } else if(sch->level == Qshr) {
258                         shr = sch->shr;
259                         h = &shr->umh;
260                         wq2 = nil;
261                         rlock(&h->lock);
262                         for(m = h->mount; m && wq2 == nil; m = m->next){
263                                 if(m->to == nil)
264                                         continue;
265                                 if(waserror())
266                                         continue;
267                                 wq2 = devtab[m->to->type]->walk(m->to, nil, name + j, nname - j);
268                                 poperror();
269                         }
270                         runlock(&h->lock);
271                         if(wq2 == nil)
272                                 error(Enonexist);
273                         memmove(wq->qid + wq->nqid, wq2->qid, wq2->nqid);
274                         wq->nqid += wq2->nqid;
275                         if(alloc)
276                                 cclose(wq->clone);
277                         wq->clone = wq2->clone;
278                         free(wq2);
279                         poperror();
280                         return wq;
281                 } else
282                         error(Egreg);
283                 wq->qid[wq->nqid++] = nc->qid;
284         }
285         poperror();
286         return wq;
287 }
288
289 static int
290 shrgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
291 {
292         Mpt *mpt;
293         Sch *sch;
294         Shr *shr;
295         Mhead *h;
296         Mount *m;
297
298         sch = tosch(c);
299         switch(sch->level){
300         default:
301                 return -1;
302         case Qroot:
303         case Qcroot:
304                 qlock(&shrslk);
305                 for(shr = shrs; shr && s; shr = shr->next)
306                         s--;
307                 if(shr == nil){
308                         qunlock(&shrslk);
309                         return -1;
310                 }
311                 kstrcpy(up->genbuf, shr->name, sizeof up->genbuf);
312                 if(sch->level == Qroot)
313                         devdir(c, shrqid(Qshr, shr->id), up->genbuf, 0, shr->owner,
314                                 shr->perm & ~0222, dp);
315                 else
316                         devdir(c, shrqid(Qcshr, shr->id), up->genbuf, 0, shr->owner,
317                                 shr->perm, dp);
318                 qunlock(&shrslk);
319                 return 1;
320         case Qcshr:
321                 shr = sch->shr;
322                 h = &shr->umh;
323                 rlock(&h->lock);
324                 for(m = h->mount; m && s; m = m->next)
325                         s--;
326                 if(m == nil){
327                         runlock(&h->lock);
328                         return -1;
329                 }
330                 mpt = tompt(m);
331                 kstrcpy(up->genbuf, mpt->name, sizeof up->genbuf);
332                 devdir(c, shrqid(Qcmpt, mpt->id), up->genbuf, 0, mpt->owner, mpt->perm, dp);
333                 runlock(&h->lock);
334                 return 1;
335         }
336 }
337
338 static int
339 shrstat(Chan *c, uchar *db, int n)
340 {
341         Sch *sch;
342         Dir dir;
343         int rc;
344
345         sch = tosch(c);
346         switch(sch->level){
347         default:
348                 error(Egreg);
349         case Qroot:
350                 devdir(c, c->qid, "#σ", 0, eve, 0555, &dir);
351                 break;
352         case Qcroot:
353                 devdir(c, c->qid, "#σc", 0, eve, 0777, &dir);
354                 break;
355         case Qshr:
356                 devdir(c, c->qid, sch->shr->name, 0, sch->shr->owner, sch->shr->perm & ~0222, &dir);
357                 break;
358         case Qcshr:
359                 devdir(c, c->qid, sch->shr->name, 0, sch->shr->owner, sch->shr->perm, &dir);
360                 break;
361         case Qcmpt:
362                 devdir(c, c->qid, sch->mpt->name, 0, sch->mpt->owner, sch->mpt->perm, &dir);
363                 break;
364         }
365         rc = convD2M(&dir, db, n);
366         if(rc == 0)
367                 error(Ebadarg);
368         return rc;
369 }
370
371 static Chan*
372 shropen(Chan *c, int omode)
373 {
374         Chan *nc;
375         Sch *sch;
376         Shr *shr;
377         Mpt *mpt;
378
379         if(c->qid.type == QTDIR && omode != OREAD)
380                 error(Eisdir);
381
382         sch = tosch(c);
383         switch(sch->level){
384         default:
385                 error(Egreg);
386         case Qroot:
387         case Qcroot:
388                 break;
389         case Qshr:
390         case Qcshr:
391                 shr = sch->shr;
392                 devpermcheck(shr->owner, shr->perm, openmode(omode));
393                 break;
394         case Qcmpt:
395                 if(omode&OTRUNC)
396                         error(Eexist);
397                 shr = sch->shr;
398                 mpt = sch->mpt;
399                 devpermcheck(mpt->owner, mpt->perm, openmode(omode));
400                 rlock(&shr->umh.lock);
401                 if(mpt->m.to == nil || mpt->m.to->mchan == nil){
402                         runlock(&shr->umh.lock);
403                         error(Eshutdown);
404                 }
405                 nc = mpt->m.to->mchan;
406                 incref(nc);
407                 runlock(&shr->umh.lock);
408                 if(openmode(omode) != nc->mode){
409                         cclose(nc);
410                         error(Eperm);
411                 }
412                 cclose(c);
413                 return nc;
414         }
415         c->mode = openmode(omode);
416         c->flag |= COPEN;
417         c->offset = 0;
418         return c;
419 }
420
421 /* chan.c */
422 Chan* createdir(Chan *c, Mhead *m);
423
424 static Chan*
425 shrcreate(Chan *c, char *name, int omode, ulong perm)
426 {
427         Sch *sch;
428         Shr *shr;
429         Mpt *mpt;
430         Mhead *h;
431         Mount *m;
432         Chan *nc;
433
434         sch = tosch(c);
435         switch(sch->level){
436         case Qcroot:
437         case Qcshr:
438                 if(strcmp(up->user, "none") == 0)
439                         error(Eperm);
440         }
441         switch(sch->level){
442         default:
443                 error(Eperm);
444         case Qshr:
445                 incref(c);
446                 if(waserror()){
447                         cclose(c);
448                         nexterror();
449                 }
450                 nc = createdir(c, &sch->shr->umh);
451                 poperror();
452                 if(waserror()){
453                         cclose(nc);
454                         nexterror();
455                 }
456                 nc = devtab[nc->type]->create(nc, name, omode, perm);
457                 poperror();
458                 cclose(c);
459                 return nc;      
460         case Qcroot:
461                 if(up->pgrp->noattach)
462                         error(Enoattach);
463                 if((perm & DMDIR) == 0 || openmode(omode) != OREAD)
464                         error(Eperm);
465                 if(strlen(name) >= sizeof(up->genbuf))
466                         error(Etoolong);
467                 qlock(&shrslk);
468                 if(waserror()){
469                         qunlock(&shrslk);
470                         nexterror();
471                 }
472                 for(shr = shrs; shr; shr = shr->next)
473                         if(strcmp(name, shr->name) == 0)
474                                 error(Eexist);
475
476                 shr = smalloc(sizeof(*shr));
477                 incref(shr);
478                 shr->id = shrid++;
479
480                 kstrdup(&shr->name, name);
481                 kstrdup(&shr->owner, up->user);
482                 shr->perm = perm;
483
484                 incref(shr);
485                 shr->next = shrs;
486                 shrs = shr;
487
488                 poperror();
489                 qunlock(&shrslk);
490
491                 c->qid = shrqid(sch->level = Qcshr, shr->id);
492                 sch->shr = shr;
493                 break;
494         case Qcshr:
495                 if(up->pgrp->noattach)
496                         error(Enoattach);
497                 if((perm & DMDIR) || openmode(omode) != OWRITE)
498                         error(Eperm);
499
500                 shr = sch->shr;
501                 if(strcmp(shr->owner, eve) == 0 && !iseve())
502                         error(Eperm);
503                 devpermcheck(shr->owner, shr->perm, ORDWR);
504
505                 if(strlen(name) >= sizeof(up->genbuf))
506                         error(Etoolong);
507
508                 h = &shr->umh;
509                 wlock(&h->lock);
510                 if(waserror()){
511                         wunlock(&h->lock);
512                         nexterror();
513                 }
514                 for(m = h->mount; m; m = m->next){
515                         mpt = tompt(m);
516                         if(strcmp(name, mpt->name) == 0)
517                                 error(Eexist);
518                 }
519
520                 mpt = smalloc(sizeof(*mpt));
521                 incref(mpt);
522                 mpt->id = mptid++;
523
524                 kstrdup(&mpt->name, name);
525                 kstrdup(&mpt->owner, up->user);
526                 mpt->perm = perm;
527
528                 incref(mpt);
529                 mpt->m.mflag = (h->mount == nil) ? MCREATE : 0;
530                 mpt->m.head = h;
531                 mpt->m.next = h->mount;
532                 h->mount = &mpt->m;
533
534                 poperror();
535                 wunlock(&h->lock);
536
537                 c->qid = shrqid(sch->level = Qcmpt, mpt->id);
538                 sch->mpt = mpt;
539                 break;
540         }
541         c->flag |= COPEN;
542         c->mode = openmode(omode);
543         return c;
544 }
545
546 static void
547 shrremove(Chan *c)
548 {
549         Mount *m, **ml;
550         Shr *shr, **sl;
551         Sch *sch;
552         Mpt *mpt;
553         Mhead *h;
554
555         sch = tosch(c);
556         if(waserror()){
557                 shrclunk(c);
558                 nexterror();
559         }
560         switch(sch->level){
561         default:
562                 error(Eperm);
563         case Qcshr:
564         case Qcmpt:
565                 shr = sch->shr;
566                 if(!iseve()){
567                         if(strcmp(shr->owner, eve) == 0)
568                                 error(Eperm);
569                         devpermcheck(shr->owner, shr->perm, ORDWR);
570                 }
571         }
572         switch(sch->level){
573         case Qcshr:
574                 h = &shr->umh;
575                 qlock(&shrslk);
576                 rlock(&h->lock);
577                 if(h->mount){
578                         runlock(&h->lock);
579                         qunlock(&shrslk);
580                         error("directory not empty");
581                 }
582                 runlock(&h->lock);
583                 for(sl = &shrs; *sl; sl = &((*sl)->next))
584                         if(*sl == shr){
585                                 *sl = shr->next;
586                                 shr->next = nil;
587                                 putshr(shr);
588                                 break;
589                         }
590                 qunlock(&shrslk);
591                 break;
592         case Qcmpt:
593                 mpt = sch->mpt;
594                 m = &mpt->m;
595                 h = &shr->umh;
596                 wlock(&h->lock);
597                 for(ml = &h->mount; *ml; ml = &((*ml)->next))
598                         if(*ml == m){
599                                 *ml = m->next;
600                                 m->next = nil;
601                                 m->head = nil;
602                                 putmpt(mpt);
603                                 break;
604                         }
605                 wunlock(&h->lock);
606                 break;
607         }
608         poperror();
609         shrclunk(c);
610 }
611
612 static int
613 shrwstat(Chan *c, uchar *dp, int n)
614 {
615         char *strs;
616         Mhead *h;
617         Sch *sch;
618         Ent *ent;
619         Dir d;
620
621         h = nil;
622         sch = tosch(c);
623         switch(sch->level){
624         default:
625                 error(Eperm);
626         case Qcshr:
627                 ent = sch->shr;
628                 qlock(&shrslk);
629                 if(waserror()){
630                         qunlock(&shrslk);
631                         nexterror();
632                 }
633                 break;
634         case Qcmpt:
635                 ent = sch->mpt;
636                 h = &sch->shr->umh;
637                 wlock(&h->lock);
638                 if(waserror()){
639                         wunlock(&h->lock);
640                         nexterror();
641                 }
642                 break;
643         }
644
645         if(strcmp(ent->owner, up->user) && !iseve())
646                 error(Eperm);
647
648         strs = smalloc(n);
649         if(waserror()){
650                 free(strs);
651                 nexterror();
652         }
653         n = convM2D(dp, n, &d, strs);
654         if(n == 0)
655                 error(Eshortstat);
656         if(d.mode != ~0UL)
657                 ent->perm = d.mode & 0777;
658         if(d.uid && *d.uid)
659                 kstrdup(&ent->owner, d.uid);
660         if(d.name && *d.name && strcmp(ent->name, d.name) != 0) {
661                 if(strchr(d.name, '/') != nil)
662                         error(Ebadchar);
663                 if(strlen(d.name) >= sizeof(up->genbuf))
664                         error(Etoolong);
665                 kstrdup(&ent->name, d.name);
666         }
667         poperror();
668         free(strs);
669
670         switch(sch->level){
671         case Qcshr:
672                 poperror();
673                 qunlock(&shrslk);
674                 break;
675         case Qcmpt:
676                 poperror();
677                 wunlock(&h->lock);
678                 break;
679         }
680         return n;
681 }
682
683 static long
684 shrread(Chan *c, void *va, long n, vlong)
685 {
686         Mhead *omh;
687         Sch *sch;
688
689         sch = tosch(c);
690         switch(sch->level){
691         default:
692                 error(Egreg);
693         case Qroot:
694         case Qcroot:
695         case Qcshr:
696                 return devdirread(c, va, n, 0, 0, shrgen);
697         case Qshr:
698                 omh = c->umh;
699                 c->umh = &sch->shr->umh;
700                 if(waserror()){
701                         c->umh = omh;
702                         nexterror();
703                 }
704                 n = unionread(c, va, n);
705                 poperror();
706                 c->umh = omh;
707                 return n;
708         }
709 }
710
711 static long
712 shrwrite(Chan *c, void *va, long n, vlong)
713 {
714         Sch *sch;
715         char *buf, *p, *aname;
716         int fd;
717         Chan *bc, *c0;
718         Mhead *h;
719         Mount *m;
720         struct{
721                 Chan    *chan;
722                 Chan    *authchan;
723                 char    *spec;
724                 int     flags;
725         }bogus;
726
727         if(up->pgrp->noattach)
728                 error(Enoattach);
729         sch = tosch(c);
730         if(sch->level != Qcmpt)
731                 error(Egreg);
732
733         buf = smalloc(n+1);
734         if(waserror()){
735                 free(buf);
736                 nexterror();
737         }
738         memmove(buf, va, n);
739         buf[n] = 0;
740         
741         fd = strtol(buf, &p, 10);
742         if(p == buf || (*p != 0 && *p != '\n'))
743                 error(Ebadarg);
744         if(*p == '\n' && *(p+1) != 0)
745                 aname = p + 1;
746         else
747                 aname = nil;
748         
749         bc = fdtochan(fd, ORDWR, 0, 1);
750         if(waserror()) {
751                 cclose(bc);
752                 nexterror();
753         }
754         bogus.flags = 0;
755         bogus.chan = bc;
756         bogus.authchan = nil;
757         bogus.spec = aname;
758         c0 = devtab[devno('M', 0)]->attach((char*)&bogus);
759         poperror();
760         cclose(bc);
761         poperror();
762         free(buf);
763
764         if(c0 == nil)
765                 error(Egreg);
766
767         m = &sch->mpt->m;
768         h = &sch->shr->umh;
769         wlock(&h->lock);
770         bc = m->to;
771         m->to = c0;
772         wunlock(&h->lock);
773
774         if(bc)
775                 cclose(bc);
776
777         return n;
778 }
779
780 static void
781 shrclose(Chan *c)
782 {
783         if(c->flag & CRCLOSE)
784                 shrremove(c);
785         else
786                 shrclunk(c);
787 }
788
789 Dev shrdevtab = {
790         L'σ',
791         "shr",
792
793         devreset,
794         shrinit,        
795         devshutdown,
796         shrattach,
797         shrwalk,
798         shrstat,
799         shropen,
800         shrcreate,
801         shrclose,
802         shrread,
803         devbread,
804         shrwrite,
805         devbwrite,
806         shrremove,
807         shrwstat,
808 };
809
810 static void
811 chowner(Ent *ent, char *old, char *new)
812 {
813         if(ent->owner!=nil && strcmp(old, ent->owner)==0)
814                 kstrdup(&ent->owner, new);
815 }
816
817 void
818 shrrenameuser(char *old, char *new)
819 {
820         Shr *shr;
821         Mount *m;
822
823         qlock(&shrslk);
824         for(shr = shrs; shr; shr = shr->next){
825                 wlock(&shr->umh.lock);
826                 for(m = shr->umh.mount; m; m = m->next)
827                         chowner(tompt(m), old, new);
828                 wunlock(&shr->umh.lock);
829                 chowner(shr, old, new);
830         }
831         qunlock(&shrslk);
832 }