use crate::{ Fat32FileSystem, ReadSeek, ReadWriteSeek, entry::{DirEntry, DirectoryIterator}, error::Error, file::{File, RawFile}, path::Path, }; use io::{self, IoBase, Read, Seek, Write}; pub struct Dir<'a, T> { raw: RawFile<'a, T>, fs: &'a Fat32FileSystem, } impl<'a, T: IoBase> IoBase for Dir<'a, T> { type Error = Error; } impl<'a, T: ReadSeek> Seek for Dir<'a, T> { fn seek(&mut self, pos: io::SeekFrom) -> Result { self.raw.seek(pos) } } impl<'a, T: ReadSeek> Read for Dir<'a, T> { fn read(&mut self, buf: &mut [u8]) -> Result { self.raw.read(buf) } } impl<'a, T: ReadWriteSeek> Write for Dir<'a, T> { fn write(&mut self, buf: &[u8]) -> Result { self.raw.write(buf) } fn flush(&mut self) -> Result<(), Self::Error> { self.raw.flush() } } impl<'a, T> Dir<'a, T> { pub fn new(raw: RawFile<'a, T>, fs: &'a Fat32FileSystem) -> Self { Self { raw, fs } } pub fn iter(&self) -> DirectoryIterator<'a, T> { DirectoryIterator::new(RawFile::new(self.fs, self.raw.first_cluster(), None)) } } impl<'a, T: ReadSeek> Dir<'a, T> { pub fn open_entry>(&self, path: P) -> Result, Error> { if path.as_ref().is_absolute() { return self.fs.open_entry(path); } let (start, entryname) = path.as_ref().split_path(); for file in self.iter() { let f = file?; if f.name_is(start) { if let Some(entry_name) = entryname { if f.is_dir() { return f.to_dir().open_entry(entry_name); } else { return Err(Error::NotFound); } } else { return Ok(f); } } } Err(Error::NotFound) } pub fn open_file>(&self, path: P) -> Result, Error> { if path.as_ref().is_absolute() { return self.fs.open_file(path); } let (start, dirname) = path.as_ref().split_path(); let entry = self.open_entry(start)?; match dirname { Some(name) => { if !entry.is_dir() { return Err(Error::NotFound); } entry.to_dir().open_file(name) } None => { if !entry.is_file() { return Err(Error::NotFound); } Ok(entry.to_file()) } } } pub fn open_dir>(&self, path: P) -> Result> { let path = path.as_ref(); if path.is_absolute() { return self.fs.open_dir(path); } let (start, dirname) = path.split_path(); let entry = self.open_entry(start)?; if !entry.is_dir() { return Err(Error::NotFound); } match dirname { Some(name) => entry.to_dir().open_dir(name), None => Ok(entry.to_dir()), } } }