From 37da2899f40661e3e9631e497da8dc59b971cbd0 Mon Sep 17 00:00:00 2001 From: "Charles.Forsyth" Date: Fri, 22 Dec 2006 17:07:39 +0000 Subject: 20060303a --- appl/lib/disks.b | 377 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) create mode 100644 appl/lib/disks.b (limited to 'appl/lib/disks.b') diff --git a/appl/lib/disks.b b/appl/lib/disks.b new file mode 100644 index 00000000..ac718af1 --- /dev/null +++ b/appl/lib/disks.b @@ -0,0 +1,377 @@ +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 + && 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 + || readn(d.fd, buf, 512) != 512 + || int t[Omagic] != Magic0 + || int t[Omagic+1] != Magic1) + return -1; + } + + h := s := -1; + for(i:=0; i + 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= 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 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); +} + +readn(fd: ref Sys->FD, buf: array of byte, nb: int): int +{ + for(nr := 0; nr < nb;){ + n := sys->read(fd, buf[nr:], nb-nr); + if(n <= 0){ + if(nr == 0) + return n; + break; + } + nr += n; + } + return nr; +} -- cgit v1.2.3