Dump9660 (and mk9660). Until we either do something
intelligent with symlinks or put in a switch for things like dump9660, this is of rather limited utility under Unix.
This commit is contained in:
parent
e1dddc0532
commit
7285a491c1
20 changed files with 4375 additions and 0 deletions
632
src/cmd/9660/cdrdwr.c
Normal file
632
src/cmd/9660/cdrdwr.c
Normal file
|
|
@ -0,0 +1,632 @@
|
|||
#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->flags |= CDbootable;
|
||||
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, block*Blocksize, 0) != 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, block*Blocksize+offsetof(Cvoldesc, rootdir[0])+offsetof(Cdir, dloc[0]));
|
||||
Cputn(cd, dloc, 4);
|
||||
Cputn(cd, dlen, 4);
|
||||
}
|
||||
|
||||
void
|
||||
setvolsize(Cdimg *cd, ulong block, ulong size)
|
||||
{
|
||||
assert(block != 0);
|
||||
|
||||
Cwseek(cd, block*Blocksize+offsetof(Cvoldesc, volsize[0]));
|
||||
Cputn(cd, size, 4);
|
||||
}
|
||||
|
||||
void
|
||||
setpathtable(Cdimg *cd, ulong block, ulong sz, ulong lloc, ulong bloc)
|
||||
{
|
||||
assert(block != 0);
|
||||
|
||||
Cwseek(cd, 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) == 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, ulong val, int size)
|
||||
{
|
||||
switch(size) {
|
||||
default:
|
||||
sysfatal("bad size %d in bputnl", size);
|
||||
case 2:
|
||||
Cputc(cd, val);
|
||||
Cputc(cd, val>>8);
|
||||
break;
|
||||
case 4:
|
||||
Cputc(cd, val);
|
||||
Cputc(cd, val>>8);
|
||||
Cputc(cd, val>>16);
|
||||
Cputc(cd, val>>24);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cputnm(Cdimg *cd, ulong val, int size)
|
||||
{
|
||||
switch(size) {
|
||||
default:
|
||||
sysfatal("bad size %d in bputnl", size);
|
||||
case 2:
|
||||
Cputc(cd, val>>8);
|
||||
Cputc(cd, val);
|
||||
break;
|
||||
case 4:
|
||||
Cputc(cd, val>>24);
|
||||
Cputc(cd, val>>16);
|
||||
Cputc(cd, val>>8);
|
||||
Cputc(cd, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cputn(Cdimg *cd, long 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, ulong offset)
|
||||
{
|
||||
Bseek(&cd->bwr, offset, 0);
|
||||
}
|
||||
|
||||
ulong
|
||||
Cwoffset(Cdimg *cd)
|
||||
{
|
||||
return Boffset(&cd->bwr);
|
||||
}
|
||||
|
||||
void
|
||||
Cwflush(Cdimg *cd)
|
||||
{
|
||||
Bflush(&cd->bwr);
|
||||
}
|
||||
|
||||
ulong
|
||||
Croffset(Cdimg *cd)
|
||||
{
|
||||
return Boffset(&cd->brd);
|
||||
}
|
||||
|
||||
void
|
||||
Crseek(Cdimg *cd, ulong offset)
|
||||
{
|
||||
Bseek(&cd->brd, offset, 0);
|
||||
}
|
||||
|
||||
int
|
||||
Cgetc(Cdimg *cd)
|
||||
{
|
||||
int c;
|
||||
|
||||
Cwflush(cd);
|
||||
if((c = Bgetc(&cd->brd)) == Beof) {
|
||||
fprint(2, "getc at %lud\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);
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue