1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #include "dat.h" 6 #include "fns.h" 7 #include "iso9660.h" 8 9 static void ireset(void); 10 static int iattach(Xfile*); 11 static void iclone(Xfile*, Xfile*); 12 static void iwalkup(Xfile*); 13 static void iwalk(Xfile*, char*); 14 static void iopen(Xfile*, int); 15 static void icreate(Xfile*, char*, long, int); 16 static long ireaddir(Xfile*, void*, long, long); 17 static long iread(Xfile*, void*, long, long); 18 static long iwrite(Xfile*, void*, long, long); 19 static void iclunk(Xfile*); 20 static void iremove(Xfile*); 21 static void istat(Xfile*, Dir*); 22 static void iwstat(Xfile*, Dir*); 23 24 static char* nstr(void*, int); 25 static char* rdate(void*, int); 26 static int getdrec(Xfile*, void*); 27 static int opendotdot(Xfile*, Xfile*); 28 static int showdrec(int, int, void*); 29 static long gtime(void*); 30 static long l16(void*); 31 static long l32(void*); 32 static void newdrec(Xfile*, Drec*); 33 static int rzdir(int, Dir*, int, Drec*); 34 35 Xfsub isosub = 36 { 37 ireset, iattach, iclone, iwalkup, iwalk, iopen, icreate, 38 ireaddir, iread, iwrite, iclunk, iremove, istat, iwstat 39 }; 40 41 static void 42 ireset(void) 43 {} 44 45 static int 46 iattach(Xfile *root) 47 { 48 Xfs *cd = root->xf; 49 Iobuf *p; Voldesc *v; Isofile *fp; Drec *dp; 50 int fmt, blksize; 51 52 p = getbuf(cd->d, VOLDESC); 53 v = (Voldesc*)(p->iobuf); 54 if(memcmp(v->byte, "\01CD001\01", 7) == 0){ /* iso */ 55 fmt = 'z'; 56 dp = (Drec*)v->z.desc.rootdir; 57 blksize = l16(v->z.desc.blksize); 58 chat("iso, blksize=%d...", blksize); 59 }else if(memcmp(&v->byte[8], "\01CDROM\01", 7) == 0){ /* high sierra */ 60 fmt = 'r'; 61 dp = (Drec*)v->r.desc.rootdir; 62 blksize = l16(v->r.desc.blksize); 63 chat("high sierra, blksize=%d...", blksize); 64 }else{ 65 putbuf(p); 66 return -1; 67 } 68 if(chatty) 69 showdrec(2, fmt, dp); 70 if(blksize > Sectorsize){ 71 chat("blksize too big..."); 72 putbuf(p); 73 return -1; 74 } 75 if(waserror()){ 76 putbuf(p); 77 nexterror(); 78 } 79 root->len = sizeof(Isofile) - sizeof(Drec) + dp->reclen; 80 root->ptr = fp = ealloc(root->len); 81 root->xf->isplan9 = (strncmp((char*)v->z.boot.sysid, "PLAN 9", 6)==0); 82 fp->fmt = fmt; 83 fp->blksize = blksize; 84 fp->offset = 0; 85 fp->doffset = 0; 86 memmove(&fp->d, dp, dp->reclen); 87 root->qid.path = CHDIR|l32(dp->addr); 88 putbuf(p); 89 poperror(); 90 return 0; 91 } 92 93 static void 94 iclone(Xfile *of, Xfile *nf) 95 { 96 USED(of, nf); 97 } 98 99 static void 100 iwalkup(Xfile *f) 101 { 102 long paddr; 103 uchar dbuf[256]; 104 Drec *d = (Drec *)dbuf; 105 Xfile pf, ppf; 106 Isofile piso, ppiso; 107 108 memset(&pf, 0, sizeof pf); 109 memset(&ppf, 0, sizeof ppf); 110 pf.ptr = &piso; 111 ppf.ptr = &ppiso; 112 if(opendotdot(f, &pf) < 0) 113 error("can't open pf"); 114 paddr = l32(((Isofile *)pf.ptr)->d.addr); 115 if(l32(((Isofile *)f->ptr)->d.addr) == paddr) 116 return; 117 if(opendotdot(&pf, &ppf) < 0) 118 error("can't open ppf"); 119 while(getdrec(&ppf, d) >= 0){ 120 if(l32(d->addr) == paddr){ 121 newdrec(f, d); 122 f->qid.path = paddr|CHDIR; 123 return; 124 } 125 } 126 error("can't find addr of .."); 127 } 128 129 static void 130 iwalk(Xfile *f, char *name) 131 { 132 Isofile *ip = f->ptr; 133 uchar dbuf[256]; 134 char nbuf[NAMELEN]; 135 Drec *d = (Drec*)dbuf; 136 Dir dir; 137 char *p; 138 int len, vers, dvers; 139 140 vers = -1; 141 if(p = strchr(name, ';')) { /* assign = */ 142 len = p-name; 143 if(len >= NAMELEN) 144 len = NAMELEN-1; 145 memmove(nbuf, name, len); 146 vers = strtoul(p+1, 0, 10); 147 name = nbuf; 148 } 149 len = strlen(name); 150 if(len >= NAMELEN) 151 len = NAMELEN-1; 152 name[len] = 0; 153 154 chat("%d \"%s\"...", len, name); 155 ip->offset = 0; 156 while(getdrec(f, d) >= 0) { 157 dvers = rzdir(f->xf->isplan9, &dir, 'z', d); 158 if(strcmp(name, dir.name) != 0) 159 continue; 160 newdrec(f, d); 161 f->qid.path = dir.qid.path; 162 USED(dvers); 163 return; 164 } 165 USED(vers); 166 error(Enonexist); 167 } 168 169 static void 170 iopen(Xfile *f, int mode) 171 { 172 mode &= ~OCEXEC; 173 if(mode != OREAD && mode != OEXEC) 174 error(Eperm); 175 ((Isofile*)f->ptr)->offset = 0; 176 ((Isofile*)f->ptr)->doffset = 0; 177 } 178 179 static void 180 icreate(Xfile *f, char *name, long perm, int mode) 181 { 182 USED(f, name, perm, mode); 183 error(Eperm); 184 } 185 186 static long 187 ireaddir(Xfile *f, char *buf, long offset, long count) 188 { 189 Isofile *ip = f->ptr; 190 Dir d; 191 uchar dbuf[256]; 192 Drec *drec = (Drec *)dbuf; 193 int rcnt = 0; 194 195 if(offset < ip->doffset){ 196 ip->offset = 0; 197 ip->doffset = 0; 198 } 199 while(rcnt < count && getdrec(f, drec) >= 0){ 200 if(drec->namelen == 1){ 201 if(drec->name[0] == 0) 202 continue; 203 if(drec->name[0] == 1) 204 continue; 205 } 206 if(ip->doffset < offset){ 207 ip->doffset += DIRLEN; 208 continue; 209 } 210 rzdir(f->xf->isplan9, &d, ip->fmt, drec); 211 d.qid.vers = f->qid.vers; 212 rcnt += convD2M(&d, &buf[rcnt]); 213 } 214 ip->doffset += rcnt; 215 return rcnt; 216 } 217 218 static long 219 iread(Xfile *f, char *buf, long offset, long count) 220 { 221 Isofile *ip = f->ptr; 222 long size, addr, o, n; 223 int rcnt = 0; 224 Iobuf *p; 225 226 size = l32(ip->d.size); 227 if(offset >= size) 228 return 0; 229 if(offset+count > size) 230 count = size - offset; 231 addr = (l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + offset; 232 o = addr % Sectorsize; 233 addr /= Sectorsize; 234 /*chat("d.addr=0x%x, addr=0x%x, o=0x%x...", l32(ip->d.addr), addr, o);*/ 235 n = Sectorsize - o; 236 237 while(count > 0){ 238 if(n > count) 239 n = count; 240 p = getbuf(f->xf->d, addr); 241 memmove(&buf[rcnt], &p->iobuf[o], n); 242 putbuf(p); 243 count -= n; 244 rcnt += n; 245 ++addr; 246 o = 0; 247 n = Sectorsize; 248 } 249 return rcnt; 250 } 251 252 static long 253 iwrite(Xfile *f, uchar *buf, long offset, long count) 254 { 255 USED(f, buf, offset, count); 256 error(Eperm); 257 return 0; 258 } 259 260 static void 261 iclunk(Xfile *f) 262 { 263 USED(f); 264 } 265 266 static void 267 iremove(Xfile *f) 268 { 269 USED(f); 270 error(Eperm); 271 } 272 273 static void 274 istat(Xfile *f, Dir *d) 275 { 276 Isofile *ip = f->ptr; 277 278 rzdir(f->xf->isplan9, d, ip->fmt, &ip->d); 279 d->qid.vers = f->qid.vers; 280 if(d->qid.path==f->xf->rootqid.path) 281 d->qid.path = CHDIR; 282 } 283 284 static void 285 iwstat(Xfile *f, Dir *d) 286 { 287 USED(f, d); 288 error(Eperm); 289 } 290 291 static int 292 showdrec(int fd, int fmt, void *x) 293 { 294 Drec *d = (Drec *)x; 295 int namelen, syslen; 296 297 if(d->reclen == 0) 298 return 0; 299 fprint(fd, "%d %d %d %d ", 300 d->reclen, d->attrlen, l32(d->addr), l32(d->size)); 301 fprint(fd, "%s 0x%2.2x %d %d %d ", 302 rdate(d->date, fmt), (fmt=='z' ? d->flags : d->r_flags), 303 d->unitsize, d->gapsize, l16(d->vseqno)); 304 fprint(fd, "%d %s", d->namelen, nstr(d->name, d->namelen)); 305 namelen = d->namelen + (1-(d->namelen&1)); 306 syslen = d->reclen - 33 - namelen; 307 if(syslen != 0) 308 fprint(fd, " %s", nstr(&d->name[namelen], syslen)); 309 fprint(fd, "\n"); 310 return d->reclen + (d->reclen&1); 311 } 312 313 static void 314 newdrec(Xfile *f, Drec *dp) 315 { 316 Isofile *x = f->ptr; 317 Isofile *n; 318 int len; 319 320 len = sizeof(Isofile) - sizeof(Drec) + dp->reclen; 321 n = ealloc(len); 322 n->fmt = x->fmt; 323 n->blksize = x->blksize; 324 n->offset = 0; 325 n->doffset = 0; 326 memmove(&n->d, dp, dp->reclen); 327 free(x); 328 f->ptr = n; 329 f->len = len; 330 } 331 332 static int 333 getdrec(Xfile *f, void *buf) 334 { 335 Isofile *ip = f->ptr; 336 int len = 0, boff = 0; 337 long size, addr; 338 Iobuf *p = 0; 339 340 if(!ip) 341 return -1; 342 size = l32(ip->d.size); 343 while(ip->offset<size){ 344 addr = (l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + ip->offset; 345 boff = addr % Sectorsize; 346 if(boff > Sectorsize-34){ 347 ip->offset += Sectorsize-boff; 348 continue; 349 } 350 p = getbuf(f->xf->d, addr/Sectorsize); 351 len = p->iobuf[boff]; 352 if(len >= 34) 353 break; 354 putbuf(p); 355 p = 0; 356 ip->offset += Sectorsize-boff; 357 } 358 if(p) { 359 memmove(buf, &p->iobuf[boff], len); 360 putbuf(p); 361 ip->offset += len + (len&1); 362 } 363 if(p) 364 return 0; 365 return -1; 366 } 367 368 static int 369 opendotdot(Xfile *f, Xfile *pf) 370 { 371 uchar dbuf[256]; 372 Drec *d = (Drec *)dbuf; 373 Isofile *ip = f->ptr, *pip = pf->ptr; 374 375 ip->offset = 0; 376 if(getdrec(f, d) < 0){ 377 chat("opendotdot: getdrec(.) failed..."); 378 return -1; 379 } 380 if(d->namelen != 1 || d->name[0] != 0){ 381 chat("opendotdot: no . entry..."); 382 return -1; 383 } 384 if(l32(d->addr) != l32(ip->d.addr)){ 385 chat("opendotdot: bad . address..."); 386 return -1; 387 } 388 if(getdrec(f, d) < 0){ 389 chat("opendotdot: getdrec(..) failed..."); 390 return -1; 391 } 392 if(d->namelen != 1 || d->name[0] != 1){ 393 chat("opendotdot: no .. entry..."); 394 return -1; 395 } 396 397 pf->xf = f->xf; 398 pip->fmt = ip->fmt; 399 pip->blksize = ip->blksize; 400 pip->offset = 0; 401 pip->doffset = 0; 402 pip->d = *d; 403 return 0; 404 } 405 406 static int 407 rzdir(int isplan9, Dir *d, int fmt, Drec *dp) 408 { 409 int n, flags, i, nl, vers; 410 uchar *s; 411 char *p; 412 413 flags = 0; 414 vers = -1; 415 d->qid.path = l32(dp->addr); 416 d->qid.vers = 0; 417 n = dp->namelen; 418 if(n >= NAMELEN) 419 n = NAMELEN-1; 420 memset(d->name, 0, NAMELEN); 421 if(n == 1) { 422 switch(dp->name[0]){ 423 case 1: 424 d->name[1] = '.'; 425 /* fall through */ 426 case 0: 427 d->name[0] = '.'; 428 break; 429 default: 430 d->name[0] = tolower(dp->name[0]); 431 } 432 } else { 433 for(i=0; i<n; i++) 434 d->name[i] = tolower(dp->name[i]); 435 } 436 437 if(isplan9 && dp->reclen>34+dp->namelen) { 438 /* 439 * get gid, uid, mode and possibly name 440 * from plan9 directory extension 441 */ 442 s = (uchar*)dp->name + dp->namelen; 443 if(((ulong)s) & 1) 444 s++; 445 nl = *s; 446 if(nl >= NAMELEN) 447 nl = NAMELEN-1; 448 if(nl) { 449 memset(d->name, 0, NAMELEN); 450 memmove(d->name, s+1, nl); 451 } 452 s += 1 + *s; 453 nl = *s; 454 if(nl >= NAMELEN) 455 nl = NAMELEN-1; 456 memset(d->uid, 0, NAMELEN); 457 memmove(d->uid, s+1, nl); 458 s += 1 + *s; 459 nl = *s; 460 if(nl >= NAMELEN) 461 nl = NAMELEN-1; 462 memset(d->gid, 0, NAMELEN); 463 memmove(d->gid, s+1, nl); 464 s += 1 + *s; 465 if(((ulong)s) & 1) 466 s++; 467 d->mode = l32(s); 468 if(d->mode & CHDIR) 469 d->qid.path |= CHDIR; 470 } else { 471 d->mode = 0444; 472 switch(fmt) { 473 case 'z': 474 strcpy(d->gid, "iso"); 475 flags = dp->flags; 476 break; 477 case 'r': 478 strcpy(d->gid, "sierra"); 479 flags = dp->r_flags; 480 break; 481 } 482 if(flags & 0x02){ 483 d->qid.path |= CHDIR; 484 d->mode |= CHDIR|0111; 485 } 486 strcpy(d->uid, "cdrom"); 487 p = strchr(d->name, ';'); 488 if(p != 0) { 489 vers = strtoul(p+1, 0, 10); 490 memset(p, 0, NAMELEN-(p-d->name)); 491 } 492 } 493 d->length = 0; 494 if((d->mode & CHDIR) == 0) 495 d->length = l32(dp->size); 496 d->type = 0; 497 d->dev = 0; 498 d->atime = gtime(dp->date); 499 d->mtime = d->atime; 500 return vers; 501 } 502 503 static char * 504 nstr(uchar *p, int n) 505 { 506 static char buf[132]; 507 char *q = buf; 508 509 while(--n >= 0){ 510 if(*p == '\\') 511 *q++ = '\\'; 512 if(' ' <= *p && *p <= '~') 513 *q++ = *p++; 514 else 515 q += sprint(q, "\\%2.2ux", *p++); 516 } 517 *q = 0; 518 return buf; 519 } 520 521 static char * 522 rdate(uchar *p, int fmt) 523 { 524 static char buf[64]; 525 int htz, s, n; 526 527 n = sprint(buf, "%2.2d.%2.2d.%2.2d %2.2d:%2.2d:%2.2d", 528 p[0], p[1], p[2], p[3], p[4], p[5]); 529 if(fmt == 'z'){ 530 htz = p[6]; 531 if(htz >= 128){ 532 htz = 256-htz; 533 s = '-'; 534 }else 535 s = '+'; 536 sprint(&buf[n], " (%c%.1f)", s, (float)htz/2); 537 } 538 return buf; 539 } 540 541 static char 542 dmsize[12] = 543 { 544 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 545 }; 546 547 static int 548 dysize(int y) 549 { 550 551 if((y%4) == 0) 552 return 366; 553 return 365; 554 } 555 556 static long 557 gtime(uchar *p) /* yMdhmsz */ 558 { 559 long t; 560 int i, y, M, d, h, m, s, tz; 561 y=p[0]; M=p[1]; d=p[2]; 562 h=p[3]; m=p[4]; s=p[5]; tz=p[6]; 563 USED(tz); 564 if (y < 70) 565 return 0; 566 if (M < 1 || M > 12) 567 return 0; 568 if (d < 1 || d > dmsize[M-1]) 569 return 0; 570 if (h > 23) 571 return 0; 572 if (m > 59) 573 return 0; 574 if (s > 59) 575 return 0; 576 y += 1900; 577 t = 0; 578 for(i=1970; i<y; i++) 579 t += dysize(i); 580 if (dysize(y)==366 && M >= 3) 581 t++; 582 while(--M) 583 t += dmsize[M-1]; 584 t += d-1; 585 t = 24*t + h; 586 t = 60*t + m; 587 t = 60*t + s; 588 return t; 589 } 590 591 #define p ((uchar*)arg) 592 593 static long 594 l16(void *arg) 595 { 596 long v; 597 598 v = ((long)p[1]<<8)|p[0]; 599 if (v >= 0x8000L) 600 v -= 0x10000L; 601 return v; 602 } 603 604 static long 605 l32(void *arg) 606 { 607 return ((((((long)p[3]<<8)|p[2])<<8)|p[1])<<8)|p[0]; 608 } 609 610 #undef p 611