1#![no_implicit_prelude]
21
22extern crate core;
23extern crate rpsp;
24
25use core::cmp::PartialEq;
26use core::convert::{AsRef, Into, TryInto};
27use core::marker::PhantomData;
28use core::mem::{drop, transmute};
29use core::ops::{Deref, Drop};
30use core::option::Option::{None, Some};
31use core::result::Result::{self, Err, Ok};
32use core::{cmp, matches, mem};
33
34use rpsp::ignore_error;
35use rpsp::io::{Read, Seek, SeekFrom, Write};
36use rpsp::time::{Time, Weekday};
37
38use crate::fs::state::{Safe, Unsafe};
39use crate::fs::{Block, BlockCache, BlockDevice, BlockPtr, Cache, Cluster, DIR_SIZE, DeviceError, DirectoryIndex, Error, FatVersion, LongName, LongNamePtr, ShortName, Storage, Volume, le_u16, le_u32, to_le_u16, to_le_u32};
40
41const FILE_MAX_SIZE: u32 = 0xFFFFFFFFu32;
42
43pub enum Mode {}
44
45pub struct DirEntry {
46 name: ShortName,
47 lfn: u8,
48 size: u32,
49 attrs: u8,
50 block: u32,
51 offset: u32,
52 created: Time,
53 cluster: Cluster,
54 modified: Time,
55}
56pub struct DirEntryFull {
57 lfn: LongNamePtr,
58 sum: u8,
59 entry: DirEntry,
60}
61pub struct Reader<'a, B: BlockDevice> {
62 f: File<'a, B, Unsafe>,
63 bp: u32,
64 buf: BlockPtr,
65}
66pub struct Directory<'a, B: BlockDevice> {
67 vol: &'a Volume<'a, B>,
68 dir: DirEntry,
69}
70pub struct File<'a, B: BlockDevice, S: FileSync = Safe> {
71 vol: &'a Volume<'a, B>,
72 pos: u32,
73 file: DirEntry,
74 last: u32,
75 mode: u8,
76 short: u32,
77 _p: PhantomData<*const S>,
78}
79
80pub trait FileSync {
81 fn cache() -> BlockPtr;
82}
83
84impl Mode {
85 pub const READ: u8 = 0x0u8;
86 pub const WRITE: u8 = 0x1u8;
87 pub const CREATE: u8 = 0x2u8;
88 pub const APPEND: u8 = 0x4u8;
89 pub const TRUNCATE: u8 = 0x8u8;
90
91 #[inline(always)]
92 pub(super) fn is_create(m: u8) -> bool {
93 m & Mode::CREATE != 0 && (m & Mode::WRITE != 0 || m & Mode::APPEND != 0)
94 }
95 #[inline(always)]
96 pub(super) fn is_mode_valid(m: u8) -> bool {
97 if (m >> 4) > 0 || m & (Mode::TRUNCATE | Mode::APPEND) == 0x12 || m == Mode::CREATE {
98 false
99 } else {
100 true
101 }
102 }
103}
104impl DirEntry {
105 #[inline]
106 pub(super) fn new_root() -> DirEntry {
107 DirEntry {
108 lfn: 0,
109 name: ShortName::empty(),
110 size: 0u32,
111 block: 0u32,
112 attrs: 0x10u8,
113 offset: 0u32,
114 created: Time::empty(),
115 cluster: None,
116 modified: Time::empty(),
117 }
118 }
119 #[inline]
120 pub(super) fn new(attrs: u8, lfn: u8) -> DirEntry {
121 DirEntry {
122 lfn,
123 attrs,
124 name: ShortName::empty(),
125 size: 0u32,
126 block: 0u32,
127 offset: 0u32,
128 created: Time::empty(),
129 cluster: Some(0),
130 modified: Time::empty(),
131 }
132 }
133 #[inline]
134 pub(super) fn new_self(parent: &DirEntry, block: u32) -> DirEntry {
135 DirEntry {
136 block,
137 lfn: 0u8,
138 name: ShortName::SELF,
139 size: 0u32,
140 attrs: 0x10u8,
141 offset: 0u32,
142 created: Time::empty(),
143 cluster: parent.cluster,
144 modified: Time::empty(),
145 }
146 }
147 #[inline]
148 pub(super) fn new_parent(cluster: Cluster, block: u32) -> DirEntry {
149 DirEntry {
150 block,
151 cluster,
152 lfn: 0u8,
153 name: ShortName::PARENT,
154 size: 0u32,
155 attrs: 0x10u8,
156 offset: 0x20u32,
157 created: Time::empty(),
158 modified: Time::empty(),
159 }
160 }
161
162 #[inline(always)]
163 pub fn size(&self) -> u32 {
164 self.size
165 }
166 #[inline(always)]
167 pub fn name(&self) -> &str {
168 self.name.as_str()
169 }
170 #[inline(always)]
171 pub fn offset(&self) -> u32 {
172 self.offset
173 }
174 #[inline(always)]
175 pub fn is_file(&self) -> bool {
176 !self.is_directory()
177 }
178 #[inline(always)]
179 pub fn created(&self) -> &Time {
180 &self.created
181 }
182 #[inline(always)]
183 pub fn attributes(&self) -> u8 {
184 self.attrs
185 }
186 #[inline(always)]
187 pub fn modified(&self) -> &Time {
188 &self.modified
189 }
190 #[inline(always)]
191 pub fn cluster(&self) -> Cluster {
192 self.cluster
193 }
194 #[inline(always)]
195 pub fn is_directory(&self) -> bool {
196 self.attrs & 0x10 == 0x10
197 }
198 #[inline(always)]
199 pub fn filename(&self) -> &ShortName {
200 &self.name
201 }
202 #[inline(always)]
203 pub fn set_created(&mut self, t: Time) {
204 self.created = t
205 }
206 #[inline(always)]
207 pub fn set_modified(&mut self, t: Time) {
208 self.modified = t
209 }
210 #[inline(always)]
211 pub fn set_attributes(&mut self, a: u8) {
212 self.attrs = a
213 }
214 #[inline]
215 pub fn into_dir<'a, B: BlockDevice>(self, vol: &'a Volume<B>) -> Result<Directory<'a, B>, DeviceError> {
216 if !self.is_directory() {
217 return Err(DeviceError::NotADirectory);
218 }
219 Ok(Directory::new(self, vol))
220 }
221 #[inline]
222 pub fn into_file<'a, B: BlockDevice>(self, vol: &'a Volume<B>, mode: u8) -> Result<File<'a, B>, DeviceError> {
223 if !Mode::is_mode_valid(mode) {
224 return Err(DeviceError::InvalidOptions);
225 }
226 if !self.is_file() {
227 return Err(DeviceError::NotAFile);
228 }
229 Ok(File::new(self, mode, vol))
230 }
231
232 #[inline(always)]
233 pub(super) fn fill(&mut self, v: &[u8]) {
234 self.name.fill(v);
235 }
236 #[inline(always)]
237 pub(super) fn cluster_abs(&self) -> u32 {
238 self.cluster.unwrap_or(0xFFFFFFFC)
239 }
240 #[inline]
241 pub(super) fn is_root_or_parent(&self) -> bool {
242 match self.cluster {
243 Some(v) if v == 0xFFFFFFFC => return true,
244 None => return true,
245 _ => (),
246 }
247 self.name.0.is_empty() || self.name.is_self() || self.name.is_parent()
248 }
249 #[inline(always)]
250 pub(super) fn write_prep(&mut self, block: u32, offset: usize) {
251 self.block = block;
252 self.offset = offset as u32;
253 }
254 pub(super) fn write_entry(&self, f: &FatVersion, b: &mut [u8]) {
255 b[0..ShortName::SIZE].copy_from_slice(&self.name.as_bytes());
256 b[11] = self.attrs;
257 b[12] = 0;
258 b[13] = 0;
259 time_write(&self.created, &mut b[14..]);
260 let c = self.cluster_abs();
261 match f {
262 FatVersion::Fat16(_) => (b[20], b[21]) = (0, 0),
263 FatVersion::Fat32(_) => to_le_u16(((c >> 16) & 0xFFFF) as u16, &mut b[20..]),
264 }
265 time_write(&self.modified, &mut b[22..]);
266 to_le_u16((c & 0xFFFF) as u16, &mut b[26..]);
267 to_le_u32(self.size, &mut b[28..])
268 }
269 pub(super) fn write_lfn_entry(&self, lfn: &LongName, pos: u8, s: u8, b: &mut [u8]) {
270 let (n, c) = (lfn.len(), self.name.checksum());
271 b[0..DIR_SIZE].fill(0);
272 b[0] = if pos == 0 { 0x40 } else { 0 } | (s - pos) as u8;
273 b[0xB] = 0xF;
274 b[0xD] = c;
275 let (s, mut p) = ((s - 1 - pos) as usize * 0xD, 0);
276 for v in s..cmp::min(s + 0xD, n) {
277 b[LongName::pos_to_lfn(p)] = lfn.0[v];
278 p += 1;
279 }
280 if p < 0xC {
282 b[LongName::pos_to_lfn(p + 1)] = 0;
283 p += 1;
284 }
285 if p < 0xC {
287 for x in LongName::pos_to_lfn(p)..DIR_SIZE {
288 match x {
289 0 | 0xB | 0xC | 0xD | 0x1A | 0x1B => continue,
290 _ => (),
291 }
292 b[x] = 0xFF
293 }
294 }
295 }
296 pub(super) fn delete(&self, vol: &Volume<impl BlockDevice>, scratch: &mut Block) -> Result<(), DeviceError> {
297 vol.dev.read_single(scratch, self.block)?;
298 if self.offset as usize > Block::SIZE {
299 return Err(DeviceError::BadData);
300 }
301 scratch[self.offset as usize] = 0xE5;
302 if self.lfn == 0 {
303 return vol.dev.write_single(scratch, self.block);
304 }
305 let n = self.lfn as u32 * DIR_SIZE as u32;
308 if n > self.offset {
309 return vol.dev.write_single(scratch, self.block);
310 }
311 let mut i = self.offset.saturating_sub(n) as usize;
312 while i < self.offset as usize {
313 scratch[i..i + DIR_SIZE].fill(0);
314 i += DIR_SIZE;
315 }
316 vol.dev.write_single(scratch, self.block)?;
317 if let Some(v) = self.cluster {
318 vol.man.cluster_truncate(vol.dev, scratch, v)?;
319 }
320 Ok(())
321 }
322 #[inline(always)]
323 pub(super) fn allocate(&mut self, vol: &Volume<impl BlockDevice>, scratch: &mut Block) -> Result<(), DeviceError> {
324 self.cluster = Some(vol.man.cluster_allocate(vol.dev, scratch, None, false)?);
325 Ok(())
326 }
327 #[inline]
328 pub(super) fn sync(&self, dev: &Storage<impl BlockDevice>, scratch: &mut Block, f: &FatVersion) -> Result<(), DeviceError> {
329 dev.read_single(scratch, self.block)?;
330 if self.offset as usize > Block::SIZE {
331 return Err(DeviceError::BadData);
332 }
333 self.write_entry(f, &mut scratch[self.offset as usize..]);
334 dev.write_single(scratch, self.block)
335 }
336}
337impl DirEntryFull {
338 #[inline]
339 pub(super) fn new() -> DirEntryFull {
340 DirEntryFull {
341 lfn: Cache::lfn(),
342 sum: 0u8,
343 entry: DirEntry::new(0, 0),
344 }
345 }
346
347 #[inline]
348 pub fn name(&self) -> &str {
349 if self.entry.lfn == 0 || self.lfn.is_empty() {
350 self.entry.name.as_str()
351 } else {
352 self.lfn.as_str()
353 }
354 }
355 #[inline(always)]
356 pub fn longname(&self) -> &LongName {
357 &self.lfn
358 }
359 #[inline(always)]
360 pub fn is_name(&self, v: &str) -> bool {
361 self.eq(v)
362 }
363
364 #[inline]
365 pub(super) fn reset(&mut self) {
366 self.lfn.reset();
367 self.sum = 0;
368 self.entry.lfn = 0;
369 }
370 #[inline(always)]
371 pub(super) fn fill(&mut self, b: &[u8]) {
372 self.sum = self.lfn.fill_lfn(b)
373 }
374 #[inline]
375 pub(super) fn entry(&mut self) -> DirEntry {
376 let mut n = DirEntry::new(0, 0);
377 mem::swap(&mut self.entry, &mut n);
378 n
379 }
380 pub(super) fn load(&mut self, f: &FatVersion, b: &[u8], block: u32, offset: u32) {
381 let v = if matches!(f, FatVersion::Fat32(_)) {
382 (le_u16(&b[20..]) as u32) << 16 | le_u16(&b[26..]) as u32
383 } else {
384 le_u16(&b[26..]) as u32
385 };
386 self.entry.lfn = self.lfn.lfn_size();
387 self.entry.name.fill_inner(b);
388 if self.sum != self.entry.name.checksum() {
389 self.lfn.reset();
390 self.entry.lfn = 0;
391 }
392 self.entry.block = block;
393 self.entry.offset = offset;
394 self.entry.size = le_u32(&b[28..]);
395 self.entry.attrs = b[11];
396 self.entry.created = time_read(le_u16(&b[16..]), le_u16(&b[14..]));
397 self.entry.cluster = if v == 0 && b[11] & 0x10 == 0x10 { None } else { Some(v) };
398 self.entry.modified = time_read(le_u16(&b[24..]), le_u16(&b[22..]));
399 }
400}
401impl<'a, B: BlockDevice> File<'a, B> {
402 #[inline(always)]
403 pub(super) fn new(file: DirEntry, mode: u8, vol: &'a Volume<'a, B>) -> File<'a, B, Safe> {
404 File {
405 last: file.cluster_abs(),
406 vol,
407 file,
408 mode,
409 pos: 0u32,
410 short: 0u32,
411 _p: PhantomData,
412 }
413 }
414}
415impl<'a, B: BlockDevice> Reader<'a, B> {
416 #[inline(always)]
417 pub fn cursor(&self) -> usize {
418 self.f.pos as usize
419 }
420 #[inline(always)]
421 pub fn available(&self) -> usize {
422 self.f.file.size.saturating_sub(self.f.pos) as usize
423 }
424 #[inline(always)]
425 pub fn volume(&self) -> &Volume<'a, B> {
426 self.f.vol
427 }
428 #[inline(always)]
429 pub fn into_file(self) -> File<'a, B, Unsafe> {
430 drop(self.buf);
431 self.f
432 }
433 pub fn read(&mut self, b: &mut [u8]) -> Result<usize, DeviceError> {
438 if b.is_empty() {
439 return Ok(0);
440 }
441 let (mut p, t) = (0, b.len());
442 let (d, mut c) = (&mut *self.buf, BlockCache::new());
443 while p < t && self.f.pos < self.f.file.size {
444 let (i, o, a) = match self.f.data(d, &mut c) {
445 Err(DeviceError::EndOfFile) => return Ok(p),
446 Err(e) => return Err(e),
447 Ok(v) => v,
448 };
449 if self.bp == 0 || self.bp != i {
450 self.f.vol.dev.read_single(d, i)?;
453 self.bp = i;
454 }
455 let n = cmp::min(cmp::min(a, t - p), self.f.available());
456 if n == 0 {
457 break;
458 }
459 b[p..p + n].copy_from_slice(&d[o..o + n]);
460 self.f.pos = self.f.pos.saturating_add(n as u32);
461 p = p.saturating_add(n);
462 }
463 Ok(p)
464 }
465}
466impl<'a, B: BlockDevice> Directory<'a, B> {
467 #[inline(always)]
468 pub(super) fn new(dir: DirEntry, vol: &'a Volume<'a, B>) -> Directory<'a, B> {
469 Directory { vol, dir }
470 }
471
472 #[inline(always)]
473 pub fn volume(&self) -> &Volume<'a, B> {
474 self.vol
475 }
476 #[inline]
477 pub fn delete(self, force: bool) -> Result<(), DeviceError> {
478 let mut b = Cache::block_a();
479 Directory::delete_inner(self.vol, &self.dir, &mut b, force)
480 }
481 #[inline(always)]
482 pub fn list(&self) -> Result<DirectoryIndex<'a, B>, DeviceError> {
483 unsafe { self.vol.list_entry(Some(&self.dir)) }
485 }
486 #[inline]
487 pub fn file(&'a self, name: impl AsRef<str>, mode: u8) -> Result<File<'a, B>, DeviceError> {
488 unsafe { self.vol.file_entry(name, Some(&self.dir), mode) }
490 }
491 #[inline]
492 pub fn dir(&'a self, name: impl AsRef<str>, create: bool) -> Result<Directory<'a, B>, DeviceError> {
493 unsafe { self.vol.dir_entry(name, Some(&self.dir), create) }
495 }
496
497 #[inline(always)]
498 pub(super) fn entry(&self) -> &DirEntry {
499 &self.dir
500 }
501 #[inline(always)]
502 pub(super) fn cluster(&self) -> Cluster {
503 self.dir.cluster
504 }
505
506 fn delete_inner(vol: &'a Volume<'a, B>, dir: &DirEntry, scratch: &mut Block, force: bool) -> Result<(), DeviceError> {
507 for e in unsafe { vol.list_entry(Some(dir))? } {
511 if !force {
512 return Err(DeviceError::NonEmptyDirectory);
513 }
514 let v = e?;
515 if v.is_root_or_parent() {
516 break;
520 }
521 if v.is_directory() {
522 Directory::delete_inner(vol, &v, scratch, force)?;
523 } else {
524 v.delete(vol, scratch)?;
525 }
526 }
527 dir.delete(vol, scratch)?;
528 vol.man.cluster_truncate(vol.dev, scratch, dir.cluster_abs())
529 }
530}
531impl<'a, B: BlockDevice> File<'a, B, Safe> {
532 #[inline(always)]
533 pub unsafe fn into_unsafe(self) -> File<'a, B, Unsafe> {
538 unsafe { transmute(self) }
539 }
540 #[inline(always)]
541 pub unsafe fn into_reader(self) -> Result<Reader<'a, B>, DeviceError> {
544 if !self.is_readable() {
545 return Err(DeviceError::NotReadable);
546 }
547 Ok(Reader {
548 f: unsafe { self.into_unsafe() },
549 bp: 0u32,
550 buf: Cache::block_a(),
551 })
552 }
553}
554impl<'a, B: BlockDevice> File<'a, B, Unsafe> {
555 #[inline(always)]
556 pub fn into_safe(self) -> File<'a, B, Safe> {
557 unsafe { transmute(self) }
558 }
559}
560impl<'a, B: BlockDevice, S: FileSync> File<'a, B, S> {
561 #[inline(always)]
562 pub fn cursor(&self) -> usize {
563 self.pos as usize
564 }
565 #[inline(always)]
566 pub fn is_dirty(&self) -> bool {
567 self.mode & 0x80 != 0
568 }
569 #[inline(always)]
570 pub fn available(&self) -> usize {
571 self.file.size.saturating_sub(self.pos) as usize
572 }
573 #[inline(always)]
574 pub fn is_readable(&self) -> bool {
575 self.mode >> 4 == 0 || self.mode & Mode::READ != 0
576 }
577 #[inline(always)]
578 pub fn is_writeable(&self) -> bool {
579 self.mode & Mode::WRITE != 0
580 }
581 #[inline(always)]
582 pub fn is_allocated(&self) -> bool {
583 self.file.cluster.is_some_and(|v| v > 2)
584 }
585 #[inline(always)]
586 pub fn volume(&self) -> &Volume<'a, B> {
587 self.vol
588 }
589 #[inline]
590 pub fn delete(self) -> Result<(), DeviceError> {
591 let mut b = S::cache();
592 self.file.delete(self.vol, &mut b)
593 }
594 #[inline(always)]
595 pub fn close(mut self) -> Result<(), DeviceError> {
596 self.flush()
597 }
598 #[inline]
599 pub fn flush(&mut self) -> Result<(), DeviceError> {
600 if !self.is_dirty() {
601 return Ok(());
602 }
603 let mut b = S::cache();
604 self.vol.man.sync(self.vol.dev, &mut b)?;
605 self.file.sync(self.vol.dev, &mut b, &self.vol.man.ver)
606 }
607 pub fn write(&mut self, b: &[u8]) -> Result<usize, DeviceError> {
608 if !self.is_writeable() {
609 return Err(DeviceError::NotWritable);
610 }
611 if b.is_empty() {
612 return Ok(0);
613 }
614 self.mode |= 0x80;
615 let mut d = S::cache();
616 if !self.is_allocated() {
617 self.file.cluster = Some(self.vol.man.cluster_allocate(self.vol.dev, &mut d, None, false)?);
618 d.clear();
619 }
620 let c = self.file.cluster.ok_or(DeviceError::Write)?;
621 if self.last < c {
622 (self.last, self.short) = (c, 0);
623 }
624 let t = cmp::min(b.len(), (FILE_MAX_SIZE - self.pos) as usize);
625 let (mut c, mut p) = (BlockCache::new(), 0);
626 while p < t {
627 let (i, o, a) = match self.data(&mut d, &mut c) {
628 Ok(v) => v,
629 Err(DeviceError::EndOfFile) => {
630 self.vol
631 .man
632 .cluster_allocate(self.vol.dev, &mut d, self.cluster(), false)
633 .map_err(|_| DeviceError::NoSpace)?;
634 self.data(&mut d, &mut c).map_err(|_| DeviceError::Write)?
635 },
636 Err(e) => return Err(e),
637 };
638 let n = cmp::min(a, t.saturating_sub(p));
639 if n == 0 {
640 break;
641 }
642 if o != 0 {
643 self.vol.dev.read_single(&mut d, i)?;
644 }
645 d[o..o + n].copy_from_slice(&b[p..p + n]);
646 self.vol.dev.write_single(&d, i)?;
647 self.file.size = self.file.size.saturating_add(n as u32);
648 self.pos = self.pos.saturating_add(n as u32);
649 p = p.saturating_add(n);
650 }
651 self.file.attrs |= 0x20;
652 Ok(p)
653 }
654 pub fn truncate(&mut self, pos: usize) -> Result<(), DeviceError> {
657 let i = pos.try_into().map_err(|_| DeviceError::Overflow)?;
658 if i > self.file.size {
659 return Err(DeviceError::InvalidIndex);
660 }
661 self.file.size = i;
662 if self.file.size > self.pos {
663 self.pos = i;
664 }
665 Ok(())
666 }
667 pub fn read(&mut self, b: &mut [u8]) -> Result<usize, DeviceError> {
668 if !self.is_readable() {
669 return Err(DeviceError::NotReadable);
670 }
671 if b.is_empty() {
672 return Ok(0);
673 }
674 let (mut p, t) = (0, b.len());
675 let (mut d, mut c) = (S::cache(), BlockCache::new());
676 while p < t && self.pos < self.file.size {
677 let (i, o, a) = match self.data(&mut d, &mut c) {
678 Err(DeviceError::EndOfFile) => return Ok(p),
679 Err(e) => return Err(e),
680 Ok(v) => v,
681 };
682 self.vol.dev.read_single(&mut d, i)?;
683 let n = cmp::min(cmp::min(a, t - p), self.available());
684 if n == 0 {
685 break;
686 }
687 b[p..p + n].copy_from_slice(&d[o..o + n]);
688 self.pos = self.pos.saturating_add(n as u32);
689 p = p.saturating_add(n);
690 }
691 Ok(p)
692 }
693
694 #[inline(always)]
695 pub(super) fn zero(&mut self) {
696 self.file.size = 0
697 }
698 #[inline(always)]
699 pub(super) fn seek_to_end(&mut self) {
700 self.pos = self.file.size
701 }
702
703 fn data(&mut self, scratch: &mut Block, cache: &mut BlockCache) -> Result<(u32, usize, usize), DeviceError> {
704 if self.pos < self.short {
705 (self.short, self.last) = (0, self.cluster_abs());
706 }
707 let c = self.vol.man.blocks.bytes_per_cluster();
708 let n = self.pos.saturating_sub(self.short);
709 cache.clear();
710 for _ in 0..(n / c) {
711 self.last = self
712 .vol
713 .man
714 .cluster_next(self.vol.dev, scratch, cache, self.last)?
715 .ok_or_else(|| DeviceError::EndOfFile)?;
716 self.short += c;
717 }
718 let i = self.vol.man.block_pos_at(self.last) + (self.pos.saturating_sub(self.short) / Block::SIZE as u32);
719 let o = self.pos as usize % Block::SIZE;
720 Ok((i, o, Block::SIZE - o))
721 }
722}
723
724impl<B: BlockDevice, S: FileSync> Drop for File<'_, B, S> {
725 #[inline(always)]
726 fn drop(&mut self) {
727 ignore_error!(self.flush());
728 }
729}
730impl<B: BlockDevice, S: FileSync> Deref for File<'_, B, S> {
731 type Target = DirEntry;
732
733 #[inline(always)]
734 fn deref(&self) -> &DirEntry {
735 &self.file
736 }
737}
738impl<B: BlockDevice, S: FileSync> Seek<DeviceError> for File<'_, B, S> {
739 fn seek(&mut self, s: SeekFrom) -> Result<u64, Error> {
740 let r = match s {
741 SeekFrom::End(v) => {
742 if v > 0 {
743 return Err(Error::InvalidIndex);
744 }
745 self.pos
746 .saturating_sub(v.unsigned_abs().try_into().map_err(|_| DeviceError::Overflow)?)
747 },
748 SeekFrom::Start(v) => v.try_into().map_err(|_| DeviceError::Overflow)?,
749 SeekFrom::Current(v) if v > 0 => self.pos.saturating_add(v.try_into().map_err(|_| DeviceError::Overflow)?),
750 SeekFrom::Current(v) => self
751 .pos
752 .saturating_sub(v.unsigned_abs().try_into().map_err(|_| DeviceError::Overflow)?),
753 };
754 if r > self.file.size {
755 return Err(Error::InvalidIndex);
756 }
757 self.pos = r;
758 Ok(self.pos as u64)
759 }
760}
761impl<B: BlockDevice, S: FileSync> Read<DeviceError> for File<'_, B, S> {
762 #[inline(always)]
763 fn read(&mut self, b: &mut [u8]) -> Result<usize, Error> {
764 Ok(self.read(b)?)
765 }
766}
767impl<B: BlockDevice, S: FileSync> Write<DeviceError> for File<'_, B, S> {
768 #[inline(always)]
769 fn flush(&mut self) -> Result<(), Error> {
770 Ok(self.flush()?)
771 }
772 #[inline(always)]
773 fn write(&mut self, b: &[u8]) -> Result<usize, Error> {
774 Ok(self.write(b)?)
775 }
776}
777
778impl<B: BlockDevice> Deref for Reader<'_, B> {
779 type Target = DirEntry;
780
781 #[inline(always)]
782 fn deref(&self) -> &DirEntry {
783 &self.f.file
784 }
785}
786impl<B: BlockDevice> Seek<DeviceError> for Reader<'_, B> {
787 fn seek(&mut self, s: SeekFrom) -> Result<u64, Error> {
788 self.f.seek(s)
789 }
790}
791impl<B: BlockDevice> Read<DeviceError> for Reader<'_, B> {
792 #[inline(always)]
793 fn read(&mut self, b: &mut [u8]) -> Result<usize, Error> {
794 Ok(self.read(b)?)
795 }
796}
797
798impl PartialEq<str> for DirEntry {
799 #[inline(always)]
800 fn eq(&self, other: &str) -> bool {
801 self.eq(other.as_bytes())
802 }
803}
804impl PartialEq<[u8]> for DirEntry {
805 #[inline(always)]
806 fn eq(&self, other: &[u8]) -> bool {
807 self.name.eq(other)
808 }
809}
810
811impl Deref for DirEntryFull {
812 type Target = DirEntry;
813
814 #[inline(always)]
815 fn deref(&self) -> &DirEntry {
816 &self.entry
817 }
818}
819impl PartialEq<str> for DirEntryFull {
820 #[inline(always)]
821 fn eq(&self, other: &str) -> bool {
822 self.eq(other.as_bytes())
823 }
824}
825impl PartialEq<[u8]> for DirEntryFull {
826 #[inline]
827 fn eq(&self, other: &[u8]) -> bool {
828 if self.entry.lfn == 0 { self.entry.name.eq(other) } else { self.lfn.eq(other) }
829 }
830}
831
832impl FileSync for Safe {
833 #[inline(always)]
834 fn cache() -> BlockPtr {
835 Cache::block_a()
836 }
837}
838impl FileSync for Unsafe {
839 #[inline(always)]
840 fn cache() -> BlockPtr {
841 unsafe { Cache::block_a_nolock() }
842 }
843}
844
845impl<B: BlockDevice> Deref for Directory<'_, B> {
846 type Target = DirEntry;
847
848 #[inline(always)]
849 fn deref(&self) -> &DirEntry {
850 &self.dir
851 }
852}
853
854#[inline]
855fn time_read(a: u16, b: u16) -> Time {
856 Time {
857 year: ((a >> 0x9) + 0xA) + 0x7B2u16,
858 month: (((a >> 0x5) & 0xF) as u8 + 1).into(),
859 day: (a & 0x1F) as u8,
860 hours: ((b >> 0xB) & 0x1F) as u8,
861 mins: ((b >> 0x5) & 0x3F) as u8,
862 secs: ((b << 0x1) & 0x3F) as u8,
863 weekday: Weekday::None,
864 }
865}
866#[inline]
867fn time_write(t: &Time, b: &mut [u8]) {
868 to_le_u16(
869 (((t.hours as u16) << 11) & 0xF800) | (((t.mins as u16) << 5) & 0x7E0) | (((t.secs as u16) / 2) & 0x1F),
870 b,
871 );
872 to_le_u16(
873 (((t.year.saturating_sub(0x7B2)).saturating_sub(10) << 9) & 0xFE00) | (((t.month as u16 + 1) << 5) & 0x1E0) | ((t.day as u16 + 1) & 0x1F),
874 &mut b[2..],
875 )
876}
877
878pub mod state {
879 pub struct Safe;
880 pub struct Unsafe;
881}