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 * the zeroth element of the table MUST be the directory itself for .. 54 */ 55 int 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 72 devreset(void) 73 { 74 } 75 76 void 77 devinit(void) 78 { 79 } 80 81 void 82 devshutdown(void) 83 { 84 } 85 86 Chan* 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* 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* 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 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 error(Egreg); /* not reached? */ 262 return -1; 263 } 264 265 long 266 devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen) 267 { 268 long m, dsz; 269 struct{ 270 Dir; 271 char slop[100]; 272 }dir; 273 274 for(m=0; m<n; c->dri++) { 275 switch((*gen)(c, nil, tab, ntab, c->dri, &dir)){ 276 case -1: 277 return m; 278 279 case 0: 280 break; 281 282 case 1: 283 dsz = convD2M(&dir, (uchar*)d, n-m); 284 if(dsz <= BIT16SZ){ /* <= not < because this isn't stat; read is stuck */ 285 if(m == 0) 286 error(Eshort); 287 return m; 288 } 289 m += dsz; 290 d += dsz; 291 break; 292 } 293 } 294 295 return m; 296 } 297 298 /* 299 * error(Eperm) if open permission not granted for up->env->user. 300 */ 301 void 302 devpermcheck(char *fileuid, ulong perm, int omode) 303 { 304 ulong t; 305 static int access[] = { 0400, 0200, 0600, 0100 }; 306 307 if(strcmp(up->env->user, fileuid) == 0) 308 perm <<= 0; 309 else 310 if(strcmp(up->env->user, eve) == 0) 311 perm <<= 3; 312 else 313 perm <<= 6; 314 315 t = access[omode&3]; 316 if((t&perm) != t) 317 error(Eperm); 318 } 319 320 Chan* 321 devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen) 322 { 323 int i; 324 Dir dir; 325 326 for(i=0;; i++) { 327 switch((*gen)(c, nil, tab, ntab, i, &dir)){ 328 case -1: 329 goto Return; 330 case 0: 331 break; 332 case 1: 333 if(c->qid.path == dir.qid.path) { 334 devpermcheck(dir.uid, dir.mode, omode); 335 goto Return; 336 } 337 break; 338 } 339 } 340 Return: 341 c->offset = 0; 342 if((c->qid.type&QTDIR) && omode!=OREAD) 343 error(Eperm); 344 c->mode = openmode(omode); 345 c->flag |= COPEN; 346 return c; 347 } 348 349 void 350 devcreate(Chan*, char*, int, ulong) 351 { 352 error(Eperm); 353 } 354 355 Block* 356 devbread(Chan *c, long n, ulong offset) 357 { 358 Block *bp; 359 360 bp = allocb(n); 361 if(bp == 0) 362 error(Enomem); 363 if(waserror()) { 364 freeb(bp); 365 nexterror(); 366 } 367 bp->wp += devtab[c->type]->read(c, bp->wp, n, offset); 368 poperror(); 369 return bp; 370 } 371 372 long 373 devbwrite(Chan *c, Block *bp, ulong offset) 374 { 375 long n; 376 377 if(waserror()) { 378 freeb(bp); 379 nexterror(); 380 } 381 n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset); 382 poperror(); 383 freeb(bp); 384 385 return n; 386 } 387 388 void 389 devremove(Chan*) 390 { 391 error(Eperm); 392 } 393 394 int 395 devwstat(Chan*, uchar*, int) 396 { 397 error(Eperm); 398 return 0; 399 } 400 401 void 402 devpower(int) 403 { 404 error(Eperm); 405 } 406 407 int 408 devconfig(int, char *, DevConf *) 409 { 410 error(Eperm); 411 return 0; 412 } 413 414 /* 415 * check that the name in a wstat is plausible 416 */ 417 void 418 validwstatname(char *name) 419 { 420 validname(name, 0); 421 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) 422 error(Efilename); 423 } 424 425 Dev* 426 devbyname(char *name) 427 { 428 int i; 429 430 for(i = 0; devtab[i] != nil; i++) 431 if(strcmp(devtab[i]->name, name) == 0) 432 return devtab[i]; 433 return nil; 434 } 435