forsyth20121205-174063a80cc13 years agoHistory
363 lines · 6.9 KB · Brainfuck
RawDownload
implement Disks; # adapted from /sys/src/libdisk on Plan 9: subject to Lucent Public License 1.02 include "sys.m";	sys: Sys; include "bufio.m";	bufio: Bufio;	Iobuf: import bufio; include "disks.m"; scsiverbose := 0; Codefile: con "/lib/scsicodes"; Code: adt {	v:	int;	# (asc<<8) | ascq	s:	string;};codes: array of Code; init(){	sys = load Sys Sys->PATH;	bufio = load Bufio Bufio->PATH;} ## Discover the disk geometry by various sleazeful means.# # First, if there is a partition table in sector 0,# see if all the partitions have the same end head# and sector; if so, we'll assume that that's the # right count.# # If that fails, we'll try looking at the geometry that the ATA# driver supplied, if any, and translate that as a# BIOS might. # # If that too fails, which should only happen on a SCSI# disk with no currently defined partitions, we'll try# various common (h, s) pairs used by BIOSes when faking# the geometries.# # table entry:	Oactive,			# active flag	Ostarth,			# starting head	Ostarts,			# starting sector	Ostartc,			# starting cylinder	Otype,			# partition type	Oendh,			# ending head	Oends,			# ending sector	Oendc: con iota;		# ending cylinder	Oxlba: con Oendc+1;	# starting LBA from start of disc or partition [4]	Oxsize: con Oxlba+4;	# size in sectors[4] # Table: entry[NTentry][TentrySize] magic[2]Omagic: con NTentry*TentrySize; partitiongeometry(d: ref Disk): int{	buf := array[512] of byte;	t := buf[Toffset:]; 	#	# look for an MBR first in the /dev/sdXX/data partition, otherwise	# attempt to fall back on the current partition.	#	rawfd := sys->open(d.prefix+"data", Sys->OREAD);	if(rawfd != nil	&& sys->seek(rawfd, big 0, 0) == big 0	&& sys->readn(rawfd, buf, 512) == 512	&& int t[Omagic] == Magic0	&& int t[Omagic+1] == Magic1) {		rawfd = nil;	}else{		rawfd = nil;		if(sys->seek(d.fd, big 0, 0) < big 0		|| sys->readn(d.fd, buf, 512) != 512		|| int t[Omagic] != Magic0		|| int t[Omagic+1] != Magic1)			return -1;	} 	h := s := -1;	for(i:=0; i<NTentry*TentrySize; i += TentrySize) {		if(t[i+Otype] == byte 0)			continue; 		t[i+Oends] &= byte 63;		if(h == -1) {			h = int t[i+Oendh];			s = int t[i+Oends];		} else {			#			# Only accept the partition info if every			# partition is consistent.			#			if(h != int t[i+Oendh] || s != int t[i+Oends])				return -1;		}	} 	if(h == -1)		return -1; 	d.h = h+1;	# heads count from 0	d.s = s;	# sectors count from 1	d.c = int (d.secs / big (d.h*d.s));	d.chssrc = "part";	return 0;} ## If there is ATA geometry, use it, perhaps massaged#drivergeometry(d: ref Disk): int{	if(d.c == 0 || d.h == 0 || d.s == 0)		return -1; 	d.chssrc = "disk";	if(d.c < 1024)		return 0; 	case d.h {	15 =>		d.h = 255;		d.c /= 17; 	* =>		for(m := 2; m*d.h < 256; m *= 2) {			if(d.c/m < 1024) {				d.c /= m;				d.h *= m;				return 0;			}		} 		# set to 255, 63 and be done with it		d.h = 255;		d.s = 63;		d.c = int (d.secs / big(d.h * d.s));	}	return 0;} ## There's no ATA geometry and no partitions.# Our guess is as good as anyone's.#Guess: adt {	h:	int;	s:	int;};guess: array of Guess = array[] of {	(64, 32),	(64, 63),	(128, 63),	(255, 63),}; guessgeometry(d: ref Disk){	d.chssrc = "guess";	c := 1024;	for(i:=0; i<len guess; i++)		if(big(c*guess[i].h*guess[i].s) >= d.secs) {			d.h = guess[i].h;			d.s = guess[i].s;			d.c = int(d.secs / big(d.h * d.s));			return;		} 	# use maximum values	d.h = 255;	d.s = 63;	d.c = int(d.secs / big(d.h * d.s));} findgeometry(disk: ref Disk){	disk.h = disk.s = disk.c = 0;	if(partitiongeometry(disk) < 0 &&	   drivergeometry(disk) < 0)		guessgeometry(disk);} openfile(d: ref Disk): ref Disk{	(ok, db) := sys->fstat(d.fd);	if(ok < 0)		return nil; 	d.secsize = 512;	d.size = db.length;	d.secs = d.size / big d.secsize;	d.offset = big 0; 	findgeometry(d);	return mkwidth(d);} opensd(d: ref Disk): ref Disk{	b := bufio->fopen(d.ctlfd, Bufio->OREAD);	while((p := b.gets('\n')) != nil){		p = p[0:len p - 1];		(nf, f) := sys->tokenize(p, " \t");	# might need str->unquote		if(nf >= 3 && hd f == "geometry") {			d.secsize = int hd tl tl f;			if(nf >= 6) {				d.c = int hd tl tl tl f;				d.h = int hd tl tl tl tl f;				d.s = int hd tl tl tl tl tl f;			}		}		if(nf >= 4 && hd f == "part" && hd tl f == d.part) {			d.offset = big hd tl tl f;			d.secs = big hd tl tl tl f - d.offset;		}	} 		d.size = d.secs * big d.secsize;	if(d.size <= big 0) {		d.part = "";		d.dtype = "file";		return openfile(d);	} 	findgeometry(d);	return mkwidth(d);} Disk.open(name: string, mode: int, noctl: int): ref Disk{	d := ref Disk;	d.rdonly = mode == Sys->OREAD;	d.fd = sys->open(name, Sys->OREAD);	if(d.fd == nil)		return nil; 	if(mode != Sys->OREAD){		d.wfd = sys->open(name, Sys->OWRITE);		if(d.wfd == nil)			d.rdonly = 1;	} 	if(noctl)		return openfile(d); 	# check for floppy(3) disk	if(len name >= 7) {		q := name[len name-7:];		if(q[0] == 'f' && q[1] == 'd' && isdigit(q[2]) && q[3:] == "disk") {			if((d.ctlfd = sys->open(name[0:len name-4]+"ctl", Sys->ORDWR)) != nil) {				d.prefix = name[0:len name-4];	# fdN (unlike Plan 9)				d.dtype = "floppy";				return openfile(d);			}		}	} 	# attempt to find sd(3) disk or partition	d.prefix = name;	for(i := len name; --i >= 0;)		if(name[i] == '/'){			d.prefix = name[0:i+1];			break;		} 	if((d.ctlfd = sys->open(d.prefix+"ctl", Sys->ORDWR)) != nil) {		d.dtype = "sd";		d.part = name[len d.prefix:];		return opensd(d);	} 	# assume we have just a normal file	d.dtype = "file";	return openfile(d);} mkwidth(d: ref Disk): ref Disk{	d.width = len sys->sprint("%bd", d.size);	return d;} isdigit(c: int): int{	return c >= '0' && c <= '9';} putchs(d: ref Disk, p: array of byte, lba: big){	s := int (lba % big d.s);	h := int (lba / big d.s % big d.h);	c := int (lba / (big d.s * big d.h)); 	if(c >= 1024) {		c = 1023;		h = d.h - 1;		s = d.s - 1;	} 	p[0] = byte h;	p[1] = byte (((s+1) & 16r3F) | ((c>>2) & 16rC0));	p[2] = byte c;} PCpart.bytes(p: self PCpart, d: ref Disk): array of byte{	a := array[TentrySize] of byte;	a[Oactive] = byte p.active;	a[Otype] = byte p.ptype;	putchs(d, a[Ostarth:], p.base+p.offset);	putchs(d, a[Oendh:], p.base+p.offset+p.size-big 1);	putle32(a[Oxlba:], p.offset);	putle32(a[Oxsize:], p.size);	return a;} PCpart.extract(a: array of byte, nil: ref Disk): PCpart{	p: PCpart;	p.active = int a[Oactive];	p.ptype = int a[Otype];	p.base = big 0;	p.offset = getle32(a[Oxlba:]);	p.size = getle32(a[Oxsize:]);	return p;} getle32(p: array of byte): big{	return (big p[3]<<24) | (big p[2]<<16) | (big p[1] << 8) | big p[0];} putle32(p: array of byte, i: big){	p[0] = byte i;	p[1] = byte (i>>8);	p[2] = byte (i>>16);	p[3] = byte (i>>24);} Disk.readn(d: self ref Disk, buf: array of byte, nb: int): int{	return sys->readn(d.fd, buf, nb);} chstext(p: array of byte): string{	h := int p[0];	c := int p[2];	c |= (int p[1]&16rC0)<<2;	s := (int p[1] & 16r3F);	return sys->sprint("%d/%d/%d", c, h, s);}