Blob


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"
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*);
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*);
37 Xfsub isosub =
38 {
39 ireset, iattach, iclone, iwalkup, iwalk, iopen, icreate,
40 ireaddir, iread, iwrite, iclunk, iremove, istat, iwstat
41 };
43 static void
44 ireset(void)
45 {}
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;
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);
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 }
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 }
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;
121 putbuf(p);
122 if(v->byte[0] == 0xFF)
123 break;
126 if(fmt == 0){
127 if(dirp)
128 putbuf(dirp);
129 return -1;
131 assert(dirp != nil);
133 if(chatty)
134 showdrec(2, fmt, dp);
135 if(blksize > Sectorsize){
136 chat("blksize too big...");
137 putbuf(dirp);
138 return -1;
140 if(waserror()){
141 putbuf(dirp);
142 nexterror();
144 root->len = sizeof(Isofile) - sizeof(Drec) + dp->z.reclen;
145 root->ptr = fp = ealloc(root->len);
147 if(haveplan9)
148 root->xf->isplan9 = 1;
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--;
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;
190 if(root->xf->isrock)
191 chat("Rock Ridge...");
192 fp->offset = 0;
193 fp->doffset = 0;
194 return 0;
197 static void
198 iclone(Xfile *of, Xfile *nf)
200 USED(of);
201 USED(nf);
204 static void
205 iwalkup(Xfile *f)
207 long paddr;
208 uchar dbuf[256];
209 Drec *d = (Drec *)dbuf;
210 Xfile pf, ppf;
211 Isofile piso, ppiso;
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;
232 error("can't find addr of ..");
235 static int
236 casestrcmp(int isplan9, char *a, char *b)
238 int ca, cb;
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;
254 if(ca == 0)
255 return 0;
259 static void
260 iwalk(Xfile *f, char *name)
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;
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;
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;
287 name[len] = 0;
289 */
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;
304 USED(vers);
305 error(Enonexist);
308 static void
309 iopen(Xfile *f, int mode)
311 mode &= ~OCEXEC;
312 if(mode != OREAD && mode != OEXEC)
313 error(Eperm);
314 f->ptr->offset = 0;
315 f->ptr->doffset = 0;
318 static void
319 icreate(Xfile *f, char *name, long perm, int mode)
321 USED(f);
322 USED(name);
323 USED(perm);
324 USED(mode);
325 error(Eperm);
328 static long
329 ireaddir(Xfile *f, uchar *buf, long offset, long count)
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;
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");
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;
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;
359 rcnt += n;
361 ip->doffset += rcnt;
362 return rcnt;
365 static long
366 iread(Xfile *f, char *buf, vlong offset, long count)
368 int n, o, rcnt = 0;
369 long size;
370 vlong addr;
371 Isofile *ip = f->ptr;
372 Iobuf *p;
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;
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;
397 return rcnt;
400 static long
401 iwrite(Xfile *f, char *buf, vlong offset, long count)
403 USED(f);
404 USED(buf);
405 USED(offset);
406 USED(count);
407 error(Eperm);
408 return 0;
411 static void
412 iclunk(Xfile *f)
414 USED(f);
417 static void
418 iremove(Xfile *f)
420 USED(f);
421 error(Eperm);
424 static void
425 istat(Xfile *f, Dir *d)
427 Isofile *ip = f->ptr;
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;
437 static void
438 iwstat(Xfile *f, Dir *d)
440 USED(f);
441 USED(d);
442 error(Eperm);
445 static int
446 showdrec(int fd, int fmt, void *x)
448 Drec *d = (Drec *)x;
449 int namelen;
450 int syslen;
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));
466 fprint(fd, "\n");
467 return d->z.reclen + (d->z.reclen&1);
470 static void
471 newdrec(Xfile *f, Drec *dp)
473 Isofile *x = f->ptr;
474 Isofile *n;
475 int len;
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;
489 static void
490 ungetdrec(Xfile *f)
492 Isofile *ip = f->ptr;
494 if(ip->offset >= ip->odelta){
495 ip->offset -= ip->odelta;
496 ip->odelta = 0;
500 static int
501 getdrec(Xfile *f, void *buf)
503 Isofile *ip = f->ptr;
504 int len = 0, boff = 0;
505 ulong size;
506 vlong addr;
507 Iobuf *p = 0;
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;
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;
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;
534 return -1;
537 static int
538 opendotdot(Xfile *f, Xfile *pf)
540 uchar dbuf[256];
541 Drec *d = (Drec *)dbuf;
542 Isofile *ip = f->ptr, *pip = pf->ptr;
544 ip->offset = 0;
545 if(getdrec(f, d) < 0){
546 chat("opendotdot: getdrec(.) failed...");
547 return -1;
549 if(d->z.namelen != 1 || d->z.name[0] != 0){
550 chat("opendotdot: no . entry...");
551 return -1;
553 if(l32(d->z.addr) != l32(ip->d.z.addr)){
554 chat("opendotdot: bad . address...");
555 return -1;
557 if(getdrec(f, d) < 0){
558 chat("opendotdot: getdrec(..) failed...");
559 return -1;
561 if(d->z.namelen != 1 || d->z.name[0] != 1){
562 chat("opendotdot: no .. entry...");
563 return -1;
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;
575 enum {
576 Hname = 1,
577 Hmode = 2,
578 };
580 static int
581 rzdir(Xfs *fs, Dir *d, int fmt, Drec *dp)
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 */
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]);
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);
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]);
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--;
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);
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;
689 if(flags & 0x02){
690 d->qid.type |= QTDIR;
691 d->mode |= DMDIR|0111;
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.)
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';
711 if((p=strchr(d->name, '.')) != nil && *(p+1)=='\0')
712 *p = '\0';
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--;
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;
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;
744 if(s[4] == 0)
745 have |= Hname;
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;
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;
765 static int
766 getcontin(Xdata *dev, uchar *p, uchar **s)
768 long bn, off, len;
769 Iobuf *b;
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;
780 *s = b->iobuf+off;
781 putbuf(b);
782 return len;
785 static char *
786 nstr(uchar *p, int n)
788 static char buf[132];
789 char *q = buf;
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++);
799 *q = 0;
800 return buf;
803 static char *
804 rdate(uchar *p, int fmt)
806 static char buf[64];
807 int htz, s, n;
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);
820 return buf;
823 static char
824 dmsize[12] =
826 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
827 };
829 #define dysize mydysize
831 static int
832 dysize(int y)
835 if((y%4) == 0)
836 return 366;
837 return 365;
840 static long
841 gtime(uchar *p) /* yMdhmsz */
843 long t;
844 int i, y, M, d, h, m, s, tz;
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;
877 #define p ((uchar*)arg)
879 static long
880 l16(void *arg)
882 long v;
884 v = ((long)p[1]<<8)|p[0];
885 if (v >= 0x8000L)
886 v -= 0x10000L;
887 return v;
890 static long
891 l32(void *arg)
893 return ((((((long)p[3]<<8)|p[2])<<8)|p[1])<<8)|p[0];
896 #undef p