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