123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565 |
- /*
- * Initialize a fossil file system from an ISO9660 image already in the
- * file system. This is a fairly bizarre thing to do, but it lets us generate
- * installation CDs that double as valid Plan 9 disk partitions.
- * People having trouble booting the CD can just copy it into a disk
- * partition and you've got a working Plan 9 system.
- *
- * I've tried hard to keep all the associated cruft in this file.
- * If you deleted this file and cut out the three calls into it from flfmt.c,
- * no traces would remain.
- */
- #include "stdinc.h"
- #include "dat.h"
- #include "fns.h"
- #include "flfmt9660.h"
- #include <bio.h>
- #include <ctype.h>
- static Biobuf *b;
- enum{
- Tag = 0x96609660,
- Blocksize = 2048,
- };
- #pragma varargck type "s" uchar*
- #pragma varargck type "L" uchar*
- #pragma varargck type "B" uchar*
- #pragma varargck type "N" uchar*
- #pragma varargck type "T" uchar*
- #pragma varargck type "D" uchar*
- typedef struct Voldesc Voldesc;
- struct Voldesc {
- uchar magic[8]; /* 0x01, "CD001", 0x01, 0x00 */
- uchar systemid[32]; /* system identifier */
- uchar volumeid[32]; /* volume identifier */
- uchar unused[8]; /* character set in secondary desc */
- uchar volsize[8]; /* volume size */
- uchar charset[32];
- uchar volsetsize[4]; /* volume set size = 1 */
- uchar volseqnum[4]; /* volume sequence number = 1 */
- uchar blocksize[4]; /* logical block size */
- uchar pathsize[8]; /* path table size */
- uchar lpathloc[4]; /* Lpath */
- uchar olpathloc[4]; /* optional Lpath */
- uchar mpathloc[4]; /* Mpath */
- uchar ompathloc[4]; /* optional Mpath */
- uchar rootdir[34]; /* root directory */
- uchar volsetid[128]; /* volume set identifier */
- uchar publisher[128];
- uchar prepid[128]; /* data preparer identifier */
- uchar applid[128]; /* application identifier */
- uchar notice[37]; /* copyright notice file */
- uchar abstract[37]; /* abstract file */
- uchar biblio[37]; /* bibliographic file */
- uchar cdate[17]; /* creation date */
- uchar mdate[17]; /* modification date */
- uchar xdate[17]; /* expiration date */
- uchar edate[17]; /* effective date */
- uchar fsvers; /* file system version = 1 */
- };
- static void
- dumpbootvol(void *a)
- {
- Voldesc *v;
- v = a;
- print("magic %.2ux %.5s %.2ux %2ux\n",
- v->magic[0], v->magic+1, v->magic[6], v->magic[7]);
- if(v->magic[0] == 0xFF)
- return;
- print("system %.32T\n", v->systemid);
- print("volume %.32T\n", v->volumeid);
- print("volume size %.4N\n", v->volsize);
- print("charset %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n",
- v->charset[0], v->charset[1], v->charset[2], v->charset[3],
- v->charset[4], v->charset[5], v->charset[6], v->charset[7]);
- print("volume set size %.2N\n", v->volsetsize);
- print("volume sequence number %.2N\n", v->volseqnum);
- print("logical block size %.2N\n", v->blocksize);
- print("path size %.4L\n", v->pathsize);
- print("lpath loc %.4L\n", v->lpathloc);
- print("opt lpath loc %.4L\n", v->olpathloc);
- print("mpath loc %.4B\n", v->mpathloc);
- print("opt mpath loc %.4B\n", v->ompathloc);
- print("rootdir %D\n", v->rootdir);
- print("volume set identifier %.128T\n", v->volsetid);
- print("publisher %.128T\n", v->publisher);
- print("preparer %.128T\n", v->prepid);
- print("application %.128T\n", v->applid);
- print("notice %.37T\n", v->notice);
- print("abstract %.37T\n", v->abstract);
- print("biblio %.37T\n", v->biblio);
- print("creation date %.17s\n", v->cdate);
- print("modification date %.17s\n", v->mdate);
- print("expiration date %.17s\n", v->xdate);
- print("effective date %.17s\n", v->edate);
- print("fs version %d\n", v->fsvers);
- }
- typedef struct Cdir Cdir;
- struct Cdir {
- uchar len;
- uchar xlen;
- uchar dloc[8];
- uchar dlen[8];
- uchar date[7];
- uchar flags;
- uchar unitsize;
- uchar gapsize;
- uchar volseqnum[4];
- uchar namelen;
- uchar name[1]; /* chumminess */
- };
- #pragma varargck type "D" Cdir*
- static int
- Dfmt(Fmt *fmt)
- {
- char buf[128];
- Cdir *c;
- c = va_arg(fmt->args, Cdir*);
- if(c->namelen == 1 && c->name[0] == '\0' || c->name[0] == '\001') {
- snprint(buf, sizeof buf, ".%s dloc %.4N dlen %.4N",
- c->name[0] ? "." : "", c->dloc, c->dlen);
- } else {
- snprint(buf, sizeof buf, "%.*T dloc %.4N dlen %.4N", c->namelen, c->name,
- c->dloc, c->dlen);
- }
- fmtstrcpy(fmt, buf);
- return 0;
- }
- char longc, shortc;
- static void
- bigend(void)
- {
- longc = 'B';
- }
- static void
- littleend(void)
- {
- longc = 'L';
- }
- static ulong
- big(void *a, int n)
- {
- uchar *p;
- ulong v;
- int i;
- p = a;
- v = 0;
- for(i=0; i<n; i++)
- v = (v<<8) | *p++;
- return v;
- }
- static ulong
- little(void *a, int n)
- {
- uchar *p;
- ulong v;
- int i;
- p = a;
- v = 0;
- for(i=0; i<n; i++)
- v |= (*p++<<(i*8));
- return v;
- }
- /* numbers in big or little endian. */
- static int
- BLfmt(Fmt *fmt)
- {
- ulong v;
- uchar *p;
- char buf[20];
- p = va_arg(fmt->args, uchar*);
- if(!(fmt->flags&FmtPrec)) {
- fmtstrcpy(fmt, "*BL*");
- return 0;
- }
- if(fmt->r == 'B')
- v = big(p, fmt->prec);
- else
- v = little(p, fmt->prec);
- sprint(buf, "0x%.*lux", fmt->prec*2, v);
- fmt->flags &= ~FmtPrec;
- fmtstrcpy(fmt, buf);
- return 0;
- }
- /* numbers in both little and big endian */
- static int
- Nfmt(Fmt *fmt)
- {
- char buf[100];
- uchar *p;
- p = va_arg(fmt->args, uchar*);
- sprint(buf, "%.*L %.*B", fmt->prec, p, fmt->prec, p+fmt->prec);
- fmt->flags &= ~FmtPrec;
- fmtstrcpy(fmt, buf);
- return 0;
- }
- static int
- asciiTfmt(Fmt *fmt)
- {
- char *p, buf[256];
- int i;
- p = va_arg(fmt->args, char*);
- for(i=0; i<fmt->prec; i++)
- buf[i] = *p++;
- buf[i] = '\0';
- for(p=buf+strlen(buf); p>buf && p[-1]==' '; p--)
- ;
- p[0] = '\0';
- fmt->flags &= ~FmtPrec;
- fmtstrcpy(fmt, buf);
- return 0;
- }
- static void
- ascii(void)
- {
- fmtinstall('T', asciiTfmt);
- }
- static int
- runeTfmt(Fmt *fmt)
- {
- Rune buf[256], *r;
- int i;
- uchar *p;
- p = va_arg(fmt->args, uchar*);
- for(i=0; i*2+2<=fmt->prec; i++, p+=2)
- buf[i] = (p[0]<<8)|p[1];
- buf[i] = L'\0';
- for(r=buf+i; r>buf && r[-1]==L' '; r--)
- ;
- r[0] = L'\0';
- fmt->flags &= ~FmtPrec;
- return fmtprint(fmt, "%S", buf);
- }
- static void
- getsect(uchar *buf, int n)
- {
- if(Bseek(b, n*2048, 0) != n*2048 || Bread(b, buf, 2048) != 2048)
- {
- abort();
- sysfatal("reading block at %,d: %r\n", n*2048);
- }
- }
- static Header *h;
- static int fd;
- static char *file9660;
- static int off9660;
- static ulong startoff;
- static ulong endoff;
- static ulong fsoff;
- static uchar root[2048];
- static Voldesc *v;
- static ulong iso9660start(Cdir*);
- static void iso9660copydir(Fs*, File*, Cdir*);
- static void iso9660copyfile(Fs*, File*, Cdir*);
- void
- iso9660init(int xfd, Header *xh, char *xfile9660, int xoff9660)
- {
- uchar sect[2048], sect2[2048];
- fmtinstall('L', BLfmt);
- fmtinstall('B', BLfmt);
- fmtinstall('N', Nfmt);
- fmtinstall('D', Dfmt);
- fd = xfd;
- h = xh;
- file9660 = xfile9660;
- off9660 = xoff9660;
- if((b = Bopen(file9660, OREAD)) == nil)
- vtFatal("Bopen %s: %r", file9660);
- getsect(root, 16);
- ascii();
- v = (Voldesc*)root;
- if(memcmp(v->magic, "\x01CD001\x01\x00", 8) != 0)
- vtFatal("%s not a cd image", file9660);
- startoff = iso9660start((Cdir*)v->rootdir)*Blocksize;
- endoff = little(v->volsize, 4); /* already in bytes */
- fsoff = off9660 + h->data*h->blockSize;
- if(fsoff > startoff)
- vtFatal("fossil data starts after cd data");
- if(off9660 + (vlong)h->end*h->blockSize < endoff)
- vtFatal("fossil data ends before cd data");
- if(fsoff%h->blockSize)
- vtFatal("cd offset not a multiple of fossil block size");
- /* Read "same" block via CD image and via Fossil image */
- getsect(sect, startoff/Blocksize);
- if(seek(fd, startoff-off9660, 0) < 0)
- vtFatal("cannot seek to first data sector on cd via fossil");
- fprint(2, "look for %lud at %lud\n", startoff, startoff-off9660);
- if(readn(fd, sect2, Blocksize) != Blocksize)
- vtFatal("cannot read first data sector on cd via fossil");
- if(memcmp(sect, sect2, Blocksize) != 0)
- vtFatal("iso9660 offset is a lie %08ux %08ux", *(long*)sect, *(long*)sect2);
- }
- void
- iso9660labels(Disk *disk, uchar *buf, void (*write)(int, u32int))
- {
- ulong sb, eb, bn, lb, llb;
- Label l;
- int lpb;
- uchar sect[Blocksize];
- if(!diskReadRaw(disk, PartData, (startoff-fsoff)/h->blockSize, buf))
- vtFatal("disk read failed: %r");
- getsect(sect, startoff/Blocksize);
- if(memcmp(buf, sect, Blocksize) != 0)
- vtFatal("fsoff is wrong");
- sb = (startoff-fsoff)/h->blockSize;
- eb = (endoff-fsoff+h->blockSize-1)/h->blockSize;
- lpb = h->blockSize/LabelSize;
- /* for each reserved block, mark label */
- llb = ~0;
- l.type = BtData;
- l.state = BsAlloc;
- l.tag = Tag;
- l.epoch = 1;
- l.epochClose = ~(u32int)0;
- for(bn=sb; bn<eb; bn++){
- lb = bn/lpb;
- if(lb != llb){
- if(llb != ~0)
- (*write)(PartLabel, llb);
- memset(buf, 0, h->blockSize);
- }
- llb = lb;
- labelPack(&l, buf, bn%lpb);
- }
- if(llb != ~0)
- (*write)(PartLabel, llb);
- }
- void
- iso9660copy(Fs *fs)
- {
- File *root;
- root = fileOpen(fs, "/active");
- iso9660copydir(fs, root, (Cdir*)v->rootdir);
- fileDecRef(root);
- vtRUnlock(fs->elk);
- if(!fsSnapshot(fs, nil, nil, 0))
- vtFatal("snapshot failed: %R");
- vtRLock(fs->elk);
- }
- /*
- * The first block used is the first data block of the leftmost file in the tree.
- * (Just an artifact of how mk9660 works.)
- */
- static ulong
- iso9660start(Cdir *c)
- {
- uchar sect[Blocksize];
- while(c->flags&2){
- getsect(sect, little(c->dloc, 4));
- c = (Cdir*)sect;
- c = (Cdir*)((uchar*)c+c->len); /* skip dot */
- c = (Cdir*)((uchar*)c+c->len); /* skip dotdot */
- /* oops: might happen if leftmost directory is empty or leftmost file is zero length! */
- if(little(c->dloc, 4) == 0)
- vtFatal("error parsing cd image or unfortunate cd image");
- }
- return little(c->dloc, 4);
- }
- static void
- iso9660copydir(Fs *fs, File *dir, Cdir *cd)
- {
- ulong off, end, len;
- uchar sect[Blocksize], *esect, *p;
- Cdir *c;
- len = little(cd->dlen, 4);
- off = little(cd->dloc, 4)*Blocksize;
- end = off+len;
- esect = sect+Blocksize;
- for(; off<end; off+=Blocksize){
- getsect(sect, off/Blocksize);
- p = sect;
- while(p < esect){
- c = (Cdir*)p;
- if(c->len <= 0)
- break;
- if(c->namelen!=1 || c->name[0]>1)
- iso9660copyfile(fs, dir, c);
- p += c->len;
- }
- }
- }
- static char*
- getname(uchar **pp)
- {
- uchar *p;
- int l;
- p = *pp;
- l = *p;
- *pp = p+1+l;
- if(l == 0)
- return "";
- memmove(p, p+1, l);
- p[l] = 0;
- return (char*)p;
- }
- static char*
- getcname(Cdir *c)
- {
- uchar *up;
- char *p, *q;
- up = &c->namelen;
- p = getname(&up);
- for(q=p; *q; q++)
- *q = tolower(*q);
- return p;
- }
- static char
- dmsize[12] =
- {
- 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
- };
- static ulong
- getcdate(uchar *p) /* yMdhmsz */
- {
- Tm tm;
- int y, M, d, h, m, s, tz;
- y=p[0]; M=p[1]; d=p[2];
- h=p[3]; m=p[4]; s=p[5]; tz=p[6];
- USED(tz);
- if (y < 70)
- return 0;
- if (M < 1 || M > 12)
- return 0;
- if (d < 1 || d > dmsize[M-1])
- return 0;
- if (h > 23)
- return 0;
- if (m > 59)
- return 0;
- if (s > 59)
- return 0;
- memset(&tm, 0, sizeof tm);
- tm.sec = s;
- tm.min = m;
- tm.hour = h;
- tm.mday = d;
- tm.mon = M-1;
- tm.year = 1900+y;
- tm.zone[0] = 0;
- return tm2sec(&tm);
- }
- static int ind;
- static void
- iso9660copyfile(Fs *fs, File *dir, Cdir *c)
- {
- Dir d;
- DirEntry de;
- int sysl;
- uchar score[VtScoreSize];
- ulong off, foff, len, mode;
- uchar *p;
- File *f;
- ind++;
- memset(&d, 0, sizeof d);
- p = c->name + c->namelen;
- if(((uintptr)p) & 1)
- p++;
- sysl = (uchar*)c + c->len - p;
- if(sysl <= 0)
- vtFatal("missing plan9 directory entry on %d/%d/%.*s", c->namelen, c->name[0], c->namelen, c->name);
- d.name = getname(&p);
- d.uid = getname(&p);
- d.gid = getname(&p);
- if((uintptr)p & 1)
- p++;
- d.mode = little(p, 4);
- if(d.name[0] == 0)
- d.name = getcname(c);
- d.mtime = getcdate(c->date);
- d.atime = d.mtime;
- if(d.mode&DMDIR) print("%*scopy %s %s %s %luo\n", ind*2, "", d.name, d.uid, d.gid, d.mode);
- mode = d.mode&0777;
- if(d.mode&DMDIR)
- mode |= ModeDir;
- if((f = fileCreate(dir, d.name, mode, d.uid)) == nil)
- vtFatal("could not create file '%s': %r", d.name);
- if(d.mode&DMDIR)
- iso9660copydir(fs, f, c);
- else{
- len = little(c->dlen, 4);
- off = little(c->dloc, 4)*Blocksize;
- for(foff=0; foff<len; foff+=h->blockSize){
- localToGlobal((off+foff-fsoff)/h->blockSize, score);
- if(!fileMapBlock(f, foff/h->blockSize, score, Tag))
- vtFatal("fileMapBlock: %R");
- }
- if(!fileSetSize(f, len))
- vtFatal("fileSetSize: %R");
- }
- if(!fileGetDir(f, &de))
- vtFatal("fileGetDir: %R");
- de.uid = d.uid;
- de.gid = d.gid;
- de.mtime = d.mtime;
- de.atime = d.atime;
- de.mode = d.mode&0777;
- if(!fileSetDir(f, &de, "sys"))
- vtFatal("fileSetDir: %R");
- fileDecRef(f);
- ind--;
- }
|