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