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*, uchar*, long, long); 17 static long iread(Xfile*, char*, long, long); 18 static long iwrite(Xfile*, char*, 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(uchar*, int); 25 static char* rdate(uchar*, int); 26 static int getcontin(Xdata*, uchar*, uchar**); 27 static int getdrec(Xfile*, void*); 28 static void ungetdrec(Xfile*); 29 static int opendotdot(Xfile*, Xfile*); 30 static int showdrec(int, int, void*); 31 static long gtime(uchar*); 32 static long l16(void*); 33 static long l32(void*); 34 static void newdrec(Xfile*, Drec*); 35 static int rzdir(Xfs*, Dir*, int, Drec*); 36 37 Xfsub isosub = 38 { 39 ireset, iattach, iclone, iwalkup, iwalk, iopen, icreate, 40 ireaddir, iread, iwrite, iclunk, iremove, istat, iwstat 41 }; 42 43 static void 44 ireset(void) 45 {} 46 47 static int 48 iattach(Xfile *root) 49 { 50 Xfs *cd = root->xf; 51 Iobuf *p; Voldesc *v; Isofile *fp; Drec *dp; 52 int fmt, blksize, i, n, l, haveplan9; 53 Iobuf *dirp; 54 uchar dbuf[256]; 55 Drec *rd = (Drec *)dbuf; 56 uchar *q, *s; 57 58 dirp = nil; 59 blksize = 0; 60 fmt = 0; 61 dp = nil; 62 haveplan9 = 0; 63 for(i=VOLDESC;i<VOLDESC+100; i++){ /* +100 for sanity */ 64 p = getbuf(cd->d, i); 65 v = (Voldesc*)(p->iobuf); 66 if(memcmp(v->byte, "\01CD001\01", 7) == 0){ /* iso */ 67 if(dirp) 68 putbuf(dirp); 69 dirp = p; 70 fmt = 'z'; 71 dp = (Drec*)v->z.desc.rootdir; 72 blksize = l16(v->z.desc.blksize); 73 chat("iso, blksize=%d...", blksize); 74 75 v = (Voldesc*)(dirp->iobuf); 76 haveplan9 = (strncmp((char*)v->z.boot.sysid, "PLAN 9", 6)==0); 77 if(haveplan9){ 78 if(noplan9) { 79 chat("ignoring plan9"); 80 haveplan9 = 0; 81 } else { 82 fmt = '9'; 83 chat("plan9 iso..."); 84 } 85 } 86 continue; 87 } 88 89 if(memcmp(&v->byte[8], "\01CDROM\01", 7) == 0){ /* high sierra */ 90 if(dirp) 91 putbuf(dirp); 92 dirp = p; 93 fmt = 'r'; 94 dp = (Drec*)v->r.desc.rootdir; 95 blksize = l16(v->r.desc.blksize); 96 chat("high sierra, blksize=%d...", blksize); 97 continue; 98 } 99 100 if(haveplan9==0 && !nojoliet 101 && memcmp(v->byte, "\02CD001\01", 7) == 0){ 102 chat("%d %d\n", haveplan9, nojoliet); 103 /* 104 * The right thing to do is walk the escape sequences looking 105 * for one of 25 2F 4[035], but Microsoft seems to not honor 106 * the format, which makes it hard to walk over. 107 */ 108 q = v->z.desc.escapes; 109 if(q[0] == 0x25 && q[1] == 0x2F && (q[2] == 0x40 || q[2] == 0x43 || q[2] == 0x45)){ /* Joliet, it appears */ 110 if(dirp) 111 putbuf(dirp); 112 dirp = p; 113 fmt = 'J'; 114 dp = (Drec*)v->z.desc.rootdir; 115 if(blksize != l16(v->z.desc.blksize)) 116 fprint(2, "warning: suspicious Joliet blocksize\n"); 117 chat("joliet..."); 118 continue; 119 } 120 } 121 putbuf(p); 122 if(v->byte[0] == 0xFF) 123 break; 124 } 125 126 if(fmt == 0){ 127 if(dirp) 128 putbuf(dirp); 129 return -1; 130 } 131 assert(dirp != nil); 132 133 if(chatty) 134 showdrec(2, fmt, dp); 135 if(blksize > Sectorsize){ 136 chat("blksize too big..."); 137 putbuf(dirp); 138 return -1; 139 } 140 if(waserror()){ 141 putbuf(dirp); 142 nexterror(); 143 } 144 root->len = sizeof(Isofile) - sizeof(Drec) + dp->reclen; 145 root->ptr = fp = ealloc(root->len); 146 147 if(haveplan9) 148 root->xf->isplan9 = 1; 149 150 fp->fmt = fmt; 151 fp->blksize = blksize; 152 fp->offset = 0; 153 fp->doffset = 0; 154 memmove(&fp->d, dp, dp->reclen); 155 root->qid.path = l32(dp->addr); 156 root->qid.type = QTDIR; 157 putbuf(dirp); 158 poperror(); 159 if(getdrec(root, rd) >= 0){ 160 n = rd->reclen-(34+rd->namelen); 161 s = (uchar*)rd->name + rd->namelen; 162 if((ulong)s & 1){ 163 s++; 164 n--; 165 } 166 if(n >= 7 && s[0] == 'S' && s[1] == 'P' && s[2] == 7 && 167 s[3] == 1 && s[4] == 0xBE && s[5] == 0xEF){ 168 root->xf->issusp = 1; 169 root->xf->suspoff = s[6]; 170 n -= root->xf->suspoff; 171 s += root->xf->suspoff; 172 for(; n >= 4; s += l, n -= l){ 173 l = s[2]; 174 if(s[0] == 'E' && s[1] == 'R'){ 175 if(!norock && s[4] == 10 && memcmp(s+8, "RRIP_1991A", 10) == 0) 176 root->xf->isrock = 1; 177 break; 178 } else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){ 179 n = getcontin(root->xf->d, s, &s); 180 continue; 181 } else if(s[0] == 'R' && s[1] == 'R'){ 182 if(!norock) 183 root->xf->isrock = 1; 184 break; 185 } else if(s[0] == 'S' && s[1] == 'T') 186 break; 187 } 188 } 189 } 190 if(root->xf->isrock) 191 chat("Rock Ridge..."); 192 fp->offset = 0; 193 fp->doffset = 0; 194 return 0; 195 } 196 197 static void 198 iclone(Xfile *of, Xfile *nf) 199 { 200 USED(of, nf); 201 } 202 203 static void 204 iwalkup(Xfile *f) 205 { 206 long paddr; 207 uchar dbuf[256]; 208 Drec *d = (Drec *)dbuf; 209 Xfile pf, ppf; 210 Isofile piso, ppiso; 211 212 memset(&pf, 0, sizeof pf); 213 memset(&ppf, 0, sizeof ppf); 214 pf.ptr = &piso; 215 ppf.ptr = &ppiso; 216 if(opendotdot(f, &pf) < 0) 217 error("can't open pf"); 218 paddr = l32(pf.ptr->d.addr); 219 if(l32(f->ptr->d.addr) == paddr) 220 return; 221 if(opendotdot(&pf, &ppf) < 0) 222 error("can't open ppf"); 223 while(getdrec(&ppf, d) >= 0){ 224 if(l32(d->addr) == paddr){ 225 newdrec(f, d); 226 f->qid.path = paddr; 227 f->qid.type = QTDIR; 228 return; 229 } 230 } 231 error("can't find addr of .."); 232 } 233 234 static int 235 casestrcmp(int isplan9, char *a, char *b) 236 { 237 int ca, cb; 238 239 if(isplan9) 240 return strcmp(a, b); 241 for(;;) { 242 ca = *a++; 243 cb = *b++; 244 if(ca >= 'A' && ca <= 'Z') 245 ca += 'a' - 'A'; 246 if(cb >= 'A' && cb <= 'Z') 247 cb += 'a' - 'A'; 248 if(ca != cb) { 249 if(ca > cb) 250 return 1; 251 return -1; 252 } 253 if(ca == 0) 254 return 0; 255 } 256 } 257 258 static void 259 iwalk(Xfile *f, char *name) 260 { 261 Isofile *ip = f->ptr; 262 uchar dbuf[256]; 263 char nbuf[4*Maxname]; 264 Drec *d = (Drec*)dbuf; 265 Dir dir; 266 char *p; 267 int len, vers, dvers; 268 269 vers = -1; 270 if(p = strchr(name, ';')) { /* assign = */ 271 len = p-name; 272 if(len >= Maxname) 273 len = Maxname-1; 274 memmove(nbuf, name, len); 275 vers = strtoul(p+1, 0, 10); 276 name = nbuf; 277 } 278 /* 279 len = strlen(name); 280 if(len >= Maxname){ 281 len = Maxname-1; 282 if(name != nbuf){ 283 memmove(nbuf, name, len); 284 name = nbuf; 285 } 286 name[len] = 0; 287 } 288 */ 289 290 chat("%d \"%s\"...", strlen(name), name); 291 ip->offset = 0; 292 setnames(&dir, nbuf); 293 while(getdrec(f, d) >= 0) { 294 dvers = rzdir(f->xf, &dir, ip->fmt, d); 295 if(casestrcmp(f->xf->isplan9||f->xf->isrock, name, dir.name) != 0) 296 continue; 297 newdrec(f, d); 298 f->qid.path = dir.qid.path; 299 f->qid.type = dir.qid.type; 300 USED(dvers); 301 return; 302 } 303 USED(vers); 304 error(Enonexist); 305 } 306 307 static void 308 iopen(Xfile *f, int mode) 309 { 310 mode &= ~OCEXEC; 311 if(mode != OREAD && mode != OEXEC) 312 error(Eperm); 313 f->ptr->offset = 0; 314 f->ptr->doffset = 0; 315 } 316 317 static void 318 icreate(Xfile *f, char *name, long perm, int mode) 319 { 320 USED(f, name, perm, mode); 321 error(Eperm); 322 } 323 324 static long 325 ireaddir(Xfile *f, uchar *buf, long offset, long count) 326 { 327 Isofile *ip = f->ptr; 328 Dir d; 329 char names[4*Maxname]; 330 uchar dbuf[256]; 331 Drec *drec = (Drec *)dbuf; 332 int n, rcnt; 333 334 if(offset==0){ 335 ip->offset = 0; 336 ip->doffset = 0; 337 }else if(offset != ip->doffset) 338 error("seek in directory not allowed"); 339 340 rcnt = 0; 341 setnames(&d, names); 342 while(rcnt < count && getdrec(f, drec) >= 0){ 343 if(drec->namelen == 1){ 344 if(drec->name[0] == 0) 345 continue; 346 if(drec->name[0] == 1) 347 continue; 348 } 349 rzdir(f->xf, &d, ip->fmt, drec); 350 d.qid.vers = f->qid.vers; 351 if((n = convD2M(&d, buf+rcnt, count-rcnt)) <= BIT16SZ){ 352 ungetdrec(f); 353 break; 354 } 355 rcnt += n; 356 } 357 ip->doffset += rcnt; 358 return rcnt; 359 } 360 361 static long 362 iread(Xfile *f, char *buf, long offset, long count) 363 { 364 Isofile *ip = f->ptr; 365 long size, addr, o, n; 366 int rcnt = 0; 367 Iobuf *p; 368 369 size = l32(ip->d.size); 370 if(offset >= size) 371 return 0; 372 if(offset+count > size) 373 count = size - offset; 374 addr = (l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + offset; 375 o = (ulong)addr % Sectorsize; 376 addr = (ulong)addr / Sectorsize; 377 /*chat("d.addr=0x%x, addr=0x%x, o=0x%x...", l32(ip->d.addr), addr, o);*/ 378 n = Sectorsize - o; 379 380 while(count > 0){ 381 if(n > count) 382 n = count; 383 p = getbuf(f->xf->d, addr); 384 memmove(&buf[rcnt], &p->iobuf[o], n); 385 putbuf(p); 386 count -= n; 387 rcnt += n; 388 ++addr; 389 o = 0; 390 n = Sectorsize; 391 } 392 return rcnt; 393 } 394 395 static long 396 iwrite(Xfile *f, char *buf, long offset, long count) 397 { 398 USED(f, buf, offset, count); 399 error(Eperm); 400 return 0; 401 } 402 403 static void 404 iclunk(Xfile *f) 405 { 406 USED(f); 407 } 408 409 static void 410 iremove(Xfile *f) 411 { 412 USED(f); 413 error(Eperm); 414 } 415 416 static void 417 istat(Xfile *f, Dir *d) 418 { 419 Isofile *ip = f->ptr; 420 421 rzdir(f->xf, d, ip->fmt, &ip->d); 422 d->qid.vers = f->qid.vers; 423 if(d->qid.path==f->xf->rootqid.path){ 424 d->qid.path = 0; 425 d->qid.type = QTDIR; 426 } 427 } 428 429 static void 430 iwstat(Xfile *f, Dir *d) 431 { 432 USED(f, d); 433 error(Eperm); 434 } 435 436 static int 437 showdrec(int fd, int fmt, void *x) 438 { 439 Drec *d = (Drec *)x; 440 int namelen; 441 int syslen; 442 443 if(d->reclen == 0) 444 return 0; 445 fprint(fd, "%d %d %ld %ld ", 446 d->reclen, d->attrlen, l32(d->addr), l32(d->size)); 447 fprint(fd, "%s 0x%2.2x %d %d %ld ", 448 rdate(d->date, fmt), (fmt=='z' ? d->flags : d->r_flags), 449 d->unitsize, d->gapsize, l16(d->vseqno)); 450 fprint(fd, "%d %s", d->namelen, nstr(d->name, d->namelen)); 451 if(fmt != 'J'){ 452 namelen = d->namelen + (1-(d->namelen&1)); 453 syslen = d->reclen - 33 - namelen; 454 if(syslen != 0) 455 fprint(fd, " %s", nstr(&d->name[namelen], syslen)); 456 } 457 fprint(fd, "\n"); 458 return d->reclen + (d->reclen&1); 459 } 460 461 static void 462 newdrec(Xfile *f, Drec *dp) 463 { 464 Isofile *x = f->ptr; 465 Isofile *n; 466 int len; 467 468 len = sizeof(Isofile) - sizeof(Drec) + dp->reclen; 469 n = ealloc(len); 470 n->fmt = x->fmt; 471 n->blksize = x->blksize; 472 n->offset = 0; 473 n->doffset = 0; 474 memmove(&n->d, dp, dp->reclen); 475 free(x); 476 f->ptr = n; 477 f->len = len; 478 } 479 480 static void 481 ungetdrec(Xfile *f) 482 { 483 Isofile *ip = f->ptr; 484 485 if(ip->offset >= ip->odelta){ 486 ip->offset -= ip->odelta; 487 ip->odelta = 0; 488 } 489 } 490 491 static int 492 getdrec(Xfile *f, void *buf) 493 { 494 Isofile *ip = f->ptr; 495 int len = 0, boff = 0; 496 long size, addr; 497 Iobuf *p = 0; 498 499 if(!ip) 500 return -1; 501 size = l32(ip->d.size); 502 while(ip->offset<size){ 503 addr = (l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + ip->offset; 504 boff = (ulong)addr % Sectorsize; 505 if(boff > Sectorsize-34){ 506 ip->offset += Sectorsize-boff; 507 continue; 508 } 509 p = getbuf(f->xf->d, (ulong)addr/Sectorsize); 510 len = p->iobuf[boff]; 511 if(len >= 34) 512 break; 513 putbuf(p); 514 p = 0; 515 ip->offset += Sectorsize-boff; 516 } 517 if(p) { 518 memmove(buf, &p->iobuf[boff], len); 519 putbuf(p); 520 ip->odelta = len + (len&1); 521 ip->offset += ip->odelta; 522 } 523 if(p) 524 return 0; 525 return -1; 526 } 527 528 static int 529 opendotdot(Xfile *f, Xfile *pf) 530 { 531 uchar dbuf[256]; 532 Drec *d = (Drec *)dbuf; 533 Isofile *ip = f->ptr, *pip = pf->ptr; 534 535 ip->offset = 0; 536 if(getdrec(f, d) < 0){ 537 chat("opendotdot: getdrec(.) failed..."); 538 return -1; 539 } 540 if(d->namelen != 1 || d->name[0] != 0){ 541 chat("opendotdot: no . entry..."); 542 return -1; 543 } 544 if(l32(d->addr) != l32(ip->d.addr)){ 545 chat("opendotdot: bad . address..."); 546 return -1; 547 } 548 if(getdrec(f, d) < 0){ 549 chat("opendotdot: getdrec(..) failed..."); 550 return -1; 551 } 552 if(d->namelen != 1 || d->name[0] != 1){ 553 chat("opendotdot: no .. entry..."); 554 return -1; 555 } 556 557 pf->xf = f->xf; 558 pip->fmt = ip->fmt; 559 pip->blksize = ip->blksize; 560 pip->offset = 0; 561 pip->doffset = 0; 562 pip->d = *d; 563 return 0; 564 } 565 566 enum { 567 Hname = 1, 568 Hmode = 2, 569 }; 570 571 static int 572 rzdir(Xfs *fs, Dir *d, int fmt, Drec *dp) 573 { 574 int n, flags, i, j, lj, nl, vers, sysl, mode, l, have; 575 uchar *s; 576 char *p; 577 char buf[Maxname+UTFmax+1]; 578 uchar *q; 579 Rune r; 580 enum { ONAMELEN = 28 }; /* old Plan 9 directory name length */ 581 582 have = 0; 583 flags = 0; 584 vers = -1; 585 d->qid.path = l32(dp->addr); 586 d->qid.type = 0; 587 d->qid.vers = 0; 588 n = dp->namelen; 589 memset(d->name, 0, Maxname); 590 if(n == 1) { 591 switch(dp->name[0]){ 592 case 1: 593 d->name[1] = '.'; 594 /* fall through */ 595 case 0: 596 d->name[0] = '.'; 597 have = Hname; 598 break; 599 default: 600 d->name[0] = tolower(dp->name[0]); 601 } 602 } else { 603 if(fmt == 'J'){ /* Joliet, 16-bit Unicode */ 604 q = (uchar*)dp->name; 605 for(i=j=lj=0; i<n && j<Maxname; i+=2){ 606 lj = j; 607 r = (q[i]<<8)|q[i+1]; 608 j += runetochar(buf+j, &r); 609 } 610 if(j >= Maxname) 611 j = lj; 612 memmove(d->name, buf, j); 613 }else{ 614 if(n >= Maxname) 615 n = Maxname-1; 616 for(i=0; i<n; i++) 617 d->name[i] = tolower(dp->name[i]); 618 } 619 } 620 621 sysl = dp->reclen-(34+dp->namelen); 622 s = (uchar*)dp->name + dp->namelen; 623 if(((ulong)s) & 1) { 624 s++; 625 sysl--; 626 } 627 if(fs->isplan9 && sysl > 0) { 628 /* 629 * get gid, uid, mode and possibly name 630 * from plan9 directory extension 631 */ 632 nl = *s; 633 if(nl >= ONAMELEN) 634 nl = ONAMELEN-1; 635 if(nl) { 636 memset(d->name, 0, ONAMELEN); 637 memmove(d->name, s+1, nl); 638 } 639 s += 1 + *s; 640 nl = *s; 641 if(nl >= ONAMELEN) 642 nl = ONAMELEN-1; 643 memset(d->uid, 0, ONAMELEN); 644 memmove(d->uid, s+1, nl); 645 s += 1 + *s; 646 nl = *s; 647 if(nl >= ONAMELEN) 648 nl = ONAMELEN-1; 649 memset(d->gid, 0, ONAMELEN); 650 memmove(d->gid, s+1, nl); 651 s += 1 + *s; 652 if(((ulong)s) & 1) 653 s++; 654 d->mode = l32(s); 655 if(d->mode & DMDIR) 656 d->qid.type |= QTDIR; 657 } else { 658 d->mode = 0444; 659 switch(fmt) { 660 case 'z': 661 if(fs->isrock) 662 strcpy(d->gid, "ridge"); 663 else 664 strcpy(d->gid, "iso9660"); 665 flags = dp->flags; 666 break; 667 case 'r': 668 strcpy(d->gid, "sierra"); 669 flags = dp->r_flags; 670 break; 671 case 'J': 672 strcpy(d->gid, "joliet"); 673 flags = dp->flags; 674 break; 675 case '9': 676 strcpy(d->gid, "plan9"); 677 flags = dp->flags; 678 break; 679 } 680 if(flags & 0x02){ 681 d->qid.type |= QTDIR; 682 d->mode |= DMDIR|0111; 683 } 684 strcpy(d->uid, "cdrom"); 685 if(fmt!='9' && !(d->mode&DMDIR)){ 686 /* 687 * ISO 9660 actually requires that you always have a . and a ;, 688 * even if there is no version and no extension. Very few writers 689 * do this. If the version is present, we use it for qid.vers. 690 * If there is no extension but there is a dot, we strip it off. 691 * (VMS heads couldn't comprehend the dot as a file name character 692 * rather than as just a separator between name and extension.) 693 * 694 * We don't do this for directory names because directories are 695 * not allowed to have extensions and versions. 696 */ 697 if((p=strchr(d->name, ';')) != nil){ 698 vers = strtoul(p+1, 0, 0); 699 d->qid.vers = vers; 700 *p = '\0'; 701 } 702 if((p=strchr(d->name, '.')) != nil && *(p+1)=='\0') 703 *p = '\0'; 704 } 705 if(fs->issusp){ 706 nl = 0; 707 s += fs->suspoff; 708 sysl -= fs->suspoff; 709 for(; sysl >= 4 && have != (Hname|Hmode); sysl -= l, s += l){ 710 if(s[0] == 0 && ((ulong)s & 1)){ 711 /* MacOS pads individual entries, contrary to spec */ 712 s++; 713 sysl--; 714 } 715 l = s[2]; 716 if(s[0] == 'P' && s[1] == 'X' && s[3] == 1){ 717 /* posix file attributes */ 718 mode = l32(s+4); 719 d->mode = mode & 0777; 720 if((mode & 0170000) == 040000){ 721 d->mode |= DMDIR; 722 d->qid.type |= QTDIR; 723 } 724 have |= Hmode; 725 } else if(s[0] == 'N' && s[1] == 'M' && s[3] == 1){ 726 /* alternative name */ 727 if((s[4] & ~1) == 0){ 728 i = nl+l-5; 729 if(i >= Maxname) 730 i = Maxname-1; 731 if((i -= nl) > 0){ 732 memmove(d->name+nl, s+5, i); 733 nl += i; 734 } 735 if(s[4] == 0) 736 have |= Hname; 737 } 738 } else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){ 739 sysl = getcontin(fs->d, s, &s); 740 continue; 741 } else if(s[0] == 'S' && s[1] == 'T') 742 break; 743 } 744 } 745 } 746 d->length = 0; 747 if((d->mode & DMDIR) == 0) 748 d->length = l32(dp->size); 749 d->type = 0; 750 d->dev = 0; 751 d->atime = gtime(dp->date); 752 d->mtime = d->atime; 753 return vers; 754 } 755 756 static int 757 getcontin(Xdata *dev, uchar *p, uchar **s) 758 { 759 long bn, off, len; 760 Iobuf *b; 761 762 bn = l32(p+4); 763 off = l32(p+12); 764 len = l32(p+20); 765 chat("getcontin %d...", bn); 766 b = getbuf(dev, bn); 767 if(b == 0){ 768 *s = 0; 769 return 0; 770 } 771 *s = b->iobuf+off; 772 putbuf(b); 773 return len; 774 } 775 776 static char * 777 nstr(uchar *p, int n) 778 { 779 static char buf[132]; 780 char *q = buf; 781 782 while(--n >= 0){ 783 if(*p == '\\') 784 *q++ = '\\'; 785 if(' ' <= *p && *p <= '~') 786 *q++ = *p++; 787 else 788 q += sprint(q, "\\%2.2ux", *p++); 789 } 790 *q = 0; 791 return buf; 792 } 793 794 static char * 795 rdate(uchar *p, int fmt) 796 { 797 static char buf[64]; 798 int htz, s, n; 799 800 n = sprint(buf, "%2.2d.%2.2d.%2.2d %2.2d:%2.2d:%2.2d", 801 p[0], p[1], p[2], p[3], p[4], p[5]); 802 if(fmt == 'z'){ 803 htz = p[6]; 804 if(htz >= 128){ 805 htz = 256-htz; 806 s = '-'; 807 }else 808 s = '+'; 809 sprint(&buf[n], " (%c%.1f)", s, (float)htz/2); 810 } 811 return buf; 812 } 813 814 static char 815 dmsize[12] = 816 { 817 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 818 }; 819 820 static int 821 dysize(int y) 822 { 823 824 if((y%4) == 0) 825 return 366; 826 return 365; 827 } 828 829 static long 830 gtime(uchar *p) /* yMdhmsz */ 831 { 832 long t; 833 int i, y, M, d, h, m, s, tz; 834 y=p[0]; M=p[1]; d=p[2]; 835 h=p[3]; m=p[4]; s=p[5]; tz=p[6]; 836 USED(tz); 837 if (y < 70) 838 return 0; 839 if (M < 1 || M > 12) 840 return 0; 841 if (d < 1 || d > dmsize[M-1]) 842 return 0; 843 if (h > 23) 844 return 0; 845 if (m > 59) 846 return 0; 847 if (s > 59) 848 return 0; 849 y += 1900; 850 t = 0; 851 for(i=1970; i<y; i++) 852 t += dysize(i); 853 if (dysize(y)==366 && M >= 3) 854 t++; 855 while(--M) 856 t += dmsize[M-1]; 857 t += d-1; 858 t = 24*t + h; 859 t = 60*t + m; 860 t = 60*t + s; 861 return t; 862 } 863 864 #define p ((uchar*)arg) 865 866 static long 867 l16(void *arg) 868 { 869 long v; 870 871 v = ((long)p[1]<<8)|p[0]; 872 if (v >= 0x8000L) 873 v -= 0x10000L; 874 return v; 875 } 876 877 static long 878 l32(void *arg) 879 { 880 return ((((((long)p[3]<<8)|p[2])<<8)|p[1])<<8)|p[0]; 881 } 882 883 #undef p 884