897 lines
17 KiB
C
897 lines
17 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <auth.h>
|
|
#include <fcall.h>
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
#include "iso9660.h"
|
|
|
|
static void ireset(void);
|
|
static int iattach(Xfile*);
|
|
static void iclone(Xfile*, Xfile*);
|
|
static void iwalkup(Xfile*);
|
|
static void iwalk(Xfile*, char*);
|
|
static void iopen(Xfile*, int);
|
|
static void icreate(Xfile*, char*, long, int);
|
|
static long ireaddir(Xfile*, uchar*, long, long);
|
|
static long iread(Xfile*, char*, vlong, long);
|
|
static long iwrite(Xfile*, char*, vlong, long);
|
|
static void iclunk(Xfile*);
|
|
static void iremove(Xfile*);
|
|
static void istat(Xfile*, Dir*);
|
|
static void iwstat(Xfile*, Dir*);
|
|
|
|
static char* nstr(uchar*, int);
|
|
static char* rdate(uchar*, int);
|
|
static int getcontin(Xdata*, uchar*, uchar**);
|
|
static int getdrec(Xfile*, void*);
|
|
static void ungetdrec(Xfile*);
|
|
static int opendotdot(Xfile*, Xfile*);
|
|
static int showdrec(int, int, void*);
|
|
static long gtime(uchar*);
|
|
static long l16(void*);
|
|
static long l32(void*);
|
|
static void newdrec(Xfile*, Drec*);
|
|
static int rzdir(Xfs*, Dir*, int, Drec*);
|
|
|
|
Xfsub isosub =
|
|
{
|
|
ireset, iattach, iclone, iwalkup, iwalk, iopen, icreate,
|
|
ireaddir, iread, iwrite, iclunk, iremove, istat, iwstat
|
|
};
|
|
|
|
static void
|
|
ireset(void)
|
|
{}
|
|
|
|
static int
|
|
iattach(Xfile *root)
|
|
{
|
|
Xfs *cd = root->xf;
|
|
Iobuf *p; Voldesc *v; Isofile *fp; Drec *dp;
|
|
int fmt, blksize, i, n, l, haveplan9;
|
|
Iobuf *dirp;
|
|
uchar dbuf[256];
|
|
Drec *rd = (Drec *)dbuf;
|
|
uchar *q, *s;
|
|
|
|
dirp = nil;
|
|
blksize = 0;
|
|
fmt = 0;
|
|
dp = nil;
|
|
haveplan9 = 0;
|
|
for(i=VOLDESC;i<VOLDESC+100; i++){ /* +100 for sanity */
|
|
p = getbuf(cd->d, i);
|
|
v = (Voldesc*)(p->iobuf);
|
|
if(memcmp(v->byte, "\01CD001\01", 7) == 0){ /* iso */
|
|
if(dirp)
|
|
putbuf(dirp);
|
|
dirp = p;
|
|
fmt = 'z';
|
|
dp = (Drec*)v->z.desc.rootdir;
|
|
blksize = l16(v->z.desc.blksize);
|
|
chat("iso, blksize=%d...", blksize);
|
|
|
|
v = (Voldesc*)(dirp->iobuf);
|
|
haveplan9 = (strncmp((char*)v->z.boot.sysid, "PLAN 9", 6)==0);
|
|
if(haveplan9){
|
|
if(noplan9) {
|
|
chat("ignoring plan9");
|
|
haveplan9 = 0;
|
|
} else {
|
|
fmt = '9';
|
|
chat("plan9 iso...");
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if(memcmp(&v->byte[8], "\01CDROM\01", 7) == 0){ /* high sierra */
|
|
if(dirp)
|
|
putbuf(dirp);
|
|
dirp = p;
|
|
fmt = 'r';
|
|
dp = (Drec*)v->r.desc.rootdir;
|
|
blksize = l16(v->r.desc.blksize);
|
|
chat("high sierra, blksize=%d...", blksize);
|
|
continue;
|
|
}
|
|
|
|
if(haveplan9==0 && !nojoliet
|
|
&& memcmp(v->byte, "\02CD001\01", 7) == 0){
|
|
chat("%d %d\n", haveplan9, nojoliet);
|
|
/*
|
|
* The right thing to do is walk the escape sequences looking
|
|
* for one of 25 2F 4[035], but Microsoft seems to not honor
|
|
* the format, which makes it hard to walk over.
|
|
*/
|
|
q = v->z.desc.escapes;
|
|
if(q[0] == 0x25 && q[1] == 0x2F && (q[2] == 0x40 || q[2] == 0x43 || q[2] == 0x45)){ /* Joliet, it appears */
|
|
if(dirp)
|
|
putbuf(dirp);
|
|
dirp = p;
|
|
fmt = 'J';
|
|
dp = (Drec*)v->z.desc.rootdir;
|
|
if(blksize != l16(v->z.desc.blksize))
|
|
fprint(2, "warning: suspicious Joliet blocksize\n");
|
|
chat("joliet...");
|
|
continue;
|
|
}
|
|
}
|
|
putbuf(p);
|
|
if(v->byte[0] == 0xFF)
|
|
break;
|
|
}
|
|
|
|
if(fmt == 0){
|
|
if(dirp)
|
|
putbuf(dirp);
|
|
return -1;
|
|
}
|
|
assert(dirp != nil);
|
|
|
|
if(chatty)
|
|
showdrec(2, fmt, dp);
|
|
if(blksize > Sectorsize){
|
|
chat("blksize too big...");
|
|
putbuf(dirp);
|
|
return -1;
|
|
}
|
|
if(waserror()){
|
|
putbuf(dirp);
|
|
nexterror();
|
|
}
|
|
root->len = sizeof(Isofile) - sizeof(Drec) + dp->z.reclen;
|
|
root->ptr = fp = ealloc(root->len);
|
|
|
|
if(haveplan9)
|
|
root->xf->isplan9 = 1;
|
|
|
|
fp->fmt = fmt;
|
|
fp->blksize = blksize;
|
|
fp->offset = 0;
|
|
fp->doffset = 0;
|
|
memmove(&fp->d, dp, dp->z.reclen);
|
|
root->qid.path = l32(dp->z.addr);
|
|
root->qid.type = QTDIR;
|
|
putbuf(dirp);
|
|
poperror();
|
|
if(getdrec(root, rd) >= 0){
|
|
n = rd->z.reclen-(34+rd->z.namelen);
|
|
s = (uchar*)rd->z.name + rd->z.namelen;
|
|
if((uintptr)s & 1){
|
|
s++;
|
|
n--;
|
|
}
|
|
if(n >= 7 && s[0] == 'S' && s[1] == 'P' && s[2] == 7 &&
|
|
s[3] == 1 && s[4] == 0xBE && s[5] == 0xEF){
|
|
root->xf->issusp = 1;
|
|
root->xf->suspoff = s[6];
|
|
n -= root->xf->suspoff;
|
|
s += root->xf->suspoff;
|
|
for(; n >= 4; s += l, n -= l){
|
|
l = s[2];
|
|
if(s[0] == 'E' && s[1] == 'R'){
|
|
if(!norock && s[4] == 10 && memcmp(s+8, "RRIP_1991A", 10) == 0)
|
|
root->xf->isrock = 1;
|
|
break;
|
|
} else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){
|
|
n = getcontin(root->xf->d, s, &s);
|
|
continue;
|
|
} else if(s[0] == 'R' && s[1] == 'R'){
|
|
if(!norock)
|
|
root->xf->isrock = 1;
|
|
break;
|
|
} else if(s[0] == 'S' && s[1] == 'T')
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(root->xf->isrock)
|
|
chat("Rock Ridge...");
|
|
fp->offset = 0;
|
|
fp->doffset = 0;
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
iclone(Xfile *of, Xfile *nf)
|
|
{
|
|
USED(of);
|
|
USED(nf);
|
|
}
|
|
|
|
static void
|
|
iwalkup(Xfile *f)
|
|
{
|
|
long paddr;
|
|
uchar dbuf[256];
|
|
Drec *d = (Drec *)dbuf;
|
|
Xfile pf, ppf;
|
|
Isofile piso, ppiso;
|
|
|
|
memset(&pf, 0, sizeof pf);
|
|
memset(&ppf, 0, sizeof ppf);
|
|
pf.ptr = &piso;
|
|
ppf.ptr = &ppiso;
|
|
if(opendotdot(f, &pf) < 0)
|
|
error("can't open pf");
|
|
paddr = l32(pf.ptr->d.z.addr);
|
|
if(l32(f->ptr->d.z.addr) == paddr)
|
|
return;
|
|
if(opendotdot(&pf, &ppf) < 0)
|
|
error("can't open ppf");
|
|
while(getdrec(&ppf, d) >= 0){
|
|
if(l32(d->z.addr) == paddr){
|
|
newdrec(f, d);
|
|
f->qid.path = paddr;
|
|
f->qid.type = QTDIR;
|
|
return;
|
|
}
|
|
}
|
|
error("can't find addr of ..");
|
|
}
|
|
|
|
static int
|
|
casestrcmp(int isplan9, char *a, char *b)
|
|
{
|
|
int ca, cb;
|
|
|
|
if(isplan9)
|
|
return strcmp(a, b);
|
|
for(;;) {
|
|
ca = *a++;
|
|
cb = *b++;
|
|
if(ca >= 'A' && ca <= 'Z')
|
|
ca += 'a' - 'A';
|
|
if(cb >= 'A' && cb <= 'Z')
|
|
cb += 'a' - 'A';
|
|
if(ca != cb) {
|
|
if(ca > cb)
|
|
return 1;
|
|
return -1;
|
|
}
|
|
if(ca == 0)
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
iwalk(Xfile *f, char *name)
|
|
{
|
|
Isofile *ip = f->ptr;
|
|
uchar dbuf[256];
|
|
char nbuf[4*Maxname];
|
|
Drec *d = (Drec*)dbuf;
|
|
Dir dir;
|
|
char *p;
|
|
int len, vers, dvers;
|
|
|
|
vers = -1;
|
|
if(p = strchr(name, ';')) { /* assign = */
|
|
len = p-name;
|
|
if(len >= Maxname)
|
|
len = Maxname-1;
|
|
memmove(nbuf, name, len);
|
|
vers = strtoul(p+1, 0, 10);
|
|
name = nbuf;
|
|
}
|
|
/*
|
|
len = strlen(name);
|
|
if(len >= Maxname){
|
|
len = Maxname-1;
|
|
if(name != nbuf){
|
|
memmove(nbuf, name, len);
|
|
name = nbuf;
|
|
}
|
|
name[len] = 0;
|
|
}
|
|
*/
|
|
|
|
chat("%d \"%s\"...", strlen(name), name);
|
|
ip->offset = 0;
|
|
setnames(&dir, nbuf);
|
|
while(getdrec(f, d) >= 0) {
|
|
dvers = rzdir(f->xf, &dir, ip->fmt, d);
|
|
if(casestrcmp(f->xf->isplan9||f->xf->isrock, name, dir.name) != 0)
|
|
continue;
|
|
newdrec(f, d);
|
|
f->qid.path = dir.qid.path;
|
|
f->qid.type = dir.qid.type;
|
|
USED(dvers);
|
|
return;
|
|
}
|
|
USED(vers);
|
|
error(Enonexist);
|
|
}
|
|
|
|
static void
|
|
iopen(Xfile *f, int mode)
|
|
{
|
|
mode &= ~OCEXEC;
|
|
if(mode != OREAD && mode != OEXEC)
|
|
error(Eperm);
|
|
f->ptr->offset = 0;
|
|
f->ptr->doffset = 0;
|
|
}
|
|
|
|
static void
|
|
icreate(Xfile *f, char *name, long perm, int mode)
|
|
{
|
|
USED(f);
|
|
USED(name);
|
|
USED(perm);
|
|
USED(mode);
|
|
error(Eperm);
|
|
}
|
|
|
|
static long
|
|
ireaddir(Xfile *f, uchar *buf, long offset, long count)
|
|
{
|
|
Isofile *ip = f->ptr;
|
|
Dir d;
|
|
char names[4*Maxname];
|
|
uchar dbuf[256];
|
|
Drec *drec = (Drec *)dbuf;
|
|
int n, rcnt;
|
|
|
|
if(offset==0){
|
|
ip->offset = 0;
|
|
ip->doffset = 0;
|
|
}else if(offset != ip->doffset)
|
|
error("seek in directory not allowed");
|
|
|
|
rcnt = 0;
|
|
setnames(&d, names);
|
|
while(rcnt < count && getdrec(f, drec) >= 0){
|
|
if(drec->z.namelen == 1){
|
|
if(drec->z.name[0] == 0)
|
|
continue;
|
|
if(drec->z.name[0] == 1)
|
|
continue;
|
|
}
|
|
rzdir(f->xf, &d, ip->fmt, drec);
|
|
d.qid.vers = f->qid.vers;
|
|
if((n = convD2M(&d, buf+rcnt, count-rcnt)) <= BIT16SZ){
|
|
ungetdrec(f);
|
|
break;
|
|
}
|
|
rcnt += n;
|
|
}
|
|
ip->doffset += rcnt;
|
|
return rcnt;
|
|
}
|
|
|
|
static long
|
|
iread(Xfile *f, char *buf, vlong offset, long count)
|
|
{
|
|
int n, o, rcnt = 0;
|
|
long size;
|
|
vlong addr;
|
|
Isofile *ip = f->ptr;
|
|
Iobuf *p;
|
|
|
|
size = l32(ip->d.z.size);
|
|
if(offset >= size)
|
|
return 0;
|
|
if(offset+count > size)
|
|
count = size - offset;
|
|
addr = ((vlong)l32(ip->d.z.addr) + ip->d.z.attrlen)*ip->blksize + offset;
|
|
o = addr % Sectorsize;
|
|
addr /= Sectorsize;
|
|
/*chat("d.addr=%ld, addr=%lld, o=%d...", l32(ip->d.z.addr), addr, o);*/
|
|
n = Sectorsize - o;
|
|
|
|
while(count > 0){
|
|
if(n > count)
|
|
n = count;
|
|
p = getbuf(f->xf->d, addr);
|
|
memmove(&buf[rcnt], &p->iobuf[o], n);
|
|
putbuf(p);
|
|
count -= n;
|
|
rcnt += n;
|
|
++addr;
|
|
o = 0;
|
|
n = Sectorsize;
|
|
}
|
|
return rcnt;
|
|
}
|
|
|
|
static long
|
|
iwrite(Xfile *f, char *buf, vlong offset, long count)
|
|
{
|
|
USED(f);
|
|
USED(buf);
|
|
USED(offset);
|
|
USED(count);
|
|
error(Eperm);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
iclunk(Xfile *f)
|
|
{
|
|
USED(f);
|
|
}
|
|
|
|
static void
|
|
iremove(Xfile *f)
|
|
{
|
|
USED(f);
|
|
error(Eperm);
|
|
}
|
|
|
|
static void
|
|
istat(Xfile *f, Dir *d)
|
|
{
|
|
Isofile *ip = f->ptr;
|
|
|
|
rzdir(f->xf, d, ip->fmt, &ip->d);
|
|
d->qid.vers = f->qid.vers;
|
|
if(d->qid.path==f->xf->rootqid.path){
|
|
d->qid.path = 0;
|
|
d->qid.type = QTDIR;
|
|
}
|
|
}
|
|
|
|
static void
|
|
iwstat(Xfile *f, Dir *d)
|
|
{
|
|
USED(f);
|
|
USED(d);
|
|
error(Eperm);
|
|
}
|
|
|
|
static int
|
|
showdrec(int fd, int fmt, void *x)
|
|
{
|
|
Drec *d = (Drec *)x;
|
|
int namelen;
|
|
int syslen;
|
|
|
|
if(d->z.reclen == 0)
|
|
return 0;
|
|
fprint(fd, "%d %d %ld %ld ",
|
|
d->z.reclen, d->z.attrlen, l32(d->z.addr), l32(d->z.size));
|
|
fprint(fd, "%s 0x%2.2x %d %d %ld ",
|
|
rdate(d->z.date, fmt), (fmt=='z' ? d->z.flags : d->r.flags),
|
|
d->z.unitsize, d->z.gapsize, l16(d->z.vseqno));
|
|
fprint(fd, "%d %s", d->z.namelen, nstr(d->z.name, d->z.namelen));
|
|
if(fmt != 'J'){
|
|
namelen = d->z.namelen + (1-(d->z.namelen&1));
|
|
syslen = d->z.reclen - 33 - namelen;
|
|
if(syslen != 0)
|
|
fprint(fd, " %s", nstr(&d->z.name[namelen], syslen));
|
|
}
|
|
fprint(fd, "\n");
|
|
return d->z.reclen + (d->z.reclen&1);
|
|
}
|
|
|
|
static void
|
|
newdrec(Xfile *f, Drec *dp)
|
|
{
|
|
Isofile *x = f->ptr;
|
|
Isofile *n;
|
|
int len;
|
|
|
|
len = sizeof(Isofile) - sizeof(Drec) + dp->z.reclen;
|
|
n = ealloc(len);
|
|
n->fmt = x->fmt;
|
|
n->blksize = x->blksize;
|
|
n->offset = 0;
|
|
n->doffset = 0;
|
|
memmove(&n->d, dp, dp->z.reclen);
|
|
free(x);
|
|
f->ptr = n;
|
|
f->len = len;
|
|
}
|
|
|
|
static void
|
|
ungetdrec(Xfile *f)
|
|
{
|
|
Isofile *ip = f->ptr;
|
|
|
|
if(ip->offset >= ip->odelta){
|
|
ip->offset -= ip->odelta;
|
|
ip->odelta = 0;
|
|
}
|
|
}
|
|
|
|
static int
|
|
getdrec(Xfile *f, void *buf)
|
|
{
|
|
Isofile *ip = f->ptr;
|
|
int len = 0, boff = 0;
|
|
ulong size;
|
|
vlong addr;
|
|
Iobuf *p = 0;
|
|
|
|
if(!ip)
|
|
return -1;
|
|
size = l32(ip->d.z.size);
|
|
while(ip->offset < size){
|
|
addr = (l32(ip->d.z.addr)+ip->d.z.attrlen)*ip->blksize + ip->offset;
|
|
boff = addr % Sectorsize;
|
|
if(boff > Sectorsize-34){
|
|
ip->offset += Sectorsize-boff;
|
|
continue;
|
|
}
|
|
p = getbuf(f->xf->d, addr/Sectorsize);
|
|
len = p->iobuf[boff];
|
|
if(len >= 34)
|
|
break;
|
|
putbuf(p);
|
|
p = 0;
|
|
ip->offset += Sectorsize-boff;
|
|
}
|
|
if(p) {
|
|
memmove(buf, &p->iobuf[boff], len);
|
|
putbuf(p);
|
|
ip->odelta = len + (len&1);
|
|
ip->offset += ip->odelta;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
opendotdot(Xfile *f, Xfile *pf)
|
|
{
|
|
uchar dbuf[256];
|
|
Drec *d = (Drec *)dbuf;
|
|
Isofile *ip = f->ptr, *pip = pf->ptr;
|
|
|
|
ip->offset = 0;
|
|
if(getdrec(f, d) < 0){
|
|
chat("opendotdot: getdrec(.) failed...");
|
|
return -1;
|
|
}
|
|
if(d->z.namelen != 1 || d->z.name[0] != 0){
|
|
chat("opendotdot: no . entry...");
|
|
return -1;
|
|
}
|
|
if(l32(d->z.addr) != l32(ip->d.z.addr)){
|
|
chat("opendotdot: bad . address...");
|
|
return -1;
|
|
}
|
|
if(getdrec(f, d) < 0){
|
|
chat("opendotdot: getdrec(..) failed...");
|
|
return -1;
|
|
}
|
|
if(d->z.namelen != 1 || d->z.name[0] != 1){
|
|
chat("opendotdot: no .. entry...");
|
|
return -1;
|
|
}
|
|
|
|
pf->xf = f->xf;
|
|
pip->fmt = ip->fmt;
|
|
pip->blksize = ip->blksize;
|
|
pip->offset = 0;
|
|
pip->doffset = 0;
|
|
pip->d = *d;
|
|
return 0;
|
|
}
|
|
|
|
enum {
|
|
Hname = 1,
|
|
Hmode = 2,
|
|
};
|
|
|
|
static int
|
|
rzdir(Xfs *fs, Dir *d, int fmt, Drec *dp)
|
|
{
|
|
int n, flags, i, j, lj, nl, vers, sysl, mode, l, have;
|
|
uchar *s;
|
|
char *p;
|
|
char buf[Maxname+UTFmax+1];
|
|
uchar *q;
|
|
Rune r;
|
|
enum { ONAMELEN = 28 }; /* old Plan 9 directory name length */
|
|
|
|
have = 0;
|
|
flags = 0;
|
|
vers = -1;
|
|
d->qid.path = l32(dp->z.addr);
|
|
d->qid.type = 0;
|
|
d->qid.vers = 0;
|
|
n = dp->z.namelen;
|
|
memset(d->name, 0, Maxname);
|
|
if(n == 1) {
|
|
switch(dp->z.name[0]){
|
|
case 1:
|
|
d->name[1] = '.';
|
|
/* fall through */
|
|
case 0:
|
|
d->name[0] = '.';
|
|
have = Hname;
|
|
break;
|
|
default:
|
|
d->name[0] = tolower(dp->z.name[0]);
|
|
}
|
|
} else {
|
|
if(fmt == 'J'){ /* Joliet, 16-bit Unicode */
|
|
q = (uchar*)dp->z.name;
|
|
for(i=j=lj=0; i<n && j<Maxname; i+=2){
|
|
lj = j;
|
|
r = (q[i]<<8)|q[i+1];
|
|
j += runetochar(buf+j, &r);
|
|
}
|
|
if(j >= Maxname)
|
|
j = lj;
|
|
memmove(d->name, buf, j);
|
|
}else{
|
|
if(n >= Maxname)
|
|
n = Maxname-1;
|
|
for(i=0; i<n; i++)
|
|
d->name[i] = tolower(dp->z.name[i]);
|
|
}
|
|
}
|
|
|
|
sysl = dp->z.reclen-(34+dp->z.namelen);
|
|
s = (uchar*)dp->z.name + dp->z.namelen;
|
|
if(((uintptr)s) & 1) {
|
|
s++;
|
|
sysl--;
|
|
}
|
|
if(fs->isplan9 && sysl > 0) {
|
|
/*
|
|
* get gid, uid, mode and possibly name
|
|
* from plan9 directory extension
|
|
*/
|
|
nl = *s;
|
|
if(nl >= ONAMELEN)
|
|
nl = ONAMELEN-1;
|
|
if(nl) {
|
|
memset(d->name, 0, ONAMELEN);
|
|
memmove(d->name, s+1, nl);
|
|
}
|
|
s += 1 + *s;
|
|
nl = *s;
|
|
if(nl >= ONAMELEN)
|
|
nl = ONAMELEN-1;
|
|
memset(d->uid, 0, ONAMELEN);
|
|
memmove(d->uid, s+1, nl);
|
|
s += 1 + *s;
|
|
nl = *s;
|
|
if(nl >= ONAMELEN)
|
|
nl = ONAMELEN-1;
|
|
memset(d->gid, 0, ONAMELEN);
|
|
memmove(d->gid, s+1, nl);
|
|
s += 1 + *s;
|
|
if(((uintptr)s) & 1)
|
|
s++;
|
|
d->mode = l32(s);
|
|
if(d->mode & DMDIR)
|
|
d->qid.type |= QTDIR;
|
|
} else {
|
|
d->mode = 0444;
|
|
switch(fmt) {
|
|
case 'z':
|
|
if(fs->isrock)
|
|
strcpy(d->gid, "ridge");
|
|
else
|
|
strcpy(d->gid, "iso9660");
|
|
flags = dp->z.flags;
|
|
break;
|
|
case 'r':
|
|
strcpy(d->gid, "sierra");
|
|
flags = dp->r.flags;
|
|
break;
|
|
case 'J':
|
|
strcpy(d->gid, "joliet");
|
|
flags = dp->z.flags;
|
|
break;
|
|
case '9':
|
|
strcpy(d->gid, "plan9");
|
|
flags = dp->z.flags;
|
|
break;
|
|
}
|
|
if(flags & 0x02){
|
|
d->qid.type |= QTDIR;
|
|
d->mode |= DMDIR|0111;
|
|
}
|
|
strcpy(d->uid, "cdrom");
|
|
if(fmt!='9' && !(d->mode&DMDIR)){
|
|
/*
|
|
* ISO 9660 actually requires that you always have a . and a ;,
|
|
* even if there is no version and no extension. Very few writers
|
|
* do this. If the version is present, we use it for qid.vers.
|
|
* If there is no extension but there is a dot, we strip it off.
|
|
* (VMS heads couldn't comprehend the dot as a file name character
|
|
* rather than as just a separator between name and extension.)
|
|
*
|
|
* We don't do this for directory names because directories are
|
|
* not allowed to have extensions and versions.
|
|
*/
|
|
if((p=strchr(d->name, ';')) != nil){
|
|
vers = strtoul(p+1, 0, 0);
|
|
d->qid.vers = vers;
|
|
*p = '\0';
|
|
}
|
|
if((p=strchr(d->name, '.')) != nil && *(p+1)=='\0')
|
|
*p = '\0';
|
|
}
|
|
if(fs->issusp){
|
|
nl = 0;
|
|
s += fs->suspoff;
|
|
sysl -= fs->suspoff;
|
|
for(; sysl >= 4 && have != (Hname|Hmode); sysl -= l, s += l){
|
|
if(s[0] == 0 && ((uintptr)s & 1)){
|
|
/* MacOS pads individual entries, contrary to spec */
|
|
s++;
|
|
sysl--;
|
|
}
|
|
l = s[2];
|
|
if(s[0] == 'P' && s[1] == 'X' && s[3] == 1){
|
|
/* posix file attributes */
|
|
mode = l32(s+4);
|
|
d->mode = mode & 0777;
|
|
if((mode & 0170000) == 040000){
|
|
d->mode |= DMDIR;
|
|
d->qid.type |= QTDIR;
|
|
}
|
|
have |= Hmode;
|
|
} else if(s[0] == 'N' && s[1] == 'M' && s[3] == 1){
|
|
/* alternative name */
|
|
if((s[4] & ~1) == 0){
|
|
i = nl+l-5;
|
|
if(i >= Maxname)
|
|
i = Maxname-1;
|
|
if((i -= nl) > 0){
|
|
memmove(d->name+nl, s+5, i);
|
|
nl += i;
|
|
}
|
|
if(s[4] == 0)
|
|
have |= Hname;
|
|
}
|
|
} else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){
|
|
sysl = getcontin(fs->d, s, &s);
|
|
continue;
|
|
} else if(s[0] == 'S' && s[1] == 'T')
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
d->length = 0;
|
|
if((d->mode & DMDIR) == 0)
|
|
d->length = l32(dp->z.size);
|
|
d->type = 0;
|
|
d->dev = 0;
|
|
d->atime = gtime(dp->z.date);
|
|
d->mtime = d->atime;
|
|
return vers;
|
|
}
|
|
|
|
static int
|
|
getcontin(Xdata *dev, uchar *p, uchar **s)
|
|
{
|
|
long bn, off, len;
|
|
Iobuf *b;
|
|
|
|
bn = l32(p+4);
|
|
off = l32(p+12);
|
|
len = l32(p+20);
|
|
chat("getcontin %d...", bn);
|
|
b = getbuf(dev, bn);
|
|
if(b == 0){
|
|
*s = 0;
|
|
return 0;
|
|
}
|
|
*s = b->iobuf+off;
|
|
putbuf(b);
|
|
return len;
|
|
}
|
|
|
|
static char *
|
|
nstr(uchar *p, int n)
|
|
{
|
|
static char buf[132];
|
|
char *q = buf;
|
|
|
|
while(--n >= 0){
|
|
if(*p == '\\')
|
|
*q++ = '\\';
|
|
if(' ' <= *p && *p <= '~')
|
|
*q++ = *p++;
|
|
else
|
|
q += sprint(q, "\\%2.2ux", *p++);
|
|
}
|
|
*q = 0;
|
|
return buf;
|
|
}
|
|
|
|
static char *
|
|
rdate(uchar *p, int fmt)
|
|
{
|
|
static char buf[64];
|
|
int htz, s, n;
|
|
|
|
n = sprint(buf, "%2.2d.%2.2d.%2.2d %2.2d:%2.2d:%2.2d",
|
|
p[0], p[1], p[2], p[3], p[4], p[5]);
|
|
if(fmt == 'z'){
|
|
htz = p[6];
|
|
if(htz >= 128){
|
|
htz = 256-htz;
|
|
s = '-';
|
|
}else
|
|
s = '+';
|
|
sprint(&buf[n], " (%c%.1f)", s, (float)htz/2);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
static char
|
|
dmsize[12] =
|
|
{
|
|
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
|
|
};
|
|
|
|
#define dysize mydysize
|
|
|
|
static int
|
|
dysize(int y)
|
|
{
|
|
|
|
if((y%4) == 0)
|
|
return 366;
|
|
return 365;
|
|
}
|
|
|
|
static long
|
|
gtime(uchar *p) /* yMdhmsz */
|
|
{
|
|
long t;
|
|
int i, y, M, d, h, m, s, tz;
|
|
|
|
y=p[0]; M=p[1]; d=p[2];
|
|
h=p[3]; m=p[4]; s=p[5]; tz=p[6];
|
|
USED(tz);
|
|
y += 1900;
|
|
if (y < 1970)
|
|
return 0;
|
|
if (M < 1 || M > 12)
|
|
return 0;
|
|
if (d < 1 || d > dmsize[M-1])
|
|
if (!(M == 2 && d == 29 && dysize(y) == 366))
|
|
return 0;
|
|
if (h > 23)
|
|
return 0;
|
|
if (m > 59)
|
|
return 0;
|
|
if (s > 59)
|
|
return 0;
|
|
t = 0;
|
|
for(i=1970; i<y; i++)
|
|
t += dysize(i);
|
|
if (dysize(y)==366 && M >= 3)
|
|
t++;
|
|
while(--M)
|
|
t += dmsize[M-1];
|
|
t += d-1;
|
|
t = 24*t + h;
|
|
t = 60*t + m;
|
|
t = 60*t + s;
|
|
return t;
|
|
}
|
|
|
|
#define p ((uchar*)arg)
|
|
|
|
static long
|
|
l16(void *arg)
|
|
{
|
|
long v;
|
|
|
|
v = ((long)p[1]<<8)|p[0];
|
|
if (v >= 0x8000L)
|
|
v -= 0x10000L;
|
|
return v;
|
|
}
|
|
|
|
static long
|
|
l32(void *arg)
|
|
{
|
|
return ((((((long)p[3]<<8)|p[2])<<8)|p[1])<<8)|p[0];
|
|
}
|
|
|
|
#undef p
|