498 lines · 9.0 KB · C
RawDownload
#include	"all.h"#include	"mem.h"#include	"io.h"#include "../pc/dosfs.h" #define dprint(...)	if(pdebug)print(__VA_ARGS__) enum{	Npart	= 8,	Ntab	= 8,	Sblank	= 0,	Eblank	= 0,}; typedef struct{	char	type;	uchar	rem;			/* unaligned partition */	Devsize	start;	Devsize	end;	char	name[NAMELEN];}Part; typedef struct{	char	devstr[NAMELEN];	int	n;	Part	tab[Npart];}Tab; static Tab	*tab;static int		ntab;static int		pdebug = 0; static voidinitpart(void){	static int done; 	if(done++)		return;	tab = ialloc(Ntab*sizeof *tab, 0);} /* * each Device has one partition table, even if d->dno is different. */ Tab*devtotab(Device *d, int *new){	char *s, buf[NAMELEN];	int i;	Tab *t; 	initpart();	snprint(buf, sizeof buf, "%Z", d);	for(i = 0; i < Ntab; i++){		t = tab+i;		s = t->devstr;		if(*s == 0){			memmove(s, buf, sizeof buf);			*new = 1;			return t;		}else if(!strcmp(buf, s))			return t;	}	panic("too many partitioned devices");	return 0;} Devsizesectooff(Device *d, uvlong sec){	return (sec*devsecsize(d))/RBUFSIZE;} uvlongofftosec(Device *d, Off off){	return ((uvlong)off*RBUFSIZE)/devsecsize(d);} Part*addpart(Device *parent, Device *d, char *s, uvlong a, uvlong b, int sec){	uint sperrb;	Tab *t;	Part *p; 	dprint("  %Z %s [%lld, %lld) -> ", d, s, a, b);	t = parent->private;	if(t->n+1 == Npart){		print("too many partitions; part %s %lld %lld dropped\n", s, a, b);		return t->tab+t->n;	}	p = t->tab+t->n++;	sperrb = offtosec(d, 1);	if(sperrb > 0)		p->rem = a%sperrb;	else		p->rem = 0;	if(sec){		p->type = 's';		p->start = sectooff(d, a+sperrb-1)+Sblank;		/* round up */		p->end = sectooff(d, b&~(sperrb-1))-Eblank;	/* round down */	}else{		p->type = 'o';		p->start = a;		p->end = b;	}	if(p->end < p->start)		print("bad partition %s %lld not < %lld\n", s, p->start, p->end);	strncpy(p->name, s, NAMELEN);	dprint("[%lld, %lld)\n", p->start, p->end);	return p;} /* * read raw disk; only used for groking partition tables & reading * fat during configuration.  very inefficient. */static inttailio(Device *d, int write, uvlong byte, ulong l, void *buf){	int r;	ulong rem;	Devsize off;	Msgbuf *t; 	t = mballoc(RBUFSIZE, 0, Mxxx);	rem = byte&(RBUFSIZE-1);	off = byte/RBUFSIZE; //	print("tailio(%Z, %c, byte %llud [b %llud], %lud)\n", d, "rw"[write], byte, off, rem); 	r = devread(d, off, t->data);	if(!r && write){		memmove(t->data+rem, buf, l);		r = devwrite(d, off, t->data);	}else if(!r)		memmove(buf, t->data+rem, l);	mbfree(t);	return r;} Offbyteio0(Device *d, int write, uvlong byte, ulong l, void *vbuf){	uchar *buf;	ulong rem, l0;	int (*io)(Device*, Off, void*); 	l0 = l;	buf = vbuf;	io = write? devwrite: devread;	rem = RBUFSIZE - (byte%RBUFSIZE);	if(rem){		if(rem > l)			rem = l;		if(tailio(d, write, byte, rem, buf))			goto done;		byte += rem;		buf += rem;		l -= rem;	}	while(l >= RBUFSIZE){		if(io(d, byte/RBUFSIZE, buf))			goto done;		byte += RBUFSIZE;		buf += RBUFSIZE;		l -= RBUFSIZE;	}	if(l){		if(byte%RBUFSIZE != 0)			panic("byte%%rbufsize");		if(tailio(d, write, byte, l, buf))			goto done;		byte += l;//		buf += l;		l -= l;	}done:	return l0-l;} intsecio(Device *d, int write, uvlong sec, void *buf){	return byteio0(d, write, sec*512, 512, buf) != 512;}  /* * deal with dos partitions placed on odd-sized boundaries. * to further our misfortune, byteio0 can't deal with negative * offsets. */static Part *findpart(Device*, char*);Offbyteio(Device *d, int write, uvlong byte, ulong l, void *vbuf){	uvlong rem;	Part *p; 	if(d->type == Devpart){		p = findpart(d, d->part.name);		rem = p->rem*devsecsize(d);		if(rem)			byte -= RBUFSIZE-rem;		byte -= Sblank*RBUFSIZE;		byte += d->part.base*RBUFSIZE;		d = d->part.d;	}	return byteio0(d, write, byte, l, vbuf);} intmbrread(Device *d, uvlong sec, void *buf){	uchar *u; 	if(byteio(d, 0, sec*512, 512, buf) != 512)		return 1;	u = buf;	if(u[0x1fe] != 0x55 || u[0x1ff] != 0xaa)		return 1;	return 0;} static intp9part(Device *parent, Device *d, uvlong sec, char *buf){	char *field[4], *line[Npart+1];	uvlong start, end;	int i, n; 	if(secio(d, 0, sec+1, buf))		return 1;	buf[512-1] = '\0';	if(strncmp(buf, "part ", 5))		return 1; 	n = getfields(buf, line, Npart+1, 1, "\n");	dprint("p9part %d lines..", n);	if(n == 0)		return -1;	for(i = 0; i < n; i++){		if(strncmp(line[i], "part ", 5) != 0)			break;		if(getfields(line[i], field, 4, 0, " ") != 4)			break;		start = strtoull(field[2], 0, 0);		end = strtoull(field[3], 0, 0);		if(start >= end || end > offtosec(d, d->size))			break;		addpart(parent, d, field[1], sec+start, sec+end, 1);	}	return 0;} intisdos(int t){	return t==FAT12 || t==FAT16 || t==FATHUGE || t==FAT32 || t==FAT32X;} intisextend(int t){	return t==EXTEND || t==EXTHUGE || t==LEXTEND;} static intmbrpart(Device *parent, Device *d, char *mbrbuf, char *partbuf){	char name[10];	int ndos, i, nplan9;	ulong sec, start, end;	ulong firstx, nextx, npart;	Dospart *dp;	int (*repart)(Device*, Device*, uvlong, char*); 	sec = 0;	dp = (Dospart*)&mbrbuf[0x1be]; 	/* get the MBR (allowing for DMDDO) */	if(mbrread(d, sec, mbrbuf))		return 1;	for(i=0; i<4; i++)		if(dp[i].type == DMDDO) {			dprint("DMDDO %d\n", i);			sec = 63;			if(mbrread(d, sec, mbrbuf))				return 1;			i = -1;	/* start over */		}	/*	 * Read the partitions, first from the MBR and then	 * from successive extended partition tables.	 */	nplan9 = 0;	ndos = 0;	firstx = 0;	for(npart=0;; npart++) {		if(mbrread(d, sec, mbrbuf))			return 1;		if(firstx)			print("%Z ext %lud ", d, sec);		else			print("%Z mbr ", d);		nextx = 0;		for(i=0; i<4; i++) {			start = sec+GLONG(dp[i].start);			end = start+GLONG(dp[i].len);			if(dp[i].type == 0 && start == 0 && end == 0)				continue;			dprint("type %x [%ld, %ld)", dp[i].type, start, end);			repart = 0;			if(dp[i].type == PLAN9) {				if(nplan9 == 0)					strcpy(name, "plan9");				else					sprint(name, "plan9.%d", nplan9);				repart = p9part;				nplan9++;			}else if(!ndos && isdos(dp[i].type)){				ndos = 1;				strcpy(name, "dos");			}else				snprint(name, sizeof name, "%ld", npart);			if(end != 0){				dprint(" %s..", name);				addpart(parent, d, name, start, end, 1);			}			if(repart)				repart(parent, d, start, partbuf);						/* nextx is relative to firstx (or 0), not sec */			if(isextend(dp[i].type)){				nextx = start-sec+firstx;				dprint("link %lud...", nextx);			}		}		dprint("\n");		if(!nextx)			break;		if(!firstx)			firstx = nextx;		sec = nextx;	}		return 0;} static intguessparttab(Tab *t){	int i, c;  	for(i = 0; i < t->n; i++){		c = t->tab[i].type;		if(c == 's' || c == 'o')			return 1;	}	return 0;} static Part*findpart(Device *d, char *s){	char c;	int i;	uvlong l, start, end;	Part *p;	Tab *t; 	t = d->private;	if(s == 0)		goto mkpart;	for(i = 0; i < t->n; i++)		if(!strcmp(t->tab[i].name, s))			return t->tab+i;	panic("part %Z not found", d);mkpart:	if(guessparttab(t))		print("warning: ignoring part table on %Z\n", d->part.d);	if(d->part.base < 101 && d->part.size < 101){		c = '%';		l = d->part.d->size / 100;		start = d->part.base*l;		end = start + d->part.size*l;	}else{		c = 'b';		start = d->part.base;		end = d->part.size;	}	for(i = 0; i < t->n; i++){		p = t->tab+i;		if(start == p->start)		if(end == p->end)			return p;	}	p = addpart(d, d->part.d, "", start, end, 0);	if(c)		p->type = c;	snprint(p->name, sizeof p->name, "f%ld%ld", t-tab, p-t->tab);	// BOTCH	return p;} voidpartition(Device *parent, Device *d){	char *m, *p;	int new;	Msgbuf *mbr, *part;	Part *q; 	new = 0;	parent->private = devtotab(d, &new);	if(new){		mbr = mballoc(RBUFSIZE, 0, Mxxx);		part = mballoc(RBUFSIZE, 0, Mxxx);		m = (char*)mbr->data;		p = (char*)part->data;		!mbrpart(parent, d, m, p) || p9part(parent, d, 0, p);		mbfree(mbr);		mbfree(part);	}	q = findpart(parent, parent->part.name);	parent->part.base = q->start;	parent->part.size = q->end-q->start;} voidcmd_part(int argc, char **argv){	int i, j;	Part *p;	Tab *t; 	if(argc == 1 && !strcmp(*argv, "trace")){		pdebug ^= 1;		return;	}	for(i = 0; i < Ntab; i++){		t = tab+i;		if(*t->devstr == 0)			continue;		print("%d %s\n", i, t->devstr);		for(j = 0; j < Npart; j++){			p = t->tab+j;			if(*p->name == 0 && p->start == 0 && p->end == 0)				continue;			print("  %c\t%s\t%llud\t%llud r %d\n", p->type, p->name, p->start, p->end, p->rem);		}	}} voidpartinit(Device *d){	static int once; 	if(once++ == 0)		cmd_install("part", "-- partition info", cmd_part);	devinit(d->part.d);	d->part.d->size = devsize(d->part.d);	partition(d, d->part.d);} Devsizepartsize(Device *d){	return d->part.size;} intpartread(Device *d, Off b, void *c){	if(b < d->part.size)		return devread(d->part.d, d->part.base+b, c);	print("partread %llud %llud\n", (Wideoff)b, d->part.size);	return 1;} intpartwrite(Device *d, Off b, void *c){	if(b < d->part.size)		return devwrite(d->part.d, d->part.base+b, c);	print("partwrite %llud %llud\n", (Wideoff)b, d->part.size);	return 1;} voidpartream(Device *d, int){	devream(d->part.d, 0);}