URI:
       twrite.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       twrite.c (8762B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <libsec.h>
            5 
            6 #include "iso9660.h"
            7 
            8 static void
            9 writelittlebig4(uchar *buf, ulong x)
           10 {
           11         buf[0] = buf[7] = x;
           12         buf[1] = buf[6] = x>>8;
           13         buf[2] = buf[5] = x>>16;
           14         buf[3] = buf[4] = x>>24;
           15 }
           16 
           17 void
           18 rewritedot(Cdimg *cd, Direc *d)
           19 {
           20         uchar buf[Blocksize];
           21         Cdir *c;
           22 
           23         Creadblock(cd, buf, d->block, Blocksize);
           24         c = (Cdir*)buf;
           25         assert(c->len != 0);
           26         assert(c->namelen == 1 && c->name[0] == '\0');        /* dot */
           27         writelittlebig4(c->dloc, d->block);
           28         writelittlebig4(c->dlen, d->length);
           29 
           30         Cwseek(cd, d->block*Blocksize);
           31         Cwrite(cd, buf, Blocksize);
           32 }
           33 
           34 void
           35 rewritedotdot(Cdimg *cd, Direc *d, Direc *dparent)
           36 {
           37         uchar buf[Blocksize];
           38         Cdir *c;
           39 
           40         Creadblock(cd, buf, d->block, Blocksize);
           41         c = (Cdir*)buf;
           42         assert(c->len != 0);
           43         assert(c->namelen == 1 && c->name[0] == '\0');        /* dot */
           44 
           45         c = (Cdir*)(buf+c->len);
           46         assert(c->len != 0);
           47         assert(c->namelen == 1 && c->name[0] == '\001');        /* dotdot*/
           48 
           49         writelittlebig4(c->dloc, dparent->block);
           50         writelittlebig4(c->dlen, dparent->length);
           51 
           52         Cwseek(cd, d->block*Blocksize);
           53         Cwrite(cd, buf, Blocksize);
           54 }
           55 
           56 /*
           57  * Write each non-directory file.  We copy the file to
           58  * the cd image, and then if it turns out that we've
           59  * seen this stream of bits before, we push the next block
           60  * pointer back.  This ensures consistency between the MD5s
           61  * and the data on the CD image.  MD5 summing on one pass
           62  * and copying on another would not ensure this.
           63  */
           64 void
           65 writefiles(Dump *d, Cdimg *cd, Direc *direc)
           66 {
           67         int i;
           68         uchar buf[8192], digest[MD5dlen];
           69         ulong length, n, start;
           70         Biobuf *b;
           71         DigestState *s;
           72         Dumpdir *dd;
           73 
           74         if(direc->mode & DMDIR) {
           75                 for(i=0; i<direc->nchild; i++)
           76                         writefiles(d, cd, &direc->child[i]);
           77                 return;
           78         }
           79 
           80         assert(direc->block == 0);
           81 
           82         if((b = Bopen(direc->srcfile, OREAD)) == nil){
           83                 fprint(2, "warning: cannot open '%s': %r\n", direc->srcfile);
           84                 direc->block = 0;
           85                 direc->length = 0;
           86                 return;
           87         }
           88 
           89         start = cd->nextblock;
           90         assert(start != 0);
           91 
           92         Cwseek(cd, start*Blocksize);
           93 
           94         s = md5(nil, 0, nil, nil);
           95         length = 0;
           96         while((n = Bread(b, buf, sizeof buf)) > 0) {
           97                 md5(buf, n, nil, s);
           98                 Cwrite(cd, buf, n);
           99                 length += n;
          100         }
          101         md5(nil, 0, digest, s);
          102         Bterm(b);
          103         Cpadblock(cd);
          104 
          105         if(length != direc->length) {
          106                 fprint(2, "warning: %s changed size underfoot\n", direc->srcfile);
          107                 direc->length = length;
          108         }
          109 
          110         if(length == 0)
          111                 direc->block = 0;
          112         else if((dd = lookupmd5(d, digest))) {
          113                 assert(dd->length == length);
          114                 assert(dd->block != 0);
          115                 direc->block = dd->block;
          116                 cd->nextblock = start;
          117         } else {
          118                 direc->block = start;
          119                 if(chatty > 1)
          120                         fprint(2, "lookup %.16H %lud (%s) failed\n", digest, length, direc->name);
          121                 insertmd5(d, atom(direc->name), digest, start, length);
          122         }
          123 }
          124 
          125 /*
          126  * Write a directory tree.  We work from the leaves,
          127  * and patch the dotdot pointers afterward.
          128  */
          129 static void
          130 _writedirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int), int level)
          131 {
          132         int i, l, ll;
          133         ulong start, next;
          134 
          135         if((d->mode & DMDIR) == 0)
          136                 return;
          137 
          138         if(chatty)
          139                 fprint(2, "%*s%s\n", 4*level, "", d->name);
          140 
          141         for(i=0; i<d->nchild; i++)
          142                 _writedirs(cd, &d->child[i], put, level+1);
          143 
          144         l = 0;
          145         l += put(cd, d, (level == 0) ? DTrootdot : DTdot, 0, l);
          146         l += put(cd, nil, DTdotdot, 0, l);
          147         for(i=0; i<d->nchild; i++)
          148                 l += put(cd, &d->child[i], DTiden, 0, l);
          149 
          150         start = cd->nextblock;
          151         cd->nextblock += (l+Blocksize-1)/Blocksize;
          152         next = cd->nextblock;
          153 
          154         Cwseek(cd, start*Blocksize);
          155         ll = 0;
          156         ll += put(cd, d, (level == 0) ? DTrootdot : DTdot, 1, ll);
          157         ll += put(cd, nil, DTdotdot, 1, ll);
          158         for(i=0; i<d->nchild; i++)
          159                 ll += put(cd, &d->child[i], DTiden, 1, ll);
          160         assert(ll == l);
          161         Cpadblock(cd);
          162         assert(Cwoffset(cd) == next*Blocksize);
          163 
          164         d->block = start;
          165         d->length = (next - start) * Blocksize;
          166         rewritedot(cd, d);
          167         rewritedotdot(cd, d, d);
          168 
          169         for(i=0; i<d->nchild; i++)
          170                 if(d->child[i].mode & DMDIR)
          171                         rewritedotdot(cd, &d->child[i], d);
          172 }
          173 
          174 void
          175 writedirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int))
          176 {
          177         /*
          178          * If we're writing a mk9660 image, then the root really
          179          * is the root, so start at level 0.  If we're writing a dump image,
          180          * then the "root" is really going to be two levels down once
          181          * we patch in the dump hierarchy above it, so start at level non-zero.
          182          */
          183         if(chatty)
          184                 fprint(2, ">>> writedirs\n");
          185         _writedirs(cd, d, put, mk9660 ? 0 : 1);
          186 }
          187 
          188 
          189 /*
          190  * Write the dump tree.  This is like writedirs but once we get to
          191  * the roots of the individual days we just patch the parent dotdot blocks.
          192  */
          193 static void
          194 _writedumpdirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int), int level)
          195 {
          196         int i;
          197         ulong start;
          198 
          199         switch(level) {
          200         case 0:
          201                 /* write root, list of years, also conform.map */
          202                 for(i=0; i<d->nchild; i++)
          203                         if(d->child[i].mode & DMDIR)
          204                                 _writedumpdirs(cd, &d->child[i], put, level+1);
          205                 chat("write dump root dir at %lud\n", cd->nextblock);
          206                 goto Writedir;
          207 
          208         case 1:        /* write year, list of days */
          209                 for(i=0; i<d->nchild; i++)
          210                         _writedumpdirs(cd, &d->child[i], put, level+1);
          211                 chat("write dump %s dir at %lud\n", d->name, cd->nextblock);
          212                 goto Writedir;
          213 
          214         Writedir:
          215                 start = cd->nextblock;
          216                 Cwseek(cd, start*Blocksize);
          217 
          218                 put(cd, d, (level == 0) ? DTrootdot : DTdot, 1, Cwoffset(cd));
          219                 put(cd, nil, DTdotdot, 1, Cwoffset(cd));
          220                 for(i=0; i<d->nchild; i++)
          221                         put(cd, &d->child[i], DTiden, 1, Cwoffset(cd));
          222                 Cpadblock(cd);
          223 
          224                 d->block = start;
          225                 d->length = (cd->nextblock - start) * Blocksize;
          226 
          227                 rewritedot(cd, d);
          228                 rewritedotdot(cd, d, d);
          229 
          230                 for(i=0; i<d->nchild; i++)
          231                         if(d->child[i].mode & DMDIR)
          232                                 rewritedotdot(cd, &d->child[i], d);
          233                 break;
          234 
          235         case 2:        /* write day: already written, do nothing */
          236                 break;
          237 
          238         default:
          239                 assert(0);
          240         }
          241 }
          242 
          243 void
          244 writedumpdirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int))
          245 {
          246         _writedumpdirs(cd, d, put, 0);
          247 }
          248 
          249 static int
          250 Cputplan9(Cdimg *cd, Direc *d, int dot, int dowrite)
          251 {
          252         int l, n;
          253 
          254         if(dot != DTiden)
          255                 return 0;
          256 
          257         l = 0;
          258         if(d->flags & Dbadname) {
          259                 n = strlen(d->name);
          260                 l += 1+n;
          261                 if(dowrite) {
          262                         Cputc(cd, n);
          263                         Cputs(cd, d->name, n);
          264                 }
          265         } else {
          266                 l++;
          267                 if(dowrite)
          268                         Cputc(cd, 0);
          269         }
          270 
          271         n = strlen(d->uid);
          272         l += 1+n;
          273         if(dowrite) {
          274                 Cputc(cd, n);
          275                 Cputs(cd, d->uid, n);
          276         }
          277 
          278         n = strlen(d->gid);
          279         l += 1+n;
          280         if(dowrite) {
          281                 Cputc(cd, n);
          282                 Cputs(cd, d->gid, n);
          283         }
          284 
          285         if(l & 1) {
          286                 l++;
          287                 if(dowrite)
          288                         Cputc(cd, 0);
          289         }
          290         l += 8;
          291         if(dowrite)
          292                 Cputn(cd, d->mode, 4);
          293 
          294         return l;
          295 }
          296 
          297 /*
          298  * Write a directory entry.
          299  */
          300 static int
          301 genputdir(Cdimg *cd, Direc *d, int dot, int joliet, int dowrite, int offset)
          302 {
          303         int f, n, l, lp;
          304         long o;
          305 
          306         f = 0;
          307         if(dot != DTiden || (d->mode & DMDIR))
          308                 f |= 2;
          309 
          310         n = 1;
          311         if(dot == DTiden) {
          312                 if(joliet)
          313                         n = 2*utflen(d->confname);
          314                 else
          315                         n = strlen(d->confname);
          316         }
          317 
          318         l = 33+n;
          319         if(l & 1)
          320                 l++;
          321         assert(l <= 255);
          322 
          323         if(joliet == 0) {
          324                 if(cd->flags & CDplan9)
          325                         l += Cputplan9(cd, d, dot, 0);
          326                 else if(cd->flags & CDrockridge)
          327                         l += Cputsysuse(cd, d, dot, 0, l);
          328                 assert(l <= 255);
          329         }
          330 
          331         if(dowrite == 0) {
          332                 if(Blocksize - offset%Blocksize < l)
          333                         l += Blocksize - offset%Blocksize;
          334                 return l;
          335         }
          336 
          337         assert(offset%Blocksize == Cwoffset(cd)%Blocksize);
          338 
          339         o = Cwoffset(cd);
          340         lp = 0;
          341         if(Blocksize - Cwoffset(cd)%Blocksize < l) {
          342                 lp = Blocksize - Cwoffset(cd)%Blocksize;
          343                 Cpadblock(cd);
          344         }
          345 
          346         Cputc(cd, l);                        /* length of directory record */
          347         Cputc(cd, 0);                        /* extended attribute record length */
          348         if(d) {
          349                 if((d->mode & DMDIR) == 0)
          350                         assert(d->length == 0 || d->block >= 18);
          351 
          352                 Cputn(cd, d->block, 4);                /* location of extent */
          353                 Cputn(cd, d->length, 4);                /* data length */
          354         } else {
          355                 Cputn(cd, 0, 4);
          356                 Cputn(cd, 0, 4);
          357         }
          358         Cputdate(cd, d ? d->mtime : now);                /* recorded date */
          359         Cputc(cd, f);                        /* file flags */
          360         Cputc(cd, 0);                        /* file unit size */
          361         Cputc(cd, 0);                        /* interleave gap size */
          362         Cputn(cd, 1, 2);                       /* volume sequence number */
          363         Cputc(cd, n);                        /* length of file identifier */
          364 
          365         if(dot == DTiden) {                /* identifier */
          366                 if(joliet)
          367                         Cputrscvt(cd, d->confname, n);
          368                 else
          369                         Cputs(cd, d->confname, n);
          370         }else
          371         if(dot == DTdotdot)
          372                 Cputc(cd, 1);
          373         else
          374                 Cputc(cd, 0);
          375 
          376         if(Cwoffset(cd) & 1)                        /* pad */
          377                 Cputc(cd, 0);
          378 
          379         if(joliet == 0) {
          380                 if(cd->flags & CDplan9)
          381                         Cputplan9(cd, d, dot, 1);
          382                 else if(cd->flags & CDrockridge)
          383                         Cputsysuse(cd, d, dot, 1, Cwoffset(cd)-(o+lp));
          384         }
          385 
          386         assert(o+lp+l == Cwoffset(cd));
          387         return lp+l;
          388 }
          389 
          390 int
          391 Cputisodir(Cdimg *cd, Direc *d, int dot, int dowrite, int offset)
          392 {
          393         return genputdir(cd, d, dot, 0, dowrite, offset);
          394 }
          395 
          396 int
          397 Cputjolietdir(Cdimg *cd, Direc *d, int dot, int dowrite, int offset)
          398 {
          399         return genputdir(cd, d, dot, 1, dowrite, offset);
          400 }
          401 
          402 void
          403 Cputendvd(Cdimg *cd)
          404 {
          405         Cputc(cd, 255);                                /* volume descriptor set terminator */
          406         Cputs(cd, "CD001", 5);                        /* standard identifier */
          407         Cputc(cd, 1);                                /* volume descriptor version */
          408         Cpadblock(cd);
          409 }