flfmt9660.c

来自「这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易」· C语言 代码 · 共 566 行

C
566
字号
/* * 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 voiddumpbootvol(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 intDfmt(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 voidbigend(void){	longc = 'B';}static voidlittleend(void){	longc = 'L';}static ulongbig(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 ulonglittle(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 intBLfmt(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 intNfmt(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 intasciiTfmt(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 voidascii(void){	fmtinstall('T', asciiTfmt);}static intruneTfmt(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 voidgetsect(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*);voidiso9660init(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);}voidiso9660labels(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);}voidiso9660copy(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 ulongiso9660start(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 voidiso9660copydir(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 chardmsize[12] ={	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,};static ulonggetcdate(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 voidiso9660copyfile(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--;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?