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 extern ulong kerndate;
9
10 void
mkqid(Qid * q,vlong path,ulong vers,int type)11 mkqid(Qid *q, vlong path, ulong vers, int type)
12 {
13 q->type = type;
14 q->vers = vers;
15 q->path = path;
16 }
17
18 int
devno(int c,int user)19 devno(int c, int user)
20 {
21 int i;
22
23 for(i = 0; devtab[i] != nil; i++) {
24 if(devtab[i]->dc == c)
25 return i;
26 }
27 if(user == 0)
28 panic("devno %C 0x%ux", c, c);
29
30 return -1;
31 }
32
33 void
devdir(Chan * c,Qid qid,char * n,vlong length,char * user,long perm,Dir * db)34 devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db)
35 {
36 db->name = n;
37 if(c->flag&CMSG)
38 qid.type |= QTMOUNT;
39 db->qid = qid;
40 db->type = devtab[c->type]->dc;
41 db->dev = c->dev;
42 db->mode = perm;
43 db->mode |= qid.type << 24;
44 db->atime = seconds();
45 db->mtime = kerndate;
46 db->length = length;
47 db->uid = user;
48 db->gid = eve;
49 db->muid = user;
50 }
51
52 /*
53 * the zeroth element of the table MUST be the directory itself for ..
54 */
55 int
devgen(Chan * c,char *,Dirtab * tab,int ntab,int i,Dir * dp)56 devgen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp)
57 {
58 if(tab == 0)
59 return -1;
60 if(i != DEVDOTDOT){
61 /* skip over the first element, that for . itself */
62 i++;
63 if(i >= ntab)
64 return -1;
65 tab += i;
66 }
67 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
68 return 1;
69 }
70
71 void
devreset(void)72 devreset(void)
73 {
74 }
75
76 void
devinit(void)77 devinit(void)
78 {
79 }
80
81 void
devshutdown(void)82 devshutdown(void)
83 {
84 }
85
86 Chan*
devattach(int tc,char * spec)87 devattach(int tc, char *spec)
88 {
89 Chan *c;
90 char *buf;
91
92 c = newchan();
93 mkqid(&c->qid, 0, 0, QTDIR);
94 c->type = devno(tc, 0);
95 if(spec == nil)
96 spec = "";
97 buf = smalloc(4+strlen(spec)+1);
98 sprint(buf, "#%C%s", tc, spec);
99 c->name = newcname(buf);
100 free(buf);
101 return c;
102 }
103
104
105 Chan*
devclone(Chan * c)106 devclone(Chan *c)
107 {
108 Chan *nc;
109
110 if(c->flag & COPEN)
111 panic("clone of open file type %C\n", devtab[c->type]->dc);
112
113 nc = newchan();
114
115 nc->type = c->type;
116 nc->dev = c->dev;
117 nc->mode = c->mode;
118 nc->qid = c->qid;
119 nc->offset = c->offset;
120 nc->umh = nil;
121 nc->mountid = c->mountid;
122 nc->aux = c->aux;
123 nc->mqid = c->mqid;
124 nc->mcp = c->mcp;
125 return nc;
126 }
127
128 Walkqid*
devwalk(Chan * c,Chan * nc,char ** name,int nname,Dirtab * tab,int ntab,Devgen * gen)129 devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen)
130 {
131 int i, j, alloc;
132 Walkqid *wq;
133 char *n;
134 Dir dir;
135
136 if(nname > 0)
137 isdir(c);
138
139 alloc = 0;
140 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
141 if(waserror()){
142 if(alloc && wq->clone!=nil)
143 cclose(wq->clone);
144 free(wq);
145 return nil;
146 }
147 if(nc == nil){
148 nc = devclone(c);
149 nc->type = 0; /* device doesn't know about this channel yet */
150 alloc = 1;
151 }
152 wq->clone = nc;
153
154 for(j=0; j<nname; j++){
155 if(!(nc->qid.type&QTDIR)){
156 if(j==0)
157 error(Enotdir);
158 goto Done;
159 }
160 n = name[j];
161 if(strcmp(n, ".") == 0){
162 Accept:
163 wq->qid[wq->nqid++] = nc->qid;
164 continue;
165 }
166 if(strcmp(n, "..") == 0){
167 (*gen)(nc, nil, tab, ntab, DEVDOTDOT, &dir);
168 nc->qid = dir.qid;
169 goto Accept;
170 }
171 /*
172 * Ugly problem: If we're using devgen, make sure we're
173 * walking the directory itself, represented by the first
174 * entry in the table, and not trying to step into a sub-
175 * directory of the table, e.g. /net/net. Devgen itself
176 * should take care of the problem, but it doesn't have
177 * the necessary information (that we're doing a walk).
178 */
179 if(gen==devgen && nc->qid.path!=tab[0].qid.path)
180 goto Notfound;
181 for(i=0;; i++) {
182 switch((*gen)(nc, n, tab, ntab, i, &dir)){
183 case -1:
184 Notfound:
185 if(j == 0)
186 error(Enonexist);
187 kstrcpy(up->env->errstr, Enonexist, ERRMAX);
188 goto Done;
189 case 0:
190 continue;
191 case 1:
192 if(strcmp(n, dir.name) == 0){
193 nc->qid = dir.qid;
194 goto Accept;
195 }
196 continue;
197 }
198 }
199 }
200 /*
201 * We processed at least one name, so will return some data.
202 * If we didn't process all nname entries succesfully, we drop
203 * the cloned channel and return just the Qids of the walks.
204 */
205 Done:
206 poperror();
207 if(wq->nqid < nname){
208 if(alloc)
209 cclose(wq->clone);
210 wq->clone = nil;
211 }else if(wq->clone){
212 /* attach cloned channel to same device */
213 wq->clone->type = c->type;
214 }
215 return wq;
216 }
217
218 int
devstat(Chan * c,uchar * db,int n,Dirtab * tab,int ntab,Devgen * gen)219 devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen)
220 {
221 int i;
222 Dir dir;
223 char *p, *elem;
224
225 for(i=0;; i++)
226 switch((*gen)(c, nil, tab, ntab, i, &dir)){
227 case -1:
228 if(c->qid.type & QTDIR){
229 if(c->name == nil)
230 elem = "???";
231 else if(strcmp(c->name->s, "/") == 0)
232 elem = "/";
233 else
234 for(elem=p=c->name->s; *p; p++)
235 if(*p == '/')
236 elem = p+1;
237 devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir);
238 n = convD2M(&dir, db, n);
239 if(n == 0)
240 error(Ebadarg);
241 return n;
242 }
243 print("%s %s: devstat %C %llux\n",
244 up->text, up->env->user,
245 devtab[c->type]->dc, c->qid.path);
246
247 error(Enonexist);
248 case 0:
249 break;
250 case 1:
251 if(c->qid.path == dir.qid.path) {
252 if(c->flag&CMSG)
253 dir.mode |= DMMOUNT;
254 n = convD2M(&dir, db, n);
255 if(n == 0)
256 error(Ebadarg);
257 return n;
258 }
259 break;
260 }
261 }
262
263 long
devdirread(Chan * c,char * d,long n,Dirtab * tab,int ntab,Devgen * gen)264 devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen)
265 {
266 long m, dsz;
267 struct{
268 Dir;
269 char slop[100];
270 }dir;
271
272 for(m=0; m<n; c->dri++) {
273 switch((*gen)(c, nil, tab, ntab, c->dri, &dir)){
274 case -1:
275 return m;
276
277 case 0:
278 break;
279
280 case 1:
281 dsz = convD2M(&dir, (uchar*)d, n-m);
282 if(dsz <= BIT16SZ){ /* <= not < because this isn't stat; read is stuck */
283 if(m == 0)
284 error(Eshort);
285 return m;
286 }
287 m += dsz;
288 d += dsz;
289 break;
290 }
291 }
292
293 return m;
294 }
295
296 /*
297 * error(Eperm) if open permission not granted for up->env->user.
298 */
299 void
devpermcheck(char * fileuid,ulong perm,int omode)300 devpermcheck(char *fileuid, ulong perm, int omode)
301 {
302 ulong t;
303 static int access[] = { 0400, 0200, 0600, 0100 };
304
305 if(strcmp(up->env->user, fileuid) == 0)
306 perm <<= 0;
307 else
308 if(strcmp(up->env->user, eve) == 0)
309 perm <<= 3;
310 else
311 perm <<= 6;
312
313 t = access[omode&3];
314 if((t&perm) != t)
315 error(Eperm);
316 }
317
318 Chan*
devopen(Chan * c,int omode,Dirtab * tab,int ntab,Devgen * gen)319 devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen)
320 {
321 int i;
322 Dir dir;
323
324 for(i=0;; i++) {
325 switch((*gen)(c, nil, tab, ntab, i, &dir)){
326 case -1:
327 goto Return;
328 case 0:
329 break;
330 case 1:
331 if(c->qid.path == dir.qid.path) {
332 devpermcheck(dir.uid, dir.mode, omode);
333 goto Return;
334 }
335 break;
336 }
337 }
338 Return:
339 c->offset = 0;
340 if((c->qid.type&QTDIR) && omode!=OREAD)
341 error(Eperm);
342 c->mode = openmode(omode);
343 c->flag |= COPEN;
344 return c;
345 }
346
347 void
devcreate(Chan *,char *,int,ulong)348 devcreate(Chan*, char*, int, ulong)
349 {
350 error(Eperm);
351 }
352
353 Block*
devbread(Chan * c,long n,ulong offset)354 devbread(Chan *c, long n, ulong offset)
355 {
356 Block *bp;
357
358 bp = allocb(n);
359 if(bp == 0)
360 error(Enomem);
361 if(waserror()) {
362 freeb(bp);
363 nexterror();
364 }
365 bp->wp += devtab[c->type]->read(c, bp->wp, n, offset);
366 poperror();
367 return bp;
368 }
369
370 long
devbwrite(Chan * c,Block * bp,ulong offset)371 devbwrite(Chan *c, Block *bp, ulong offset)
372 {
373 long n;
374
375 if(waserror()) {
376 freeb(bp);
377 nexterror();
378 }
379 n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset);
380 poperror();
381 freeb(bp);
382
383 return n;
384 }
385
386 void
devremove(Chan *)387 devremove(Chan*)
388 {
389 error(Eperm);
390 }
391
392 int
devwstat(Chan *,uchar *,int)393 devwstat(Chan*, uchar*, int)
394 {
395 error(Eperm);
396 return 0;
397 }
398
399 void
devpower(int)400 devpower(int)
401 {
402 error(Eperm);
403 }
404
405 int
devconfig(int,char *,DevConf *)406 devconfig(int, char *, DevConf *)
407 {
408 error(Eperm);
409 return 0;
410 }
411
412 /*
413 * check that the name in a wstat is plausible
414 */
415 void
validwstatname(char * name)416 validwstatname(char *name)
417 {
418 validname(name, 0);
419 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
420 error(Efilename);
421 }
422
423 Dev*
devbyname(char * name)424 devbyname(char *name)
425 {
426 int i;
427
428 for(i = 0; devtab[i] != nil; i++)
429 if(strcmp(devtab[i]->name, name) == 0)
430 return devtab[i];
431 return nil;
432 }
433