]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vnc/dev.c
devdraw: simplify drawgen()
[plan9front.git] / sys / src / cmd / vnc / dev.c
1 #include        <u.h>
2 #include        <libc.h>
3 #include        <fcall.h>
4 #include        "compat.h"
5 #include        "error.h"
6
7 extern ulong    kerndate;
8
9 void
10 mkqid(Qid *q, vlong path, ulong vers, int type)
11 {
12         q->type = type;
13         q->vers = vers;
14         q->path = path;
15 }
16
17 int
18 devno(int c, int user)
19 {
20         int i;
21
22         for(i = 0; devtab[i] != nil; i++){
23                 if(devtab[i]->dc == c)
24                         return i;
25         }
26         if(user == 0)
27                 panic("devno %C 0x%ux", c, c);
28
29         return -1;
30 }
31
32 void
33 devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db)
34 {
35         db->name = n;
36         db->qid = qid;
37         db->type = devtab[c->type]->dc;
38         db->dev = c->dev;
39         db->mode = (qid.type << 24) | perm;
40         db->atime = seconds();
41         db->mtime = kerndate;
42         db->length = length;
43         db->uid = user;
44         db->gid = eve;
45         db->muid = user;
46 }
47
48 /*
49  * the zeroth element of the table MUST be the directory itself for ..
50 */
51 int
52 devgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
53 {
54         if(tab == 0)
55                 return -1;
56         if(i != DEVDOTDOT){
57                 i++; /* skip first element for . itself */
58                 if(i >= ntab)
59                         return -1;
60                 tab += i;
61         }
62         devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
63         return 1;
64 }
65
66 void
67 devreset(void)
68 {
69 }
70
71 void
72 devinit(void)
73 {
74 }
75
76 Chan*
77 devattach(int tc, char *spec)
78 {
79         Chan *c;
80         char *buf;
81
82         c = newchan();
83         mkqid(&c->qid, 0, 0, QTDIR);
84         c->type = devno(tc, 0);
85         if(spec == nil)
86                 spec = "";
87         buf = smalloc(4+strlen(spec)+1);
88         sprint(buf, "#%C%s", tc, spec);
89         c->name = newcname(buf);
90         free(buf);
91         return c;
92 }
93
94
95 Chan*
96 devclone(Chan *c)
97 {
98         Chan *nc;
99
100         if(c->flag & COPEN)
101                 panic("clone of open file type %C\n", devtab[c->type]->dc);
102
103         nc = newchan();
104
105         nc->type = c->type;
106         nc->dev = c->dev;
107         nc->mode = c->mode;
108         nc->qid = c->qid;
109         nc->offset = c->offset;
110         nc->aux = c->aux;
111         return nc;
112 }
113
114 Walkqid*
115 devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen)
116 {
117         int i, j, alloc;
118         Walkqid *wq;
119         char *n;
120         Dir dir;
121
122         isdir(c);
123
124         alloc = 0;
125         wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
126         if(waserror()){
127                 if(alloc && wq->clone!=nil)
128                         cclose(wq->clone);
129                 free(wq);
130                 return nil;
131         }
132         if(nc == nil){
133                 nc = devclone(c);
134                 nc->type = 0;   /* device doesn't know about this channel yet */
135                 alloc = 1;
136         }
137         wq->clone = nc;
138
139         for(j=0; j<nname; j++){
140                 isdir(nc);
141                 n = name[j];
142                 if(strcmp(n, ".") == 0){
143     Accept:
144                         wq->qid[wq->nqid++] = nc->qid;
145                         continue;
146                 }
147                 if(strcmp(n, "..") == 0){
148                         (*gen)(nc, tab, ntab, DEVDOTDOT, &dir);
149                         nc->qid = dir.qid;
150                         goto Accept;
151                 }
152                 for(i=0;; i++){
153                         switch((*gen)(nc, tab, ntab, i, &dir)){
154                         case -1:
155                                 if(j == 0)
156                                         error(Enonexist);
157                                 strncpy(up->error, Enonexist, ERRMAX);
158                                 goto Done;
159                         case 0:
160                                 continue;
161                         case 1:
162                                 if(strcmp(n, dir.name) == 0){
163                                         nc->qid = dir.qid;
164                                         goto Accept;
165                                 }
166                                 continue;
167                         }
168                 }
169         }
170         /*
171          * We processed at least one name, so will return some data.
172          * If we didn't process all nname entries succesfully, we drop
173          * the cloned channel and return just the Qids of the walks.
174          */
175 Done:
176         poperror();
177         if(wq->nqid < nname){
178                 if(alloc)
179                         cclose(wq->clone);
180                 wq->clone = nil;
181         }else if(wq->clone){
182                 /* attach cloned channel to same device */
183                 wq->clone->type = c->type;
184         }
185         return wq;
186 }
187
188 int
189 devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen)
190 {
191         int i;
192         Dir dir;
193         char *p, *elem;
194
195         for(i=0;; i++)
196                 switch((*gen)(c, tab, ntab, i, &dir)){
197                 case -1:
198                         if(c->qid.type & QTDIR){
199                                 if(c->name == nil)
200                                         elem = "???";
201                                 else if(strcmp(c->name->s, "/") == 0)
202                                         elem = "/";
203                                 else
204                                         for(elem=p=c->name->s; *p; p++)
205                                                 if(*p == '/')
206                                                         elem = p+1;
207                                 devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir);
208                                 return convD2M(&dir, db, n);
209                         }
210
211                         error(Enonexist);
212                 case 0:
213                         break;
214                 case 1:
215                         if(c->qid.path == dir.qid.path){
216                                 return convD2M(&dir, db, n);
217                         }
218                         break;
219                 }
220 }
221
222 long
223 devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen)
224 {
225         long k, m, dsz;
226         struct{
227                 Dir;
228                 char slop[100];
229         }dir;
230
231         k = c->offset;
232         for(m=0; m<n; k++){
233                 switch((*gen)(c, tab, ntab, k, &dir)){
234                 case -1:
235                         return m;
236
237                 case 0:
238                         c->offset++;    /* BUG??? (was DIRLEN: skip entry) */
239                         break;
240
241                 case 1:
242                         dsz = convD2M(&dir, (uchar*)d, n-m);
243                         if(dsz <= BIT16SZ){     /* <= not < because this isn't stat; read is stuck */
244                                 if(m == 0)
245                                         return -1;
246                                 return m;
247                         }
248                         m += dsz;
249                         d += dsz;
250                         break;
251                 }
252         }
253
254         return m;
255 }
256
257 /*
258  * error(Eperm) if open permission not granted for up->user.
259  */
260 void
261 devpermcheck(char *fileuid, ulong perm, int omode)
262 {
263         ulong t;
264         static int access[] = { 0400, 0200, 0600, 0100 };
265
266         if(strcmp(up->user, fileuid) == 0)
267                 perm <<= 0;
268         else
269         if(strcmp(up->user, eve) == 0)
270                 perm <<= 3;
271         else
272                 perm <<= 6;
273
274         t = access[omode&3];
275         if((t&perm) != t)
276                 error(Eperm);
277 }
278
279 Chan*
280 devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen)
281 {
282         int i;
283         Dir dir;
284
285         for(i=0;; i++){
286                 switch((*gen)(c, tab, ntab, i, &dir)){
287                 case -1:
288                         goto Return;
289                 case 0:
290                         break;
291                 case 1:
292                         if(c->qid.path == dir.qid.path){
293                                 devpermcheck(dir.uid, dir.mode, omode);
294                                 goto Return;
295                         }
296                         break;
297                 }
298         }
299 Return:
300         c->offset = 0;
301         if((c->qid.type&QTDIR) && omode!=OREAD)
302                 error(Eperm);
303         c->mode = openmode(omode);
304         c->flag |= COPEN;
305         return c;
306 }
307
308 void
309 devcreate(Chan*, char*, int, ulong)
310 {
311         error(Eperm);
312 }
313
314 Block*
315 devbread(Chan *, long, ulong)
316 {
317         panic("no block read");
318         return nil;
319 }
320
321 long
322 devbwrite(Chan *, Block *, ulong)
323 {
324         panic("no block write");
325         return 0;
326 }
327
328 void
329 devremove(Chan*)
330 {
331         error(Eperm);
332 }
333
334 int
335 devwstat(Chan*, uchar*, int)
336 {
337         error(Eperm);
338         return 0;
339 }