use alloc::sync::Arc;
use axdriver::prelude::*;
use spin::Mutex;
const BLOCK_SIZE: usize = 512;
#[derive(Clone)]
pub struct Disk {
block_id: u64,
offset: usize,
dev: Arc<Mutex<AxBlockDevice>>,
}
impl Disk {
pub fn new(dev: AxBlockDevice) -> Self {
assert_eq!(BLOCK_SIZE, dev.block_size());
Self {
block_id: 0,
offset: 0,
dev: Arc::new(Mutex::new(dev)),
}
}
pub fn size(&self) -> u64 {
let dev = self.dev.lock();
dev.num_blocks() * BLOCK_SIZE as u64
}
pub fn position(&self) -> u64 {
self.block_id * BLOCK_SIZE as u64 + self.offset as u64
}
pub fn set_position(&mut self, pos: u64) {
self.block_id = pos / BLOCK_SIZE as u64;
self.offset = pos as usize % BLOCK_SIZE;
}
pub fn read_one(&mut self, buf: &mut [u8]) -> DevResult<usize> {
let read_size = if self.offset == 0 && buf.len() >= BLOCK_SIZE {
let mut dev = self.dev.lock();
dev.read_block(self.block_id, &mut buf[0..BLOCK_SIZE])?;
self.block_id += 1;
BLOCK_SIZE
} else {
let mut data = [0u8; BLOCK_SIZE];
let start = self.offset;
let count = buf.len().min(BLOCK_SIZE - self.offset);
{
let mut dev = self.dev.lock();
dev.read_block(self.block_id, &mut data)?;
}
buf[..count].copy_from_slice(&data[start..start + count]);
self.offset += count;
if self.offset >= BLOCK_SIZE {
self.block_id += 1;
self.offset -= BLOCK_SIZE;
}
count
};
Ok(read_size)
}
pub fn write_one(&mut self, buf: &[u8]) -> DevResult<usize> {
let write_size = if self.offset == 0 && buf.len() >= BLOCK_SIZE {
let mut dev = self.dev.lock();
dev.write_block(self.block_id, &buf[0..BLOCK_SIZE])?;
self.block_id += 1;
BLOCK_SIZE
} else {
let mut data = [0u8; BLOCK_SIZE];
let start = self.offset;
let count = buf.len().min(BLOCK_SIZE - self.offset);
let mut dev = self.dev.lock();
dev.read_block(self.block_id, &mut data)?;
data[start..start + count].copy_from_slice(&buf[..count]);
dev.write_block(self.block_id, &data)?;
self.offset += count;
if self.offset >= BLOCK_SIZE {
self.block_id += 1;
self.offset -= BLOCK_SIZE;
}
count
};
Ok(write_size)
}
}
pub struct Partition {
disk: Arc<Mutex<Disk>>,
start_lba: u64,
end_lba: u64,
position: u64,
}
impl Partition {
pub fn new(disk: Disk, start_lba: u64, end_lba: u64) -> Self {
Self {
disk: Arc::new(Mutex::new(disk)),
start_lba,
end_lba,
position: 0,
}
}
pub fn size(&self) -> u64 {
(self.end_lba - self.start_lba + 1) * BLOCK_SIZE as u64
}
pub fn position(&self) -> u64 {
self.position
}
pub fn set_position(&mut self, pos: u64) {
self.position = pos.min(self.size());
}
pub fn read_one(&mut self, buf: &mut [u8]) -> DevResult<usize> {
if self.position >= self.size() {
return Ok(0);
}
let remaining = self.size() - self.position;
let to_read = buf.len().min(remaining as usize);
let buf = &mut buf[..to_read];
let abs_pos = self.start_lba * BLOCK_SIZE as u64 + self.position;
let read_len = {
let mut disk = self.disk.lock();
disk.set_position(abs_pos);
disk.read_one(buf)?
};
self.position += read_len as u64;
Ok(read_len)
}
pub fn write_one(&mut self, buf: &[u8]) -> DevResult<usize> {
if self.position >= self.size() {
return Ok(0);
}
let remaining = self.size() - self.position;
let to_write = buf.len().min(remaining as usize);
let buf = &buf[..to_write];
let abs_pos = self.start_lba * BLOCK_SIZE as u64 + self.position;
let write_len = {
let mut disk = self.disk.lock();
disk.set_position(abs_pos);
disk.write_one(buf)?
};
self.position += write_len as u64;
Ok(write_len)
}
}