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 106 nc->type = c->type; 107 nc->dev = c->dev; 108 nc->mode = c->mode; 109 nc->qid = c->qid; 110 nc->offset = c->offset; 111 nc->umh = nil; 112 nc->mountid = c->mountid; 113 nc->aux = c->aux; 114 nc->mqid = c->mqid; 115 nc->mcp = c->mcp; 116 return nc; 117 } 118 119 Walkqid* 120 devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen) 121 { 122 int i, j, 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 error(Egreg); /* not reached? */ 253 return -1; 254 } 255 256 long 257 devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen) 258 { 259 long m, dsz; 260 struct{ 261 Dir d; 262 char slop[100]; /* TO DO */ 263 }dir; 264 265 for(m=0; m<n; c->dri++) { 266 switch((*gen)(c, nil, tab, ntab, c->dri, &dir.d)){ 267 case -1: 268 return m; 269 270 case 0: 271 break; 272 273 case 1: 274 dsz = convD2M(&dir.d, (uchar*)d, n-m); 275 if(dsz <= BIT16SZ){ /* <= not < because this isn't stat; read is stuck */ 276 if(m == 0) 277 error(Eshort); 278 return m; 279 } 280 m += dsz; 281 d += dsz; 282 break; 283 } 284 } 285 286 return m; 287 } 288 289 /* 290 * error(Eperm) if open permission not granted for up->env->user. 291 */ 292 void 293 devpermcheck(char *fileuid, ulong perm, int omode) 294 { 295 ulong t; 296 static int access[] = { 0400, 0200, 0600, 0100 }; 297 298 if(strcmp(up->env->user, fileuid) == 0) 299 perm <<= 0; 300 else 301 if(strcmp(up->env->user, eve) == 0) 302 perm <<= 3; 303 else 304 perm <<= 6; 305 306 t = access[omode&3]; 307 if((t&perm) != t) 308 error(Eperm); 309 } 310 311 Chan* 312 devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen) 313 { 314 int i; 315 Dir dir; 316 317 for(i=0;; i++) { 318 switch((*gen)(c, nil, tab, ntab, i, &dir)){ 319 case -1: 320 goto Return; 321 case 0: 322 break; 323 case 1: 324 if(c->qid.path == dir.qid.path) { 325 devpermcheck(dir.uid, dir.mode, omode); 326 goto Return; 327 } 328 break; 329 } 330 } 331 Return: 332 c->offset = 0; 333 if((c->qid.type&QTDIR) && omode!=OREAD) 334 error(Eperm); 335 c->mode = openmode(omode); 336 c->flag |= COPEN; 337 return c; 338 } 339 340 Block* 341 devbread(Chan *c, long n, ulong offset) 342 { 343 Block *bp; 344 345 bp = allocb(n); 346 if(waserror()) { 347 freeb(bp); 348 nexterror(); 349 } 350 bp->wp += devtab[c->type]->read(c, bp->wp, n, offset); 351 poperror(); 352 return bp; 353 } 354 355 long 356 devbwrite(Chan *c, Block *bp, ulong offset) 357 { 358 long n; 359 360 if(waserror()) { 361 freeb(bp); 362 nexterror(); 363 } 364 n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset); 365 poperror(); 366 freeb(bp); 367 368 return n; 369 } 370 371 void 372 devcreate(Chan *c, char *name, int mode, ulong perm) 373 { 374 USED(c); 375 USED(name); 376 USED(mode); 377 USED(perm); 378 error(Eperm); 379 } 380 381 void 382 devremove(Chan *c) 383 { 384 USED(c); 385 error(Eperm); 386 } 387 388 int 389 devwstat(Chan *c, uchar *dp, int n) 390 { 391 USED(c); 392 USED(dp); 393 USED(n); 394 error(Eperm); 395 return 0; 396 } 397 398 int 399 readstr(ulong off, char *buf, ulong n, char *str) 400 { 401 int size; 402 403 size = strlen(str); 404 if(off >= size) 405 return 0; 406 if(off+n > size) 407 n = size-off; 408 memmove(buf, str+off, n); 409 return n; 410 } 411 412 int 413 readnum(ulong off, char *buf, ulong n, ulong val, int size) 414 { 415 char tmp[64]; 416 417 if(size > 64) size = 64; 418 419 snprint(tmp, sizeof(tmp), "%*.0lud ", size, val); 420 if(off >= size) 421 return 0; 422 if(off+n > size) 423 n = size-off; 424 memmove(buf, tmp+off, n); 425 return n; 426 } 427 428 /* 429 * check that the name in a wstat is plausible 430 */ 431 void 432 validwstatname(char *name) 433 { 434 validname(name, 0); 435 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) 436 error(Efilename); 437 } 438 439 Dev* 440 devbyname(char *name) 441 { 442 int i; 443 444 for(i = 0; devtab[i] != nil; i++) 445 if(strcmp(devtab[i]->name, name) == 0) 446 return devtab[i]; 447 return nil; 448 } 449