8 static int readisodesc(Cdimg*, Voldesc*);
9 static int readjolietdesc(Cdimg*, Voldesc*);
12 * It's not strictly conforming; instead it's enough to
13 * get us up and running; presumably the real CD writing
14 * will take care of being conforming.
16 * Things not conforming include:
18 * - root directories are of length zero
21 createcd(char *file, Cdinfo info)
26 if(access(file, AEXIST) == 0){
27 werrstr("file already exists");
31 if((fd = create(file, ORDWR, 0666)) < 0)
34 cd = emalloc(sizeof *cd);
35 cd->file = atom(file);
37 Binit(&cd->brd, fd, OREAD);
39 if((xfd = open(file, ORDWR)) < 0)
40 sysfatal("can't open file again: %r");
41 Binit(&cd->bwr, xfd, OWRITE);
43 Crepeat(cd, 0, 16*Blocksize);
45 if(info.flags & CDbootable){
46 cd->bootimage = info.bootimage;
47 cd->flags |= CDbootable;
51 if(readisodesc(cd, &cd->iso) < 0)
53 if(info.flags & CDplan9)
55 else if(info.flags & CDrockridge)
56 cd->flags |= CDrockridge;
57 if(info.flags & CDjoliet) {
58 Cputjolietsvd(cd, info);
59 if(readjolietdesc(cd, &cd->joliet) < 0)
61 cd->flags |= CDjoliet;
65 if(info.flags & CDdump){
66 cd->nulldump = Cputdumpblock(cd);
69 if(cd->flags & CDbootable){
74 if(info.flags & CDconform)
75 cd->flags |= CDconform;
78 cd->nextblock = Cwoffset(cd) / Blocksize;
79 assert(cd->nextblock != 0);
85 opencd(char *file, Cdinfo info)
91 if((fd = open(file, ORDWR)) < 0) {
92 if(access(file, AEXIST) == 0)
94 return createcd(file, info);
97 if((d = dirfstat(fd)) == nil) {
101 if(d->length == 0 || d->length % Blocksize) {
102 werrstr("bad length %lld", d->length);
108 cd = emalloc(sizeof *cd);
109 cd->file = atom(file);
110 cd->nextblock = d->length / Blocksize;
111 assert(cd->nextblock != 0);
114 Binit(&cd->brd, fd, OREAD);
116 if((xfd = open(file, ORDWR)) < 0)
117 sysfatal("can't open file again: %r");
118 Binit(&cd->bwr, xfd, OWRITE);
120 if(readisodesc(cd, &cd->iso) < 0) {
127 /* lowercase because of isostring */
128 if(strstr(cd->iso.systemid, "iso9660") == nil
129 && strstr(cd->iso.systemid, "utf8") == nil) {
130 werrstr("unknown systemid %s", cd->iso.systemid);
137 if(strstr(cd->iso.systemid, "plan 9"))
138 cd->flags |= CDplan9;
139 if(strstr(cd->iso.systemid, "iso9660"))
140 cd->flags |= CDconform;
141 if(strstr(cd->iso.systemid, "rrip"))
142 cd->flags |= CDrockridge;
143 if(strstr(cd->iso.systemid, "boot"))
144 cd->flags |= CDbootable;
145 if(readjolietdesc(cd, &cd->joliet) == 0)
146 cd->flags |= CDjoliet;
168 little(void *a, int n)
182 Creadblock(Cdimg *cd, void *buf, ulong block, ulong len)
184 assert(block != 0); /* nothing useful there */
187 if(Bseek(&cd->brd, block*Blocksize, 0) != block*Blocksize)
188 sysfatal("error seeking to block %lud", block);
189 if(Bread(&cd->brd, buf, len) != len)
190 sysfatal("error reading %lud bytes at block %lud: %r %lld", len, block, Bseek(&cd->brd, 0, 2));
194 parsedir(Cdimg *cd, Direc *d, uchar *buf, int len, char *(*cvtname)(uchar*, int))
196 enum { NAMELEN = 28 };
201 memset(d, 0, sizeof *d);
206 werrstr("buffer too small");
210 if(c->namelen == 1 && c->name[0] == '\0')
212 else if(c->namelen == 1 && c->name[0] == '\001')
213 d->name = atom("..");
215 d->name = cvtname(c->name, c->namelen);
217 d->block = little(c->dloc, 4);
218 d->length = little(c->dlen, 4);
223 /*BUG: do we really need to parse the plan 9 fields? */
224 /* plan 9 use fields */
225 if((cd->flags & CDplan9) && cvtname == isostring
226 && (c->namelen != 1 || c->name[0] > 1)) {
227 p = buf+33+c->namelen;
230 assert(p < buf+c->len);
231 assert(*p < NAMELEN);
233 memmove(name, p+1, *p);
235 d->confname = d->name;
236 d->name = atom(name);
239 assert(*p < NAMELEN);
240 memmove(name, p+1, *p);
244 assert(*p < NAMELEN);
245 memmove(name, p+1, *p);
251 d->mode = little(p, 4);
254 /* BUG: rock ridge extensions */
259 setroot(Cdimg *cd, ulong block, ulong dloc, ulong dlen)
263 Cwseek(cd, block*Blocksize+offsetof(Cvoldesc, rootdir[0])+offsetof(Cdir, dloc[0]));
269 setvolsize(Cdimg *cd, ulong block, ulong size)
273 Cwseek(cd, block*Blocksize+offsetof(Cvoldesc, volsize[0]));
278 setpathtable(Cdimg *cd, ulong block, ulong sz, ulong lloc, ulong bloc)
282 Cwseek(cd, block*Blocksize+offsetof(Cvoldesc, pathsize[0]));
288 assert(Cwoffset(cd) == block*Blocksize+offsetof(Cvoldesc, rootdir[0]));
293 parsedesc(Voldesc *v, Cvoldesc *cv, char *(*string)(uchar*, int))
295 v->systemid = string(cv->systemid, sizeof cv->systemid);
297 v->pathsize = little(cv->pathsize, 4);
298 v->lpathloc = little(cv->lpathloc, 4);
299 v->mpathloc = little(cv->mpathloc, 4);
301 v->volumeset = string(cv->volumeset, sizeof cv->volumeset);
302 v->publisher = string(cv->publisher, sizeof cv->publisher);
303 v->preparer = string(cv->preparer, sizeof cv->preparer);
304 v->application = string(cv->application, sizeof cv->application);
306 v->abstract = string(cv->abstract, sizeof cv->abstract);
307 v->biblio = string(cv->biblio, sizeof cv->biblio);
308 v->notice = string(cv->notice, sizeof cv->notice);
312 readisodesc(Cdimg *cd, Voldesc *v)
314 static uchar magic[] = { 0x01, 'C', 'D', '0', '0', '1', 0x01, 0x00 };
317 memset(v, 0, sizeof *v);
319 Creadblock(cd, &cv, 16, sizeof cv);
320 if(memcmp(cv.magic, magic, sizeof magic) != 0) {
321 werrstr("bad pvd magic");
325 if(little(cv.blocksize, 2) != Blocksize) {
326 werrstr("block size not %d", Blocksize);
331 parsedesc(v, &cv, isostring);
333 return parsedir(cd, &v->root, cv.rootdir, sizeof cv.rootdir, isostring);
337 readjolietdesc(Cdimg *cd, Voldesc *v)
340 static uchar magic[] = { 0x02, 'C', 'D', '0', '0', '1', 0x01, 0x00 };
343 memset(v, 0, sizeof *v);
345 for(i=16; i<24; i++) {
346 Creadblock(cd, &cv, i, sizeof cv);
347 if(memcmp(cv.magic, magic, sizeof magic) != 0)
349 if(cv.charset[0] != 0x25 || cv.charset[1] != 0x2F
350 || (cv.charset[2] != 0x40 && cv.charset[2] != 0x43 && cv.charset[2] != 0x45))
356 werrstr("could not find Joliet SVD");
360 if(little(cv.blocksize, 2) != Blocksize) {
361 werrstr("block size not %d", Blocksize);
366 parsedesc(v, &cv, jolietstring);
368 return parsedir(cd, &v->root, cv.rootdir, sizeof cv.rootdir, jolietstring);
372 * CD image buffering routines.
375 Cputc(Cdimg *cd, int c)
377 assert(Boffset(&cd->bwr) >= 16*Blocksize || c == 0);
379 if(Boffset(&cd->bwr) == 0x9962)
380 if(c >= 256) abort();
381 if(Bputc(&cd->bwr, c) < 0)
382 sysfatal("Bputc: %r");
387 Cputnl(Cdimg *cd, ulong val, int size)
391 sysfatal("bad size %d in bputnl", size);
406 Cputnm(Cdimg *cd, ulong val, int size)
410 sysfatal("bad size %d in bputnl", size);
425 Cputn(Cdimg *cd, long val, int size)
427 Cputnl(cd, val, size);
428 Cputnm(cd, val, size);
432 * ASCII/UTF string writing
435 Crepeat(Cdimg *cd, int c, int n)
442 Cputs(Cdimg *cd, char *s, int size)
447 Crepeat(cd, ' ', size);
451 for(n=0; n<size && *s; n++)
454 Crepeat(cd, ' ', size-n);
458 Cwrite(Cdimg *cd, void *buf, int n)
460 assert(Boffset(&cd->bwr) >= 16*Blocksize);
462 if(Bwrite(&cd->bwr, buf, n) != n)
463 sysfatal("Bwrite: %r");
468 Cputr(Cdimg *cd, Rune r)
475 Crepeatr(Cdimg *cd, Rune r, int n)
484 Cputrs(Cdimg *cd, Rune *s, int osize)
490 Crepeatr(cd, (Rune)' ', size);
492 for(n=0; *s && n<size; n++)
495 Crepeatr(cd, ' ', size-n);
498 Cputc(cd, 0); /* what else can we do? */
502 Cputrscvt(Cdimg *cd, char *s, int size)
507 Cputrs(cd, strtorune(r, s), size);
516 n = Blocksize - (Boffset(&cd->bwr) % Blocksize);
520 nb = Boffset(&cd->bwr)/Blocksize;
522 if(nb > cd->nextblock)
527 Cputdate(Cdimg *cd, ulong ust)
537 Cputc(cd, tm->mon+1);
546 Cputdate1(Cdimg *cd, ulong ust)
552 Crepeat(cd, '0', 16);
557 sprint(str, "%.4d%.2d%.2d%.2d%.2d%.4d",
569 Cwseek(Cdimg *cd, ulong offset)
571 Bseek(&cd->bwr, offset, 0);
577 return Boffset(&cd->bwr);
589 return Boffset(&cd->brd);
593 Crseek(Cdimg *cd, ulong offset)
595 Bseek(&cd->brd, offset, 0);
604 if((c = Bgetc(&cd->brd)) == Beof) {
605 fprint(2, "getc at %lud\n", Croffset(cd));
607 /*sysfatal("Bgetc: %r"); */
613 Cread(Cdimg *cd, void *buf, int n)
616 if(Bread(&cd->brd, buf, n) != n)
617 sysfatal("Bread: %r");
621 Crdline(Cdimg *cd, int c)
624 return Brdline(&cd->brd, c);
630 return Blinelen(&cd->brd);