URI:
       tflfmt9660.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
       ---
       tflfmt9660.c (10445B)
       ---
            1 /*
            2  * Initialize a fossil file system from an ISO9660 image already in the
            3  * file system.  This is a fairly bizarre thing to do, but it lets us generate
            4  * installation CDs that double as valid Plan 9 disk partitions.
            5  * People having trouble booting the CD can just copy it into a disk
            6  * partition and you've got a working Plan 9 system.
            7  *
            8  * I've tried hard to keep all the associated cruft in this file.
            9  * If you deleted this file and cut out the three calls into it from flfmt.c,
           10  * no traces would remain.
           11  */
           12 
           13 #include "stdinc.h"
           14 #include "dat.h"
           15 #include "fns.h"
           16 #include "flfmt9660.h"
           17 #include <bio.h>
           18 #include <ctype.h>
           19 
           20 static Biobuf *b;
           21 
           22 enum{
           23         Tag = 0x96609660,
           24         Blocksize = 2048,
           25 };
           26 
           27 #pragma varargck type "s" uchar*
           28 #pragma varargck type "L" uchar*
           29 #pragma varargck type "B" uchar*
           30 #pragma varargck type "N" uchar*
           31 #pragma varargck type "C" uchar*
           32 #pragma varargck type "D" uchar*
           33 
           34 typedef struct Voldesc Voldesc;
           35 struct Voldesc {
           36         uchar        magic[8];        /* 0x01, "CD001", 0x01, 0x00 */
           37         uchar        systemid[32];        /* system identifier */
           38         uchar        volumeid[32];        /* volume identifier */
           39         uchar        unused[8];        /* character set in secondary desc */
           40         uchar        volsize[8];        /* volume size */
           41         uchar        charset[32];
           42         uchar        volsetsize[4];        /* volume set size = 1 */
           43         uchar        volseqnum[4];        /* volume sequence number = 1 */
           44         uchar        blocksize[4];        /* logical block size */
           45         uchar        pathsize[8];        /* path table size */
           46         uchar        lpathloc[4];        /* Lpath */
           47         uchar        olpathloc[4];        /* optional Lpath */
           48         uchar        mpathloc[4];        /* Mpath */
           49         uchar        ompathloc[4];        /* optional Mpath */
           50         uchar        rootdir[34];        /* root directory */
           51         uchar        volsetid[128];        /* volume set identifier */
           52         uchar        publisher[128];
           53         uchar        prepid[128];        /* data preparer identifier */
           54         uchar        applid[128];        /* application identifier */
           55         uchar        notice[37];        /* copyright notice file */
           56         uchar        abstract[37];        /* abstract file */
           57         uchar        biblio[37];        /* bibliographic file */
           58         uchar        cdate[17];        /* creation date */
           59         uchar        mdate[17];        /* modification date */
           60         uchar        xdate[17];        /* expiration date */
           61         uchar        edate[17];        /* effective date */
           62         uchar        fsvers;                /* file system version = 1 */
           63 };
           64 
           65 typedef struct Cdir Cdir;
           66 struct Cdir {
           67         uchar        len;
           68         uchar        xlen;
           69         uchar        dloc[8];
           70         uchar        dlen[8];
           71         uchar        date[7];
           72         uchar        flags;
           73         uchar        unitsize;
           74         uchar        gapsize;
           75         uchar        volseqnum[4];
           76         uchar        namelen;
           77         uchar        name[1];        /* chumminess */
           78 };
           79 #pragma varargck type "D" Cdir*
           80 
           81 static int
           82 Dfmt(Fmt *fmt)
           83 {
           84         char buf[128];
           85         Cdir *c;
           86 
           87         c = va_arg(fmt->args, Cdir*);
           88         if(c->namelen == 1 && c->name[0] == '\0' || c->name[0] == '\001') {
           89                 snprint(buf, sizeof buf, ".%s dloc %.4N dlen %.4N",
           90                         c->name[0] ? "." : "", c->dloc, c->dlen);
           91         } else {
           92                 snprint(buf, sizeof buf, "%.*C dloc %.4N dlen %.4N", c->namelen, c->name,
           93                         c->dloc, c->dlen);
           94         }
           95         fmtstrcpy(fmt, buf);
           96         return 0;
           97 }
           98 
           99 static ulong
          100 big(void *a, int n)
          101 {
          102         uchar *p;
          103         ulong v;
          104         int i;
          105 
          106         p = a;
          107         v = 0;
          108         for(i=0; i<n; i++)
          109                 v = (v<<8) | *p++;
          110         return v;
          111 }
          112 
          113 static ulong
          114 little(void *a, int n)
          115 {
          116         uchar *p;
          117         ulong v;
          118         int i;
          119 
          120         p = a;
          121         v = 0;
          122         for(i=0; i<n; i++)
          123                 v |= (*p++<<(i*8));
          124         return v;
          125 }
          126 
          127 /* numbers in big or little endian. */
          128 static int
          129 BLfmt(Fmt *fmt)
          130 {
          131         ulong v;
          132         uchar *p;
          133         char buf[20];
          134 
          135         p = va_arg(fmt->args, uchar*);
          136 
          137         if(!(fmt->flags&FmtPrec)) {
          138                 fmtstrcpy(fmt, "*BL*");
          139                 return 0;
          140         }
          141 
          142         if(fmt->r == 'B')
          143                 v = big(p, fmt->prec);
          144         else
          145                 v = little(p, fmt->prec);
          146 
          147         sprint(buf, "0x%.*lux", fmt->prec*2, v);
          148         fmt->flags &= ~FmtPrec;
          149         fmtstrcpy(fmt, buf);
          150         return 0;
          151 }
          152 
          153 /* numbers in both little and big endian */
          154 static int
          155 Nfmt(Fmt *fmt)
          156 {
          157         char buf[100];
          158         uchar *p;
          159 
          160         p = va_arg(fmt->args, uchar*);
          161 
          162         sprint(buf, "%.*L %.*B", fmt->prec, p, fmt->prec, p+fmt->prec);
          163         fmt->flags &= ~FmtPrec;
          164         fmtstrcpy(fmt, buf);
          165         return 0;
          166 }
          167 
          168 static int
          169 asciiTfmt(Fmt *fmt)
          170 {
          171         char *p, buf[256];
          172         int i;
          173 
          174         p = va_arg(fmt->args, char*);
          175         for(i=0; i<fmt->prec; i++)
          176                 buf[i] = *p++;
          177         buf[i] = '\0';
          178         for(p=buf+strlen(buf); p>buf && p[-1]==' '; p--)
          179                 ;
          180         p[0] = '\0';
          181         fmt->flags &= ~FmtPrec;
          182         fmtstrcpy(fmt, buf);
          183         return 0;
          184 }
          185 
          186 static void
          187 ascii(void)
          188 {
          189         fmtinstall('C', asciiTfmt);
          190 }
          191 
          192 static void
          193 getsect(uchar *buf, int n)
          194 {
          195         if(Bseek(b, n*2048, 0) != n*2048 || Bread(b, buf, 2048) != 2048)
          196 {
          197 abort();
          198                 sysfatal("reading block at %,d: %r", n*2048);
          199 }
          200 }
          201 
          202 static Header *h;
          203 static int fd;
          204 static char *file9660;
          205 static int off9660;
          206 static ulong startoff;
          207 static ulong endoff;
          208 static ulong fsoff;
          209 static uchar root[2048];
          210 static Voldesc *v;
          211 static ulong iso9660start(Cdir*);
          212 static void iso9660copydir(Fs*, File*, Cdir*);
          213 static void iso9660copyfile(Fs*, File*, Cdir*);
          214 
          215 void
          216 iso9660init(int xfd, Header *xh, char *xfile9660, int xoff9660)
          217 {
          218         uchar sect[2048], sect2[2048];
          219 
          220         fmtinstall('L', BLfmt);
          221         fmtinstall('B', BLfmt);
          222         fmtinstall('N', Nfmt);
          223         fmtinstall('D', Dfmt);
          224 
          225         fd = xfd;
          226         h = xh;
          227         file9660 = xfile9660;
          228         off9660 = xoff9660;
          229 
          230         if((b = Bopen(file9660, OREAD)) == nil)
          231                 sysfatal("Bopen %s: %r", file9660);
          232 
          233         getsect(root, 16);
          234         ascii();
          235 
          236         v = (Voldesc*)root;
          237         if(memcmp(v->magic, "\001CD001\001\000", 8) != 0)
          238                 sysfatal("%s not a cd image", file9660);
          239 
          240         startoff = iso9660start((Cdir*)v->rootdir)*Blocksize;
          241         endoff = little(v->volsize, 4);        /* already in bytes */
          242 
          243         fsoff = off9660 + h->data*h->blockSize;
          244         if(fsoff > startoff)
          245                 sysfatal("fossil data starts after cd data");
          246         if(off9660 + (vlong)h->end*h->blockSize < endoff)
          247                 sysfatal("fossil data ends before cd data");
          248         if(fsoff%h->blockSize)
          249                 sysfatal("cd offset not a multiple of fossil block size");
          250 
          251         /* Read "same" block via CD image and via Fossil image */
          252         getsect(sect, startoff/Blocksize);
          253         if(seek(fd, startoff-off9660, 0) < 0)
          254                 sysfatal("cannot seek to first data sector on cd via fossil");
          255 fprint(2, "look for %lud at %lud\n", startoff, startoff-off9660);
          256         if(readn(fd, sect2, Blocksize) != Blocksize)
          257                 sysfatal("cannot read first data sector on cd via fossil");
          258         if(memcmp(sect, sect2, Blocksize) != 0)
          259                 sysfatal("iso9660 offset is a lie");
          260 }
          261 
          262 void
          263 iso9660labels(Disk *disk, uchar *buf, void (*write)(int, u32int))
          264 {
          265         ulong sb, eb, bn, lb, llb;
          266         Label l;
          267         int lpb;
          268         uchar sect[Blocksize];
          269 
          270         if(!diskReadRaw(disk, PartData, (startoff-fsoff)/h->blockSize, buf))
          271                 sysfatal("disk read failed: %r");
          272         getsect(sect, startoff/Blocksize);
          273         if(memcmp(buf, sect, Blocksize) != 0)
          274                 sysfatal("fsoff is wrong");
          275 
          276         sb = (startoff-fsoff)/h->blockSize;
          277         eb = (endoff-fsoff+h->blockSize-1)/h->blockSize;
          278 
          279         lpb = h->blockSize/LabelSize;
          280 
          281         /* for each reserved block, mark label */
          282         llb = ~0;
          283         l.type = BtData;
          284         l.state = BsAlloc;
          285         l.tag = Tag;
          286         l.epoch = 1;
          287         l.epochClose = ~(u32int)0;
          288         for(bn=sb; bn<eb; bn++){
          289                 lb = bn/lpb;
          290                 if(lb != llb){
          291                         if(llb != ~0)
          292                                 (*write)(PartLabel, llb);
          293                         memset(buf, 0, h->blockSize);
          294                 }
          295                 llb = lb;
          296                 labelPack(&l, buf, bn%lpb);
          297         }
          298         if(llb != ~0)
          299                 (*write)(PartLabel, llb);
          300 }
          301 
          302 void
          303 iso9660copy(Fs *fs)
          304 {
          305         File *root;
          306 
          307         root = fileOpen(fs, "/active");
          308         iso9660copydir(fs, root, (Cdir*)v->rootdir);
          309         fileDecRef(root);
          310         runlock(&fs->elk);
          311         if(!fsSnapshot(fs, nil, nil, 0))
          312                 sysfatal("snapshot failed: %r");
          313         rlock(&fs->elk);
          314 }
          315 
          316 /*
          317  * The first block used is the first data block of the leftmost file in the tree.
          318  * (Just an artifact of how mk9660 works.)
          319  */
          320 static ulong
          321 iso9660start(Cdir *c)
          322 {
          323         uchar sect[Blocksize];
          324 
          325         while(c->flags&2){
          326                 getsect(sect, little(c->dloc, 4));
          327                 c = (Cdir*)sect;
          328                 c = (Cdir*)((uchar*)c+c->len);        /* skip dot */
          329                 c = (Cdir*)((uchar*)c+c->len);        /* skip dotdot */
          330                 /* oops: might happen if leftmost directory is empty or leftmost file is zero length! */
          331                 if(little(c->dloc, 4) == 0)
          332                         sysfatal("error parsing cd image or unfortunate cd image");
          333         }
          334         return little(c->dloc, 4);
          335 }
          336 
          337 static void
          338 iso9660copydir(Fs *fs, File *dir, Cdir *cd)
          339 {
          340         ulong off, end, len;
          341         uchar sect[Blocksize], *esect, *p;
          342         Cdir *c;
          343 
          344         len = little(cd->dlen, 4);
          345         off = little(cd->dloc, 4)*Blocksize;
          346         end = off+len;
          347         esect = sect+Blocksize;
          348 
          349         for(; off<end; off+=Blocksize){
          350                 getsect(sect, off/Blocksize);
          351                 p = sect;
          352                 while(p < esect){
          353                         c = (Cdir*)p;
          354                         if(c->len <= 0)
          355                                 break;
          356                         if(c->namelen!=1 || c->name[0]>1)
          357                                 iso9660copyfile(fs, dir, c);
          358                         p += c->len;
          359                 }
          360         }
          361 }
          362 
          363 static char*
          364 getname(uchar **pp)
          365 {
          366         uchar *p;
          367         int l;
          368 
          369         p = *pp;
          370         l = *p;
          371         *pp = p+1+l;
          372         if(l == 0)
          373                 return "";
          374         memmove(p, p+1, l);
          375         p[l] = 0;
          376         return (char*)p;
          377 }
          378 
          379 static char*
          380 getcname(Cdir *c)
          381 {
          382         uchar *up;
          383         char *p, *q;
          384 
          385         up = &c->namelen;
          386         p = getname(&up);
          387         for(q=p; *q; q++)
          388                 *q = tolower(*q);
          389         return p;
          390 }
          391 
          392 static char
          393 dmsize[12] =
          394 {
          395         31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
          396 };
          397 
          398 static ulong
          399 getcdate(uchar *p)        /* yMdhmsz */
          400 {
          401         Tm tm;
          402         int y, M, d, h, m, s, tz;
          403 
          404         y=p[0]; M=p[1]; d=p[2];
          405         h=p[3]; m=p[4]; s=p[5]; tz=p[6];
          406         USED(tz);
          407         if (y < 70)
          408                 return 0;
          409         if (M < 1 || M > 12)
          410                 return 0;
          411         if (d < 1 || d > dmsize[M-1])
          412                 return 0;
          413         if (h > 23)
          414                 return 0;
          415         if (m > 59)
          416                 return 0;
          417         if (s > 59)
          418                 return 0;
          419 
          420         memset(&tm, 0, sizeof tm);
          421         tm.sec = s;
          422         tm.min = m;
          423         tm.hour = h;
          424         tm.mday = d;
          425         tm.mon = M-1;
          426         tm.year = 1900+y;
          427         tm.zone[0] = 0;
          428         return tm2sec(&tm);
          429 }
          430 
          431 static int ind;
          432 
          433 static void
          434 iso9660copyfile(Fs *fs, File *dir, Cdir *c)
          435 {
          436         Dir d;
          437         DirEntry de;
          438         int sysl;
          439         uchar score[VtScoreSize];
          440         ulong off, foff, len, mode;
          441         uchar *p;
          442         File *f;
          443 
          444         ind++;
          445         memset(&d, 0, sizeof d);
          446         p = c->name + c->namelen;
          447         if(((uintptr)p) & 1)
          448                 p++;
          449         sysl = (uchar*)c + c->len - p;
          450         if(sysl <= 0)
          451                 sysfatal("missing plan9 directory entry on %d/%d/%.*s", c->namelen, c->name[0], c->namelen, c->name);
          452         d.name = getname(&p);
          453         d.uid = getname(&p);
          454         d.gid = getname(&p);
          455         if((uintptr)p & 1)
          456                 p++;
          457         d.mode = little(p, 4);
          458         if(d.name[0] == 0)
          459                 d.name = getcname(c);
          460         d.mtime = getcdate(c->date);
          461         d.atime = d.mtime;
          462 
          463 if(d.mode&DMDIR)        print("%*scopy %s %s %s %luo\n", ind*2, "", d.name, d.uid, d.gid, d.mode);
          464 
          465         mode = d.mode&0777;
          466         if(d.mode&DMDIR)
          467                 mode |= ModeDir;
          468         if((f = fileCreate(dir, d.name, mode, d.uid)) == nil)
          469                 sysfatal("could not create file '%s': %r", d.name);
          470         if(d.mode&DMDIR)
          471                 iso9660copydir(fs, f, c);
          472         else{
          473                 len = little(c->dlen, 4);
          474                 off = little(c->dloc, 4)*Blocksize;
          475                 for(foff=0; foff<len; foff+=h->blockSize){
          476                         localToGlobal((off+foff-fsoff)/h->blockSize, score);
          477                         if(!fileMapBlock(f, foff/h->blockSize, score, Tag))
          478                                 sysfatal("fileMapBlock: %r");
          479                 }
          480                 if(!fileSetSize(f, len))
          481                         sysfatal("fileSetSize: %r");
          482         }
          483         if(!fileGetDir(f, &de))
          484                 sysfatal("fileGetDir: %r");
          485         de.uid = d.uid;
          486         de.gid = d.gid;
          487         de.mtime = d.mtime;
          488         de.atime = d.atime;
          489         de.mode = d.mode&0777;
          490         if(!fileSetDir(f, &de, "sys"))
          491                 sysfatal("fileSetDir: %r");
          492         fileDecRef(f);
          493         ind--;
          494 }