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