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