plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

dump9660.c (9081B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <bio.h>
      4 #include <disk.h>
      5 #include <libsec.h>
      6 #include "iso9660.h"
      7 
      8 ulong now;
      9 int chatty;
     10 int doabort;
     11 int docolon;
     12 int mk9660;
     13 Conform *map;
     14 
     15 static void addprotofile(char *new, char *old, Dir *d, void *a);
     16 void usage(void);
     17 
     18 char *argv0;
     19 
     20 void
     21 usage(void)
     22 {
     23 	if(mk9660)
     24 		fprint(2, "usage: mk9660 [-D:] [-9cjr] [-b bootfile] [-p proto] [-s src] cdimage\n");
     25 	else
     26 		fprint(2, "usage: dump9660 [-D:] [-9cjr] [-m maxsize] [-n now] [-p proto] [-s src] cdimage\n");
     27 	exits("usage");
     28 }
     29 
     30 int
     31 main(int argc, char **argv)
     32 {
     33 	int fix;
     34 	char buf[256], *dumpname, *proto, *s, *src, *status;
     35 	ulong block, length, newnull, cblock, clength, maxsize;
     36 	Cdimg *cd;
     37 	Cdinfo info;
     38 	XDir dir;
     39 	Direc *iconform, idumproot, iroot, *jconform, jdumproot, jroot, *r;
     40 	Dump *dump;
     41 
     42 	fix = 0;
     43 	status = nil;
     44 	memset(&info, 0, sizeof info);
     45 	proto = unsharp("#9/proto/allproto");
     46 	src = "./";
     47 
     48 	info.volumename = atom("9CD");
     49 	info.volumeset = atom("9VolumeSet");
     50 	info.publisher = atom("9Publisher");
     51 	info.preparer = atom("dump9660");
     52 	info.application = atom("dump9660");
     53 	info.flags = CDdump;
     54 	maxsize = 0;
     55 	mk9660 = 0;
     56 	fmtinstall('H', encodefmt);
     57 
     58 	ARGBEGIN{
     59 	case 'D':
     60 		chatty++;
     61 		break;
     62 	case 'M':
     63 		mk9660 = 1;
     64 		argv0 = "disk/mk9660";
     65 		info.flags &= ~CDdump;
     66 		break;
     67 	case '9':
     68 		info.flags |= CDplan9;
     69 		break;
     70 	case ':':
     71 		docolon = 1;
     72 		break;
     73 	case 'a':
     74 		doabort = 1;
     75 		break;
     76 	case 'b':
     77 		if(!mk9660)
     78 			usage();
     79 		info.flags |= CDbootable;
     80 		info.bootimage = EARGF(usage());
     81 		break;
     82 	case 'c':
     83 		info.flags |= CDconform;
     84 		break;
     85 	case 'f':
     86 		fix = 1;
     87 		break;
     88 	case 'j':
     89 		info.flags |= CDjoliet;
     90 		break;
     91 	case 'n':
     92 		now = atoi(EARGF(usage()));
     93 		break;
     94 	case 'm':
     95 		maxsize = strtoul(EARGF(usage()), 0, 0);
     96 		break;
     97 	case 'p':
     98 		proto = EARGF(usage());
     99 		break;
    100 	case 'r':
    101 		info.flags |= CDrockridge;
    102 		break;
    103 	case 's':
    104 		src = EARGF(usage());
    105 		break;
    106 	case 'v':
    107 		info.volumename = atom(EARGF(usage()));
    108 		break;
    109 	default:
    110 		usage();
    111 	}ARGEND
    112 
    113 	if(mk9660 && (fix || now || maxsize))
    114 		usage();
    115 
    116 	if(argc != 1)
    117 		usage();
    118 
    119 	if(now == 0)
    120 		now = (ulong)time(0);
    121 	if(mk9660){
    122 		if((cd = createcd(argv[0], info)) == nil)
    123 			sysfatal("cannot create '%s': %r", argv[0]);
    124 	}else{
    125 		if((cd = opencd(argv[0], info)) == nil)
    126 			sysfatal("cannot open '%s': %r", argv[0]);
    127 		if(!(cd->flags & CDdump))
    128 			sysfatal("not a dump cd");
    129 	}
    130 
    131 	/* create ISO9660/Plan 9 tree in memory */
    132 	memset(&dir, 0, sizeof dir);
    133 	dir.name = atom("");
    134 	dir.uid = atom("sys");
    135 	dir.gid = atom("sys");
    136 	dir.uidno = 0;
    137 	dir.gidno = 0;
    138 	dir.mode = DMDIR | 0755;
    139 	dir.mtime = now;
    140 	dir.atime = now;
    141 	dir.ctime = now;
    142 
    143 	mkdirec(&iroot, &dir);
    144 	iroot.srcfile = src;
    145 
    146 	/*
    147 	 * Read new files into memory
    148 	 */
    149 	if(rdproto(proto, src, addprotofile, 0, &iroot) < 0)
    150 		sysfatal("rdproto: %r");
    151 
    152 	if(mk9660){
    153 		dump = emalloc(sizeof *dump);
    154 		dumpname = nil;
    155 	}else{
    156 		/*
    157 		 * Read current dump tree and _conform.map.
    158 		 */
    159 		idumproot = readdumpdirs(cd, &dir, isostring);
    160 		readdumpconform(cd);
    161 		if(cd->flags & CDjoliet)
    162 			jdumproot = readdumpdirs(cd, &dir, jolietstring);
    163 
    164 		if(fix){
    165 			dumpname = nil;
    166 			cd->nextblock = cd->nulldump+1;
    167 			cd->nulldump = 0;
    168 			Cwseek(cd, cd->nextblock*Blocksize);
    169 			goto Dofix;
    170 		}
    171 
    172 		dumpname = adddumpdir(&idumproot, now, &dir);
    173 		/* note that we assume all names are conforming and thus sorted */
    174 		if(cd->flags & CDjoliet) {
    175 			s = adddumpdir(&jdumproot, now, &dir);
    176 			if(s != dumpname)
    177 				sysfatal("dumpnames don't match %s %s\n", dumpname, s);
    178 		}
    179 		dump = dumpcd(cd, &idumproot);
    180 		cd->nextblock = cd->nulldump+1;
    181 	}
    182 
    183 	/*
    184 	 * Write new files, starting where the dump tree was.
    185  	 * Must be done before creation of the Joliet tree so that
    186  	 * blocks and lengths are correct.
    187 	 */
    188 	Cwseek(cd, cd->nextblock*Blocksize);
    189 	writefiles(dump, cd, &iroot);
    190 
    191 	if(cd->bootimage){
    192 		findbootimage(cd, &iroot);
    193 		Cupdatebootcat(cd);
    194 	}
    195 
    196 	/* create Joliet tree */
    197 	if(cd->flags & CDjoliet)
    198 		copydirec(&jroot, &iroot);
    199 
    200 	if(info.flags & CDconform) {
    201 		checknames(&iroot, isbadiso9660);
    202 		convertnames(&iroot, struprcpy);
    203 	} else
    204 		convertnames(&iroot, (char* (*)(char*, char*))strcpy);
    205 
    206 /*	isoabstract = findconform(&iroot, abstract); */
    207 /*	isobiblio = findconform(&iroot, biblio); */
    208 /*	isonotice = findconform(&iroot, notice); */
    209 
    210 	dsort(&iroot, isocmp);
    211 
    212 	if(cd->flags & CDjoliet) {
    213 	/*	jabstract = findconform(&jroot, abstract); */
    214 	/*	jbiblio = findconform(&jroot, biblio); */
    215 	/*	jnotice = findconform(&jroot, notice); */
    216 
    217 		checknames(&jroot, isbadjoliet);
    218 		convertnames(&jroot, (char* (*)(char*, char*))strcpy);
    219 		dsort(&jroot, jolietcmp);
    220 	}
    221 
    222 	/*
    223 	 * Write directories.
    224 	 */
    225 	writedirs(cd, &iroot, Cputisodir);
    226 	if(cd->flags & CDjoliet)
    227 		writedirs(cd, &jroot, Cputjolietdir);
    228 
    229 	if(mk9660){
    230 		cblock = 0;
    231 		clength = 0;
    232 		newnull = 0;
    233 	}else{
    234 		/*
    235 		 * Write incremental _conform.map block.
    236 		 */
    237 		wrconform(cd, cd->nconform, &cblock, &clength);
    238 
    239 		/* jump here if we're just fixing up the cd */
    240 Dofix:
    241 		/*
    242 		 * Write null dump header block; everything after this will be
    243 		 * overwritten at the next dump.  Because of this, it needs to be
    244 		 * reconstructable.  We reconstruct the _conform.map and dump trees
    245 		 * from the header blocks in dump.c, and we reconstruct the path
    246 		 * tables by walking the cd.
    247 		 */
    248 		newnull = Cputdumpblock(cd);
    249 	}
    250 
    251 	/*
    252 	 * Write _conform.map.
    253 	 */
    254 	dir.mode = 0444;
    255 	if(cd->flags & (CDconform|CDjoliet)) {
    256 		if(!mk9660 && cd->nconform == 0){
    257 			block = cblock;
    258 			length = clength;
    259 		}else
    260 			wrconform(cd, 0, &block, &length);
    261 
    262 		if(mk9660)
    263 {
    264 			idumproot = iroot;
    265 			jdumproot = jroot;
    266 		}
    267 		if(length) {
    268 			/* The ISO9660 name will get turned into uppercase when written. */
    269 			if((iconform = walkdirec(&idumproot, "_conform.map")) == nil)
    270 				iconform = adddirec(&idumproot, "_conform.map", &dir);
    271 			jconform = nil;
    272 			if(cd->flags & CDjoliet) {
    273 				if((jconform = walkdirec(&jdumproot, "_conform.map")) == nil)
    274 					jconform = adddirec(&jdumproot, "_conform.map", &dir);
    275 			}
    276 			iconform->block = block;
    277 			iconform->length = length;
    278 			if(cd->flags & CDjoliet) {
    279 				jconform->block = block;
    280 				jconform->length = length;
    281 			}
    282 		}
    283 		if(mk9660) {
    284 			iroot = idumproot;
    285 			jroot = jdumproot;
    286 		}
    287 	}
    288 
    289 	if(mk9660){
    290 		/*
    291 		 * Patch in root directories.
    292 		 */
    293 		setroot(cd, cd->iso9660pvd, iroot.block, iroot.length);
    294 		setvolsize(cd, cd->iso9660pvd, cd->nextblock*Blocksize);
    295 		if(cd->flags & CDjoliet){
    296 			setroot(cd, cd->jolietsvd, jroot.block, jroot.length);
    297 			setvolsize(cd, cd->jolietsvd, cd->nextblock*Blocksize);
    298 		}
    299 	}else{
    300 		/*
    301 		 * Write dump tree at end.  We assume the name characters
    302 		 * are all conforming, so everything is already sorted properly.
    303 		 */
    304 		convertnames(&idumproot, (info.flags & CDconform) ? struprcpy : (char* (*)(char*, char*)) strcpy);
    305 		if(cd->nulldump) {
    306 			r = walkdirec(&idumproot, dumpname);
    307 			assert(r != nil);
    308 			copybutname(r, &iroot);
    309 		}
    310 		if(cd->flags & CDjoliet) {
    311 			convertnames(&jdumproot, (char* (*)(char*, char*))strcpy);
    312 			if(cd->nulldump) {
    313 				r = walkdirec(&jdumproot, dumpname);
    314 				assert(r != nil);
    315 				copybutname(r, &jroot);
    316 			}
    317 		}
    318 
    319 		writedumpdirs(cd, &idumproot, Cputisodir);
    320 		if(cd->flags & CDjoliet)
    321 			writedumpdirs(cd, &jdumproot, Cputjolietdir);
    322 
    323 		/*
    324 		 * Patch in new root directory entry.
    325 		 */
    326 		setroot(cd, cd->iso9660pvd, idumproot.block, idumproot.length);
    327 		setvolsize(cd, cd->iso9660pvd, cd->nextblock*Blocksize);
    328 		if(cd->flags & CDjoliet){
    329 			setroot(cd, cd->jolietsvd, jdumproot.block, jdumproot.length);
    330 			setvolsize(cd, cd->jolietsvd, cd->nextblock*Blocksize);
    331 		}
    332 	}
    333 	writepathtables(cd);
    334 
    335 	if(!mk9660){
    336 		/*
    337 		 * If we've gotten too big, truncate back to what we started with,
    338 		 * fix up the cd, and exit with a non-zero status.
    339 		 */
    340 		Cwflush(cd);
    341 		if(cd->nulldump && maxsize && Cwoffset(cd) > maxsize){
    342 			fprint(2, "too big; writing old tree back\n");
    343 			status = "cd too big; aborted";
    344 
    345 			rmdumpdir(&idumproot, dumpname);
    346 			rmdumpdir(&jdumproot, dumpname);
    347 
    348 			cd->nextblock = cd->nulldump+1;
    349 			cd->nulldump = 0;
    350 			Cwseek(cd, cd->nextblock*Blocksize);
    351 			goto Dofix;
    352 		}
    353 
    354 		/*
    355 		 * Write old null header block; this commits all our changes.
    356 		 */
    357 		if(cd->nulldump){
    358 			Cwseek(cd, cd->nulldump*Blocksize);
    359 			sprint(buf, "plan 9 dump cd\n");
    360 			sprint(buf+strlen(buf), "%s %lud %lud %lud %lud %lud %lud",
    361 				dumpname, now, newnull, cblock, clength, iroot.block,
    362 				iroot.length);
    363 			if(cd->flags & CDjoliet)
    364 				sprint(buf+strlen(buf), " %lud %lud",
    365 					jroot.block, jroot.length);
    366 			strcat(buf, "\n");
    367 			Cwrite(cd, buf, strlen(buf));
    368 			Cpadblock(cd);
    369 			Cwflush(cd);
    370 		}
    371 	}
    372 	fdtruncate(cd->fd, cd->nextblock*Blocksize);
    373 	exits(status);
    374 	return 0;
    375 }
    376 
    377 static void
    378 addprotofile(char *new, char *old, Dir *d, void *a)
    379 {
    380 	char *name, *p;
    381 	Direc *direc;
    382 	XDir xd;
    383 
    384 	dirtoxdir(&xd, d);
    385 	name = nil;
    386 	if(docolon && strchr(new, ':')) {
    387 		name = emalloc(strlen(new)+1);
    388 		strcpy(name, new);
    389 		while((p=strchr(name, ':')))
    390 			*p=' ';
    391 		new = name;
    392 	}
    393 	if((direc = adddirec((Direc*)a, new, &xd))) {
    394 		direc->srcfile = atom(old);
    395 
    396 		/* BUG: abstract, biblio, notice */
    397 	}
    398 	if(name)
    399 		free(name);
    400 
    401 }