Files
RedBear-OS/block-io-wrapper/src/lib.rs
T
2023-08-04 03:50:45 -07:00

50 lines
1.7 KiB
Rust

use std::cmp::min;
use std::io::Error;
/// Split the read operation into a series of block reads.
/// `read_fn` will be called with a block number to be read, and a buffer to be filled.
/// The buffer must be large enough to hold `blksize` of data.
/// `read_fn` must return a full block of data.
/// Result will be the number of bytes read.
pub fn read(
offset: u64,
blksize: u32,
buf: &mut [u8],
block_bytes: &mut [u8],
mut read_fn: impl FnMut(u64, &mut [u8]) -> Result<(), Error>,
) -> Result<usize, Error> {
// TODO: Yield sometimes, perhaps after a few blocks or something.
if buf.len() == 0 {
return Ok(0);
}
let to_copy = usize::try_from(
offset.saturating_add(u64::try_from(buf.len()).expect("buf.len() larger than u64"))
- offset,
)
.expect("bytes to copy larger than usize");
let mut curr_buf = &mut buf[..to_copy];
let mut curr_offset = offset;
let blk_size = usize::try_from(blksize).expect("blksize larger than usize");
let mut total_read = 0;
while curr_buf.len() > 0 {
// TODO: Async/await? I mean, shouldn't AHCI be async?
let blk_offset =
usize::try_from(curr_offset % u64::from(blksize)).expect("usize smaller than blksize");
let to_copy = min(curr_buf.len(), blk_size - blk_offset);
assert!(blk_offset + to_copy <= blk_size);
read_fn(curr_offset / u64::from(blksize), block_bytes)?;
let src_buf = &block_bytes[blk_offset..];
curr_buf[..to_copy].copy_from_slice(&src_buf[..to_copy]);
curr_buf = &mut curr_buf[to_copy..];
curr_offset += u64::try_from(to_copy).expect("bytes to copy larger than u64");
total_read += to_copy;
}
Ok(total_read)
}