feat(storage-server): implement FAT16 filesystem with read, write, create, delete, list, and cluster chain management
This commit is contained in:
112
crates/servers/storage-server/src/tests/fat16.rs
Normal file
112
crates/servers/storage-server/src/tests/fat16.rs
Normal file
@@ -0,0 +1,112 @@
|
||||
use crate::adapters::mock_block::MockBlockDevice;
|
||||
use crate::block_device::{BlockDevice, SectorId};
|
||||
use crate::filesystem::{DirEntry, FileSystem};
|
||||
use crate::fs::fat16::Fat16;
|
||||
|
||||
fn format_fat16_disk(sectors: usize) -> MockBlockDevice {
|
||||
let mut dev = MockBlockDevice::new(sectors);
|
||||
let mut boot = [0u8; 512];
|
||||
|
||||
// BPB
|
||||
boot[11] = 0x00; boot[12] = 0x02; // bytes_per_sector = 512
|
||||
boot[13] = 1; // sectors_per_cluster = 1
|
||||
boot[14] = 1; boot[15] = 0; // reserved_sectors = 1
|
||||
boot[16] = 1; // num_fats = 1
|
||||
boot[17] = 16; boot[18] = 0; // root_entry_count = 16
|
||||
boot[19] = sectors as u8; // total_sectors
|
||||
boot[20] = (sectors >> 8) as u8;
|
||||
boot[22] = 1; boot[23] = 0; // sectors_per_fat = 1
|
||||
|
||||
// boot signature
|
||||
boot[510] = 0x55;
|
||||
boot[511] = 0xAA;
|
||||
|
||||
dev.write_sector(SectorId::new(0), &boot);
|
||||
|
||||
// FAT sector (sector 1) — all zeros = all free
|
||||
let fat = [0u8; 512];
|
||||
dev.write_sector(SectorId::new(1), &fat);
|
||||
|
||||
dev
|
||||
}
|
||||
|
||||
fn mount_test_disk() -> Fat16<MockBlockDevice> {
|
||||
let dev = format_fat16_disk(32);
|
||||
Fat16::mount(dev).expect("mount failed")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mount_valid_disk() {
|
||||
let dev = format_fat16_disk(32);
|
||||
assert!(Fat16::mount(dev).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mount_invalid_disk() {
|
||||
let dev = MockBlockDevice::new(32); // no boot signature
|
||||
assert!(Fat16::mount(dev).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_and_open_file() {
|
||||
let mut fs = mount_test_disk();
|
||||
let h = fs.create(b"hello.txt").expect("create");
|
||||
fs.close(h);
|
||||
|
||||
let h2 = fs.open(b"hello.txt").expect("open");
|
||||
assert_eq!(fs.file_size(h2), Some(0));
|
||||
fs.close(h2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_and_read_file() {
|
||||
let mut fs = mount_test_disk();
|
||||
let h = fs.create(b"data.bin").expect("create");
|
||||
|
||||
let data = b"Hello, FAT16!";
|
||||
let written = fs.write(h, data).expect("write");
|
||||
assert_eq!(written, data.len());
|
||||
|
||||
fs.close(h);
|
||||
|
||||
let h2 = fs.open(b"data.bin").expect("open");
|
||||
assert_eq!(fs.file_size(h2), Some(data.len()));
|
||||
|
||||
let mut buf = [0u8; 32];
|
||||
let read = fs.read(h2, &mut buf).expect("read");
|
||||
assert_eq!(read, data.len());
|
||||
assert_eq!(&buf[..read], data);
|
||||
fs.close(h2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delete_file() {
|
||||
let mut fs = mount_test_disk();
|
||||
fs.create(b"temp.txt").map(|h| fs.close(h));
|
||||
assert!(fs.delete(b"temp.txt"));
|
||||
assert!(fs.open(b"temp.txt").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_directory() {
|
||||
let mut fs = mount_test_disk();
|
||||
fs.create(b"a.txt").map(|h| fs.close(h));
|
||||
fs.create(b"b.txt").map(|h| fs.close(h));
|
||||
|
||||
let mut entries = [DirEntry::empty(); 16];
|
||||
let count = fs.list_dir(b"/", &mut entries).expect("list");
|
||||
assert_eq!(count, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn open_nonexistent_returns_none() {
|
||||
let mut fs = mount_test_disk();
|
||||
assert!(fs.open(b"nope.txt").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_duplicate_returns_none() {
|
||||
let mut fs = mount_test_disk();
|
||||
fs.create(b"dup.txt").map(|h| fs.close(h));
|
||||
assert!(fs.create(b"dup.txt").is_none());
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
mod fat16;
|
||||
mod protocol;
|
||||
mod server;
|
||||
|
||||
Reference in New Issue
Block a user