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*, vlong, 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
46 if(len == (1UL << 31) - 1) /* max. 9660 size? */
47 len = (1ULL << 63) - 1; /* pretend it's vast */
59 Iobuf *p; Voldesc *v; Isofile *fp; Drec *dp;
60 int fmt, blksize, i, n, l, haveplan9;
63 Drec *rd = (Drec *)dbuf;
71 for(i=VOLDESC;i<VOLDESC+100; i++){ /* +100 for sanity */
72 p = getbuf(cd->d, i, 1);
73 v = (Voldesc*)(p->iobuf);
74 if(memcmp(v->byte, "\01CD001\01", 7) == 0){ /* iso */
79 dp = (Drec*)v->z.desc.rootdir;
80 blksize = l16(v->z.desc.blksize);
81 chat("iso, blksize=%d...", blksize);
83 v = (Voldesc*)(dirp->iobuf);
84 haveplan9 = (strncmp((char*)v->z.boot.sysid, "PLAN 9", 6)==0);
87 chat("ignoring plan9");
97 if(memcmp(&v->byte[8], "\01CDROM\01", 7) == 0){ /* high sierra */
102 dp = (Drec*)v->r.desc.rootdir;
103 blksize = l16(v->r.desc.blksize);
104 chat("high sierra, blksize=%d...", blksize);
108 if(haveplan9==0 && !nojoliet
109 && memcmp(v->byte, "\02CD001\01", 7) == 0){
110 chat("%d %d\n", haveplan9, nojoliet);
112 * The right thing to do is walk the escape sequences looking
113 * for one of 25 2F 4[035], but Microsoft seems to not honor
114 * the format, which makes it hard to walk over.
116 q = v->z.desc.escapes;
117 if(q[0] == 0x25 && q[1] == 0x2F && (q[2] == 0x40 || q[2] == 0x43 || q[2] == 0x45)){ /* Joliet, it appears */
122 dp = (Drec*)v->z.desc.rootdir;
123 if(blksize != l16(v->z.desc.blksize))
124 fprint(2, "warning: suspicious Joliet blocksize\n");
130 if(v->byte[0] == 0xFF)
142 showdrec(2, fmt, dp);
143 if(blksize > Sectorsize){
144 chat("blksize too big...");
152 root->len = sizeof(Isofile) - sizeof(Drec) + dp->reclen;
153 root->ptr = fp = ealloc(root->len);
156 root->xf->isplan9 = 1;
159 fp->blksize = blksize;
162 memmove(&fp->d, dp, dp->reclen);
163 root->qid.path = l32(dp->addr);
164 root->qid.type = QTDIR;
167 if(getdrec(root, rd) >= 0){
168 n = rd->reclen-(34+rd->namelen);
169 s = (uchar*)rd->name + rd->namelen;
174 if(n >= 7 && s[0] == 'S' && s[1] == 'P' && s[2] == 7 &&
175 s[3] == 1 && s[4] == 0xBE && s[5] == 0xEF){
176 root->xf->issusp = 1;
177 root->xf->suspoff = s[6];
178 n -= root->xf->suspoff;
179 s += root->xf->suspoff;
180 for(; n >= 4; s += l, n -= l){
182 if(s[0] == 'E' && s[1] == 'R'){
183 if(!norock && s[4] == 10 && memcmp(s+8, "RRIP_1991A", 10) == 0)
184 root->xf->isrock = 1;
186 } else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){
187 n = getcontin(root->xf->d, s, &s);
189 } else if(s[0] == 'R' && s[1] == 'R'){
191 root->xf->isrock = 1;
193 } else if(s[0] == 'S' && s[1] == 'T')
199 chat("Rock Ridge...");
206 iclone(Xfile *of, Xfile *nf)
216 Drec *d = (Drec *)dbuf;
220 memset(&pf, 0, sizeof pf);
221 memset(&ppf, 0, sizeof ppf);
224 if(opendotdot(f, &pf) < 0)
225 error("can't open pf");
226 paddr = l32(pf.ptr->d.addr);
227 if(l32(f->ptr->d.addr) == paddr)
229 if(opendotdot(&pf, &ppf) < 0)
230 error("can't open ppf");
231 while(getdrec(&ppf, d) >= 0){
232 if(l32(d->addr) == paddr){
239 error("can't find addr of ..");
243 casestrcmp(int isplan9, char *a, char *b)
247 return cistrcmp(a, b);
251 iwalk(Xfile *f, char *name)
253 Isofile *ip = f->ptr;
255 char nbuf[4*Maxname];
256 Drec *d = (Drec*)dbuf;
259 int len, vers, dvers;
262 if(p = strchr(name, ';')) { /* assign = */
266 memmove(nbuf, name, len);
267 vers = strtoul(p+1, 0, 10);
275 memmove(nbuf, name, len);
282 chat("%d \"%s\"...", strlen(name), name);
284 setnames(&dir, nbuf);
285 while(getdrec(f, d) >= 0) {
286 dvers = rzdir(f->xf, &dir, ip->fmt, d);
287 if(casestrcmp(f->xf->isplan9||f->xf->isrock, name, dir.name) != 0)
290 f->qid.path = dir.qid.path;
291 f->qid.type = dir.qid.type;
300 iopen(Xfile *f, int mode)
303 if(mode != OREAD && mode != OEXEC)
310 icreate(Xfile *f, char *name, long perm, int mode)
312 USED(f, name, perm, mode);
317 ireaddir(Xfile *f, uchar *buf, vlong offset, long count)
319 Isofile *ip = f->ptr;
321 char names[4*Maxname];
323 Drec *drec = (Drec *)dbuf;
329 }else if(offset != ip->doffset)
330 error("seek in directory not allowed");
334 while(rcnt < count && getdrec(f, drec) >= 0){
335 if(drec->namelen == 1){
336 if(drec->name[0] == 0)
338 if(drec->name[0] == 1)
341 rzdir(f->xf, &d, ip->fmt, drec);
342 d.qid.vers = f->qid.vers;
343 if((n = convD2M(&d, buf+rcnt, count-rcnt)) <= BIT16SZ){
354 iread(Xfile *f, char *buf, vlong offset, long count)
358 Isofile *ip = f->ptr;
361 size = fakemax(l32(ip->d.size));
364 if(offset+count > size)
365 count = size - offset;
366 addr = ((vlong)l32(ip->d.addr) + ip->d.attrlen)*ip->blksize + offset;
367 o = addr % Sectorsize;
369 /*chat("d.addr=%ld, addr=%lld, o=%d...", l32(ip->d.addr), addr, o);*/
375 p = getbuf(f->xf->d, addr, 0);
376 memmove(&buf[rcnt], &p->iobuf[o], n);
388 iwrite(Xfile *f, char *buf, vlong offset, long count)
390 USED(f, buf, offset, count);
409 istat(Xfile *f, Dir *d)
411 Isofile *ip = f->ptr;
413 rzdir(f->xf, d, ip->fmt, &ip->d);
414 d->qid.vers = f->qid.vers;
415 if(d->qid.path==f->xf->rootqid.path){
422 iwstat(Xfile *f, Dir *d)
429 showdrec(int fd, int fmt, void *x)
437 fprint(fd, "%d %d %ld %ld ",
438 d->reclen, d->attrlen, l32(d->addr), l32(d->size));
439 fprint(fd, "%s 0x%2.2x %d %d %ld ",
440 rdate(d->date, fmt), (fmt=='z' ? d->flags : d->r_flags),
441 d->unitsize, d->gapsize, l16(d->vseqno));
442 fprint(fd, "%d %s", d->namelen, nstr(d->name, d->namelen));
444 namelen = d->namelen + (1-(d->namelen&1));
445 syslen = d->reclen - 33 - namelen;
447 fprint(fd, " %s", nstr(&d->name[namelen], syslen));
450 return d->reclen + (d->reclen&1);
454 newdrec(Xfile *f, Drec *dp)
460 len = sizeof(Isofile) - sizeof(Drec) + dp->reclen;
463 n->blksize = x->blksize;
466 memmove(&n->d, dp, dp->reclen);
475 Isofile *ip = f->ptr;
477 if(ip->offset >= ip->odelta){
478 ip->offset -= ip->odelta;
484 getdrec(Xfile *f, void *buf)
486 Isofile *ip = f->ptr;
487 int len = 0, boff = 0;
494 size = fakemax(l32(ip->d.size));
495 while(ip->offset < size){
496 addr = (l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + ip->offset;
497 boff = addr % Sectorsize;
498 if(boff > Sectorsize-34){
499 ip->offset += Sectorsize-boff;
502 p = getbuf(f->xf->d, addr/Sectorsize, 1);
503 len = p->iobuf[boff];
508 ip->offset += Sectorsize-boff;
511 memmove(buf, &p->iobuf[boff], len);
513 ip->odelta = len + (len&1);
514 ip->offset += ip->odelta;
521 opendotdot(Xfile *f, Xfile *pf)
524 Drec *d = (Drec *)dbuf;
525 Isofile *ip = f->ptr, *pip = pf->ptr;
528 if(getdrec(f, d) < 0){
529 chat("opendotdot: getdrec(.) failed...");
532 if(d->namelen != 1 || d->name[0] != 0){
533 chat("opendotdot: no . entry...");
536 if(l32(d->addr) != l32(ip->d.addr)){
537 chat("opendotdot: bad . address...");
540 if(getdrec(f, d) < 0){
541 chat("opendotdot: getdrec(..) failed...");
544 if(d->namelen != 1 || d->name[0] != 1){
545 chat("opendotdot: no .. entry...");
551 pip->blksize = ip->blksize;
564 rzdir(Xfs *fs, Dir *d, int fmt, Drec *dp)
566 int n, flags, i, j, lj, nl, vers, sysl, mode, l, have;
569 char buf[Maxname+UTFmax+1];
576 d->qid.path = l32(dp->addr);
580 memset(d->name, 0, Maxname);
591 d->name[0] = tolower(dp->name[0]);
594 if(fmt == 'J'){ /* Joliet, 16-bit Unicode */
595 q = (uchar*)dp->name;
596 for(i=j=lj=0; i<n && j<Maxname; i+=2){
598 r = (q[i]<<8)|q[i+1];
599 j += runetochar(buf+j, &r);
603 memmove(d->name, buf, j);
608 d->name[i] = tolower(dp->name[i]);
612 sysl = dp->reclen-(34+dp->namelen);
613 s = (uchar*)dp->name + dp->namelen;
614 if(((uintptr)s) & 1) {
618 if(fs->isplan9 && sysl > 0) {
620 * get gid, uid, mode and possibly name
621 * from plan9 directory extension
627 memset(d->name, 0, Maxname);
628 memmove(d->name, s+1, nl);
634 memset(d->uid, 0, Maxname);
635 memmove(d->uid, s+1, nl);
640 memset(d->gid, 0, Maxname);
641 memmove(d->gid, s+1, nl);
647 d->qid.type |= QTDIR;
653 strcpy(d->gid, "ridge");
655 strcpy(d->gid, "iso9660");
659 strcpy(d->gid, "sierra");
663 strcpy(d->gid, "joliet");
667 strcpy(d->gid, "plan9");
672 d->qid.type |= QTDIR;
673 d->mode |= DMDIR|0111;
675 strcpy(d->uid, "cdrom");
676 if(fmt!='9' && !(d->mode&DMDIR)){
678 * ISO 9660 actually requires that you always have a . and a ;,
679 * even if there is no version and no extension. Very few writers
680 * do this. If the version is present, we use it for qid.vers.
681 * If there is no extension but there is a dot, we strip it off.
682 * (VMS heads couldn't comprehend the dot as a file name character
683 * rather than as just a separator between name and extension.)
685 * We don't do this for directory names because directories are
686 * not allowed to have extensions and versions.
688 if((p=strchr(d->name, ';')) != nil){
689 vers = strtoul(p+1, 0, 0);
693 if((p=strchr(d->name, '.')) != nil && *(p+1)=='\0')
700 for(; sysl >= 4 && have != (Hname|Hmode); sysl -= l, s += l){
701 if(s[0] == 0 && ((uintptr)s & 1)){
702 /* MacOS pads individual entries, contrary to spec */
707 if(s[0] == 'P' && s[1] == 'X' && s[3] == 1){
708 /* posix file attributes */
710 d->mode = mode & 0777;
711 if((mode & 0170000) == 040000){
713 d->qid.type |= QTDIR;
716 } else if(s[0] == 'N' && s[1] == 'M' && s[3] == 1){
717 /* alternative name */
718 if((s[4] & ~1) == 0){
723 memmove(d->name+nl, s+5, i);
729 } else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){
730 sysl = getcontin(fs->d, s, &s);
732 } else if(s[0] == 'S' && s[1] == 'T')
738 if((d->mode & DMDIR) == 0)
739 d->length = fakemax(l32(dp->size));
742 d->atime = gtime(dp->date);
748 getcontin(Xdata *dev, uchar *p, uchar **s)
756 chat("getcontin %d...", bn);
757 b = getbuf(dev, bn, 1);
768 nstr(uchar *p, int n)
770 static char buf[132];
776 if(' ' <= *p && *p <= '~')
779 q += sprint(q, "\\%2.2ux", *p++);
786 rdate(uchar *p, int fmt)
791 n = sprint(buf, "%2.2d.%2.2d.%2.2d %2.2d:%2.2d:%2.2d",
792 p[0], p[1], p[2], p[3], p[4], p[5]);
800 sprint(&buf[n], " (%c%.1f)", s, (float)htz/2);
808 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
821 gtime(uchar *p) /* yMdhmsz */
824 int i, y, M, d, h, m, s, tz;
826 y=p[0]; M=p[1]; d=p[2];
827 h=p[3]; m=p[4]; s=p[5]; tz=p[6];
834 if (d < 1 || d > dmsize[M-1])
835 if (!(M == 2 && d == 29 && dysize(y) == 366))
844 for(i=1970; i<y; i++)
846 if (dysize(y)==366 && M >= 3)
857 #define p ((uchar*)arg)
864 v = ((long)p[1]<<8)|p[0];
873 return ((((((long)p[3]<<8)|p[2])<<8)|p[1])<<8)|p[0];