tcdrdwr.c - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       tcdrdwr.c (11160B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <libsec.h>
            5 
            6 #include "iso9660.h"
            7 
            8 static int readisodesc(Cdimg*, Voldesc*);
            9 static int readjolietdesc(Cdimg*, Voldesc*);
           10 
           11 /*
           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.
           15  *
           16  * Things not conforming include:
           17  *        - no path table
           18  *        - root directories are of length zero
           19  */
           20 Cdimg*
           21 createcd(char *file, Cdinfo info)
           22 {
           23         int fd, xfd;
           24         Cdimg *cd;
           25 
           26         if(access(file, AEXIST) == 0){
           27                 werrstr("file already exists");
           28                 return nil;
           29         }
           30 
           31         if((fd = create(file, ORDWR, 0666)) < 0)
           32                 return nil;
           33 
           34         cd = emalloc(sizeof *cd);
           35         cd->file = atom(file);
           36 
           37         Binit(&cd->brd, fd, OREAD);
           38 
           39         if((xfd = open(file, ORDWR)) < 0)
           40                 sysfatal("can't open file again: %r");
           41         Binit(&cd->bwr, xfd, OWRITE);
           42 
           43         Crepeat(cd, 0, 16*Blocksize);
           44         Cputisopvd(cd, info);
           45         if(info.flags & CDbootable){
           46                 cd->bootimage = info.bootimage;
           47                 cd->flags |= CDbootable;
           48                 Cputbootvol(cd);
           49         }
           50 
           51         if(readisodesc(cd, &cd->iso) < 0)
           52                 assert(0);
           53         if(info.flags & CDplan9)
           54                 cd->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)
           60                         assert(0);
           61                 cd->flags |= CDjoliet;
           62         }
           63         Cputendvd(cd);
           64 
           65         if(info.flags & CDdump){
           66                 cd->nulldump = Cputdumpblock(cd);
           67                 cd->flags |= CDdump;
           68         }
           69         if(cd->flags & CDbootable){
           70                 Cputbootcat(cd);
           71                 Cupdatebootvol(cd);
           72         }
           73 
           74         if(info.flags & CDconform)
           75                 cd->flags |= CDconform;
           76 
           77         cd->flags |= CDnew;
           78         cd->nextblock = Cwoffset(cd) / Blocksize;
           79         assert(cd->nextblock != 0);
           80 
           81         return cd;
           82 }
           83 
           84 Cdimg*
           85 opencd(char *file, Cdinfo info)
           86 {
           87         int fd, xfd;
           88         Cdimg *cd;
           89         Dir *d;
           90 
           91         if((fd = open(file, ORDWR)) < 0) {
           92                 if(access(file, AEXIST) == 0)
           93                         return nil;
           94                 return createcd(file, info);
           95         }
           96 
           97         if((d = dirfstat(fd)) == nil) {
           98                 close(fd);
           99                 return nil;
          100         }
          101         if(d->length == 0 || d->length % Blocksize) {
          102                 werrstr("bad length %lld", d->length);
          103                 close(fd);
          104                 free(d);
          105                 return nil;
          106         }
          107 
          108         cd = emalloc(sizeof *cd);
          109         cd->file = atom(file);
          110         cd->nextblock = d->length / Blocksize;
          111         assert(cd->nextblock != 0);
          112         free(d);
          113 
          114         Binit(&cd->brd, fd, OREAD);
          115 
          116         if((xfd = open(file, ORDWR)) < 0)
          117                 sysfatal("can't open file again: %r");
          118         Binit(&cd->bwr, xfd, OWRITE);
          119 
          120         if(readisodesc(cd, &cd->iso) < 0) {
          121                 free(cd);
          122                 close(fd);
          123                 close(xfd);
          124                 return nil;
          125         }
          126 
          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);
          131                 free(cd);
          132                 close(fd);
          133                 close(xfd);
          134                 return nil;
          135         }
          136 
          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;
          147         if(hasdump(cd))
          148                 cd->flags |= CDdump;
          149 
          150         return cd;
          151 }
          152 
          153 ulong
          154 big(void *a, int n)
          155 {
          156         uchar *p;
          157         ulong v;
          158         int i;
          159 
          160         p = a;
          161         v = 0;
          162         for(i=0; i<n; i++)
          163                 v = (v<<8) | *p++;
          164         return v;
          165 }
          166 
          167 ulong
          168 little(void *a, int n)
          169 {
          170         uchar *p;
          171         ulong v;
          172         int i;
          173 
          174         p = a;
          175         v = 0;
          176         for(i=0; i<n; i++)
          177                 v |= (*p++<<(i*8));
          178         return v;
          179 }
          180 
          181 void
          182 Creadblock(Cdimg *cd, void *buf, ulong block, ulong len)
          183 {
          184         assert(block != 0);        /* nothing useful there */
          185 
          186         Bflush(&cd->bwr);
          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));
          191 }
          192 
          193 int
          194 parsedir(Cdimg *cd, Direc *d, uchar *buf, int len, char *(*cvtname)(uchar*, int))
          195 {
          196         enum { NAMELEN = 28 };
          197         char name[NAMELEN];
          198         uchar *p;
          199         Cdir *c;
          200 
          201         memset(d, 0, sizeof *d);
          202 
          203         c = (Cdir*)buf;
          204 
          205         if(c->len > len) {
          206                 werrstr("buffer too small");
          207                 return -1;
          208         }
          209 
          210         if(c->namelen == 1 && c->name[0] == '\0')
          211                 d->name = atom(".");
          212         else if(c->namelen == 1 && c->name[0] == '\001')
          213                 d->name = atom("..");
          214         else if(cvtname)
          215                 d->name = cvtname(c->name, c->namelen);
          216 
          217         d->block = little(c->dloc, 4);
          218         d->length = little(c->dlen, 4);
          219 
          220         if(c->flags & 2)
          221                 d->mode |= DMDIR;
          222 
          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;
          228                 if((p-buf)&1)
          229                         p++;
          230                 assert(p < buf+c->len);
          231                 assert(*p < NAMELEN);
          232                 if(*p != 0) {
          233                         memmove(name, p+1, *p);
          234                         name[*p] = '\0';
          235                         d->confname = d->name;
          236                         d->name = atom(name);
          237                 }
          238                 p += *p+1;
          239                 assert(*p < NAMELEN);
          240                 memmove(name, p+1, *p);
          241                 name[*p] = '\0';
          242                 d->uid = atom(name);
          243                 p += *p+1;
          244                 assert(*p < NAMELEN);
          245                 memmove(name, p+1, *p);
          246                 name[*p] = '\0';
          247                 d->gid = atom(name);
          248                 p += *p+1;
          249                 if((p-buf)&1)
          250                         p++;
          251                 d->mode = little(p, 4);
          252         }
          253 
          254         /* BUG: rock ridge extensions */
          255         return 0;
          256 }
          257 
          258 void
          259 setroot(Cdimg *cd, ulong block, ulong dloc, ulong dlen)
          260 {
          261         assert(block != 0);
          262 
          263         Cwseek(cd, block*Blocksize+offsetof(Cvoldesc, rootdir[0])+offsetof(Cdir, dloc[0]));
          264         Cputn(cd, dloc, 4);
          265         Cputn(cd, dlen, 4);
          266 }
          267 
          268 void
          269 setvolsize(Cdimg *cd, ulong block, ulong size)
          270 {
          271         assert(block != 0);
          272 
          273         Cwseek(cd, block*Blocksize+offsetof(Cvoldesc, volsize[0]));
          274         Cputn(cd, size, 4);
          275 }
          276 
          277 void
          278 setpathtable(Cdimg *cd, ulong block, ulong sz, ulong lloc, ulong bloc)
          279 {
          280         assert(block != 0);
          281 
          282         Cwseek(cd, block*Blocksize+offsetof(Cvoldesc, pathsize[0]));
          283         Cputn(cd, sz, 4);
          284         Cputnl(cd, lloc, 4);
          285         Cputnl(cd, 0, 4);
          286         Cputnm(cd, bloc, 4);
          287         Cputnm(cd, 0, 4);
          288         assert(Cwoffset(cd) == block*Blocksize+offsetof(Cvoldesc, rootdir[0]));
          289 }
          290 
          291 
          292 static void
          293 parsedesc(Voldesc *v, Cvoldesc *cv, char *(*string)(uchar*, int))
          294 {
          295         v->systemid = string(cv->systemid, sizeof cv->systemid);
          296 
          297         v->pathsize = little(cv->pathsize, 4);
          298         v->lpathloc = little(cv->lpathloc, 4);
          299         v->mpathloc = little(cv->mpathloc, 4);
          300 
          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);
          305 
          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);
          309 }
          310 
          311 static int
          312 readisodesc(Cdimg *cd, Voldesc *v)
          313 {
          314         static uchar magic[] = { 0x01, 'C', 'D', '0', '0', '1', 0x01, 0x00 };
          315         Cvoldesc cv;
          316 
          317         memset(v, 0, sizeof *v);
          318 
          319         Creadblock(cd, &cv, 16, sizeof cv);
          320         if(memcmp(cv.magic, magic, sizeof magic) != 0) {
          321                 werrstr("bad pvd magic");
          322                 return -1;
          323         }
          324 
          325         if(little(cv.blocksize, 2) != Blocksize) {
          326                 werrstr("block size not %d", Blocksize);
          327                 return -1;
          328         }
          329 
          330         cd->iso9660pvd = 16;
          331         parsedesc(v, &cv, isostring);
          332 
          333         return parsedir(cd, &v->root, cv.rootdir, sizeof cv.rootdir, isostring);
          334 }
          335 
          336 static int
          337 readjolietdesc(Cdimg *cd, Voldesc *v)
          338 {
          339         int i;
          340         static uchar magic[] = { 0x02, 'C', 'D', '0', '0', '1', 0x01, 0x00 };
          341         Cvoldesc cv;
          342 
          343         memset(v, 0, sizeof *v);
          344 
          345         for(i=16; i<24; i++) {
          346                 Creadblock(cd, &cv, i, sizeof cv);
          347                 if(memcmp(cv.magic, magic, sizeof magic) != 0)
          348                         continue;
          349                 if(cv.charset[0] != 0x25 || cv.charset[1] != 0x2F
          350                 || (cv.charset[2] != 0x40 && cv.charset[2] != 0x43 && cv.charset[2] != 0x45))
          351                         continue;
          352                 break;
          353         }
          354 
          355         if(i==24) {
          356                 werrstr("could not find Joliet SVD");
          357                 return -1;
          358         }
          359 
          360         if(little(cv.blocksize, 2) != Blocksize) {
          361                 werrstr("block size not %d", Blocksize);
          362                 return -1;
          363         }
          364 
          365         cd->jolietsvd = i;
          366         parsedesc(v, &cv, jolietstring);
          367 
          368         return parsedir(cd, &v->root, cv.rootdir, sizeof cv.rootdir, jolietstring);
          369 }
          370 
          371 /*
          372  * CD image buffering routines.
          373  */
          374 void
          375 Cputc(Cdimg *cd, int c)
          376 {
          377         assert(Boffset(&cd->bwr) >= 16*Blocksize || c == 0);
          378 
          379 if(Boffset(&cd->bwr) == 0x9962)
          380 if(c >= 256) abort();
          381         if(Bputc(&cd->bwr, c) < 0)
          382                 sysfatal("Bputc: %r");
          383         Bflush(&cd->brd);
          384 }
          385 
          386 void
          387 Cputnl(Cdimg *cd, ulong val, int size)
          388 {
          389         switch(size) {
          390         default:
          391                 sysfatal("bad size %d in bputnl", size);
          392         case 2:
          393                 Cputc(cd, val);
          394                 Cputc(cd, val>>8);
          395                 break;
          396         case 4:
          397                 Cputc(cd, val);
          398                 Cputc(cd, val>>8);
          399                 Cputc(cd, val>>16);
          400                 Cputc(cd, val>>24);
          401                 break;
          402         }
          403 }
          404 
          405 void
          406 Cputnm(Cdimg *cd, ulong val, int size)
          407 {
          408         switch(size) {
          409         default:
          410                 sysfatal("bad size %d in bputnl", size);
          411         case 2:
          412                 Cputc(cd, val>>8);
          413                 Cputc(cd, val);
          414                 break;
          415         case 4:
          416                 Cputc(cd, val>>24);
          417                 Cputc(cd, val>>16);
          418                 Cputc(cd, val>>8);
          419                 Cputc(cd, val);
          420                 break;
          421         }
          422 }
          423 
          424 void
          425 Cputn(Cdimg *cd, long val, int size)
          426 {
          427         Cputnl(cd, val, size);
          428         Cputnm(cd, val, size);
          429 }
          430 
          431 /*
          432  * ASCII/UTF string writing
          433  */
          434 void
          435 Crepeat(Cdimg *cd, int c, int n)
          436 {
          437         while(n-- > 0)
          438                 Cputc(cd, c);
          439 }
          440 
          441 void
          442 Cputs(Cdimg *cd, char *s, int size)
          443 {
          444         int n;
          445 
          446         if(s == nil) {
          447                 Crepeat(cd, ' ', size);
          448                 return;
          449         }
          450 
          451         for(n=0; n<size && *s; n++)
          452                 Cputc(cd, *s++);
          453         if(n<size)
          454                 Crepeat(cd, ' ', size-n);
          455 }
          456 
          457 void
          458 Cwrite(Cdimg *cd, void *buf, int n)
          459 {
          460         assert(Boffset(&cd->bwr) >= 16*Blocksize);
          461 
          462         if(Bwrite(&cd->bwr, buf, n) != n)
          463                 sysfatal("Bwrite: %r");
          464         Bflush(&cd->brd);
          465 }
          466 
          467 void
          468 Cputr(Cdimg *cd, Rune r)
          469 {
          470         Cputc(cd, r>>8);
          471         Cputc(cd, r);
          472 }
          473 
          474 void
          475 Crepeatr(Cdimg *cd, Rune r, int n)
          476 {
          477         int i;
          478 
          479         for(i=0; i<n; i++)
          480                 Cputr(cd, r);
          481 }
          482 
          483 void
          484 Cputrs(Cdimg *cd, Rune *s, int osize)
          485 {
          486         int n, size;
          487 
          488         size = osize/2;
          489         if(s == nil)
          490                 Crepeatr(cd, (Rune)' ', size);
          491         else {
          492                 for(n=0; *s && n<size; n++)
          493                         Cputr(cd, *s++);
          494                 if(n<size)
          495                         Crepeatr(cd, ' ', size-n);
          496         }
          497         if(osize&1)
          498                 Cputc(cd, 0);        /* what else can we do? */
          499 }
          500 
          501 void
          502 Cputrscvt(Cdimg *cd, char *s, int size)
          503 {
          504         Rune r[256];
          505 
          506         strtorune(r, s);
          507         Cputrs(cd, strtorune(r, s), size);
          508 }
          509 
          510 void
          511 Cpadblock(Cdimg *cd)
          512 {
          513         int n;
          514         ulong nb;
          515 
          516         n = Blocksize - (Boffset(&cd->bwr) % Blocksize);
          517         if(n != Blocksize)
          518                 Crepeat(cd, 0, n);
          519 
          520         nb = Boffset(&cd->bwr)/Blocksize;
          521         assert(nb != 0);
          522         if(nb > cd->nextblock)
          523                 cd->nextblock = nb;
          524 }
          525 
          526 void
          527 Cputdate(Cdimg *cd, ulong ust)
          528 {
          529         Tm *tm;
          530 
          531         if(ust == 0) {
          532                 Crepeat(cd, 0, 7);
          533                 return;
          534         }
          535         tm = gmtime(ust);
          536         Cputc(cd, tm->year);
          537         Cputc(cd, tm->mon+1);
          538         Cputc(cd, tm->mday);
          539         Cputc(cd, tm->hour);
          540         Cputc(cd, tm->min);
          541         Cputc(cd, tm->sec);
          542         Cputc(cd, 0);
          543 }
          544 
          545 void
          546 Cputdate1(Cdimg *cd, ulong ust)
          547 {
          548         Tm *tm;
          549         char str[20];
          550 
          551         if(ust == 0) {
          552                 Crepeat(cd, '0', 16);
          553                 Cputc(cd, 0);
          554                 return;
          555         }
          556         tm = gmtime(ust);
          557         sprint(str, "%.4d%.2d%.2d%.2d%.2d%.4d",
          558                 tm->year+1900,
          559                 tm->mon+1,
          560                 tm->mday,
          561                 tm->hour,
          562                 tm->min,
          563                 tm->sec*100);
          564         Cputs(cd, str, 16);
          565         Cputc(cd, 0);
          566 }
          567 
          568 void
          569 Cwseek(Cdimg *cd, ulong offset)
          570 {
          571         Bseek(&cd->bwr, offset, 0);
          572 }
          573 
          574 ulong
          575 Cwoffset(Cdimg *cd)
          576 {
          577         return Boffset(&cd->bwr);
          578 }
          579 
          580 void
          581 Cwflush(Cdimg *cd)
          582 {
          583         Bflush(&cd->bwr);
          584 }
          585 
          586 ulong
          587 Croffset(Cdimg *cd)
          588 {
          589         return Boffset(&cd->brd);
          590 }
          591 
          592 void
          593 Crseek(Cdimg *cd, ulong offset)
          594 {
          595         Bseek(&cd->brd, offset, 0);
          596 }
          597 
          598 int
          599 Cgetc(Cdimg *cd)
          600 {
          601         int c;
          602 
          603         Cwflush(cd);
          604         if((c = Bgetc(&cd->brd)) == Beof) {
          605                 fprint(2, "getc at %lud\n", Croffset(cd));
          606                 assert(0);
          607                 /*sysfatal("Bgetc: %r"); */
          608         }
          609         return c;
          610 }
          611 
          612 void
          613 Cread(Cdimg *cd, void *buf, int n)
          614 {
          615         Cwflush(cd);
          616         if(Bread(&cd->brd, buf, n) != n)
          617                 sysfatal("Bread: %r");
          618 }
          619 
          620 char*
          621 Crdline(Cdimg *cd, int c)
          622 {
          623         Cwflush(cd);
          624         return Brdline(&cd->brd, c);
          625 }
          626 
          627 int
          628 Clinelen(Cdimg *cd)
          629 {
          630         return Blinelen(&cd->brd);
          631 }