#include <u.h>
#include <libc.h>
#include <bio.h>
#include <disk.h>
#include <libsec.h>
#include "iso9660.h"
ulong now;
int chatty;
int doabort;
int docolon;
int mk9660;
vlong dataoffset;
int blocksize;
Conform *map;
static void addprotofile(char *new, char *old, Dir *d, void *a);
void usage(void);
char *argv0;
void
usage(void)
{
if(mk9660)
fprint(2, "usage: disk/mk9660 [-D:] [-9cjr] "
"[-[bB] bootfile] [-o offset blocksize] "
"[-p proto] [-s src] cdimage\n");
else
fprint(2, "usage: disk/dump9660 [-D:] [-9cjr] "
"[-m maxsize] [-n now] "
"[-p proto] [-s src] cdimage\n");
exits("usage");
}
void
main(int argc, char **argv)
{
int fix;
ulong block, newnull, cblock;
vlong maxsize;
uvlong length, clength;
char buf[256], *dumpname, *proto, *s, *src, *status;
Cdimg *cd;
Cdinfo info;
XDir dir;
Direc *iconform, idumproot, iroot, *jconform, jdumproot, jroot, *r;
Dump *dump;
fix = 0;
status = nil;
memset(&info, 0, sizeof info);
proto = "/sys/lib/sysconfig/proto/allproto";
src = "./";
info.volumename = atom("9CD");
info.volumeset = atom("9VolumeSet");
info.publisher = atom("9Publisher");
info.preparer = atom("dump9660");
info.application = atom("dump9660");
info.flags = CDdump;
maxsize = 0;
mk9660 = 0;
fmtinstall('H', encodefmt);
ARGBEGIN{
case 'D':
chatty++;
break;
case 'M':
mk9660 = 1;
argv0 = "disk/mk9660";
info.flags &= ~CDdump;
break;
case '9':
info.flags |= CDplan9;
break;
case ':':
docolon = 1;
break;
case 'a':
doabort = 1;
break;
case 'B':
info.flags |= CDbootnoemu;
/* fall through */
case 'b':
if(!mk9660)
usage();
info.flags |= CDbootable;
info.bootimage = EARGF(usage());
break;
case 'c':
info.flags |= CDconform;
break;
case 'f':
fix = 1;
break;
case 'j':
info.flags |= CDjoliet;
break;
case 'n':
now = atoi(EARGF(usage()));
break;
case 'm':
maxsize = strtoull(EARGF(usage()), 0, 0);
break;
case 'o':
dataoffset = atoll(EARGF(usage()));
blocksize = atoi(EARGF(usage()));
if(blocksize%Blocksize)
sysfatal("bad block size %d -- must be multiple of 2048", blocksize);
blocksize /= Blocksize;
break;
case 'p':
proto = EARGF(usage());
break;
case 'r':
info.flags |= CDrockridge;
break;
case 's':
src = EARGF(usage());
break;
case 'v':
info.volumename = atom(EARGF(usage()));
break;
case 'x':
info.flags |= CDpbs;
info.loader = EARGF(usage());
break;
default:
usage();
}ARGEND
if(info.flags & CDpbs && !(info.flags & CDbootnoemu))
usage();
if(mk9660 && (fix || now || maxsize))
usage();
if(argc != 1)
usage();
if(now == 0)
now = (ulong)time(0);
if(mk9660){
if((cd = createcd(argv[0], info)) == nil)
sysfatal("cannot create '%s': %r", argv[0]);
}else{
if((cd = opencd(argv[0], info)) == nil)
sysfatal("cannot open '%s': %r", argv[0]);
if(!(cd->flags & CDdump))
sysfatal("not a dump cd");
}
/* create ISO9660/Plan 9 tree in memory */
memset(&dir, 0, sizeof dir);
dir.name = atom("");
dir.uid = atom("sys");
dir.gid = atom("sys");
dir.uidno = 0;
dir.gidno = 0;
dir.mode = DMDIR | 0755;
dir.mtime = now;
dir.atime = now;
dir.ctime = now;
mkdirec(&iroot, &dir);
iroot.srcfile = src;
/*
* Read new files into memory
*/
if(rdproto(proto, src, addprotofile, nil, &iroot) < 0)
sysfatal("rdproto: %r");
if(mk9660){
dump = emalloc(sizeof *dump);
dumpname = nil;
}else{
/*
* Read current dump tree and _conform.map.
*/
idumproot = readdumpdirs(cd, &dir, isostring);
readdumpconform(cd);
if(cd->flags & CDjoliet)
jdumproot = readdumpdirs(cd, &dir, jolietstring);
if(fix){
dumpname = nil;
cd->nextblock = cd->nulldump+1;
cd->nulldump = 0;
Cwseek(cd, (vlong)cd->nextblock * Blocksize);
goto Dofix;
}
dumpname = adddumpdir(&idumproot, now, &dir);
/* note that we assume all names are conforming and thus sorted */
if(cd->flags & CDjoliet) {
s = adddumpdir(&jdumproot, now, &dir);
if(s != dumpname)
sysfatal("dumpnames don't match %s %s", dumpname, s);
}
dump = dumpcd(cd, &idumproot);
cd->nextblock = cd->nulldump+1;
}
/*
* Write new files, starting where the dump tree was.
* Must be done before creation of the Joliet tree so that
* blocks and lengths are correct.
*/
if(dataoffset > (vlong)cd->nextblock * Blocksize)
cd->nextblock = (dataoffset+Blocksize-1)/Blocksize;
Cwseek(cd, (vlong)cd->nextblock * Blocksize);
writefiles(dump, cd, &iroot);
if(cd->bootimage){
findbootimage(cd, &iroot);
if(cd->loader)
findloader(cd, &iroot);
Cupdatebootcat(cd);
}
/* create Joliet tree */
if(cd->flags & CDjoliet)
copydirec(&jroot, &iroot);
if(info.flags & CDconform) {
checknames(&iroot, isbadiso9660);
convertnames(&iroot, struprcpy);
} else
convertnames(&iroot, (void *) strcpy);
// isoabstract = findconform(&iroot, abstract);
// isobiblio = findconform(&iroot, biblio);
// isonotice = findconform(&iroot, notice);
dsort(&iroot, isocmp);
if(cd->flags & CDjoliet) {
// jabstract = findconform(&jroot, abstract);
// jbiblio = findconform(&jroot, biblio);
// jnotice = findconform(&jroot, notice);
checknames(&jroot, isbadjoliet);
convertnames(&jroot, (void *) strcpy);
dsort(&jroot, jolietcmp);
}
/*
* Write directories.
*/
writedirs(cd, &iroot, Cputisodir);
if(cd->flags & CDjoliet)
writedirs(cd, &jroot, Cputjolietdir);
if(mk9660){
cblock = 0;
clength = 0;
newnull = 0;
}else{
/*
* Write incremental _conform.map block.
*/
wrconform(cd, cd->nconform, &cblock, &clength);
/* jump here if we're just fixing up the cd */
Dofix:
/*
* Write null dump header block; everything after this will be
* overwritten at the next dump. Because of this, it needs to be
* reconstructable. We reconstruct the _conform.map and dump trees
* from the header blocks in dump.c, and we reconstruct the path
* tables by walking the cd.
*/
newnull = Cputdumpblock(cd);
}
if(info.flags & CDpbs)
Cfillpbs(cd);
/*
* Write _conform.map.
*/
dir.mode = 0444;
if(cd->flags & (CDconform|CDjoliet)) {
if(!mk9660 && cd->nconform == 0){
block = cblock;
length = clength;
}else
wrconform(cd, 0, &block, &length);
if(mk9660)
{
idumproot = iroot;
jdumproot = jroot;
}
if(length) {
/* The ISO9660 name will get turned into uppercase when written. */
if((iconform = walkdirec(&idumproot, "_conform.map")) == nil)
iconform = adddirec(&idumproot, "_conform.map", &dir);
jconform = nil;
if(cd->flags & CDjoliet) {
if((jconform = walkdirec(&jdumproot, "_conform.map")) == nil)
jconform = adddirec(&jdumproot, "_conform.map", &dir);
}
iconform->block = block;
iconform->length = length;
if(cd->flags & CDjoliet) {
jconform->block = block;
jconform->length = length;
}
}
if(mk9660) {
iroot = idumproot;
jroot = jdumproot;
}
}
if(mk9660){
/*
* Patch in root directories.
*/
setroot(cd, cd->iso9660pvd, iroot.block, iroot.length);
setvolsize(cd, cd->iso9660pvd, cd->nextblock);
if(cd->flags & CDjoliet){
setroot(cd, cd->jolietsvd, jroot.block, jroot.length);
setvolsize(cd, cd->jolietsvd, cd->nextblock);
}
}else{
/*
* Write dump tree at end. We assume the name characters
* are all conforming, so everything is already sorted properly.
*/
convertnames(&idumproot, (info.flags & CDconform) ? (void *) struprcpy : (void *) strcpy);
if(cd->nulldump) {
r = walkdirec(&idumproot, dumpname);
assert(r != nil);
copybutname(r, &iroot);
}
if(cd->flags & CDjoliet) {
convertnames(&jdumproot, (void *) strcpy);
if(cd->nulldump) {
r = walkdirec(&jdumproot, dumpname);
assert(r != nil);
copybutname(r, &jroot);
}
}
writedumpdirs(cd, &idumproot, Cputisodir);
if(cd->flags & CDjoliet)
writedumpdirs(cd, &jdumproot, Cputjolietdir);
/*
* Patch in new root directory entry.
*/
setroot(cd, cd->iso9660pvd, idumproot.block, idumproot.length);
setvolsize(cd, cd->iso9660pvd, cd->nextblock);
if(cd->flags & CDjoliet){
setroot(cd, cd->jolietsvd, jdumproot.block, jdumproot.length);
setvolsize(cd, cd->jolietsvd, cd->nextblock);
}
}
writepathtables(cd);
if(!mk9660){
/*
* If we've gotten too big, truncate back to what we started with,
* fix up the cd, and exit with a non-zero status.
*/
Cwflush(cd);
if(cd->nulldump && maxsize && Cwoffset(cd) > maxsize){
fprint(2, "too big; writing old tree back\n");
status = "cd too big; aborted";
rmdumpdir(&idumproot, dumpname);
rmdumpdir(&jdumproot, dumpname);
cd->nextblock = cd->nulldump+1;
cd->nulldump = 0;
Cwseek(cd, (vlong)cd->nextblock * Blocksize);
goto Dofix;
}
/*
* Write old null header block; this commits all our changes.
*/
if(cd->nulldump){
Cwseek(cd, (vlong)cd->nulldump * Blocksize);
sprint(buf, "plan 9 dump cd\n");
sprint(buf+strlen(buf), "%s %lud %lud %lud %llud %lud %lud",
dumpname, now, newnull, cblock, clength,
iroot.block, iroot.length);
if(cd->flags & CDjoliet)
sprint(buf+strlen(buf), " %lud %lud",
jroot.block, jroot.length);
strcat(buf, "\n");
Cwrite(cd, buf, strlen(buf));
Cpadblock(cd);
Cwflush(cd);
}
}
fdtruncate(cd->fd, (vlong)cd->nextblock * Blocksize);
exits(status);
}
static void
addprotofile(char *new, char *old, Dir *d, void *a)
{
char *name, *p;
Direc *direc;
XDir xd;
dirtoxdir(&xd, d);
name = nil;
if(docolon && strchr(new, ':')) {
name = emalloc(strlen(new)+1);
strcpy(name, new);
while((p=strchr(name, ':')))
*p=' ';
new = name;
}
if((direc = adddirec((Direc*)a, new, &xd))) {
direc->srcfile = atom(old);
// BUG: abstract, biblio, notice
}
if(name)
free(name);
}
|