123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <libsec.h>
- #include "iso9660.h"
- static int readisodesc(Cdimg*, Voldesc*);
- static int readjolietdesc(Cdimg*, Voldesc*);
- /*
- * It's not strictly conforming; instead it's enough to
- * get us up and running; presumably the real CD writing
- * will take care of being conforming.
- *
- * Things not conforming include:
- * - no path table
- * - root directories are of length zero
- */
- Cdimg*
- createcd(char *file, Cdinfo info)
- {
- int fd, xfd;
- Cdimg *cd;
- if(access(file, AEXIST) == 0){
- werrstr("file already exists");
- return nil;
- }
- if((fd = create(file, ORDWR, 0666)) < 0)
- return nil;
- cd = emalloc(sizeof *cd);
- cd->file = atom(file);
- Binit(&cd->brd, fd, OREAD);
- if((xfd = open(file, ORDWR)) < 0)
- sysfatal("can't open file again: %r");
- Binit(&cd->bwr, xfd, OWRITE);
- Crepeat(cd, 0, 16*Blocksize);
- Cputisopvd(cd, info);
- if(info.flags & CDbootable){
- cd->bootimage = info.bootimage;
- cd->loader = info.loader;
- cd->flags |= info.flags & (CDbootable|CDbootnoemu);
- Cputbootvol(cd);
- }
- if(readisodesc(cd, &cd->iso) < 0)
- assert(0);
- if(info.flags & CDplan9)
- cd->flags |= CDplan9;
- else if(info.flags & CDrockridge)
- cd->flags |= CDrockridge;
- if(info.flags & CDjoliet) {
- Cputjolietsvd(cd, info);
- if(readjolietdesc(cd, &cd->joliet) < 0)
- assert(0);
- cd->flags |= CDjoliet;
- }
- Cputendvd(cd);
- if(info.flags & CDdump){
- cd->nulldump = Cputdumpblock(cd);
- cd->flags |= CDdump;
- }
- if(cd->flags & CDbootable){
- Cputbootcat(cd);
- Cupdatebootvol(cd);
- }
- if(info.flags & CDconform)
- cd->flags |= CDconform;
- cd->flags |= CDnew;
- cd->nextblock = Cwoffset(cd) / Blocksize;
- assert(cd->nextblock != 0);
- return cd;
- }
- Cdimg*
- opencd(char *file, Cdinfo info)
- {
- int fd, xfd;
- Cdimg *cd;
- Dir *d;
- if((fd = open(file, ORDWR)) < 0) {
- if(access(file, AEXIST) == 0)
- return nil;
- return createcd(file, info);
- }
- if((d = dirfstat(fd)) == nil) {
- close(fd);
- return nil;
- }
- if(d->length == 0 || d->length % Blocksize) {
- werrstr("bad length %lld", d->length);
- close(fd);
- free(d);
- return nil;
- }
- cd = emalloc(sizeof *cd);
- cd->file = atom(file);
- cd->nextblock = d->length / Blocksize;
- assert(cd->nextblock != 0);
- free(d);
- Binit(&cd->brd, fd, OREAD);
- if((xfd = open(file, ORDWR)) < 0)
- sysfatal("can't open file again: %r");
- Binit(&cd->bwr, xfd, OWRITE);
- if(readisodesc(cd, &cd->iso) < 0) {
- free(cd);
- close(fd);
- close(xfd);
- return nil;
- }
- /* lowercase because of isostring */
- if(strstr(cd->iso.systemid, "iso9660") == nil
- && strstr(cd->iso.systemid, "utf8") == nil) {
- werrstr("unknown systemid %s", cd->iso.systemid);
- free(cd);
- close(fd);
- close(xfd);
- return nil;
- }
-
- if(strstr(cd->iso.systemid, "plan 9"))
- cd->flags |= CDplan9;
- if(strstr(cd->iso.systemid, "iso9660"))
- cd->flags |= CDconform;
- if(strstr(cd->iso.systemid, "rrip"))
- cd->flags |= CDrockridge;
- if(strstr(cd->iso.systemid, "boot"))
- cd->flags |= CDbootable;
- if(readjolietdesc(cd, &cd->joliet) == 0)
- cd->flags |= CDjoliet;
- if(hasdump(cd))
- cd->flags |= CDdump;
- return cd;
- }
- ulong
- big(void *a, int n)
- {
- uchar *p;
- ulong v;
- int i;
- p = a;
- v = 0;
- for(i=0; i<n; i++)
- v = (v<<8) | *p++;
- return v;
- }
- ulong
- little(void *a, int n)
- {
- uchar *p;
- ulong v;
- int i;
- p = a;
- v = 0;
- for(i=0; i<n; i++)
- v |= (*p++<<(i*8));
- return v;
- }
- void
- Creadblock(Cdimg *cd, void *buf, ulong block, ulong len)
- {
- assert(block != 0); /* nothing useful there */
- Bflush(&cd->bwr);
- if(Bseek(&cd->brd, (vlong)block * Blocksize, 0) !=
- (vlong)block * Blocksize)
- sysfatal("error seeking to block %lud", block);
- if(Bread(&cd->brd, buf, len) != len)
- sysfatal("error reading %lud bytes at block %lud: %r %lld",
- len, block, Bseek(&cd->brd, 0, 2));
- }
- int
- parsedir(Cdimg *cd, Direc *d, uchar *buf, int len, char *(*cvtname)(uchar*, int))
- {
- enum { NAMELEN = 28 };
- char name[NAMELEN];
- uchar *p;
- Cdir *c;
- memset(d, 0, sizeof *d);
- c = (Cdir*)buf;
- if(c->len > len) {
- werrstr("buffer too small");
- return -1;
- }
- if(c->namelen == 1 && c->name[0] == '\0')
- d->name = atom(".");
- else if(c->namelen == 1 && c->name[0] == '\001')
- d->name = atom("..");
- else if(cvtname)
- d->name = cvtname(c->name, c->namelen);
- d->block = little(c->dloc, 4);
- d->length = little(c->dlen, 4);
- if(c->flags & 2)
- d->mode |= DMDIR;
- /*BUG: do we really need to parse the plan 9 fields? */
- /* plan 9 use fields */
- if((cd->flags & CDplan9) && cvtname == isostring
- && (c->namelen != 1 || c->name[0] > 1)) {
- p = buf+33+c->namelen;
- if((p-buf)&1)
- p++;
- assert(p < buf+c->len);
- assert(*p < NAMELEN);
- if(*p != 0) {
- memmove(name, p+1, *p);
- name[*p] = '\0';
- d->confname = d->name;
- d->name = atom(name);
- }
- p += *p+1;
- assert(*p < NAMELEN);
- memmove(name, p+1, *p);
- name[*p] = '\0';
- d->uid = atom(name);
- p += *p+1;
- assert(*p < NAMELEN);
- memmove(name, p+1, *p);
- name[*p] = '\0';
- d->gid = atom(name);
- p += *p+1;
- if((p-buf)&1)
- p++;
- d->mode = little(p, 4);
- }
- // BUG: rock ridge extensions
- return 0;
- }
- void
- setroot(Cdimg *cd, ulong block, ulong dloc, ulong dlen)
- {
- assert(block != 0);
- Cwseek(cd, (vlong)block * Blocksize + offsetof(Cvoldesc, rootdir[0]) +
- offsetof(Cdir, dloc[0]));
- Cputn(cd, dloc, 4);
- Cputn(cd, dlen, 4);
- }
- void
- setvolsize(Cdimg *cd, uvlong block, ulong size)
- {
- assert(block != 0);
- Cwseek(cd, block * Blocksize + offsetof(Cvoldesc, volsize[0]));
- Cputn(cd, size, 4); /* size in blocks */
- }
- void
- setpathtable(Cdimg *cd, ulong block, ulong sz, ulong lloc, ulong bloc)
- {
- assert(block != 0);
- Cwseek(cd, (vlong)block * Blocksize + offsetof(Cvoldesc, pathsize[0]));
- Cputn(cd, sz, 4);
- Cputnl(cd, lloc, 4);
- Cputnl(cd, 0, 4);
- Cputnm(cd, bloc, 4);
- Cputnm(cd, 0, 4);
- assert(Cwoffset(cd) == (vlong)block * Blocksize +
- offsetof(Cvoldesc, rootdir[0]));
- }
- static void
- parsedesc(Voldesc *v, Cvoldesc *cv, char *(*string)(uchar*, int))
- {
- v->systemid = string(cv->systemid, sizeof cv->systemid);
- v->pathsize = little(cv->pathsize, 4);
- v->lpathloc = little(cv->lpathloc, 4);
- v->mpathloc = little(cv->mpathloc, 4);
- v->volumeset = string(cv->volumeset, sizeof cv->volumeset);
- v->publisher = string(cv->publisher, sizeof cv->publisher);
- v->preparer = string(cv->preparer, sizeof cv->preparer);
- v->application = string(cv->application, sizeof cv->application);
- v->abstract = string(cv->abstract, sizeof cv->abstract);
- v->biblio = string(cv->biblio, sizeof cv->biblio);
- v->notice = string(cv->notice, sizeof cv->notice);
- }
-
- static int
- readisodesc(Cdimg *cd, Voldesc *v)
- {
- static uchar magic[] = { 0x01, 'C', 'D', '0', '0', '1', 0x01, 0x00 };
- Cvoldesc cv;
- memset(v, 0, sizeof *v);
- Creadblock(cd, &cv, 16, sizeof cv);
- if(memcmp(cv.magic, magic, sizeof magic) != 0) {
- werrstr("bad pvd magic");
- return -1;
- }
- if(little(cv.blocksize, 2) != Blocksize) {
- werrstr("block size not %d", Blocksize);
- return -1;
- }
- cd->iso9660pvd = 16;
- parsedesc(v, &cv, isostring);
- return parsedir(cd, &v->root, cv.rootdir, sizeof cv.rootdir, isostring);
- }
- static int
- readjolietdesc(Cdimg *cd, Voldesc *v)
- {
- int i;
- static uchar magic[] = { 0x02, 'C', 'D', '0', '0', '1', 0x01, 0x00 };
- Cvoldesc cv;
- memset(v, 0, sizeof *v);
- for(i=16; i<24; i++) {
- Creadblock(cd, &cv, i, sizeof cv);
- if(memcmp(cv.magic, magic, sizeof magic) != 0)
- continue;
- if(cv.charset[0] != 0x25 || cv.charset[1] != 0x2F
- || (cv.charset[2] != 0x40 && cv.charset[2] != 0x43 && cv.charset[2] != 0x45))
- continue;
- break;
- }
- if(i==24) {
- werrstr("could not find Joliet SVD");
- return -1;
- }
- if(little(cv.blocksize, 2) != Blocksize) {
- werrstr("block size not %d", Blocksize);
- return -1;
- }
- cd->jolietsvd = i;
- parsedesc(v, &cv, jolietstring);
- return parsedir(cd, &v->root, cv.rootdir, sizeof cv.rootdir, jolietstring);
- }
- /*
- * CD image buffering routines.
- */
- void
- Cputc(Cdimg *cd, int c)
- {
- assert(Boffset(&cd->bwr) >= 16*Blocksize || c == 0);
- if(Boffset(&cd->bwr) == 0x9962)
- if(c >= 256) abort();
- if(Bputc(&cd->bwr, c) < 0)
- sysfatal("Bputc: %r");
- Bflush(&cd->brd);
- }
- void
- Cputnl(Cdimg *cd, uvlong val, int size)
- {
- switch(size) {
- default:
- sysfatal("bad size %d in Cputnl", size);
- case 2:
- if(val >= (1<<16))
- sysfatal("value %llud too big for size %d in Cputnl",
- val, size);
- Cputc(cd, val);
- Cputc(cd, val>>8);
- break;
- case 4:
- if(val >= (1ULL<<32))
- sysfatal("value %llud too big for size %d in Cputnl",
- val, size);
- Cputc(cd, val);
- Cputc(cd, val>>8);
- Cputc(cd, val>>16);
- Cputc(cd, val>>24);
- break;
- case 8:
- Cputc(cd, val);
- Cputc(cd, val>>8);
- Cputc(cd, val>>16);
- Cputc(cd, val>>24);
- Cputc(cd, val>>32);
- Cputc(cd, val>>40);
- Cputc(cd, val>>48);
- Cputc(cd, val>>56);
- break;
- }
- }
- void
- Cputnm(Cdimg *cd, uvlong val, int size)
- {
- switch(size) {
- default:
- sysfatal("bad size %d in Cputnm", size);
- case 2:
- if(val >= (1<<16))
- sysfatal("value %llud too big for size %d in Cputnl",
- val, size);
- Cputc(cd, val>>8);
- Cputc(cd, val);
- break;
- case 4:
- if(val >= (1ULL<<32))
- sysfatal("value %llud too big for size %d in Cputnl",
- val, size);
- Cputc(cd, val>>24);
- Cputc(cd, val>>16);
- Cputc(cd, val>>8);
- Cputc(cd, val);
- break;
- case 8:
- Cputc(cd, val>>56);
- Cputc(cd, val>>48);
- Cputc(cd, val>>40);
- Cputc(cd, val>>32);
- Cputc(cd, val>>24);
- Cputc(cd, val>>16);
- Cputc(cd, val>>8);
- Cputc(cd, val);
- break;
- }
- }
- void
- Cputn(Cdimg *cd, uvlong val, int size)
- {
- Cputnl(cd, val, size);
- Cputnm(cd, val, size);
- }
- /*
- * ASCII/UTF string writing
- */
- void
- Crepeat(Cdimg *cd, int c, int n)
- {
- while(n-- > 0)
- Cputc(cd, c);
- }
- void
- Cputs(Cdimg *cd, char *s, int size)
- {
- int n;
- if(s == nil) {
- Crepeat(cd, ' ', size);
- return;
- }
- for(n=0; n<size && *s; n++)
- Cputc(cd, *s++);
- if(n<size)
- Crepeat(cd, ' ', size-n);
- }
- void
- Cwrite(Cdimg *cd, void *buf, int n)
- {
- assert(Boffset(&cd->bwr) >= 16*Blocksize);
- if(Bwrite(&cd->bwr, buf, n) != n)
- sysfatal("Bwrite: %r");
- Bflush(&cd->brd);
- }
- void
- Cputr(Cdimg *cd, Rune r)
- {
- Cputc(cd, r>>8);
- Cputc(cd, r);
- }
- void
- Crepeatr(Cdimg *cd, Rune r, int n)
- {
- int i;
- for(i=0; i<n; i++)
- Cputr(cd, r);
- }
- void
- Cputrs(Cdimg *cd, Rune *s, int osize)
- {
- int n, size;
- size = osize/2;
- if(s == nil)
- Crepeatr(cd, (Rune)' ', size);
- else {
- for(n=0; *s && n<size; n++)
- Cputr(cd, *s++);
- if(n<size)
- Crepeatr(cd, ' ', size-n);
- }
- if(osize&1)
- Cputc(cd, 0); /* what else can we do? */
- }
- void
- Cputrscvt(Cdimg *cd, char *s, int size)
- {
- Rune r[256];
- strtorune(r, s);
- Cputrs(cd, strtorune(r, s), size);
- }
- void
- Cpadblock(Cdimg *cd)
- {
- int n;
- ulong nb;
- n = Blocksize - (Boffset(&cd->bwr) % Blocksize);
- if(n != Blocksize)
- Crepeat(cd, 0, n);
- nb = Boffset(&cd->bwr)/Blocksize;
- assert(nb != 0);
- if(nb > cd->nextblock)
- cd->nextblock = nb;
- }
- void
- Cputdate(Cdimg *cd, ulong ust)
- {
- Tm *tm;
- if(ust == 0) {
- Crepeat(cd, 0, 7);
- return;
- }
- tm = gmtime(ust);
- Cputc(cd, tm->year);
- Cputc(cd, tm->mon+1);
- Cputc(cd, tm->mday);
- Cputc(cd, tm->hour);
- Cputc(cd, tm->min);
- Cputc(cd, tm->sec);
- Cputc(cd, 0);
- }
- void
- Cputdate1(Cdimg *cd, ulong ust)
- {
- Tm *tm;
- char str[20];
- if(ust == 0) {
- Crepeat(cd, '0', 16);
- Cputc(cd, 0);
- return;
- }
- tm = gmtime(ust);
- sprint(str, "%.4d%.2d%.2d%.2d%.2d%.4d",
- tm->year+1900,
- tm->mon+1,
- tm->mday,
- tm->hour,
- tm->min,
- tm->sec*100);
- Cputs(cd, str, 16);
- Cputc(cd, 0);
- }
- void
- Cwseek(Cdimg *cd, vlong offset)
- {
- Bseek(&cd->bwr, offset, 0);
- }
- uvlong
- Cwoffset(Cdimg *cd)
- {
- return Boffset(&cd->bwr);
- }
- void
- Cwflush(Cdimg *cd)
- {
- Bflush(&cd->bwr);
- }
- uvlong
- Croffset(Cdimg *cd)
- {
- return Boffset(&cd->brd);
- }
- void
- Crseek(Cdimg *cd, vlong offset)
- {
- Bseek(&cd->brd, offset, 0);
- }
- int
- Cgetc(Cdimg *cd)
- {
- int c;
- Cwflush(cd);
- if((c = Bgetc(&cd->brd)) == Beof) {
- fprint(2, "getc at %llud\n", Croffset(cd));
- assert(0);
- //sysfatal("Bgetc: %r");
- }
- return c;
- }
- void
- Cread(Cdimg *cd, void *buf, int n)
- {
- Cwflush(cd);
- if(Bread(&cd->brd, buf, n) != n)
- sysfatal("Bread: %r");
- }
- char*
- Crdline(Cdimg *cd, int c)
- {
- Cwflush(cd);
- return Brdline(&cd->brd, c);
- }
- int
- Clinelen(Cdimg *cd)
- {
- return Blinelen(&cd->brd);
- }
|