ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/lib/diskblocks.b/
implement Diskblocks;
#
# adapted from Acme's disk.b
#
include "sys.m";
sys: Sys;
include "diskblocks.m";
init()
{
sys = load Sys Sys->PATH;
}
tempfile(): ref Sys->FD
{
user := "inferno";
fd := sys->open("/dev/user", Sys->OREAD);
if(fd != nil){
b := array[Sys->NAMEMAX] of byte;
n := sys->read(fd, b, len b);
if(n > 0)
user = string b[0:n];
}
fd = nil;
buf := sys->sprint("/tmp/X%d.%.4sblks", sys->pctl(0, nil), user);
for(i:='A'; i<='Z'; i++){
buf[5] = i;
if(sys->stat(buf).t0 == 0)
continue;
fd = sys->create(buf, Sys->ORDWR|Sys->ORCLOSE|Sys->OEXCL, 8r600);
if(fd != nil)
return fd;
}
return nil;
}
Disk.init(fd: ref Sys->FD, gran: int, maxblock: int): ref Disk
{
d := ref Disk;
if(gran == 0 || maxblock%gran != 0)
return nil;
d.maxblock = maxblock;
d.gran = gran;
d.free = array[maxblock/gran+1] of list of ref Block;
d.addr = big 0;
d.fd = fd;
d.lock = chan[1] of int;
return d;
}
ntosize(d: ref Disk, n: int): (int, int)
{
if (n > d.maxblock)
return (-1, -1);
size := n;
if((size % d.gran) != 0)
size += d.gran - size%d.gran;
# last bucket holds blocks of exactly d.maxblock
return (size, size/d.gran);
}
Disk.new(d: self ref Disk, n: int): ref Block
{
(size, i) := ntosize(d, n);
if(i < 0){
sys->werrstr("illegal Disk allocation");
return nil;
}
b: ref Block;
d.lock <-= 1;
if(d.free[i] != nil){
b = hd d.free[i];
d.free[i] = tl d.free[i];
}else{
b = ref Block(d.addr, 0);
d.addr += big size;
}
<-d.lock;
b.n = n;
return b;
}
Disk.release(d: self ref Disk, b: ref Block)
{
(nil, i) := ntosize(d, b.n);
d.lock <-= 1;
d.free[i] = b :: d.free[i];
<-d.lock;
}
Disk.write(d: self ref Disk, b: ref Block, a: array of byte, n: int): ref Block
{
if(b != nil){
(size, nil) := ntosize(d, b.n);
(nsize, nil) := ntosize(d, n);
if(size != nsize){
d.release(b);
b = d.new(n);
}
}else
b = d.new(n);
if(b == nil)
return nil;
if(sys->pwrite(d.fd, a, n, b.addr) != n){
sys->werrstr(sys->sprint("Disk write error: %r"));
return nil;
}
b.n = n;
return b;
}
Disk.read(d: self ref Disk, b: ref Block, a: array of byte, n: int): int
{
if(b == nil || n > b.n){
sys->werrstr("read request bigger than block");
return -1;
}
return sys->pread(d.fd, a, n, b.addr);
}