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.
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.
16 #include "flfmt9660.h"
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*
34 typedef struct Voldesc 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 */
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 */
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 */
65 typedef struct Cdir Cdir;
77 uchar name[1]; /* chumminess */
79 #pragma varargck type "D" Cdir*
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);
92 snprint(buf, sizeof buf, "%.*C dloc %.4N dlen %.4N", c->namelen, c->name,
114 little(void *a, int n)
127 /* numbers in big or little endian. */
135 p = va_arg(fmt->args, uchar*);
137 if(!(fmt->flags&FmtPrec)) {
138 fmtstrcpy(fmt, "*BL*");
143 v = big(p, fmt->prec);
145 v = little(p, fmt->prec);
147 sprint(buf, "0x%.*lux", fmt->prec*2, v);
148 fmt->flags &= ~FmtPrec;
153 /* numbers in both little and big endian */
160 p = va_arg(fmt->args, uchar*);
162 sprint(buf, "%.*L %.*B", fmt->prec, p, fmt->prec, p+fmt->prec);
163 fmt->flags &= ~FmtPrec;
174 p = va_arg(fmt->args, char*);
175 for(i=0; i<fmt->prec; i++)
178 for(p=buf+strlen(buf); p>buf && p[-1]==' '; p--)
181 fmt->flags &= ~FmtPrec;
189 fmtinstall('C', asciiTfmt);
193 getsect(uchar *buf, int n)
195 if(Bseek(b, n*2048, 0) != n*2048 || Bread(b, buf, 2048) != 2048)
198 sysfatal("reading block at %,d: %r", n*2048);
204 static char *file9660;
206 static ulong startoff;
209 static uchar root[2048];
211 static ulong iso9660start(Cdir*);
212 static void iso9660copydir(Fs*, File*, Cdir*);
213 static void iso9660copyfile(Fs*, File*, Cdir*);
216 iso9660init(int xfd, Header *xh, char *xfile9660, int xoff9660)
218 uchar sect[2048], sect2[2048];
220 fmtinstall('L', BLfmt);
221 fmtinstall('B', BLfmt);
222 fmtinstall('N', Nfmt);
223 fmtinstall('D', Dfmt);
227 file9660 = xfile9660;
230 if((b = Bopen(file9660, OREAD)) == nil)
231 sysfatal("Bopen %s: %r", file9660);
237 if(memcmp(v->magic, "\001CD001\001\000", 8) != 0)
238 sysfatal("%s not a cd image", file9660);
240 startoff = iso9660start((Cdir*)v->rootdir)*Blocksize;
241 endoff = little(v->volsize, 4); /* already in bytes */
243 fsoff = off9660 + h->data*h->blockSize;
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");
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");
263 iso9660labels(Disk *disk, uchar *buf, void (*write)(int, u32int))
265 ulong sb, eb, bn, lb, llb;
268 uchar sect[Blocksize];
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");
276 sb = (startoff-fsoff)/h->blockSize;
277 eb = (endoff-fsoff+h->blockSize-1)/h->blockSize;
279 lpb = h->blockSize/LabelSize;
281 /* for each reserved block, mark label */
287 l.epochClose = ~(u32int)0;
288 for(bn=sb; bn<eb; bn++){
292 (*write)(PartLabel, llb);
293 memset(buf, 0, h->blockSize);
296 labelPack(&l, buf, bn%lpb);
299 (*write)(PartLabel, llb);
307 root = fileOpen(fs, "/active");
308 iso9660copydir(fs, root, (Cdir*)v->rootdir);
311 if(!fsSnapshot(fs, nil, nil, 0))
312 sysfatal("snapshot failed: %r");
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.)
321 iso9660start(Cdir *c)
323 uchar sect[Blocksize];
326 getsect(sect, little(c->dloc, 4));
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");
334 return little(c->dloc, 4);
338 iso9660copydir(Fs *fs, File *dir, Cdir *cd)
341 uchar sect[Blocksize], *esect, *p;
344 len = little(cd->dlen, 4);
345 off = little(cd->dloc, 4)*Blocksize;
347 esect = sect+Blocksize;
349 for(; off<end; off+=Blocksize){
350 getsect(sect, off/Blocksize);
356 if(c->namelen!=1 || c->name[0]>1)
357 iso9660copyfile(fs, dir, c);
395 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
399 getcdate(uchar *p) /* yMdhmsz */
402 int y, M, d, h, m, s, tz;
404 y=p[0]; M=p[1]; d=p[2];
405 h=p[3]; m=p[4]; s=p[5]; tz=p[6];
411 if (d < 1 || d > dmsize[M-1])
420 memset(&tm, 0, sizeof tm);
434 iso9660copyfile(Fs *fs, File *dir, Cdir *c)
439 uchar score[VtScoreSize];
440 ulong off, foff, len, mode;
445 memset(&d, 0, sizeof d);
446 p = c->name + c->namelen;
449 sysl = (uchar*)c + c->len - p;
451 sysfatal("missing plan9 directory entry on %d/%d/%.*s", c->namelen, c->name[0], c->namelen, c->name);
452 d.name = getname(&p);
457 d.mode = little(p, 4);
459 d.name = getcname(c);
460 d.mtime = getcdate(c->date);
463 if(d.mode&DMDIR) print("%*scopy %s %s %s %luo\n", ind*2, "", d.name, d.uid, d.gid, d.mode);
468 if((f = fileCreate(dir, d.name, mode, d.uid)) == nil)
469 sysfatal("could not create file '%s': %r", d.name);
471 iso9660copydir(fs, f, c);
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");
480 if(!fileSetSize(f, len))
481 sysfatal("fileSetSize: %r");
483 if(!fileGetDir(f, &de))
484 sysfatal("fileGetDir: %r");
489 de.mode = d.mode&0777;
490 if(!fileSetDir(f, &de, "sys"))
491 sysfatal("fileSetDir: %r");