#![no_implicit_prelude]
extern crate core;
extern crate rpsp;
use core::cell::UnsafeCell;
use core::convert::From;
use core::fmt::{self, Debug, Formatter};
use core::result::Result::{self, Err};
use core::slice::{from_raw_parts, from_raw_parts_mut};
use rpsp::io;
use crate::Slice;
use crate::fs::{Block, Cache, Volume};
pub enum DeviceError {
Timeout,
NotAFile,
NotFound,
EndOfFile,
NotReadable,
NotWritable,
UnexpectedEoF,
NotADirectory,
NonEmptyDirectory,
Read,
Write,
BadData,
NoSpace,
Hardware(u8),
Overflow,
InvalidIndex,
InvalidOptions,
NameTooLong,
InvalidChain,
InvalidVolume,
InvalidCluster,
InvalidChecksum,
InvalidPartition,
InvalidFileSystem,
UnsupportedFileSystem,
UnsupportedVolume(u8),
}
pub struct Storage<B: BlockDevice> {
dev: UnsafeCell<B>,
}
pub trait BlockDevice {
fn blocks(&mut self) -> DevResult<u32>;
fn write(&mut self, b: &[Block], start: u32) -> DevResult<()>;
fn read(&mut self, b: &mut [Block], start: u32) -> DevResult<()>;
#[inline]
fn write_single(&mut self, b: &Block, start: u32) -> DevResult<()> {
let v = unsafe { from_raw_parts(b, 1) };
self.write(v, start)
}
#[inline]
fn read_single(&mut self, b: &mut Block, start: u32) -> DevResult<()> {
let v = unsafe { from_raw_parts_mut(b, 1) };
self.read(v, start)
}
}
pub type Error = io::Error<DeviceError>;
pub type DevError = io::Error<DeviceError>;
pub type DevResult<T> = Result<T, DeviceError>;
impl<B: BlockDevice> Storage<B> {
#[inline]
pub const fn new(dev: B) -> Storage<B> {
Storage { dev: UnsafeCell::new(dev) }
}
#[inline]
pub fn device(&self) -> &mut B {
unsafe { &mut *self.dev.get() }
}
#[inline]
pub fn root<'a>(&'a self) -> DevResult<Volume<'a, B>> {
self.volume(0)
}
#[inline]
pub fn write(&self, b: &[Block], start: u32) -> DevResult<()> {
self.device().write(b, start)
}
#[inline]
pub fn read(&self, b: &mut [Block], start: u32) -> DevResult<()> {
self.device().read(b, start)
}
#[inline]
pub fn write_single(&self, b: &Block, start: u32) -> DevResult<()> {
self.device().write_single(b, start)
}
#[inline]
pub fn read_single(&self, b: &mut Block, start: u32) -> DevResult<()> {
self.device().read_single(b, start)
}
#[inline]
pub fn volume<'a>(&'a self, index: usize) -> DevResult<Volume<'a, B>> {
if index > 3 {
return Err(DeviceError::NotFound);
}
let mut b = Cache::block_a();
let _ = self.read_single(&mut b, 0)?;
if b.read_u16(510) != 0xAA55 {
return Err(DeviceError::InvalidPartition);
}
let i = 0x1BE + (16 * index);
if i + 16 > Block::SIZE {
return Err(DeviceError::NotFound);
}
if b.read_u8(i) & 0x7F != 0 {
return Err(DeviceError::InvalidPartition);
}
match b.read_u8(i + 4) {
0x6 | 0xB | 0xE | 0xC | 0x16 | 0x1B | 0x1E | 0x66 | 0x76 | 0x83 | 0x92 | 0x97 | 0x98 | 0x9A | 0xD0 | 0xE4 | 0xE6 | 0xEF | 0xF4 | 0xF6 => (),
v => return Err(DeviceError::UnsupportedVolume(v)),
}
let (s, n) = (b.read_u32(i + 8), b.read_u32(i + 12));
Volume::new(self, &mut b, s, n)
}
}
impl Debug for DeviceError {
#[cfg(feature = "debug")]
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
DeviceError::Read => f.write_str("Read"),
DeviceError::Write => f.write_str("Write"),
DeviceError::Timeout => f.write_str("Timeout"),
DeviceError::NotAFile => f.write_str("NotAFile"),
DeviceError::NotFound => f.write_str("NotFound"),
DeviceError::EndOfFile => f.write_str("EndOfFile"),
DeviceError::NotReadable => f.write_str("NotReadable"),
DeviceError::NotWritable => f.write_str("NotWritable"),
DeviceError::UnexpectedEoF => f.write_str("UnexpectedEoF"),
DeviceError::NotADirectory => f.write_str("NotADirectory"),
DeviceError::NonEmptyDirectory => f.write_str("NonEmptyDirectory"),
DeviceError::BadData => f.write_str("BadData"),
DeviceError::NoSpace => f.write_str("NoSpace"),
DeviceError::Hardware(v) => f.debug_tuple("Hardware").field(v).finish(),
DeviceError::Overflow => f.write_str("Overflow"),
DeviceError::InvalidIndex => f.write_str("InvalidIndex"),
DeviceError::InvalidOptions => f.write_str("InvalidOptions"),
DeviceError::NameTooLong => f.write_str("NameTooLong"),
DeviceError::InvalidChain => f.write_str("InvalidChain"),
DeviceError::InvalidVolume => f.write_str("InvalidVolume"),
DeviceError::InvalidCluster => f.write_str("InvalidCluster"),
DeviceError::InvalidChecksum => f.write_str("InvalidChecksum"),
DeviceError::InvalidPartition => f.write_str("InvalidPartition"),
DeviceError::InvalidFileSystem => f.write_str("InvalidFileSystem"),
DeviceError::UnsupportedVolume(v) => f.debug_tuple("UnsupportedVolume").field(v).finish(),
DeviceError::UnsupportedFileSystem => f.write_str("UnsupportedFileSystem"),
}
}
#[cfg(not(feature = "debug"))]
#[inline]
fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {
Result::Ok(())
}
}
impl From<DeviceError> for DevError {
#[inline]
fn from(v: DeviceError) -> DevError {
match v {
DeviceError::Read => Error::Read,
DeviceError::Write => Error::Write,
DeviceError::NoSpace => Error::NoSpace,
DeviceError::Timeout => Error::Timeout,
DeviceError::Overflow => Error::Overflow,
DeviceError::NotAFile => Error::NotAFile,
DeviceError::NotFound => Error::NotFound,
DeviceError::EndOfFile => Error::EndOfFile,
DeviceError::NotReadable => Error::NotReadable,
DeviceError::NotWritable => Error::NotWritable,
DeviceError::InvalidIndex => Error::InvalidIndex,
DeviceError::NotADirectory => Error::NotADirectory,
DeviceError::UnexpectedEoF => Error::UnexpectedEof,
DeviceError::InvalidOptions => Error::InvalidOptions,
DeviceError::NonEmptyDirectory => Error::NonEmptyDirectory,
_ => Error::Other(v),
}
}
}