inky_frame/fs/
device.rs

1// Permission is hereby granted, free of charge, to any person obtaining a copy
2// of this software and associated documentation files (the "Software"), to deal
3// in the Software without restriction, including without limitation the rights
4// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5// copies of the Software, and to permit persons to whom the Software is
6// furnished to do so, subject to the following conditions:
7//
8// The above copyright notice and this permission notice shall be included in
9// all copies or substantial portions of the Software.
10//
11// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17// SOFTWARE.
18//
19
20#![no_implicit_prelude]
21
22extern crate core;
23extern crate rpsp;
24
25use core::cell::UnsafeCell;
26use core::convert::From;
27use core::default::Default;
28use core::fmt::{self, Debug, Formatter};
29use core::result::Result::{self, Err};
30use core::slice::{from_raw_parts, from_raw_parts_mut};
31
32use rpsp::io;
33
34use crate::fs::{Block, Volume};
35
36const PART_START: usize = 0x1BEusize;
37
38pub enum DeviceError {
39    // Standard IO Errors
40    Timeout,
41    NotAFile,
42    NotFound,
43    EndOfFile,
44    NotReadable,
45    NotWritable,
46    UnexpectedEoF,
47    NotADirectory,
48    NonEmptyDirectory,
49
50    // Hardware-ish/Io Errors
51    Read,
52    Write,
53    BadData,
54    NoSpace,
55    Hardware(u8),
56
57    // Validation Errors
58    Overflow,
59    InvalidIndex,
60    InvalidOptions,
61
62    // FileSystem Errors
63    NameTooLong,
64    InvalidChain,
65    InvalidVolume,
66    InvalidCluster,
67    InvalidChecksum,
68    InvalidPartition,
69    InvalidFileSystem,
70    UnsupportedVolume(u8),
71    UnsupportedFileSystem,
72}
73
74pub struct Storage<B: BlockDevice> {
75    dev: UnsafeCell<B>,
76}
77
78pub type Error = io::Error<DeviceError>;
79
80pub trait BlockDevice {
81    fn blocks(&mut self) -> Result<u32, DeviceError>;
82    fn write(&mut self, b: &[Block], start: u32) -> Result<(), DeviceError>;
83    fn read(&mut self, b: &mut [Block], start: u32) -> Result<(), DeviceError>;
84
85    #[inline]
86    fn write_single(&mut self, b: &Block, start: u32) -> Result<(), DeviceError> {
87        let v = unsafe { from_raw_parts(b, 1) };
88        self.write(v, start)
89    }
90    #[inline]
91    fn read_single(&mut self, b: &mut Block, start: u32) -> Result<(), DeviceError> {
92        let v = unsafe { from_raw_parts_mut(b, 1) };
93        self.read(v, start)
94    }
95}
96
97impl<B: BlockDevice> Storage<B> {
98    #[inline(always)]
99    pub fn new(dev: B) -> Storage<B> {
100        Storage { dev: UnsafeCell::new(dev) }
101    }
102
103    #[inline(always)]
104    pub fn device(&self) -> &mut B {
105        unsafe { &mut *self.dev.get() }
106    }
107    #[inline(always)]
108    pub fn root<'a>(&'a self) -> Result<Volume<'a, B>, DeviceError> {
109        self.volume(0)
110    }
111    pub fn volume<'a>(&'a self, index: usize) -> Result<Volume<'a, B>, DeviceError> {
112        if index > 3 {
113            return Err(DeviceError::NotFound);
114        }
115        let mut b = Block::default();
116        self.read_single(&mut b, 0)?;
117        if le_u16(&b[0x1FE..]) != 0xAA55 {
118            return Err(DeviceError::InvalidPartition);
119        }
120        let i = PART_START + (0x10 * index);
121        if i + 12 > Block::SIZE {
122            return Err(DeviceError::NotFound);
123        }
124        if b[i] & 0x7F != 0 {
125            return Err(DeviceError::InvalidPartition);
126        }
127        match b[i + 4] {
128            // NOTE(sf): All these types could have FAT volumes. We'll work it
129            // out after, but we can at least take on more types.
130            0x6 | 0xB | 0xE | 0xC | 0x16 | 0x1B | 0x1E | 0x66 | 0x76 | 0x83 | 0x92 | 0x97 | 0x98 | 0x9A | 0xD0 | 0xE4 | 0xE6 | 0xEF | 0xF4 | 0xF6 => (),
131            _ => return Err(DeviceError::UnsupportedVolume(b[i + 4])),
132        }
133        let (s, n) = (le_u32(&b[i + 8..]), le_u32(&b[i + 12..]));
134        Volume::parse(self, b, s, n)
135    }
136
137    #[inline(always)]
138    pub(super) fn write(&self, b: &[Block], start: u32) -> Result<(), DeviceError> {
139        self.device().write(b, start)
140    }
141    #[inline(always)]
142    pub(super) fn read(&self, b: &mut [Block], start: u32) -> Result<(), DeviceError> {
143        self.device().read(b, start)
144    }
145    #[inline(always)]
146    pub(super) fn write_single(&self, b: &Block, start: u32) -> Result<(), DeviceError> {
147        self.device().write_single(b, start)
148    }
149    #[inline(always)]
150    pub(super) fn read_single(&self, b: &mut Block, start: u32) -> Result<(), DeviceError> {
151        self.device().read_single(b, start)
152    }
153}
154
155impl From<DeviceError> for Error {
156    #[inline]
157    fn from(v: DeviceError) -> Error {
158        match v {
159            DeviceError::Read => Error::Read,
160            DeviceError::Write => Error::Write,
161            DeviceError::Timeout => Error::Timeout,
162            DeviceError::EndOfFile => Error::EndOfFile,
163            DeviceError::UnexpectedEoF => Error::UnexpectedEof,
164            DeviceError::NoSpace => Error::NoSpace,
165            DeviceError::NotAFile => Error::NotAFile,
166            DeviceError::NotFound => Error::NotFound,
167            DeviceError::Overflow => Error::Overflow,
168            DeviceError::NotReadable => Error::NotReadable,
169            DeviceError::NotWritable => Error::NotWritable,
170            DeviceError::NotADirectory => Error::NotADirectory,
171            DeviceError::NonEmptyDirectory => Error::NonEmptyDirectory,
172            DeviceError::InvalidIndex => Error::InvalidIndex,
173            DeviceError::InvalidOptions => Error::InvalidOptions,
174            _ => Error::Other(v),
175        }
176    }
177}
178
179#[cfg(feature = "debug")]
180impl Debug for DeviceError {
181    #[inline]
182    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
183        match self {
184            DeviceError::Read => f.write_str("Read"),
185            DeviceError::Write => f.write_str("Write"),
186            DeviceError::Timeout => f.write_str("Timeout"),
187            DeviceError::NotAFile => f.write_str("NotAFile"),
188            DeviceError::NotFound => f.write_str("NotFound"),
189            DeviceError::EndOfFile => f.write_str("EndOfFile"),
190            DeviceError::NotReadable => f.write_str("NotReadable"),
191            DeviceError::NotWritable => f.write_str("NotWritable"),
192            DeviceError::UnexpectedEoF => f.write_str("UnexpectedEoF"),
193            DeviceError::NotADirectory => f.write_str("NotADirectory"),
194            DeviceError::NonEmptyDirectory => f.write_str("NonEmptyDirectory"),
195            DeviceError::BadData => f.write_str("BadData"),
196            DeviceError::NoSpace => f.write_str("NoSpace"),
197            DeviceError::Hardware(v) => f.debug_tuple("Hardware").field(v).finish(),
198            DeviceError::Overflow => f.write_str("Overflow"),
199            DeviceError::InvalidIndex => f.write_str("InvalidIndex"),
200            DeviceError::InvalidOptions => f.write_str("InvalidOptions"),
201            DeviceError::NameTooLong => f.write_str("NameTooLong"),
202            DeviceError::InvalidChain => f.write_str("InvalidChain"),
203            DeviceError::InvalidVolume => f.write_str("InvalidVolume"),
204            DeviceError::InvalidCluster => f.write_str("InvalidCluster"),
205            DeviceError::InvalidChecksum => f.write_str("InvalidChecksum"),
206            DeviceError::InvalidPartition => f.write_str("InvalidPartition"),
207            DeviceError::InvalidFileSystem => f.write_str("InvalidFileSystem"),
208            DeviceError::UnsupportedVolume(v) => f.debug_tuple("UnsupportedVolume").field(v).finish(),
209            DeviceError::UnsupportedFileSystem => f.write_str("UnsupportedFileSystem"),
210        }
211    }
212}
213#[cfg(not(feature = "debug"))]
214impl Debug for DeviceError {
215    #[inline(always)]
216    fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {
217        Result::Ok(())
218    }
219}
220
221#[inline(always)]
222pub(super) fn le_u16(b: &[u8]) -> u16 {
223    (b[0] as u16) | (b[1] as u16) << 8
224}
225#[inline(always)]
226pub(super) fn le_u32(b: &[u8]) -> u32 {
227    (b[0] as u32) | (b[1] as u32) << 8 | (b[2] as u32) << 16 | (b[3] as u32) << 24
228}
229#[inline]
230pub(super) fn to_le_u16(v: u16, b: &mut [u8]) {
231    b[0] = v as u8;
232    b[1] = (v >> 8) as u8;
233}
234#[inline]
235pub(super) fn to_le_u32(v: u32, b: &mut [u8]) {
236    b[0] = v as u8;
237    b[1] = (v >> 8) as u8;
238    b[2] = (v >> 16) as u8;
239    b[3] = (v >> 24) as u8;
240}