From 78a779a3834cf39d7c0bcd93a15824b29df947a3 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 20 Jul 2008 03:23:19 -0400 Subject: 9660srv: import from Plan 9 --- src/cmd/9660srv/9660srv.c | 896 ++++++++++++++++++++++++++++++++++++++++++++++ src/cmd/9660srv/dat.h | 118 ++++++ src/cmd/9660srv/data.c | 22 ++ src/cmd/9660srv/fns.h | 17 + src/cmd/9660srv/iobuf.c | 177 +++++++++ src/cmd/9660srv/iso9660.h | 142 ++++++++ src/cmd/9660srv/main.c | 576 +++++++++++++++++++++++++++++ src/cmd/9660srv/mkfile | 17 + src/cmd/9660srv/xfile.c | 170 +++++++++ 9 files changed, 2135 insertions(+) create mode 100644 src/cmd/9660srv/9660srv.c create mode 100644 src/cmd/9660srv/dat.h create mode 100644 src/cmd/9660srv/data.c create mode 100644 src/cmd/9660srv/fns.h create mode 100644 src/cmd/9660srv/iobuf.c create mode 100644 src/cmd/9660srv/iso9660.h create mode 100644 src/cmd/9660srv/main.c create mode 100644 src/cmd/9660srv/mkfile create mode 100644 src/cmd/9660srv/xfile.c diff --git a/src/cmd/9660srv/9660srv.c b/src/cmd/9660srv/9660srv.c new file mode 100644 index 00000000..a64cedfd --- /dev/null +++ b/src/cmd/9660srv/9660srv.c @@ -0,0 +1,896 @@ +#include +#include +#include +#include +#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;id, 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->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->reclen); + root->qid.path = l32(dp->addr); + root->qid.type = QTDIR; + putbuf(dirp); + poperror(); + if(getdrec(root, rd) >= 0){ + n = rd->reclen-(34+rd->namelen); + s = (uchar*)rd->name + rd->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.addr); + if(l32(f->ptr->d.addr) == paddr) + return; + if(opendotdot(&pf, &ppf) < 0) + error("can't open ppf"); + while(getdrec(&ppf, d) >= 0){ + if(l32(d->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->namelen == 1){ + if(drec->name[0] == 0) + continue; + if(drec->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.size); + if(offset >= size) + return 0; + if(offset+count > size) + count = size - offset; + addr = ((vlong)l32(ip->d.addr) + ip->d.attrlen)*ip->blksize + offset; + o = addr % Sectorsize; + addr /= Sectorsize; + /*chat("d.addr=%ld, addr=%lld, o=%d...", l32(ip->d.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->reclen == 0) + return 0; + fprint(fd, "%d %d %ld %ld ", + d->reclen, d->attrlen, l32(d->addr), l32(d->size)); + fprint(fd, "%s 0x%2.2x %d %d %ld ", + rdate(d->date, fmt), (fmt=='z' ? d->flags : d->r_flags), + d->unitsize, d->gapsize, l16(d->vseqno)); + fprint(fd, "%d %s", d->namelen, nstr(d->name, d->namelen)); + if(fmt != 'J'){ + namelen = d->namelen + (1-(d->namelen&1)); + syslen = d->reclen - 33 - namelen; + if(syslen != 0) + fprint(fd, " %s", nstr(&d->name[namelen], syslen)); + } + fprint(fd, "\n"); + return d->reclen + (d->reclen&1); +} + +static void +newdrec(Xfile *f, Drec *dp) +{ + Isofile *x = f->ptr; + Isofile *n; + int len; + + len = sizeof(Isofile) - sizeof(Drec) + dp->reclen; + n = ealloc(len); + n->fmt = x->fmt; + n->blksize = x->blksize; + n->offset = 0; + n->doffset = 0; + memmove(&n->d, dp, dp->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.size); + while(ip->offset < size){ + addr = (l32(ip->d.addr)+ip->d.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->namelen != 1 || d->name[0] != 0){ + chat("opendotdot: no . entry..."); + return -1; + } + if(l32(d->addr) != l32(ip->d.addr)){ + chat("opendotdot: bad . address..."); + return -1; + } + if(getdrec(f, d) < 0){ + chat("opendotdot: getdrec(..) failed..."); + return -1; + } + if(d->namelen != 1 || d->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->addr); + d->qid.type = 0; + d->qid.vers = 0; + n = dp->namelen; + memset(d->name, 0, Maxname); + if(n == 1) { + switch(dp->name[0]){ + case 1: + d->name[1] = '.'; + /* fall through */ + case 0: + d->name[0] = '.'; + have = Hname; + break; + default: + d->name[0] = tolower(dp->name[0]); + } + } else { + if(fmt == 'J'){ /* Joliet, 16-bit Unicode */ + q = (uchar*)dp->name; + for(i=j=lj=0; i= Maxname) + j = lj; + memmove(d->name, buf, j); + }else{ + if(n >= Maxname) + n = Maxname-1; + for(i=0; iname[i] = tolower(dp->name[i]); + } + } + + sysl = dp->reclen-(34+dp->namelen); + s = (uchar*)dp->name + dp->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->flags; + break; + case 'r': + strcpy(d->gid, "sierra"); + flags = dp->r_flags; + break; + case 'J': + strcpy(d->gid, "joliet"); + flags = dp->flags; + break; + case '9': + strcpy(d->gid, "plan9"); + flags = dp->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->size); + d->type = 0; + d->dev = 0; + d->atime = gtime(dp->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= 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 diff --git a/src/cmd/9660srv/dat.h b/src/cmd/9660srv/dat.h new file mode 100644 index 00000000..bee14db6 --- /dev/null +++ b/src/cmd/9660srv/dat.h @@ -0,0 +1,118 @@ +typedef struct Ioclust Ioclust; +typedef struct Iobuf Iobuf; +typedef struct Isofile Isofile; +typedef struct Xdata Xdata; +typedef struct Xfile Xfile; +typedef struct Xfs Xfs; +typedef struct Xfsub Xfsub; + +#pragma incomplete Isofile + +enum +{ + Sectorsize = 2048, + Maxname = 256, +}; + +struct Iobuf +{ + Ioclust* clust; + long addr; + uchar* iobuf; +}; + +struct Ioclust +{ + long addr; /* in sectors; good to 8TB */ + Xdata* dev; + Ioclust* next; + Ioclust* prev; + int busy; + int nbuf; + Iobuf* buf; + uchar* iobuf; +}; + +struct Xdata +{ + Xdata* next; + char* name; /* of underlying file */ + Qid qid; + short type; + short fdev; + int ref; /* attach count */ + int dev; /* for read/write */ +}; + +struct Xfsub +{ + void (*reset)(void); + int (*attach)(Xfile*); + void (*clone)(Xfile*, Xfile*); + void (*walkup)(Xfile*); + void (*walk)(Xfile*, char*); + void (*open)(Xfile*, int); + void (*create)(Xfile*, char*, long, int); + long (*readdir)(Xfile*, uchar*, long, long); + long (*read)(Xfile*, char*, vlong, long); + long (*write)(Xfile*, char*, vlong, long); + void (*clunk)(Xfile*); + void (*remove)(Xfile*); + void (*stat)(Xfile*, Dir*); + void (*wstat)(Xfile*, Dir*); +}; + +struct Xfs +{ + Xdata* d; /* how to get the bits */ + Xfsub* s; /* how to use them */ + int ref; + int issusp; /* follows system use sharing protocol */ + long suspoff; /* if so, offset at which SUSP area begins */ + int isrock; /* Rock Ridge format */ + int isplan9; /* has Plan 9-specific directory info */ + Qid rootqid; + Isofile* ptr; /* private data */ +}; + +struct Xfile +{ + Xfile* next; /* in fid hash bucket */ + Xfs* xf; + long fid; + ulong flags; + Qid qid; + int len; /* of private data */ + Isofile* ptr; +}; + +enum +{ + Asis, + Clean, + Clunk +}; + +enum +{ + Oread = 1, + Owrite = 2, + Orclose = 4, + Omodes = 3, +}; + +extern char Enonexist[]; /* file does not exist */ +extern char Eperm[]; /* permission denied */ +extern char Enofile[]; /* no file system specified */ +extern char Eauth[]; /* authentication failed */ + +extern char *srvname; +extern char *deffile; +extern int chatty; +extern jmp_buf err_lab[]; +extern int nerr_lab; +extern char err_msg[]; + +extern int nojoliet; +extern int noplan9; +extern int norock; diff --git a/src/cmd/9660srv/data.c b/src/cmd/9660srv/data.c new file mode 100644 index 00000000..e89f8d1c --- /dev/null +++ b/src/cmd/9660srv/data.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include "dat.h" +#include "fns.h" + +char Enonexist[] = "file does not exist"; +char Eperm[] = "permission denied"; +char Enofile[] = "no file system specified"; +char Eauth[] = "authentication failed"; + +char *srvname = "9660"; +char *deffile = 0; + +extern Xfsub isosub; + +Xfsub* xsublist[] = +{ + &isosub, + 0 +}; diff --git a/src/cmd/9660srv/fns.h b/src/cmd/9660srv/fns.h new file mode 100644 index 00000000..1bae3b50 --- /dev/null +++ b/src/cmd/9660srv/fns.h @@ -0,0 +1,17 @@ +void chat(char*, ...); +void* ealloc(long); +void error(char*); +Iobuf* getbuf(Xdata*, ulong); +Xdata* getxdata(char*); +void iobuf_init(void); +void nexterror(void); +void panic(int, char*, ...); +void purgebuf(Xdata*); +void putbuf(Iobuf*); +void refxfs(Xfs*, int); +void showdir(int, Dir*); +Xfile* xfile(int, int); +void setnames(Dir*, char*); + +#define waserror() (++nerr_lab, setjmp(err_lab[nerr_lab-1])) +#define poperror() (--nerr_lab) diff --git a/src/cmd/9660srv/iobuf.c b/src/cmd/9660srv/iobuf.c new file mode 100644 index 00000000..30eafb3a --- /dev/null +++ b/src/cmd/9660srv/iobuf.c @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include "dat.h" +#include "fns.h" + +/* + * We used to use 100 i/o buffers of size 2kb (Sectorsize). + * Unfortunately, reading 2kb at a time often hopping around + * the disk doesn't let us get near the disk bandwidth. + * + * Based on a trace of iobuf address accesses taken while + * tarring up a Plan 9 distribution CD, we now use 16 128kb + * buffers. This works for ISO9660 because data is required + * to be laid out contiguously; effectively we're doing agressive + * readahead. Because the buffers are so big and the typical + * disk accesses so concentrated, it's okay that we have so few + * of them. + * + * If this is used to access multiple discs at once, it's not clear + * how gracefully the scheme degrades, but I'm not convinced + * it's worth worrying about. -rsc + */ + +/* trying a larger value to get greater throughput - geoff */ +#define BUFPERCLUST 256 /* sectors/cluster; was 64, 64*Sectorsize = 128kb */ +#define NCLUST 16 + +int nclust = NCLUST; + +static Ioclust* iohead; +static Ioclust* iotail; + +static Ioclust* getclust(Xdata*, long); +static void putclust(Ioclust*); +static void xread(Ioclust*); + +void +iobuf_init(void) +{ + int i, j, n; + Ioclust *c; + Iobuf *b; + uchar *mem; + + n = nclust*sizeof(Ioclust) + + nclust*BUFPERCLUST*(sizeof(Iobuf)+Sectorsize); + mem = sbrk(n); + if(mem == (void*)-1) + panic(0, "iobuf_init"); + memset(mem, 0, n); + + for(i=0; iaddr = -1; + c->prev = iotail; + if(iotail) + iotail->next = c; + iotail = c; + if(iohead == nil) + iohead = c; + + c->buf = (Iobuf*)mem; + mem += BUFPERCLUST*sizeof(Iobuf); + c->iobuf = mem; + mem += BUFPERCLUST*Sectorsize; + for(j=0; jbuf[j]; + b->clust = c; + b->addr = -1; + b->iobuf = c->iobuf+j*Sectorsize; + } + } +} + +void +purgebuf(Xdata *dev) +{ + Ioclust *p; + + for(p=iohead; p!=nil; p=p->next) + if(p->dev == dev){ + p->addr = -1; + p->busy = 0; + } +} + +static Ioclust* +getclust(Xdata *dev, long addr) +{ + Ioclust *c, *f; + + f = nil; + for(c=iohead; c; c=c->next){ + if(!c->busy) + f = c; + if(c->addr == addr && c->dev == dev){ + c->busy++; + return c; + } + } + + if(f == nil) + panic(0, "out of buffers"); + + f->addr = addr; + f->dev = dev; + f->busy++; + if(waserror()){ + f->addr = -1; /* stop caching */ + putclust(f); + nexterror(); + } + xread(f); + poperror(); + return f; +} + +static void +putclust(Ioclust *c) +{ + if(c->busy <= 0) + panic(0, "putbuf"); + c->busy--; + + /* Link onto head for LRU */ + if(c == iohead) + return; + c->prev->next = c->next; + + if(c->next) + c->next->prev = c->prev; + else + iotail = c->prev; + + c->prev = nil; + c->next = iohead; + iohead->prev = c; + iohead = c; +} + +Iobuf* +getbuf(Xdata *dev, ulong addr) +{ + int off; + Ioclust *c; + + off = addr%BUFPERCLUST; + c = getclust(dev, addr - off); + if(c->nbuf < off){ + c->busy--; + error("I/O read error"); + } + return &c->buf[off]; +} + +void +putbuf(Iobuf *b) +{ + putclust(b->clust); +} + +static void +xread(Ioclust *c) +{ + int n; + Xdata *dev; + + dev = c->dev; + seek(dev->dev, (vlong)c->addr * Sectorsize, 0); + n = readn(dev->dev, c->iobuf, BUFPERCLUST*Sectorsize); + if(n < Sectorsize) + error("I/O read error"); + c->nbuf = n/Sectorsize; +} diff --git a/src/cmd/9660srv/iso9660.h b/src/cmd/9660srv/iso9660.h new file mode 100644 index 00000000..58bcb9ff --- /dev/null +++ b/src/cmd/9660srv/iso9660.h @@ -0,0 +1,142 @@ +#define VOLDESC 16 /* sector number */ + +/* + * L means little-endian, M means big-endian, and LM means little-endian + * then again big-endian. + */ +typedef uchar Byte2L[2]; +typedef uchar Byte2M[2]; +typedef uchar Byte4LM[4]; +typedef uchar Byte4L[4]; +typedef uchar Byte4M[4]; +typedef uchar Byte8LM[8]; +typedef union Drec Drec; +typedef union Voldesc Voldesc; + +enum +{ + Boot = 0, + Primary = 1, + Supplementary = 2, + Partition = 3, + Terminator = 255 +}; + +union Voldesc +{ /* volume descriptor */ + uchar byte[Sectorsize]; + union { /* for CD001, the ECMA standard */ + struct + { + uchar type; + uchar stdid[5]; + uchar version; + uchar unused; + uchar sysid[32]; + uchar bootid[32]; + uchar data[1977]; + } boot; + struct + { + uchar type; + uchar stdid[5]; + uchar version; + uchar flags; + uchar sysid[32]; + uchar volid[32]; + Byte8LM partloc; + Byte8LM size; + uchar escapes[32]; + Byte4LM vsetsize; + Byte4LM vseqno; + Byte4LM blksize; + Byte8LM ptabsize; + Byte4L lptable; + Byte4L optlptable; + Byte4M mptable; + Byte4M optmptable; + uchar rootdir[34]; + uchar volsetid[128]; + uchar pubid[128]; + uchar prepid[128]; + uchar appid[128]; + uchar copyright[37]; + uchar abstract[37]; + uchar bibliography[37]; + uchar cdate[17]; + uchar mdate[17]; + uchar expdate[17]; + uchar effdate[17]; + uchar fsversion; + uchar unused3[1]; + uchar appuse[512]; + uchar unused4[653]; + } desc; + } z; + union + { /* for CDROM, the `High Sierra' standard */ + struct + { + Byte8LM number; + uchar type; + uchar stdid[5]; + uchar version; + uchar flags; + uchar sysid[32]; + uchar volid[32]; + Byte8LM partloc; + Byte8LM size; + uchar escapes[32]; + Byte4LM vsetsize; + Byte4LM vseqno; + Byte4LM blksize; + uchar quux[40]; + uchar rootdir[34]; + uchar volsetid[128]; + uchar pubid[128]; + uchar prepid[128]; + uchar appid[128]; + uchar copyright[32]; + uchar abstract[32]; + uchar cdate[16]; + uchar mdate[16]; + uchar expdate[16]; + uchar effdate[16]; + uchar fsversion; + } desc; + } r; +}; + +union Drec +{ + struct + { + uchar reclen; + uchar attrlen; + Byte8LM addr; + Byte8LM size; + uchar date[6]; + uchar tzone; /* flags in high sierra */ + uchar flags; /* ? in high sierra */ + uchar unitsize; /* ? in high sierra */ + uchar gapsize; /* ? in high sierra */ + Byte4LM vseqno; /* ? in high sierra */ + uchar namelen; + uchar name[1]; + }; + struct + { + uchar r_pad[24]; + uchar r_flags; + }; +}; + +struct Isofile +{ + short fmt; /* 'z' if iso, 'r' if high sierra */ + short blksize; + long offset; /* true offset when reading directory */ + long odelta; /* true size of directory just read */ + long doffset; /* plan9 offset when reading directory */ + Drec d; +}; diff --git a/src/cmd/9660srv/main.c b/src/cmd/9660srv/main.c new file mode 100644 index 00000000..c3e5d9c9 --- /dev/null +++ b/src/cmd/9660srv/main.c @@ -0,0 +1,576 @@ +#include +#include +#include +#include +#include "dat.h" +#include "fns.h" + +enum +{ + Maxfdata = 8192, + Maxiosize = IOHDRSZ+Maxfdata, +}; + +void io(int); +void rversion(void); +void rattach(void); +void rauth(void); +void rclunk(void); +void rcreate(void); +void rflush(void); +void ropen(void); +void rread(void); +void rremove(void); +void rsession(void); +void rstat(void); +void rwalk(void); +void rwrite(void); +void rwstat(void); + +static int openflags(int); +static void usage(void); + +#define Reqsize (sizeof(Fcall)+Maxfdata) + +Fcall *req; +Fcall *rep; + +uchar mdata[Maxiosize]; +char fdata[Maxfdata]; +uchar statbuf[STATMAX]; +int errno; + + +extern Xfsub *xsublist[]; +extern int nclust; + +jmp_buf err_lab[16]; +int nerr_lab; +char err_msg[ERRMAX]; + +int chatty; +int nojoliet; +int noplan9; +int norock; + +void (*fcalls[])(void) = { + [Tversion] rversion, + [Tflush] rflush, + [Tauth] rauth, + [Tattach] rattach, + [Twalk] rwalk, + [Topen] ropen, + [Tcreate] rcreate, + [Tread] rread, + [Twrite] rwrite, + [Tclunk] rclunk, + [Tremove] rremove, + [Tstat] rstat, + [Twstat] rwstat, +}; + +void +main(int argc, char **argv) +{ + int srvfd, pipefd[2], stdio; + Xfsub **xs; + char *mtpt; + + stdio = 0; + mtpt = nil; + ARGBEGIN { + case '9': + noplan9 = 1; + break; + case 'c': + nclust = atoi(EARGF(usage())); + if (nclust <= 0) + sysfatal("nclust %d non-positive", nclust); + break; + case 'f': + deffile = EARGF(usage()); + break; + case 'r': + norock = 1; + break; + case 's': + stdio = 1; + break; + case 'v': + chatty = 1; + break; + case 'J': + nojoliet = 1; + break; + case 'm': + mtpt = EARGF(usage()); + break; + default: + usage(); + } ARGEND + + switch(argc) { + case 0: + break; + case 1: + srvname = argv[0]; + break; + default: + usage(); + } + + iobuf_init(); + for(xs=xsublist; *xs; xs++) + (*(*xs)->reset)(); + + if(stdio) { + pipefd[0] = 0; + pipefd[1] = 1; + } else { + close(0); + close(1); + open("/dev/null", OREAD); + open("/dev/null", OWRITE); + if(pipe(pipefd) < 0) + panic(1, "pipe"); + + if(post9pservice(pipefd[0], srvname, mtpt) < 0) + sysfatal("post9pservice: %r"); + close(pipefd[0]); + } + srvfd = pipefd[1]; + + switch(rfork(RFNOWAIT|RFNOTEG|RFFDG|RFPROC)){ + case -1: + panic(1, "fork"); + default: + _exits(0); + case 0: + break; + } + + io(srvfd); + exits(0); +} + +void +io(int srvfd) +{ + int n, pid; + Fcall xreq, xrep; + + req = &xreq; + rep = &xrep; + pid = getpid(); + fmtinstall('F', fcallfmt); + + for(;;){ + /* + * reading from a pipe or a network device + * will give an error after a few eof reads. + * however, we cannot tell the difference + * between a zero-length read and an interrupt + * on the processes writing to us, + * so we wait for the error. + */ + n = read9pmsg(srvfd, mdata, sizeof mdata); + if(n < 0) + break; + if(n == 0) + continue; + if(convM2S(mdata, n, req) == 0) + continue; + + if(chatty) + fprint(2, "9660srv %d:<-%F\n", pid, req); + + errno = 0; + if(!waserror()){ + err_msg[0] = 0; + if(req->type >= nelem(fcalls) || !fcalls[req->type]) + error("bad fcall type"); + (*fcalls[req->type])(); + poperror(); + } + + if(err_msg[0]){ + rep->type = Rerror; + rep->ename = err_msg; + }else{ + rep->type = req->type + 1; + rep->fid = req->fid; + } + rep->tag = req->tag; + + if(chatty) + fprint(2, "9660srv %d:->%F\n", pid, rep); + n = convS2M(rep, mdata, sizeof mdata); + if(n == 0) + panic(1, "convS2M error on write"); + if(write(srvfd, mdata, n) != n) + panic(1, "mount write"); + if(nerr_lab != 0) + panic(0, "err stack %d"); + } + chat("server shut down"); +} + +static void +usage(void) +{ + fprint(2, "usage: %s [-v] [-9Jr] [-s] [-f devicefile] [srvname]\n", argv0); + exits("usage"); +} + +void +error(char *p) +{ + strecpy(err_msg, err_msg+sizeof err_msg, p); + nexterror(); +} + +void +nexterror(void) +{ + longjmp(err_lab[--nerr_lab], 1); +} + +void* +ealloc(long n) +{ + void *p; + + p = malloc(n); + if(p == 0) + error("no memory"); + return p; +} + +void +setnames(Dir *d, char *n) +{ + d->name = n; + d->uid = n+Maxname; + d->gid = n+Maxname*2; + d->muid = n+Maxname*3; + + d->name[0] = '\0'; + d->uid[0] = '\0'; + d->gid[0] = '\0'; + d->muid[0] = '\0'; +} + +void +rversion(void) +{ + if(req->msize > Maxiosize) + rep->msize = Maxiosize; + else + rep->msize = req->msize; + rep->version = "9P2000"; +} + +void +rauth(void) +{ + error("9660srv: authentication not required"); +} + +void +rflush(void) +{ +} + +void +rattach(void) +{ + Xfs *xf; + Xfile *root; + Xfsub **xs; + + chat("attach(fid=%d,uname=\"%s\",aname=\"%s\")...", + req->fid, req->uname, req->aname); + + if(waserror()){ + xfile(req->fid, Clunk); + nexterror(); + } + root = xfile(req->fid, Clean); + root->qid = (Qid){0, 0, QTDIR}; + root->xf = xf = ealloc(sizeof(Xfs)); + memset(xf, 0, sizeof(Xfs)); + xf->ref = 1; + xf->d = getxdata(req->aname); + + for(xs=xsublist; *xs; xs++) + if((*(*xs)->attach)(root) >= 0){ + poperror(); + xf->s = *xs; + xf->rootqid = root->qid; + rep->qid = root->qid; + return; + } + error("unknown format"); +} + +Xfile* +doclone(Xfile *of, int newfid) +{ + Xfile *nf, *next; + + nf = xfile(newfid, Clean); + if(waserror()){ + xfile(newfid, Clunk); + nexterror(); + } + next = nf->next; + *nf = *of; + nf->next = next; + nf->fid = newfid; + refxfs(nf->xf, 1); + if(nf->len){ + nf->ptr = ealloc(nf->len); + memmove(nf->ptr, of->ptr, nf->len); + }else + nf->ptr = of->ptr; + (*of->xf->s->clone)(of, nf); + poperror(); + return nf; +} + +void +rwalk(void) +{ + Xfile *f, *nf; + Isofile *oldptr; + int oldlen; + Qid oldqid; + + rep->nwqid = 0; + nf = nil; + f = xfile(req->fid, Asis); + if(req->fid != req->newfid) + f = nf = doclone(f, req->newfid); + + /* save old state in case of error */ + oldqid = f->qid; + oldlen = f->len; + oldptr = f->ptr; + if(oldlen){ + oldptr = ealloc(oldlen); + memmove(oldptr, f->ptr, oldlen); + } + + if(waserror()){ + if(nf != nil) + xfile(req->newfid, Clunk); + if(rep->nwqid == req->nwname){ + if(oldlen) + free(oldptr); + }else{ + /* restore previous state */ + f->qid = oldqid; + if(f->len) + free(f->ptr); + f->ptr = oldptr; + f->len = oldlen; + } + if(rep->nwqid==req->nwname || rep->nwqid > 0){ + err_msg[0] = '\0'; + return; + } + nexterror(); + } + + for(rep->nwqid=0; rep->nwqid < req->nwname && rep->nwqid < MAXWELEM; rep->nwqid++){ + chat("\twalking %s\n", req->wname[rep->nwqid]); + if(!(f->qid.type & QTDIR)){ + chat("\tnot dir: type=%#x\n", f->qid.type); + error("walk in non-directory"); + } + + if(strcmp(req->wname[rep->nwqid], "..")==0){ + if(f->qid.path != f->xf->rootqid.path) + (*f->xf->s->walkup)(f); + }else + (*f->xf->s->walk)(f, req->wname[rep->nwqid]); + rep->wqid[rep->nwqid] = f->qid; + } + poperror(); + if(oldlen) + free(oldptr); +} + +void +ropen(void) +{ + Xfile *f; + + f = xfile(req->fid, Asis); + if(f->flags&Omodes) + error("open on open file"); + if(req->mode&ORCLOSE) + error("no removes"); + (*f->xf->s->open)(f, req->mode); + f->flags = openflags(req->mode); + rep->qid = f->qid; + rep->iounit = 0; +} + +void +rcreate(void) +{ + error("no creates"); +/* + Xfile *f; + + if(strcmp(req->name, ".") == 0 || strcmp(req->name, "..") == 0) + error("create . or .."); + f = xfile(req->fid, Asis); + if(f->flags&Omodes) + error("create on open file"); + if(!(f->qid.path&CHDIR)) + error("create in non-directory"); + (*f->xf->s->create)(f, req->name, req->perm, req->mode); + chat("f->qid=0x%8.8lux...", f->qid.path); + f->flags = openflags(req->mode); + rep->qid = f->qid; +*/ +} + +void +rread(void) +{ + Xfile *f; + + f=xfile(req->fid, Asis); + if (!(f->flags&Oread)) + error("file not opened for reading"); + if(f->qid.type & QTDIR) + rep->count = (*f->xf->s->readdir)(f, (uchar*)fdata, req->offset, req->count); + else + rep->count = (*f->xf->s->read)(f, fdata, req->offset, req->count); + rep->data = fdata; +} + +void +rwrite(void) +{ + Xfile *f; + + f=xfile(req->fid, Asis); + if(!(f->flags&Owrite)) + error("file not opened for writing"); + rep->count = (*f->xf->s->write)(f, req->data, req->offset, req->count); +} + +void +rclunk(void) +{ + Xfile *f; + + if(!waserror()){ + f = xfile(req->fid, Asis); + (*f->xf->s->clunk)(f); + poperror(); + } + xfile(req->fid, Clunk); +} + +void +rremove(void) +{ + error("no removes"); +} + +void +rstat(void) +{ + Xfile *f; + Dir dir; + + chat("stat(fid=%d)...", req->fid); + f=xfile(req->fid, Asis); + setnames(&dir, fdata); + (*f->xf->s->stat)(f, &dir); + if(chatty) + showdir(2, &dir); + rep->nstat = convD2M(&dir, statbuf, sizeof statbuf); + rep->stat = statbuf; +} + +void +rwstat(void) +{ + error("no wstat"); +} + +static int +openflags(int mode) +{ + int flags = 0; + + switch(mode & ~(OTRUNC|OCEXEC|ORCLOSE)){ + case OREAD: + case OEXEC: + flags = Oread; break; + case OWRITE: + flags = Owrite; break; + case ORDWR: + flags = Oread|Owrite; break; + } + if(mode & ORCLOSE) + flags |= Orclose; + return flags; +} + +void +showdir(int fd, Dir *s) +{ + char a_time[32], m_time[32]; + char *p; + + strcpy(a_time, ctime(s->atime)); + if(p=strchr(a_time, '\n')) /* assign = */ + *p = 0; + strcpy(m_time, ctime(s->mtime)); + if(p=strchr(m_time, '\n')) /* assign = */ + *p = 0; + fprint(fd, "name=\"%s\" qid=(0x%llux,%lud) type=%d dev=%d \ +mode=0x%8.8lux=0%luo atime=%s mtime=%s length=%lld uid=\"%s\" gid=\"%s\"...", + s->name, s->qid.path, s->qid.vers, s->type, s->dev, + s->mode, s->mode, + a_time, m_time, s->length, s->uid, s->gid); +} + +#define SIZE 1024 + +void +chat(char *fmt, ...) +{ + va_list arg; + + if(chatty){ + va_start(arg, fmt); + vfprint(2, fmt, arg); + va_end(arg); + } +} + +void +panic(int rflag, char *fmt, ...) +{ + va_list arg; + char buf[SIZE]; int n; + + n = sprint(buf, "%s %d: ", argv0, getpid()); + va_start(arg, fmt); + vseprint(buf+n, buf+SIZE, fmt, arg); + va_end(arg); + fprint(2, (rflag ? "%s: %r\n" : "%s\n"), buf); + if(chatty){ + fprint(2, "abort\n"); + abort(); + } + exits("panic"); +} diff --git a/src/cmd/9660srv/mkfile b/src/cmd/9660srv/mkfile new file mode 100644 index 00000000..0e478011 --- /dev/null +++ b/src/cmd/9660srv/mkfile @@ -0,0 +1,17 @@ +<$PLAN9/src/mkhdr + +TARG=9660srv + +OFILES=\ + main.$O\ + 9660srv.$O\ + xfile.$O\ + iobuf.$O\ + data.$O\ + +HFILES=dat.h fns.h + +<$PLAN9/src/mkone + +9660srv.$O: iso9660.h + diff --git a/src/cmd/9660srv/xfile.c b/src/cmd/9660srv/xfile.c new file mode 100644 index 00000000..c46adf21 --- /dev/null +++ b/src/cmd/9660srv/xfile.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include "dat.h" +#include "fns.h" + +static Xfile* clean(Xfile*); + +#define FIDMOD 127 /* prime */ + +static Xdata* xhead; +static Xfile* xfiles[FIDMOD]; +static Xfile* freelist; + +Xdata* +getxdata(char *name) +{ + int fd; + Dir *dir; + Xdata *xf, *fxf; + int flag; + + if(name[0] == 0) + name = deffile; + if(name == 0) + error(Enofile); + flag = (access(name, 6) == 0) ? ORDWR : OREAD; + fd = open(name, flag); + if(fd < 0) + error(Enonexist); + dir = nil; + if(waserror()){ + close(fd); + free(dir); + nexterror(); + } + if((dir = dirfstat(fd)) == nil) + error("I/O error"); + if((dir->qid.type & ~QTTMP) != QTFILE) + error("attach name not a plain file"); + for(fxf=0,xf=xhead; xf; xf=xf->next){ + if(xf->name == 0){ + if(fxf == 0) + fxf = xf; + continue; + } + if(xf->qid.path != dir->qid.path || xf->qid.vers != dir->qid.vers) + continue; + if(xf->type != dir->type || xf->fdev != dir->dev) + continue; + xf->ref++; + chat("incref=%d, \"%s\", dev=%d...", xf->ref, xf->name, xf->dev); + close(fd); + poperror(); + free(dir); + return xf; + } + if(fxf==0){ + fxf = ealloc(sizeof(Xfs)); + fxf->next = xhead; + xhead = fxf; + } + chat("alloc \"%s\", dev=%d...", name, fd); + fxf->ref = 1; + fxf->name = strcpy(ealloc(strlen(name)+1), name); + fxf->qid = dir->qid; + fxf->type = dir->type; + fxf->fdev = dir->dev; + fxf->dev = fd; + free(dir); + poperror(); + return fxf; +} + +static void +putxdata(Xdata *d) +{ + if(d->ref <= 0) + panic(0, "putxdata"); + d->ref--; + chat("decref=%d, \"%s\", dev=%d...", d->ref, d->name, d->dev); + if(d->ref == 0){ + chat("purgebuf..."); + purgebuf(d); + close(d->dev); + free(d->name); + d->name = 0; + } +} + +void +refxfs(Xfs *xf, int delta) +{ + xf->ref += delta; + if(xf->ref == 0){ + if(xf->d) + putxdata(xf->d); + if(xf->ptr) + free(xf->ptr); + free(xf); + } +} + +Xfile* +xfile(int fid, int flag) +{ + int k = fid%FIDMOD; + Xfile **hp=&xfiles[k], *f, *pf; + + for(f=*hp,pf=0; f; pf=f,f=f->next) + if(f->fid == fid) + break; + if(f && pf){ + pf->next = f->next; + f->next = *hp; + *hp = f; + } + switch(flag){ + default: + panic(0, "xfile"); + case Asis: + if(f == 0) + error("unassigned fid"); + return f; + case Clean: + break; + case Clunk: + if(f){ + *hp = f->next; + clean(f); + f->next = freelist; + freelist = f; + } + return 0; + } + if(f) + return clean(f); + if(f = freelist) /* assign = */ + freelist = f->next; + else + f = ealloc(sizeof(Xfile)); + f->next = *hp; + *hp = f; + f->xf = 0; + f->fid = fid; + f->flags = 0; + f->qid = (Qid){0,0,0}; + f->len = 0; + f->ptr = 0; + return f; +} + +static Xfile * +clean(Xfile *f) +{ + if(f->xf){ + refxfs(f->xf, -1); + f->xf = 0; + } + if(f->len){ + free(f->ptr); + f->len = 0; + } + f->ptr = 0; + f->flags = 0; + f->qid = (Qid){0,0,0}; + return f; +} + -- cgit v1.2.3