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*);
39 ireset, iattach, iclone, iwalkup, iwalk, iopen, icreate,
40 ireaddir, iread, iwrite, iclunk, iremove, istat, iwstat
51 Iobuf *p; Voldesc *v; Isofile *fp; Drec *dp;
52 int fmt, blksize, i, n, l, haveplan9;
55 Drec *rd = (Drec *)dbuf;
63 for(i=VOLDESC;i<VOLDESC+100; i++){ /* +100 for sanity */
65 v = (Voldesc*)(p->iobuf);
66 if(memcmp(v->byte, "\01CD001\01", 7) == 0){ /* iso */
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);
79 chat("ignoring plan9");
89 if(memcmp(&v->byte[8], "\01CDROM\01", 7) == 0){ /* high sierra */
94 dp = (Drec*)v->r.desc.rootdir;
95 blksize = l16(v->r.desc.blksize);
96 chat("high sierra, blksize=%d...", blksize);
100 if(haveplan9==0 && !nojoliet
101 && memcmp(v->byte, "\02CD001\01", 7) == 0){
102 chat("%d %d\n", haveplan9, nojoliet);
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.
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 */
114 dp = (Drec*)v->z.desc.rootdir;
115 if(blksize != l16(v->z.desc.blksize))
116 fprint(2, "warning: suspicious Joliet blocksize\n");
122 if(v->byte[0] == 0xFF)
134 showdrec(2, fmt, dp);
135 if(blksize > Sectorsize){
136 chat("blksize too big...");
144 root->len = sizeof(Isofile) - sizeof(Drec) + dp->z.reclen;
145 root->ptr = fp = ealloc(root->len);
148 root->xf->isplan9 = 1;
151 fp->blksize = blksize;
154 memmove(&fp->d, dp, dp->z.reclen);
155 root->qid.path = l32(dp->z.addr);
156 root->qid.type = QTDIR;
159 if(getdrec(root, rd) >= 0){
160 n = rd->z.reclen-(34+rd->z.namelen);
161 s = (uchar*)rd->z.name + rd->z.namelen;
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){
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;
178 } else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){
179 n = getcontin(root->xf->d, s, &s);
181 } else if(s[0] == 'R' && s[1] == 'R'){
183 root->xf->isrock = 1;
185 } else if(s[0] == 'S' && s[1] == 'T')
191 chat("Rock Ridge...");
198 iclone(Xfile *of, Xfile *nf)
209 Drec *d = (Drec *)dbuf;
213 memset(&pf, 0, sizeof pf);
214 memset(&ppf, 0, sizeof ppf);
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)
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){
232 error("can't find addr of ..");
236 casestrcmp(int isplan9, char *a, char *b)
245 if(ca >= 'A' && ca <= 'Z')
247 if(cb >= 'A' && cb <= 'Z')
260 iwalk(Xfile *f, char *name)
262 Isofile *ip = f->ptr;
264 char nbuf[4*Maxname];
265 Drec *d = (Drec*)dbuf;
268 int len, vers, dvers;
271 if(p = strchr(name, ';')) { /* assign = */
275 memmove(nbuf, name, len);
276 vers = strtoul(p+1, 0, 10);
284 memmove(nbuf, name, len);
291 chat("%d \"%s\"...", strlen(name), name);
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)
299 f->qid.path = dir.qid.path;
300 f->qid.type = dir.qid.type;
309 iopen(Xfile *f, int mode)
312 if(mode != OREAD && mode != OEXEC)
319 icreate(Xfile *f, char *name, long perm, int mode)
329 ireaddir(Xfile *f, uchar *buf, long offset, long count)
331 Isofile *ip = f->ptr;
333 char names[4*Maxname];
335 Drec *drec = (Drec *)dbuf;
341 }else if(offset != ip->doffset)
342 error("seek in directory not allowed");
346 while(rcnt < count && getdrec(f, drec) >= 0){
347 if(drec->z.namelen == 1){
348 if(drec->z.name[0] == 0)
350 if(drec->z.name[0] == 1)
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){
366 iread(Xfile *f, char *buf, vlong offset, long count)
371 Isofile *ip = f->ptr;
374 size = l32(ip->d.z.size);
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;
382 /*chat("d.addr=%ld, addr=%lld, o=%d...", l32(ip->d.z.addr), addr, o);*/
388 p = getbuf(f->xf->d, addr);
389 memmove(&buf[rcnt], &p->iobuf[o], n);
401 iwrite(Xfile *f, char *buf, vlong offset, long count)
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){
438 iwstat(Xfile *f, Dir *d)
446 showdrec(int fd, int fmt, void *x)
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));
461 namelen = d->z.namelen + (1-(d->z.namelen&1));
462 syslen = d->z.reclen - 33 - namelen;
464 fprint(fd, " %s", nstr(&d->z.name[namelen], syslen));
467 return d->z.reclen + (d->z.reclen&1);
471 newdrec(Xfile *f, Drec *dp)
477 len = sizeof(Isofile) - sizeof(Drec) + dp->z.reclen;
480 n->blksize = x->blksize;
483 memmove(&n->d, dp, dp->z.reclen);
492 Isofile *ip = f->ptr;
494 if(ip->offset >= ip->odelta){
495 ip->offset -= ip->odelta;
501 getdrec(Xfile *f, void *buf)
503 Isofile *ip = f->ptr;
504 int len = 0, boff = 0;
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;
519 p = getbuf(f->xf->d, addr/Sectorsize);
520 len = p->iobuf[boff];
525 ip->offset += Sectorsize-boff;
528 memmove(buf, &p->iobuf[boff], len);
530 ip->odelta = len + (len&1);
531 ip->offset += ip->odelta;
538 opendotdot(Xfile *f, Xfile *pf)
541 Drec *d = (Drec *)dbuf;
542 Isofile *ip = f->ptr, *pip = pf->ptr;
545 if(getdrec(f, d) < 0){
546 chat("opendotdot: getdrec(.) failed...");
549 if(d->z.namelen != 1 || d->z.name[0] != 0){
550 chat("opendotdot: no . entry...");
553 if(l32(d->z.addr) != l32(ip->d.z.addr)){
554 chat("opendotdot: bad . address...");
557 if(getdrec(f, d) < 0){
558 chat("opendotdot: getdrec(..) failed...");
561 if(d->z.namelen != 1 || d->z.name[0] != 1){
562 chat("opendotdot: no .. entry...");
568 pip->blksize = ip->blksize;
581 rzdir(Xfs *fs, Dir *d, int fmt, Drec *dp)
583 int n, flags, i, j, lj, nl, vers, sysl, mode, l, have;
586 char buf[Maxname+UTFmax+1];
589 enum { ONAMELEN = 28 }; /* old Plan 9 directory name length */
594 d->qid.path = l32(dp->z.addr);
598 memset(d->name, 0, Maxname);
600 switch(dp->z.name[0]){
609 d->name[0] = tolower(dp->z.name[0]);
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){
616 r = (q[i]<<8)|q[i+1];
617 j += runetochar(buf+j, &r);
621 memmove(d->name, buf, j);
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) {
636 if(fs->isplan9 && sysl > 0) {
638 * get gid, uid, mode and possibly name
639 * from plan9 directory extension
645 memset(d->name, 0, ONAMELEN);
646 memmove(d->name, s+1, nl);
652 memset(d->uid, 0, ONAMELEN);
653 memmove(d->uid, s+1, nl);
658 memset(d->gid, 0, ONAMELEN);
659 memmove(d->gid, s+1, nl);
665 d->qid.type |= QTDIR;
671 strcpy(d->gid, "ridge");
673 strcpy(d->gid, "iso9660");
677 strcpy(d->gid, "sierra");
681 strcpy(d->gid, "joliet");
685 strcpy(d->gid, "plan9");
690 d->qid.type |= QTDIR;
691 d->mode |= DMDIR|0111;
693 strcpy(d->uid, "cdrom");
694 if(fmt!='9' && !(d->mode&DMDIR)){
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.
706 if((p=strchr(d->name, ';')) != nil){
707 vers = strtoul(p+1, 0, 0);
711 if((p=strchr(d->name, '.')) != nil && *(p+1)=='\0')
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 */
725 if(s[0] == 'P' && s[1] == 'X' && s[3] == 1){
726 /* posix file attributes */
728 d->mode = mode & 0777;
729 if((mode & 0170000) == 040000){
731 d->qid.type |= QTDIR;
734 } else if(s[0] == 'N' && s[1] == 'M' && s[3] == 1){
735 /* alternative name */
736 if((s[4] & ~1) == 0){
741 memmove(d->name+nl, s+5, i);
747 } else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){
748 sysl = getcontin(fs->d, s, &s);
750 } else if(s[0] == 'S' && s[1] == 'T')
756 if((d->mode & DMDIR) == 0)
757 d->length = l32(dp->z.size);
760 d->atime = gtime(dp->z.date);
766 getcontin(Xdata *dev, uchar *p, uchar **s)
774 chat("getcontin %d...", bn);
786 nstr(uchar *p, int n)
788 static char buf[132];
794 if(' ' <= *p && *p <= '~')
797 q += sprint(q, "\\%2.2ux", *p++);
804 rdate(uchar *p, int fmt)
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]);
818 sprint(&buf[n], " (%c%.1f)", s, (float)htz/2);
826 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
829 #define dysize mydysize
841 gtime(uchar *p) /* yMdhmsz */
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];
854 if (d < 1 || d > dmsize[M-1])
855 if (!(M == 2 && d == 29 && dysize(y) == 366))
864 for(i=1970; i<y; i++)
866 if (dysize(y)==366 && M >= 3)
877 #define p ((uchar*)arg)
884 v = ((long)p[1]<<8)|p[0];
893 return ((((((long)p[3]<<8)|p[2])<<8)|p[1])<<8)|p[0];