| Crates.io | affs-read |
| lib.rs | affs-read |
| version | 0.3.1 |
| created_at | 2025-11-29 11:30:29.669925+00 |
| updated_at | 2025-12-03 10:20:22.778454+00 |
| description | A no_std compatible crate for reading Amiga Fast File System (AFFS) disk images |
| homepage | |
| repository | |
| max_upload_size | |
| id | 1956603 |
| size | 216,087 |
A no_std compatible Rust crate for reading Amiga Fast File System (AFFS) disk images.
no_std compatible - Works in embedded and bare-metal environmentsAdd to your Cargo.toml:
[dependencies]
affs-read = "0.1"
| Feature | Default | Description |
|---|---|---|
std |
Yes | Enables std::error::Error implementation |
alloc |
No | Enables features requiring heap allocation |
simd |
No | Enables SIMD-optimized checksum operations, adds wide and bytemuck |
wide |
No | Enables wide usage |
bytemuck |
No | Enables bytemuck usage |
For no_std environments:
[dependencies]
affs-read = { version = "0.1", default-features = false }
use affs_read::{AffsReader, BlockDevice};
// Implement BlockDevice for your storage medium
struct DiskImage {
data: Vec<u8>,
}
impl BlockDevice for DiskImage {
fn read_block(&self, block: u32, buf: &mut [u8; 512]) -> Result<(), ()> {
let offset = block as usize * 512;
if offset + 512 <= self.data.len() {
buf.copy_from_slice(&self.data[offset..offset + 512]);
Ok(())
} else {
Err(())
}
}
}
fn main() -> Result<(), affs_read::AffsError> {
let adf_data = std::fs::read("disk.adf").unwrap();
let device = DiskImage { data: adf_data };
// Create reader for standard DD floppy (880KB)
let reader = AffsReader::new(&device)?;
// Print disk information
println!("Disk: {:?}", reader.disk_name_str());
println!("Type: {:?}", reader.fs_type());
// List root directory
for entry in reader.read_root_dir() {
let entry = entry?;
if entry.is_file() {
println!("File: {} ({} bytes)",
entry.name_str().unwrap_or("?"),
entry.size);
} else {
println!("Dir: {}/", entry.name_str().unwrap_or("?"));
}
}
Ok(())
}
// Find and read a file
let entry = reader.find_path(b"s/startup-sequence")?;
let mut file = reader.read_file(entry.block)?;
// Read into buffer
let mut buffer = vec![0u8; entry.size as usize];
file.read_all(&mut buffer)?;
// Or read in chunks
let mut chunk = [0u8; 512];
while !file.is_eof() {
let n = file.read(&mut chunk)?;
// Process chunk[..n]
}
// Find a subdirectory
let subdir = reader.find_entry(reader.root_block(), b"devs")?;
// List its contents
for entry in reader.read_dir(subdir.block)? {
let entry = entry?;
println!("{}", entry.name_str().unwrap_or("?"));
}
// Or use path-based lookup
let deep_file = reader.find_path(b"libs/icon.library")?;
// Standard DD floppy (880KB, 1760 blocks)
let reader = AffsReader::new(&device)?;
// HD floppy (1.76MB, 3520 blocks)
let reader = AffsReader::new_hd(&device)?;
// Custom size (e.g., hard disk partition)
let reader = AffsReader::with_size(&device, num_blocks)?;
| Format | DOS Type | Description |
|---|---|---|
| OFS | DOS\0 | Original File System |
| FFS | DOS\1 | Fast File System |
| OFS+INTL | DOS\2 | OFS with international mode |
| FFS+INTL | DOS\3 | FFS with international mode |
| OFS+DC | DOS\4 | OFS with directory cache |
| FFS+DC | DOS\5 | FFS with directory cache |
All operations return Result<T, AffsError>:
use affs_read::AffsError;
match reader.find_path(b"nonexistent") {
Ok(entry) => println!("Found: {}", entry.name_str().unwrap()),
Err(AffsError::EntryNotFound) => println!("File not found"),
Err(AffsError::ChecksumMismatch) => println!("Disk corruption detected"),
Err(e) => println!("Error: {}", e),
}
This crate:
#![deny(unsafe_op_in_unsafe_fn)] for strict unsafe handlingRust 2024 edition (1.85+)
Licensed under the MIT License. See LICENSE for details.
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.