Remote whitespace at the ends of lines. Remove blank lines from the ends of files. Change modes on source files so that they are not executable. Signed-off-by: Dan Cross <cross@gajendra.net>
495 lines
10 KiB
C
495 lines
10 KiB
C
/*
|
|
* 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 "C" 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 */
|
|
};
|
|
|
|
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, "%.*C dloc %.4N dlen %.4N", c->namelen, c->name,
|
|
c->dloc, c->dlen);
|
|
}
|
|
fmtstrcpy(fmt, buf);
|
|
return 0;
|
|
}
|
|
|
|
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('C', asciiTfmt);
|
|
}
|
|
|
|
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*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)
|
|
sysfatal("Bopen %s: %r", file9660);
|
|
|
|
getsect(root, 16);
|
|
ascii();
|
|
|
|
v = (Voldesc*)root;
|
|
if(memcmp(v->magic, "\001CD001\001\000", 8) != 0)
|
|
sysfatal("%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)
|
|
sysfatal("fossil data starts after cd data");
|
|
if(off9660 + (vlong)h->end*h->blockSize < endoff)
|
|
sysfatal("fossil data ends before cd data");
|
|
if(fsoff%h->blockSize)
|
|
sysfatal("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)
|
|
sysfatal("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)
|
|
sysfatal("cannot read first data sector on cd via fossil");
|
|
if(memcmp(sect, sect2, Blocksize) != 0)
|
|
sysfatal("iso9660 offset is a lie");
|
|
}
|
|
|
|
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))
|
|
sysfatal("disk read failed: %r");
|
|
getsect(sect, startoff/Blocksize);
|
|
if(memcmp(buf, sect, Blocksize) != 0)
|
|
sysfatal("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);
|
|
runlock(&fs->elk);
|
|
if(!fsSnapshot(fs, nil, nil, 0))
|
|
sysfatal("snapshot failed: %r");
|
|
rlock(&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)
|
|
sysfatal("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)
|
|
sysfatal("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)
|
|
sysfatal("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))
|
|
sysfatal("fileMapBlock: %r");
|
|
}
|
|
if(!fileSetSize(f, len))
|
|
sysfatal("fileSetSize: %r");
|
|
}
|
|
if(!fileGetDir(f, &de))
|
|
sysfatal("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"))
|
|
sysfatal("fileSetDir: %r");
|
|
fileDecRef(f);
|
|
ind--;
|
|
}
|