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
fakemax(vlong len)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
ireset(void)53 ireset(void)
54 {}
55
56 static int
iattach(Xfile * root)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
iclone(Xfile * of,Xfile * nf)207 iclone(Xfile *of, Xfile *nf)
208 {
209 USED(of, nf);
210 }
211
212 static void
iwalkup(Xfile * f)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
casestrcmp(int isplan9,char * a,char * b)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
iwalk(Xfile * f,char * name)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
iopen(Xfile * f,int mode)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
icreate(Xfile * f,char * name,long perm,int mode)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
ireaddir(Xfile * f,uchar * buf,long offset,long count)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
iread(Xfile * f,char * buf,vlong offset,long count)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
iwrite(Xfile * f,char * buf,vlong offset,long count)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
iclunk(Xfile * f)397 iclunk(Xfile *f)
398 {
399 USED(f);
400 }
401
402 static void
iremove(Xfile * f)403 iremove(Xfile *f)
404 {
405 USED(f);
406 error(Eperm);
407 }
408
409 static void
istat(Xfile * f,Dir * d)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
iwstat(Xfile * f,Dir * d)423 iwstat(Xfile *f, Dir *d)
424 {
425 USED(f, d);
426 error(Eperm);
427 }
428
429 static int
showdrec(int fd,int fmt,void * x)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
newdrec(Xfile * f,Drec * dp)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
ungetdrec(Xfile * f)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
getdrec(Xfile * f,void * buf)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
opendotdot(Xfile * f,Xfile * pf)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
rzdir(Xfs * fs,Dir * d,int fmt,Drec * dp)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
getcontin(Xdata * dev,uchar * p,uchar ** s)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 *
nstr(uchar * p,int n)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 *
rdate(uchar * p,int fmt)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
dysize(int y)814 dysize(int y)
815 {
816
817 if((y%4) == 0)
818 return 366;
819 return 365;
820 }
821
822 static long
gtime(uchar * p)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
l16(void * arg)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
l32(void * arg)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
l64(void * arg)881 l64(void *arg)
882 {
883 uchar *p;
884
885 p = arg;
886 return (vlong)l32(p+4) << 32 | (ulong)l32(p);
887 }
888