123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <libsec.h>
- #include "iso9660.h"
- static void
- writelittlebig4(uchar *buf, ulong x)
- {
- buf[0] = buf[7] = x;
- buf[1] = buf[6] = x>>8;
- buf[2] = buf[5] = x>>16;
- buf[3] = buf[4] = x>>24;
- }
- void
- rewritedot(Cdimg *cd, Direc *d)
- {
- uchar buf[Blocksize];
- Cdir *c;
- Creadblock(cd, buf, d->block, Blocksize);
- c = (Cdir*)buf;
- assert(c->len != 0);
- assert(c->namelen == 1 && c->name[0] == '\0'); /* dot */
- writelittlebig4(c->dloc, d->block);
- writelittlebig4(c->dlen, d->length);
- Cwseek(cd, (vlong)d->block * Blocksize);
- Cwrite(cd, buf, Blocksize);
- }
- void
- rewritedotdot(Cdimg *cd, Direc *d, Direc *dparent)
- {
- uchar buf[Blocksize];
- Cdir *c;
- Creadblock(cd, buf, d->block, Blocksize);
- c = (Cdir*)buf;
- assert(c->len != 0);
- assert(c->namelen == 1 && c->name[0] == '\0'); /* dot */
- c = (Cdir*)(buf+c->len);
- assert(c->len != 0);
- assert(c->namelen == 1 && c->name[0] == '\001'); /* dotdot*/
- writelittlebig4(c->dloc, dparent->block);
- writelittlebig4(c->dlen, dparent->length);
- Cwseek(cd, (vlong)d->block * Blocksize);
- Cwrite(cd, buf, Blocksize);
- }
- /*
- * Write each non-directory file. We copy the file to
- * the cd image, and then if it turns out that we've
- * seen this stream of bits before, we push the next block
- * pointer back. This ensures consistency between the MD5s
- * and the data on the CD image. MD5 summing on one pass
- * and copying on another would not ensure this.
- */
- void
- writefiles(Dump *d, Cdimg *cd, Direc *direc)
- {
- int i;
- uchar buf[8192], digest[MD5dlen];
- ulong length, n, start;
- Biobuf *b;
- DigestState *s;
- Dumpdir *dd;
- if(direc->mode & DMDIR) {
- for(i=0; i<direc->nchild; i++)
- writefiles(d, cd, &direc->child[i]);
- return;
- }
- assert(direc->block == 0);
- if((b = Bopen(direc->srcfile, OREAD)) == nil){
- fprint(2, "warning: cannot open '%s': %r\n", direc->srcfile);
- direc->block = 0;
- direc->length = 0;
- return;
- }
- start = cd->nextblock;
- assert(start != 0);
- if(blocksize && start%blocksize)
- start += blocksize-start%blocksize;
- Cwseek(cd, (vlong)start * Blocksize);
-
- s = md5(nil, 0, nil, nil);
- length = 0;
- while((n = Bread(b, buf, sizeof buf)) > 0) {
- md5(buf, n, nil, s);
- Cwrite(cd, buf, n);
- length += n;
- }
- md5(nil, 0, digest, s);
- Bterm(b);
- Cpadblock(cd);
- if(length != direc->length) {
- fprint(2, "warning: %s changed size underfoot\n", direc->srcfile);
- direc->length = length;
- }
- if(length == 0)
- direc->block = 0;
- else if((dd = lookupmd5(d, digest))) {
- assert(dd->length == length);
- assert(dd->block != 0);
- direc->block = dd->block;
- cd->nextblock = start;
- } else {
- direc->block = start;
- if(chatty > 1)
- fprint(2, "lookup %.16H %lud (%s) failed\n", digest, length, direc->name);
- insertmd5(d, atom(direc->name), digest, start, length);
- }
- }
- /*
- * Write a directory tree. We work from the leaves,
- * and patch the dotdot pointers afterward.
- */
- static void
- _writedirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int), int level)
- {
- int i, l, ll;
- ulong start, next;
- if((d->mode & DMDIR) == 0)
- return;
- if(chatty)
- fprint(2, "%*s%s\n", 4*level, "", d->name);
- for(i=0; i<d->nchild; i++)
- _writedirs(cd, &d->child[i], put, level+1);
- l = 0;
- l += put(cd, d, (level == 0) ? DTrootdot : DTdot, 0, l);
- l += put(cd, nil, DTdotdot, 0, l);
- for(i=0; i<d->nchild; i++)
- l += put(cd, &d->child[i], DTiden, 0, l);
- start = cd->nextblock;
- cd->nextblock += (l+Blocksize-1)/Blocksize;
- next = cd->nextblock;
- Cwseek(cd, (vlong)start * Blocksize);
- ll = 0;
- ll += put(cd, d, (level == 0) ? DTrootdot : DTdot, 1, ll);
- ll += put(cd, nil, DTdotdot, 1, ll);
- for(i=0; i<d->nchild; i++)
- ll += put(cd, &d->child[i], DTiden, 1, ll);
- assert(ll == l);
- Cpadblock(cd);
- assert(Cwoffset(cd) == (vlong)next * Blocksize);
- d->block = start;
- d->length = (vlong)(next - start) * Blocksize;
- rewritedot(cd, d);
- rewritedotdot(cd, d, d);
- for(i=0; i<d->nchild; i++)
- if(d->child[i].mode & DMDIR)
- rewritedotdot(cd, &d->child[i], d);
- }
- void
- writedirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int))
- {
- /*
- * If we're writing a mk9660 image, then the root really
- * is the root, so start at level 0. If we're writing a dump image,
- * then the "root" is really going to be two levels down once
- * we patch in the dump hierarchy above it, so start at level non-zero.
- */
- if(chatty)
- fprint(2, ">>> writedirs\n");
- _writedirs(cd, d, put, mk9660 ? 0 : 1);
- }
- /*
- * Write the dump tree. This is like writedirs but once we get to
- * the roots of the individual days we just patch the parent dotdot blocks.
- */
- static void
- _writedumpdirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int), int level)
- {
- int i;
- ulong start;
- switch(level) {
- case 0:
- /* write root, list of years, also conform.map */
- for(i=0; i<d->nchild; i++)
- if(d->child[i].mode & DMDIR)
- _writedumpdirs(cd, &d->child[i], put, level+1);
- chat("write dump root dir at %lud\n", cd->nextblock);
- goto Writedir;
- case 1: /* write year, list of days */
- for(i=0; i<d->nchild; i++)
- _writedumpdirs(cd, &d->child[i], put, level+1);
- chat("write dump %s dir at %lud\n", d->name, cd->nextblock);
- goto Writedir;
- Writedir:
- start = cd->nextblock;
- Cwseek(cd, (vlong)start * Blocksize);
- put(cd, d, (level == 0) ? DTrootdot : DTdot, 1, Cwoffset(cd));
- put(cd, nil, DTdotdot, 1, Cwoffset(cd));
- for(i=0; i<d->nchild; i++)
- put(cd, &d->child[i], DTiden, 1, Cwoffset(cd));
- Cpadblock(cd);
- d->block = start;
- d->length = (vlong)(cd->nextblock - start) * Blocksize;
- rewritedot(cd, d);
- rewritedotdot(cd, d, d);
- for(i=0; i<d->nchild; i++)
- if(d->child[i].mode & DMDIR)
- rewritedotdot(cd, &d->child[i], d);
- break;
- case 2: /* write day: already written, do nothing */
- break;
- default:
- assert(0);
- }
- }
- void
- writedumpdirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int))
- {
- _writedumpdirs(cd, d, put, 0);
- }
- static int
- Cputplan9(Cdimg *cd, Direc *d, int dot, int dowrite)
- {
- int l, n;
- if(dot != DTiden)
- return 0;
- l = 0;
- if(d->flags & Dbadname) {
- n = strlen(d->name);
- l += 1+n;
- if(dowrite) {
- Cputc(cd, n);
- Cputs(cd, d->name, n);
- }
- } else {
- l++;
- if(dowrite)
- Cputc(cd, 0);
- }
- n = strlen(d->uid);
- l += 1+n;
- if(dowrite) {
- Cputc(cd, n);
- Cputs(cd, d->uid, n);
- }
- n = strlen(d->gid);
- l += 1+n;
- if(dowrite) {
- Cputc(cd, n);
- Cputs(cd, d->gid, n);
- }
- if(l & 1) {
- l++;
- if(dowrite)
- Cputc(cd, 0);
- }
- l += 8;
- if(dowrite)
- Cputn(cd, d->mode, 4);
- return l;
- }
- /*
- * Write a directory entry.
- */
- static int
- genputdir(Cdimg *cd, Direc *d, int dot, int joliet, int dowrite, int offset)
- {
- int f, n, l, lp;
- vlong o;
- f = 0;
- if(dot != DTiden || (d->mode & DMDIR))
- f |= 2;
- n = 1;
- if(dot == DTiden) {
- if(joliet)
- n = 2*utflen(d->confname);
- else
- n = strlen(d->confname);
- }
- l = 33+n;
- if(l & 1)
- l++;
- assert(l <= 255);
- if(joliet == 0) {
- if(cd->flags & CDplan9)
- l += Cputplan9(cd, d, dot, 0);
- else if(cd->flags & CDrockridge)
- l += Cputsysuse(cd, d, dot, 0, l);
- assert(l <= 255);
- }
- if(dowrite == 0) {
- if(Blocksize - offset%Blocksize < l)
- l += Blocksize - offset%Blocksize;
- return l;
- }
- assert(offset%Blocksize == Cwoffset(cd)%Blocksize);
- o = Cwoffset(cd);
- lp = 0;
- if(Blocksize - Cwoffset(cd)%Blocksize < l) {
- lp = Blocksize - Cwoffset(cd)%Blocksize;
- Cpadblock(cd);
- }
- Cputc(cd, l); /* length of directory record */
- Cputc(cd, 0); /* extended attribute record length */
- if(d) {
- if((d->mode & DMDIR) == 0)
- assert(d->length == 0 || d->block >= 18);
- Cputn(cd, d->block, 4); /* location of extent */
- Cputn(cd, d->length, 4); /* data length */
- } else {
- Cputn(cd, 0, 4);
- Cputn(cd, 0, 4);
- }
- Cputdate(cd, d ? d->mtime : now); /* recorded date */
- Cputc(cd, f); /* file flags */
- Cputc(cd, 0); /* file unit size */
- Cputc(cd, 0); /* interleave gap size */
- Cputn(cd, 1, 2); /* volume sequence number */
- Cputc(cd, n); /* length of file identifier */
- if(dot == DTiden) { /* identifier */
- if(joliet)
- Cputrscvt(cd, d->confname, n);
- else
- Cputs(cd, d->confname, n);
- }else
- if(dot == DTdotdot)
- Cputc(cd, 1);
- else
- Cputc(cd, 0);
- if(Cwoffset(cd) & 1) /* pad */
- Cputc(cd, 0);
- if(joliet == 0) {
- if(cd->flags & CDplan9)
- Cputplan9(cd, d, dot, 1);
- else if(cd->flags & CDrockridge)
- Cputsysuse(cd, d, dot, 1, Cwoffset(cd)-(o+lp));
- }
- assert(o+lp+l == Cwoffset(cd));
- return lp+l;
- }
- int
- Cputisodir(Cdimg *cd, Direc *d, int dot, int dowrite, int offset)
- {
- return genputdir(cd, d, dot, 0, dowrite, offset);
- }
- int
- Cputjolietdir(Cdimg *cd, Direc *d, int dot, int dowrite, int offset)
- {
- return genputdir(cd, d, dot, 1, dowrite, offset);
- }
- void
- Cputendvd(Cdimg *cd)
- {
- Cputc(cd, 255); /* volume descriptor set terminator */
- Cputs(cd, "CD001", 5); /* standard identifier */
- Cputc(cd, 1); /* volume descriptor version */
- Cpadblock(cd);
- }
|