1#![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, 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 let mut b = Block::new();
123 self.find_dir(&mut x, &mut b, p, false)
124 }
125 #[inline]
126 pub fn dir_create(&'a self, path: impl AsRef<str>) -> Result<Directory<'a, B>, DeviceError> {
127 let mut x = DirectoryIndex::new(self);
128 let mut b: Block = Block::new();
129 self.find_dir(&mut x, &mut b, path.as_ref().as_bytes(), true)
130 }
131 #[inline]
132 pub fn file_open(&'a self, path: impl AsRef<str>, mode: u8) -> Result<File<'a, B>, DeviceError> {
133 self.open_inner(path.as_ref().as_bytes(), mode)
134 }
135
136 #[inline]
137 pub unsafe fn list_entry(&'a self, target: Option<&DirEntry>) -> Result<DirectoryIndex<'a, B>, DeviceError> {
138 let mut x = DirectoryIndex::new(self);
139 x.setup(target.and_then(|v| v.cluster()))?;
140 Ok(x)
141 }
142 #[inline]
143 pub unsafe fn file_entry(&'a self, name: impl AsRef<str>, parent: Option<&DirEntry>, mode: u8) -> Result<File<'a, B>, DeviceError> {
144 let mut x = DirectoryIndex::new(self);
145 let mut b = Block::new();
146 self.node_create_file(&mut x, &mut b, name.as_ref().as_bytes(), parent, mode)
147 }
148 pub unsafe fn dir_entry(&'a self, name: impl AsRef<str>, parent: Option<&DirEntry>, create: bool) -> Result<Directory<'a, B>, DeviceError> {
149 let p = parent.and_then(|v| v.cluster());
150 let mut x = DirectoryIndex::new(self);
151 x.setup(p)?;
152 let n = name.as_ref().as_bytes();
153 if let Some(e) = x.find(|e| e.eq(n))? {
154 return if e.is_directory() { Ok(Directory::new(e, self)) } else { Err(DeviceError::NotADirectory) };
155 }
156 if !create {
157 return Err(DeviceError::NotFound);
158 }
159 let mut b = Block::new();
160 Ok(Directory::new(self.node_create_dir(&mut b, n, p)?, self))
161 }
162
163 fn open_inner(&'a self, path: &[u8], mode: u8) -> Result<File<'a, B>, DeviceError> {
164 if !Mode::is_mode_valid(mode) {
165 return Err(DeviceError::InvalidOptions);
166 }
167 if path.is_empty() {
168 return Err(DeviceError::NotFound);
169 }
170 let mut x = DirectoryIndex::new(self);
171 let mut k = Block::new();
172 let i = match path.iter().rposition(|v| is_sep(*v)) {
174 Some(v) if v + 1 >= path.len() => return Err(DeviceError::NotAFile),
175 Some(v) => v,
176 None => return self.open_inner_file(&mut x, &mut k, path, mode),
177 };
178 let d = self.find_dir(&mut x, &mut k, &path[0..i], mode & Mode::CREATE != 0)?;
179 self.node_create_file(&mut x, &mut k, &path[i + 1..], Some(d.entry()), mode)
180 }
181 fn node_create_dir(&self, buf: &mut Block, name: &[u8], parent: Cluster) -> Result<DirEntry, DeviceError> {
182 let e = self.node_create(buf, name, 0x10, parent, true)?;
183 let i = self.man.block_pos(e.cluster());
184 let s = DirEntry::new_self(&e, i);
185 let p = DirEntry::new_parent(parent, i);
186 s.write_entry(&self.man.ver, buf);
187 p.write_entry(&self.man.ver, &mut buf[DIR_SIZE..]);
188 self.dev.write_single(&buf, i)?;
189 buf.clear();
190 for k in (i + 1)..=i + self.man.blocks.blocks_per_cluster() {
191 self.dev.write_single(&buf, k)?;
192 }
193 Ok(e)
194 }
195 fn node_create(&self, buf: &mut Block, name: &[u8], attrs: u8, parent: Cluster, alloc: bool) -> Result<DirEntry, DeviceError> {
196 let mut n = LongName::empty();
197 n.fill(name)?; let s = n.lfn_size() + 1;
199 let r = self.find_with(buf, s, parent, |_, b| b[0] == 0 || b[0] == 0xE5)?;
200 let (mut e, mut t) = (DirEntry::new(attrs, s - 1), 0u8);
201 e.fill(name); let mut w = BlockEntryIter::new(r.blocks());
203 for (_, i, l, o) in r {
204 if l && !w.in_scope(i) {
205 w.load_and_flush(self.dev, i)?;
206 }
207 let (b, v) = (w.buffer(i), o * DIR_SIZE);
208 if t + 0x1 == s {
209 e.write_prep(i, v);
210 if alloc {
211 e.allocate(self, buf)?;
212 }
213 e.write_entry(&self.man.ver, &mut b[v..]);
214 break;
215 }
216 e.write_lfn_entry(&n, t, s - 0x1, &mut b[v..]);
217 t += 0x1;
218 }
219 w.flush(self.dev)?;
220 Ok(e.into())
221 }
222 fn find_with(&self, buf: &mut Block, entries: u8, parent: Cluster, pred: fn(u32, &[u8]) -> bool) -> Result<Range, DeviceError> {
223 let mut t = self.man.entries_count(parent);
224 let mut k = parent.unwrap_or_else(|| self.man.root());
225 let (mut c, mut r) = (BlockCache::new(), Range::new());
226 'outer: loop {
227 let p = self.man.block_pos_at(k);
228 for i in p..=p + t {
229 self.dev.read_single(buf, i)?;
230 for e in 0..(Block::SIZE / DIR_SIZE) as u32 {
231 let x = e as usize * DIR_SIZE;
232 if !pred(i, &buf[x..x + DIR_SIZE]) {
233 r.clear();
234 continue;
235 }
236 if r.mark(k, i, e as u32) >= entries {
237 r.finish(k, i, e);
238 break 'outer;
239 }
240 }
241 }
242 c.clear();
243 k = match self.man.cluster_next(self.dev, buf, &mut c, k)? {
244 None => self.man.cluster_allocate(self.dev, buf, Some(k), true)?,
245 Some(v) => v,
246 };
247 t = self.man.blocks.blocks_per_cluster();
248 }
249 Ok(r)
250 }
251 #[inline]
252 fn open_inner_file(&'a self, x: &mut DirectoryIndex<'a, B>, buf: &mut Block, name: &[u8], mode: u8) -> Result<File<'a, B>, DeviceError> {
253 x.setup(None)?;
254 match x.find(|e| e.eq(name))? {
255 Some(e) if e.is_directory() => return Err(DeviceError::NotAFile),
256 Some(e) => Ok(File::new(e, mode, self)),
257 None if Mode::is_create(mode) => Ok(File::new(
258 self.node_create(buf, name, 0, None, false)?,
259 mode,
260 self,
261 )),
262 None => Err(DeviceError::NotFound),
263 }
264 }
265 fn find_dir(&'a self, x: &mut DirectoryIndex<'a, B>, buf: &mut Block, path: &[u8], makedirs: bool) -> Result<Directory<'a, B>, DeviceError> {
266 if path.is_empty() || (path.len() == 1 && is_sep(path[0])) {
267 return Ok(Directory::new(DirEntry::new_root(), self));
268 }
269 let mut p: Option<DirEntry> = None; let mut o: Option<DirEntry> = None; for (e, c) in PathIter::new(path) {
272 if e.len() == 2 && e[0] == b'.' && e[1] == b'.' {
273 (p, o) = (o, None);
276 continue;
277 }
278 let i = p.as_ref().and_then(|v| v.cluster());
279 x.setup(i)?;
280 o = p; p = match x.find(|v| v.eq(e))? {
282 Some(v) if v.is_file() => return Err(DeviceError::NotADirectory),
283 Some(v) if c => return Ok(Directory::new(v, self)),
284 Some(v) => Some(v),
285 None if makedirs && c => return Ok(Directory::new(self.node_create_dir(buf, e, i)?, self)),
286 None if makedirs => Some(self.node_create_dir(buf, e, i)?),
287 None => return Err(DeviceError::NotFound),
288 };
289 }
290 match p {
291 Some(v) => Ok(Directory::new(v, self)),
292 None => Err(DeviceError::NotFound),
293 }
294 }
295 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> {
296 if !Mode::is_mode_valid(mode) {
297 return Err(DeviceError::InvalidOptions);
298 }
299 let p = parent.and_then(|v| v.cluster());
300 x.setup(p)?;
301 match x.find(|e| e.eq(name))? {
302 Some(e) if e.is_directory() => Err(DeviceError::NotAFile),
303 Some(e) => {
304 let mut f = File::new(e, mode, self);
305 if mode & Mode::APPEND != 0 {
306 f.seek_to_end();
307 } else if mode & Mode::TRUNCATE != 0 {
308 let mut b = Block::new();
309 self.man.cluster_truncate(self.dev, &mut b, f.cluster_abs())?;
310 f.zero();
311 f.sync(self.dev, &mut b, &self.man.ver)?;
312 }
313 Ok(f)
314 },
315 None if Mode::is_create(mode) => Ok(File::new(
316 self.node_create(buf, name, 0, p, false)?,
317 mode,
318 self,
319 )),
320 None => Err(DeviceError::NotFound),
321 }
322 }
323}
324
325impl<'a> Iterator for PathIter<'a> {
326 type Item = (&'a [u8], bool);
327
328 fn next(&mut self) -> Option<(&'a [u8], bool)> {
329 if self.buf.is_empty() || self.pos >= self.buf.len() {
330 return None;
331 }
332 let (s, mut n) = (self.buf.len(), self.pos);
333 while n < s {
334 let (i, c) = match self.buf[n..].iter().position(|v| is_sep(*v)) {
335 Some(i) if i == 1 && self.buf[n] == b'.' => (i + 1, true),
336 Some(i) if i == 0 => (i + 1, true),
337 Some(i) => (i, false),
338 None => (s, false),
339 };
340 self.pos += i;
341 if !c {
342 return Some((&self.buf[n..cmp::min(self.pos, s)], self.pos >= s));
343 }
344 n += i;
345 }
346 None
347 }
348}
349
350#[inline(always)]
351fn is_sep(v: u8) -> bool {
352 v == b'\\' || v == b'/'
353}
354#[inline(always)]
355fn bp_footer(b: &Block) -> u16 {
356 le_u16(&b[510..])
357}
358#[inline]
359fn bp_fat_size(b: &Block) -> u32 {
360 let r = le_u16(&b[22..]) as u32;
361 if r > 0 { r } else { le_u32(&b[36..]) }
362}
363#[inline(always)]
364fn bp_fat32_info(b: &Block) -> u32 {
365 le_u16(&b[48..]) as u32
366}
367#[inline(always)]
368fn bp_fat_entries(b: &Block) -> u32 {
369 b[16] as u32
370}
371#[inline]
372fn bp_blocks_count(b: &Block) -> u32 {
373 let r = le_u16(&b[19..]) as u32;
374 if r > 0 { r } else { le_u32(&b[32..]) }
375}
376#[inline(always)]
377fn bp_root_entries(b: &Block) -> u32 {
378 le_u16(&b[17..]) as u32
379}
380#[inline(always)]
381fn bp_blocks_bytes(b: &Block) -> usize {
382 le_u16(&b[11..]) as usize
383}
384#[inline(always)]
385fn bp_blocks_reserved(b: &Block) -> u32 {
386 le_u16(&b[14..]) as u32
387}
388#[inline(always)]
389fn bp_blocks_in_cluster(b: &Block) -> u32 {
390 b[13] as u32
391}