inky_frame/fs/
volume.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;
23
24use core::cmp::{self, PartialEq};
25use core::convert::{AsRef, Into};
26use core::iter::Iterator;
27use core::option::Option::{self, None, Some};
28use core::result::Result::{self, Err, Ok};
29
30use crate::fs::volume::helpers::{Blocks, Manager};
31use crate::fs::{Block, BlockCache, BlockDevice, BlockEntryIter, Cache, DeviceError, Storage, le_u16, le_u32};
32
33mod file;
34mod helpers;
35mod iter;
36mod name;
37
38pub use self::file::*;
39pub use self::iter::*;
40pub use self::name::*;
41
42pub(super) const DIR_SIZE: usize = 0x20usize;
43
44pub enum FatVersion {
45    Fat16(u16),
46    Fat32(u32),
47}
48
49pub struct PathIter<'a> {
50    buf: &'a [u8],
51    pos: usize,
52}
53pub struct Volume<'a, B: BlockDevice> {
54    dev:  &'a Storage<B>,
55    man:  Manager,
56    name: VolumeName,
57}
58
59pub type Cluster = Option<u32>;
60
61impl<'a> PathIter<'a> {
62    #[inline(always)]
63    pub fn new(buf: &'a [u8]) -> PathIter<'a> {
64        PathIter { buf, pos: 0usize }
65    }
66}
67impl<'a, B: BlockDevice> Volume<'a, B> {
68    pub(super) fn parse(dev: &'a Storage<B>, mut b: Block, lba: u32, blocks: u32) -> Result<Volume<'a, B>, DeviceError> {
69        dev.read_single(&mut b, lba)?;
70        if bp_footer(&b) != 0xAA55 {
71            return Err(DeviceError::InvalidFileSystem);
72        }
73        let h = bp_root_entries(&b) * DIR_SIZE as u32;
74        let a = h / Block::SIZE as u32;
75        let n = (bp_blocks_count(&b) - (bp_blocks_reserved(&b) + (bp_fat_entries(&b) * bp_fat_size(&b)) + if a != h { a + 1 } else { a })) / bp_blocks_in_cluster(&b);
76        if n < 0xFF5 {
77            return Err(DeviceError::UnsupportedFileSystem);
78        }
79        let m = Manager::from_info(n, dev, &b, lba, Blocks::new(blocks, b[0xD]))?;
80        let n = VolumeName::from_slice(&m.ver, &b);
81        Ok(Volume { dev, man: m, name: n })
82    }
83
84    #[inline(always)]
85    pub fn name(&self) -> &str {
86        self.name.as_str()
87    }
88    #[inline(always)]
89    pub fn cluster_count(&self) -> u32 {
90        self.man.cluster_count()
91    }
92    #[inline(always)]
93    pub fn device(&self) -> &Storage<B> {
94        self.dev
95    }
96    #[inline(always)]
97    pub fn fat_version(&self) -> &FatVersion {
98        &self.man.ver
99    }
100    #[inline(always)]
101    pub fn dir_root(&'a self) -> Directory<'a, B> {
102        Directory::new(DirEntry::new_root(), self)
103    }
104    #[inline]
105    pub fn open(&'a self, path: impl AsRef<str>) -> Result<File<'a, B>, DeviceError> {
106        self.open_inner(path.as_ref().as_bytes(), Mode::READ)
107    }
108    #[inline]
109    pub fn file_create(&'a self, path: impl AsRef<str>) -> Result<File<'a, B>, DeviceError> {
110        self.open_inner(
111            path.as_ref().as_bytes(),
112            Mode::WRITE | Mode::CREATE | Mode::TRUNCATE,
113        )
114    }
115    #[inline]
116    pub fn dir_open(&'a self, path: impl AsRef<str>) -> Result<Directory<'a, B>, DeviceError> {
117        let p = path.as_ref().as_bytes();
118        if p.is_empty() || (p.len() == 1 && is_sep(p[0])) {
119            return Ok(Directory::new(DirEntry::new_root(), self));
120        }
121        let mut x: DirectoryIndex<'_, B> = DirectoryIndex::new(self);
122        {
123            let mut b = Cache::block_a();
124            self.find_dir(&mut x, &mut b, p, false)
125        }
126    }
127    #[inline]
128    pub fn dir_create(&'a self, path: impl AsRef<str>) -> Result<Directory<'a, B>, DeviceError> {
129        let mut x = DirectoryIndex::new(self);
130        {
131            let mut b = Cache::block_a();
132            self.find_dir(&mut x, &mut b, path.as_ref().as_bytes(), true)
133        }
134    }
135    #[inline]
136    pub fn file_open(&'a self, path: impl AsRef<str>, mode: u8) -> Result<File<'a, B>, DeviceError> {
137        self.open_inner(path.as_ref().as_bytes(), mode)
138    }
139
140    #[inline]
141    pub unsafe fn list_entry(&'a self, target: Option<&DirEntry>) -> Result<DirectoryIndex<'a, B>, DeviceError> {
142        let mut x = DirectoryIndex::new(self);
143        x.setup(target.and_then(|v| v.cluster()))?;
144        Ok(x)
145    }
146    #[inline]
147    pub unsafe fn file_entry(&'a self, name: impl AsRef<str>, parent: Option<&DirEntry>, mode: u8) -> Result<File<'a, B>, DeviceError> {
148        let mut x = DirectoryIndex::new(self);
149        {
150            let mut b = Cache::block_a();
151            self.node_create_file(&mut x, &mut b, name.as_ref().as_bytes(), parent, mode)
152        }
153    }
154    pub unsafe fn dir_entry(&'a self, name: impl AsRef<str>, parent: Option<&DirEntry>, create: bool) -> Result<Directory<'a, B>, DeviceError> {
155        let p = parent.and_then(|v| v.cluster());
156        let mut x = DirectoryIndex::new(self);
157        x.setup(p)?;
158        let n = name.as_ref().as_bytes();
159        if let Some(e) = x.find(|e| e.eq(n))? {
160            return if e.is_directory() { Ok(Directory::new(e, self)) } else { Err(DeviceError::NotADirectory) };
161        }
162        if !create {
163            return Err(DeviceError::NotFound);
164        }
165        {
166            let mut b = Cache::block_a();
167            Ok(Directory::new(self.node_create_dir(&mut b, n, p)?, self))
168        }
169    }
170
171    fn open_inner(&'a self, path: &[u8], mode: u8) -> Result<File<'a, B>, DeviceError> {
172        if !Mode::is_mode_valid(mode) {
173            return Err(DeviceError::InvalidOptions);
174        }
175        if path.is_empty() {
176            return Err(DeviceError::NotFound);
177        }
178        let mut x = DirectoryIndex::new(self);
179        {
180            let mut k = Cache::block_a();
181            // Split file into dirs and path.
182            let i = match path.iter().rposition(|v| is_sep(*v)) {
183                Some(v) if v + 1 >= path.len() => return Err(DeviceError::NotAFile),
184                Some(v) => v,
185                None => return self.open_inner_file(&mut x, &mut k, path, mode),
186            };
187            let d = self.find_dir(&mut x, &mut k, &path[0..i], mode & Mode::CREATE != 0)?;
188            self.node_create_file(&mut x, &mut k, &path[i + 1..], Some(d.entry()), mode)
189        }
190    }
191    fn node_create_dir(&self, buf: &mut Block, name: &[u8], parent: Cluster) -> Result<DirEntry, DeviceError> {
192        let e = self.node_create(buf, name, 0x10, parent, true)?;
193        let i = self.man.block_pos(e.cluster());
194        let s = DirEntry::new_self(&e, i);
195        let p = DirEntry::new_parent(parent, i);
196        // Write Parent and Self entries
197        s.write_entry(&self.man.ver, buf);
198        p.write_entry(&self.man.ver, &mut buf[DIR_SIZE..]);
199        self.dev.write_single(&buf, i)?;
200        buf.clear();
201        // Write empty blocks to create initial Directory space.
202        for k in (i + 1)..=i + self.man.blocks.blocks_per_cluster() {
203            self.dev.write_single(&buf, k)?;
204        }
205        Ok(e)
206    }
207    fn node_create(&self, buf: &mut Block, name: &[u8], attrs: u8, parent: Cluster, alloc: bool) -> Result<DirEntry, DeviceError> {
208        let mut n = LongName::empty();
209        n.fill(name)?; // Save stack allocations
210        let s = n.lfn_size() + 1;
211        let r = self.find_with(buf, s, parent, |_, b| b[0] == 0 || b[0] == 0xE5)?;
212        let (mut e, mut t) = (DirEntry::new(attrs, s - 1), 0u8);
213        e.fill(name); // Save stack allocations
214        let mut w = BlockEntryIter::new(r.blocks());
215        for (_, i, l, o) in r {
216            if l && !w.in_scope(i) {
217                w.load_and_flush(self.dev, i)?;
218            }
219            let (b, v) = (w.buffer(i), o * DIR_SIZE);
220            if t + 0x1 == s {
221                e.write_prep(i, v);
222                if alloc {
223                    e.allocate(self, buf)?;
224                }
225                e.write_entry(&self.man.ver, &mut b[v..]);
226                break;
227            }
228            e.write_lfn_entry(&n, t, s - 0x1, &mut b[v..]);
229            t += 0x1;
230        }
231        w.flush(self.dev)?;
232        Ok(e.into())
233    }
234    fn find_with(&self, buf: &mut Block, entries: u8, parent: Cluster, pred: fn(u32, &[u8]) -> bool) -> Result<Range, DeviceError> {
235        let mut t = self.man.entries_count(parent);
236        let mut k = parent.unwrap_or_else(|| self.man.root());
237        let (mut c, mut r) = (BlockCache::new(), Range::new());
238        'outer: loop {
239            let p = self.man.block_pos_at(k);
240            for i in p..=p + t {
241                self.dev.read_single(buf, i)?;
242                for e in 0..(Block::SIZE / DIR_SIZE) as u32 {
243                    let x = e as usize * DIR_SIZE;
244                    if !pred(i, &buf[x..x + DIR_SIZE]) {
245                        r.clear();
246                        continue;
247                    }
248                    if r.mark(k, i, e as u32) >= entries {
249                        r.finish(k, i, e);
250                        break 'outer;
251                    }
252                }
253            }
254            c.clear();
255            k = match self.man.cluster_next(self.dev, buf, &mut c, k)? {
256                None => self.man.cluster_allocate(self.dev, buf, Some(k), true)?,
257                Some(v) => v,
258            };
259            t = self.man.blocks.blocks_per_cluster();
260        }
261        Ok(r)
262    }
263    #[inline]
264    fn open_inner_file(&'a self, x: &mut DirectoryIndex<'a, B>, buf: &mut Block, name: &[u8], mode: u8) -> Result<File<'a, B>, DeviceError> {
265        x.setup(None)?;
266        match x.find(|e| e.eq(name))? {
267            Some(e) if e.is_directory() => return Err(DeviceError::NotAFile),
268            Some(e) => Ok(File::new(e, mode, self)),
269            None if Mode::is_create(mode) => Ok(File::new(
270                self.node_create(buf, name, 0, None, false)?,
271                mode,
272                self,
273            )),
274            None => Err(DeviceError::NotFound),
275        }
276    }
277    fn find_dir(&'a self, x: &mut DirectoryIndex<'a, B>, buf: &mut Block, path: &[u8], makedirs: bool) -> Result<Directory<'a, B>, DeviceError> {
278        if path.is_empty() || (path.len() == 1 && is_sep(path[0])) {
279            return Ok(Directory::new(DirEntry::new_root(), self));
280        }
281        let mut p: Option<DirEntry> = None; // Current Parent
282        let mut o: Option<DirEntry> = None; // Old Parent (for "../")
283        for (e, c) in PathIter::new(path) {
284            if e.len() == 2 && e[0] == b'.' && e[1] == b'.' {
285                // Swap out old parent to the current one, basically going "up"
286                // one directory.
287                (p, o) = (o, None);
288                continue;
289            }
290            let i = p.as_ref().and_then(|v| v.cluster());
291            x.setup(i)?;
292            o = p; // Set the current Parent as the old one before setting the new one.
293            p = match x.find(|v| v.eq(e))? {
294                Some(v) if v.is_file() => return Err(DeviceError::NotADirectory),
295                Some(v) if c => return Ok(Directory::new(v, self)),
296                Some(v) => Some(v),
297                None if makedirs && c => return Ok(Directory::new(self.node_create_dir(buf, e, i)?, self)),
298                None if makedirs => Some(self.node_create_dir(buf, e, i)?),
299                None => return Err(DeviceError::NotFound),
300            };
301        }
302        match p {
303            Some(v) => Ok(Directory::new(v, self)),
304            None => Err(DeviceError::NotFound),
305        }
306    }
307    fn node_create_file(&'a self, x: &mut DirectoryIndex<'a, B>, buf: &mut Block, name: &[u8], parent: Option<&DirEntry>, mode: u8) -> Result<File<'a, B>, DeviceError> {
308        if !Mode::is_mode_valid(mode) {
309            return Err(DeviceError::InvalidOptions);
310        }
311        let p = parent.and_then(|v| v.cluster());
312        x.setup(p)?;
313        match x.find(|e| e.eq(name))? {
314            Some(e) if e.is_directory() => Err(DeviceError::NotAFile),
315            Some(e) => {
316                let mut f = File::new(e, mode, self);
317                if mode & Mode::APPEND != 0 {
318                    f.seek_to_end();
319                } else if mode & Mode::TRUNCATE != 0 {
320                    self.man.cluster_truncate(self.dev, buf, f.cluster_abs())?;
321                    f.zero();
322                    f.sync(self.dev, buf, &self.man.ver)?;
323                }
324                Ok(f)
325            },
326            None if Mode::is_create(mode) => Ok(File::new(
327                self.node_create(buf, name, 0, p, false)?,
328                mode,
329                self,
330            )),
331            None => Err(DeviceError::NotFound),
332        }
333    }
334}
335
336impl<'a> Iterator for PathIter<'a> {
337    type Item = (&'a [u8], bool);
338
339    fn next(&mut self) -> Option<(&'a [u8], bool)> {
340        if self.buf.is_empty() || self.pos >= self.buf.len() {
341            return None;
342        }
343        let (s, mut n) = (self.buf.len(), self.pos);
344        while n < s {
345            let (i, c) = match self.buf[n..].iter().position(|v| is_sep(*v)) {
346                Some(i) if i == 1 && self.buf[n] == b'.' => (i + 1, true),
347                Some(i) if i == 0 => (i + 1, true),
348                Some(i) => (i, false),
349                None => (s, false),
350            };
351            self.pos += i;
352            if !c {
353                return Some((&self.buf[n..cmp::min(self.pos, s)], self.pos >= s));
354            }
355            n += i;
356        }
357        None
358    }
359}
360
361#[inline(always)]
362fn is_sep(v: u8) -> bool {
363    v == b'\\' || v == b'/'
364}
365#[inline(always)]
366fn bp_footer(b: &Block) -> u16 {
367    le_u16(&b[510..])
368}
369#[inline]
370fn bp_fat_size(b: &Block) -> u32 {
371    let r = le_u16(&b[22..]) as u32;
372    if r > 0 { r } else { le_u32(&b[36..]) }
373}
374#[inline(always)]
375fn bp_fat32_info(b: &Block) -> u32 {
376    le_u16(&b[48..]) as u32
377}
378#[inline(always)]
379fn bp_fat_entries(b: &Block) -> u32 {
380    b[16] as u32
381}
382#[inline]
383fn bp_blocks_count(b: &Block) -> u32 {
384    let r = le_u16(&b[19..]) as u32;
385    if r > 0 { r } else { le_u32(&b[32..]) }
386}
387#[inline(always)]
388fn bp_root_entries(b: &Block) -> u32 {
389    le_u16(&b[17..]) as u32
390}
391#[inline(always)]
392fn bp_blocks_bytes(b: &Block) -> usize {
393    le_u16(&b[11..]) as usize
394}
395#[inline(always)]
396fn bp_blocks_reserved(b: &Block) -> u32 {
397    le_u16(&b[14..]) as u32
398}
399#[inline(always)]
400fn bp_blocks_in_cluster(b: &Block) -> u32 {
401    b[13] as u32
402}