use std::io::{Read, Seek, Write, SeekFrom};
use std::sync::{Arc, Mutex};
use log::{trace, debug, info};
use simplelog::{SimpleLogger, LevelFilter, Config as LogConfig};
use fatfs::{FsOptions, FatType};
use usbd_scsi::BlockDevice;
use ghostfat::{GhostFat, File, Config};
pub struct MockDisk<'a> {
pub index: usize,
pub disk: GhostFat<'a>,
}
impl <'a> Read for MockDisk<'a> {
fn read(&mut self, buff: &mut [u8]) -> std::io::Result<usize> {
let mut lba = self.index as u32 / 512;
let offset = self.index as usize % 512;
let mut block = [0u8; 512];
let mut index = 0;
if offset > 0 && buff.len() > (512 - offset) {
trace!("Read offset chunk lba: {} offset: {} len: {}", lba, offset, 512-offset);
self.disk.read_block(lba, &mut block).unwrap();
buff[..512 - offset].copy_from_slice(&block[offset..]);
index += 512 - offset;
lba += 1;
}
for c in (&mut buff[index..]).chunks_mut(512) {
self.disk.read_block(lba, &mut block).unwrap();
c.copy_from_slice(&block[offset..][..c.len()]);
index += c.len();
lba += 1;
}
trace!("Read {} bytes at index 0x{:02x} (lba: {} offset: 0x{:02x}), data: {:02x?}", buff.len(), self.index, lba, offset, buff);
self.index += buff.len();
Ok(buff.len())
}
}
impl <'a> Write for MockDisk<'a> {
fn write(&mut self, buff: &[u8]) -> std::io::Result<usize> {
let lba = self.index as u32 / 512;
let offset = self.index as usize % 512;
trace!("Write {} bytes at index: 0x{:02x} (lba: {} offset: 0x{:02x}): data: {:02x?}", buff.len(), self.index, lba, offset, buff);
{
let mut block = [0u8; 512];
self.disk.read_block(lba, &mut block).unwrap();
block[offset..][..buff.len()].copy_from_slice(buff);
self.disk.write_block(lba, &block).unwrap();
}
#[cfg(nope)]
d.write(self.index as u32, buff).unwrap();
self.index += buff.len();
Ok(buff.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl <'a> Seek for MockDisk<'a> {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
match pos {
SeekFrom::Start(v) => self.index = v as usize,
SeekFrom::End(v) => {
todo!("Work out how long the disk is...");
},
SeekFrom::Current(v) => self.index = (self.index as i64 + v) as usize,
}
Ok(self.index as u64)
}
}
fn setup<'a>(files: &'a mut [File<'a>]) -> MockDisk<'a> {
let _ = simplelog::TermLogger::init(LevelFilter::Info, LogConfig::default(), simplelog::TerminalMode::Mixed, simplelog::ColorChoice::Auto);
let ghost_fat = GhostFat::new(files, Config::default());
let disk = MockDisk{
index: 0,
disk: ghost_fat,
};
disk
}
fn read_file<const N: usize>() {
let mut data = [0u8; N];
for i in 0..data.len() {
data[i] = rand::random::<u8>();
}
let files = &mut [
File::new("TEST.BIN", &data).unwrap(),
];
let disk = setup(files);
let fs = fatfs::FileSystem::new(disk, FsOptions::new()).unwrap();
assert_eq!(fs.fat_type(), FatType::Fat16);
let root_dir = fs.root_dir();
let f: Vec<_> = root_dir.iter().map(|v| v.unwrap() ).collect();
log::info!("Files: {:?}", f);
assert_eq!(f[0].short_file_name(), "TEST.BIN");
let mut f0 = f[0].to_file();
let mut v0 = Vec::new();
f0.read_to_end(&mut v0).unwrap();
assert_eq!(v0.as_slice() == data, true);
}
#[test]
fn read_small_file() {
read_file::<64>();
}
#[test]
fn read_multi_cluster_file() {
read_file::<1024>();
}
#[test]
fn read_multi_fat_file() {
read_file::<200_000>();
}
fn write_file<const N: usize>() {
let mut data = [0u8; N];
for i in 0..data.len() {
data[i] = rand::random::<u8>();
}
let files = &mut [
File::new("TEST.BIN", &mut data).unwrap(),
];
let disk = setup(files);
let fs = fatfs::FileSystem::new(disk, FsOptions::new()).unwrap();
assert_eq!(fs.fat_type(), FatType::Fat16);
let root_dir = fs.root_dir();
let f: Vec<_> = root_dir.iter().map(|v| v.unwrap() ).collect();
log::info!("Files: {:?}", f);
assert_eq!(f[0].short_file_name(), "TEST.BIN");
let mut d1 = [0u8; N];
for i in 0..d1.len() {
d1[i] = rand::random::<u8>();
}
let mut f0 = f[0].to_file();
f0.rewind();
f0.write_all(&d1).unwrap();
f0.flush();
drop(f0);
let mut f1 = f[0].to_file();
let mut v0 = Vec::new();
f1.read_to_end(&mut v0).unwrap();
assert_eq!(v0.as_slice(), d1);
}
#[test]
fn write_small_file() {
write_file::<64>();
}
#[test]
fn write_multi_cluster_file() {
write_file::<64_000>();
}
#[test]
fn write_multi_fat_file() {
write_file::<128_000>();
}
#[test]
fn read_many_files() {
let d1 = b"abc123456";
let d2 = b"abc123457";
let files = &mut [
File::new("TEST1.TXT", d1).unwrap(),
File::new("TEST2.TXT", d2).unwrap(),
];
let disk = setup(files);
let fs = fatfs::FileSystem::new(disk, FsOptions::new()).unwrap();
assert_eq!(fs.fat_type(), FatType::Fat16);
let root_dir = fs.root_dir();
let f: Vec<_> = root_dir.iter().map(|v| v.unwrap() ).collect();
log::info!("Files: {:?}", f);
assert_eq!(f[0].short_file_name(), "TEST1.TXT");
let mut f1 = f[0].to_file();
let mut s0 = String::new();
f1.read_to_string(&mut s0).unwrap();
assert_eq!(s0.as_bytes(), d1);
assert_eq!(f[1].short_file_name(), "TEST2.TXT");
let mut f1 = f[1].to_file();
let mut s0 = String::new();
f1.read_to_string(&mut s0).unwrap();
assert_eq!(s0.as_bytes(), d2);
}