Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 48 additions & 58 deletions awkernel_lib/src/file/fatfs/dir.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use alloc::sync::Arc;
#[cfg(all(not(feature = "std"), feature = "alloc", feature = "lfn"))]
use alloc::vec::Vec;
use core::num;
Expand All @@ -21,12 +22,12 @@ use super::time::TimeProvider;
#[cfg(feature = "lfn")]
const LFN_PADDING: u16 = 0xFFFF;

pub(crate) enum DirRawStream<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> {
File(File<'a, IO, TP, OCC>),
Root(DiskSlice<FsIoAdapter<'a, IO, TP, OCC>, FsIoAdapter<'a, IO, TP, OCC>>),
pub(crate) enum DirRawStream<IO: ReadWriteSeek + Send + Sync, TP, OCC> {
File(File<IO, TP, OCC>),
Root(DiskSlice<FsIoAdapter<IO, TP, OCC>, FsIoAdapter<IO, TP, OCC>>),
}

impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> DirRawStream<'_, IO, TP, OCC> {
impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> DirRawStream<IO, TP, OCC> {
fn abs_pos(&self) -> Option<u64> {
match self {
DirRawStream::File(file) => file.abs_pos(),
Expand All @@ -50,7 +51,7 @@ impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> DirRawStream<'_, IO, TP, OCC> {
}

// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925
impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> Clone for DirRawStream<'_, IO, TP, OCC> {
impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> Clone for DirRawStream<IO, TP, OCC> {
fn clone(&self) -> Self {
match self {
DirRawStream::File(file) => DirRawStream::File(file.clone()),
Expand All @@ -59,13 +60,11 @@ impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> Clone for DirRawStream<'_, IO, TP
}
}

impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> IoBase for DirRawStream<'_, IO, TP, OCC> {
impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> IoBase for DirRawStream<IO, TP, OCC> {
type Error = Error<IO::Error>;
}

impl<IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> Read
for DirRawStream<'_, IO, TP, OCC>
{
impl<IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> Read for DirRawStream<IO, TP, OCC> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
match self {
DirRawStream::File(file) => file.read(buf),
Expand All @@ -74,9 +73,7 @@ impl<IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> Read
}
}

impl<IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> Write
for DirRawStream<'_, IO, TP, OCC>
{
impl<IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> Write for DirRawStream<IO, TP, OCC> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
match self {
DirRawStream::File(file) => file.write(buf),
Expand All @@ -91,7 +88,7 @@ impl<IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> Write
}
}

impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> Seek for DirRawStream<'_, IO, TP, OCC> {
impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> Seek for DirRawStream<IO, TP, OCC> {
fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
match self {
DirRawStream::File(file) => file.seek(pos),
Expand All @@ -107,45 +104,40 @@ fn split_path(path: &str) -> (&str, Option<&str>) {
})
}

enum DirEntryOrShortName<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> {
DirEntry(DirEntry<'a, IO, TP, OCC>),
enum DirEntryOrShortName<IO: ReadWriteSeek + Send + Sync, TP, OCC> {
DirEntry(DirEntry<IO, TP, OCC>),
ShortName([u8; SFN_SIZE]),
}

/// A FAT filesystem directory.
///
/// This struct is created by the `open_dir` or `create_dir` methods on `Dir`.
/// The root directory is returned by the `root_dir` method on `FileSystem`.
pub struct Dir<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> {
stream: DirRawStream<'a, IO, TP, OCC>,
fs: &'a FileSystem<IO, TP, OCC>,
pub struct Dir<IO: ReadWriteSeek + Send + Sync, TP, OCC> {
stream: DirRawStream<IO, TP, OCC>,
fs: Arc<FileSystem<IO, TP, OCC>>,
}

impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> Dir<'a, IO, TP, OCC> {
pub(crate) fn new(
stream: DirRawStream<'a, IO, TP, OCC>,
fs: &'a FileSystem<IO, TP, OCC>,
) -> Self {
impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> Dir<IO, TP, OCC> {
pub(crate) fn new(stream: DirRawStream<IO, TP, OCC>, fs: Arc<FileSystem<IO, TP, OCC>>) -> Self {
Dir { stream, fs }
}

/// Creates directory entries iterator.
#[must_use]
#[allow(clippy::iter_not_returning_iterator)]
pub fn iter(&self) -> DirIter<'a, IO, TP, OCC> {
DirIter::new(self.stream.clone(), self.fs, true)
pub fn iter(&self) -> DirIter<IO, TP, OCC> {
DirIter::new(self.stream.clone(), self.fs.clone(), true)
}
}

impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter>
Dir<'a, IO, TP, OCC>
{
impl<IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> Dir<IO, TP, OCC> {
fn find_entry(
&self,
name: &str,
is_dir: Option<bool>,
mut short_name_gen: Option<&mut ShortNameGenerator>,
) -> Result<DirEntry<'a, IO, TP, OCC>, Error<IO::Error>> {
) -> Result<DirEntry<IO, TP, OCC>, Error<IO::Error>> {
for r in self.iter() {
let e = r?;
// compare name ignoring case
Expand All @@ -172,8 +164,8 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter>
#[allow(clippy::type_complexity)]
pub(crate) fn find_volume_entry(
&self,
) -> Result<Option<DirEntry<'a, IO, TP, OCC>>, Error<IO::Error>> {
for r in DirIter::new(self.stream.clone(), self.fs, false) {
) -> Result<Option<DirEntry<IO, TP, OCC>>, Error<IO::Error>> {
for r in DirIter::new(self.stream.clone(), self.fs.clone(), false) {
let e = r?;
if e.data.is_volume() {
return Ok(Some(e));
Expand All @@ -186,7 +178,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter>
&self,
name: &str,
is_dir: Option<bool>,
) -> Result<DirEntryOrShortName<'a, IO, TP, OCC>, Error<IO::Error>> {
) -> Result<DirEntryOrShortName<IO, TP, OCC>, Error<IO::Error>> {
let mut short_name_gen = ShortNameGenerator::new(name);
loop {
// find matching entry
Expand Down Expand Up @@ -241,7 +233,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter>
/// * `Error::NotFound` will be returned if `path` points to a non-existing directory entry.
/// * `Error::InvalidInput` will be returned if `path` points to a file that is a directory.
/// * `Error::Io` will be returned if the underlying storage object returned an I/O error.
pub fn open_file(&self, path: &str) -> Result<File<'a, IO, TP, OCC>, Error<IO::Error>> {
pub fn open_file(&self, path: &str) -> Result<File<IO, TP, OCC>, Error<IO::Error>> {
log::trace!("Dir::open_file {path}");
// traverse path
let (name, rest_opt) = split_path(path);
Expand All @@ -268,7 +260,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter>
/// * `Error::UnsupportedFileNameCharacter` will be returned if the file name contains an invalid character.
/// * `Error::NotEnoughSpace` will be returned if there is not enough free space to create a new file.
/// * `Error::Io` will be returned if the underlying storage object returned an I/O error.
pub fn create_file(&self, path: &str) -> Result<File<'a, IO, TP, OCC>, Error<IO::Error>> {
pub fn create_file(&self, path: &str) -> Result<File<IO, TP, OCC>, Error<IO::Error>> {
log::trace!("Dir::create_file {path}");
// traverse path
let (name, rest_opt) = split_path(path);
Expand Down Expand Up @@ -321,7 +313,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter>
// directory does not exist - create it
DirEntryOrShortName::ShortName(short_name) => {
// alloc cluster for directory data
let cluster = self.fs.alloc_cluster(None, true)?;
let cluster = FileSystem::alloc_cluster(&self.fs, None, true)?;
// create entry in parent directory
let sfn_entry =
self.create_sfn_entry(short_name, FileAttributes::DIRECTORY, Some(cluster));
Expand Down Expand Up @@ -395,7 +387,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter>
}
// free data
if let Some(n) = e.first_cluster() {
self.fs.free_cluster_chain(n)?;
FileSystem::free_cluster_chain(&self.fs, n)?;
}
// free long and short name entries
let mut stream = self.stream.clone();
Expand Down Expand Up @@ -495,7 +487,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter>
fn find_free_entries(
&self,
num_entries: u32,
) -> Result<DirRawStream<'a, IO, TP, OCC>, Error<IO::Error>> {
) -> Result<DirRawStream<IO, TP, OCC>, Error<IO::Error>> {
let mut stream = self.stream.clone();
let mut first_free: u32 = 0;
let mut num_free: u32 = 0;
Expand Down Expand Up @@ -559,7 +551,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter>
&self,
lfn_utf16: &LfnBuffer,
short_name: &[u8; SFN_SIZE],
) -> Result<(DirRawStream<'a, IO, TP, OCC>, u64), Error<IO::Error>> {
) -> Result<(DirRawStream<IO, TP, OCC>, u64), Error<IO::Error>> {
// get short name checksum
let lfn_chsum = lfn_checksum(short_name);
// create LFN entries generator
Expand All @@ -576,7 +568,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter>
}

#[allow(clippy::type_complexity)]
fn alloc_sfn_entry(&self) -> Result<(DirRawStream<'a, IO, TP, OCC>, u64), Error<IO::Error>> {
fn alloc_sfn_entry(&self) -> Result<(DirRawStream<IO, TP, OCC>, u64), Error<IO::Error>> {
let mut stream = self.find_free_entries(1)?;
let start_pos = stream.seek(super::super::io::SeekFrom::Current(0))?;
Ok((stream, start_pos))
Expand All @@ -586,7 +578,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter>
&self,
name: &str,
raw_entry: DirFileEntryData,
) -> Result<DirEntry<'a, IO, TP, OCC>, Error<IO::Error>> {
) -> Result<DirEntry<IO, TP, OCC>, Error<IO::Error>> {
log::trace!("Dir::write_entry {name}");
// check if name doesn't contain unsupported characters
validate_long_name(name)?;
Expand Down Expand Up @@ -618,7 +610,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter>
short_name,
#[cfg(feature = "lfn")]
lfn_utf16,
fs: self.fs,
fs: self.fs.clone(),
entry_pos: start_abs_pos,
offset_range: (start_pos, end_pos),
})
Expand All @@ -627,30 +619,30 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter>

// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925
impl<IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> Clone
for Dir<'_, IO, TP, OCC>
for Dir<IO, TP, OCC>
{
fn clone(&self) -> Self {
Self {
stream: self.stream.clone(),
fs: self.fs,
fs: self.fs.clone(),
}
}
}

/// An iterator over the directory entries.
///
/// This struct is created by the `iter` method on `Dir`.
pub struct DirIter<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> {
stream: DirRawStream<'a, IO, TP, OCC>,
fs: &'a FileSystem<IO, TP, OCC>,
pub struct DirIter<IO: ReadWriteSeek + Send + Sync, TP, OCC> {
stream: DirRawStream<IO, TP, OCC>,
fs: Arc<FileSystem<IO, TP, OCC>>,
skip_volume: bool,
err: bool,
}

impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> DirIter<'a, IO, TP, OCC> {
impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> DirIter<IO, TP, OCC> {
fn new(
stream: DirRawStream<'a, IO, TP, OCC>,
fs: &'a FileSystem<IO, TP, OCC>,
stream: DirRawStream<IO, TP, OCC>,
fs: Arc<FileSystem<IO, TP, OCC>>,
skip_volume: bool,
) -> Self {
DirIter {
Expand All @@ -662,7 +654,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> DirIter<'a, IO, TP, OCC> {
}
}

impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> DirIter<'a, IO, TP, OCC> {
impl<IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> DirIter<IO, TP, OCC> {
fn should_skip_entry(&self, raw_entry: &DirEntryData) -> bool {
if raw_entry.is_deleted() {
return true;
Expand All @@ -674,7 +666,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> DirIter<'a, IO,
}

#[allow(clippy::type_complexity)]
fn read_dir_entry(&mut self) -> Result<Option<DirEntry<'a, IO, TP, OCC>>, Error<IO::Error>> {
fn read_dir_entry(&mut self) -> Result<Option<DirEntry<IO, TP, OCC>>, Error<IO::Error>> {
log::trace!("DirIter::read_dir_entry");
let mut lfn_builder = LongNameBuilder::new();
let mut offset = self.stream.seek(SeekFrom::Current(0))?;
Expand Down Expand Up @@ -713,7 +705,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> DirIter<'a, IO,
short_name,
#[cfg(feature = "lfn")]
lfn_utf16: lfn_builder.into_buf(),
fs: self.fs,
fs: self.fs.clone(),
entry_pos: abs_pos,
offset_range: (begin_offset, offset),
}));
Expand All @@ -729,21 +721,19 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> DirIter<'a, IO,
}

// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925
impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> Clone for DirIter<'_, IO, TP, OCC> {
impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> Clone for DirIter<IO, TP, OCC> {
fn clone(&self) -> Self {
Self {
stream: self.stream.clone(),
fs: self.fs,
fs: self.fs.clone(),
err: self.err,
skip_volume: self.skip_volume,
}
}
}

impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> Iterator
for DirIter<'a, IO, TP, OCC>
{
type Item = Result<DirEntry<'a, IO, TP, OCC>, Error<IO::Error>>;
impl<IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> Iterator for DirIter<IO, TP, OCC> {
type Item = Result<DirEntry<IO, TP, OCC>, Error<IO::Error>>;

fn next(&mut self) -> Option<Self::Item> {
if self.err {
Expand Down
21 changes: 11 additions & 10 deletions awkernel_lib/src/file/fatfs/dir_entry.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::string::String;
use alloc::sync::Arc;
use bitflags::bitflags;
use core::char;
use core::convert::TryInto;
Expand Down Expand Up @@ -552,18 +553,18 @@ impl DirEntryEditor {
///
/// `DirEntry` is returned by `DirIter` when reading a directory.
#[derive(Clone)]
pub struct DirEntry<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> {
pub struct DirEntry<IO: ReadWriteSeek + Send + Sync, TP, OCC> {
pub(crate) data: DirFileEntryData,
pub(crate) short_name: ShortName,
#[cfg(feature = "lfn")]
pub(crate) lfn_utf16: LfnBuffer,
pub(crate) entry_pos: u64,
pub(crate) offset_range: (u64, u64),
pub(crate) fs: &'a FileSystem<IO, TP, OCC>,
pub(crate) fs: Arc<FileSystem<IO, TP, OCC>>,
}

#[allow(clippy::len_without_is_empty)]
impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC: OemCpConverter> DirEntry<'a, IO, TP, OCC> {
impl<IO: ReadWriteSeek + Send + Sync, TP, OCC: OemCpConverter> DirEntry<IO, TP, OCC> {
/// Returns short file name.
///
/// Non-ASCII characters are replaced by the replacement character (U+FFFD).
Expand Down Expand Up @@ -647,9 +648,9 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC: OemCpConverter> DirEntry<'a,
///
/// Will panic if this is not a file.
#[must_use]
pub fn to_file(&self) -> File<'a, IO, TP, OCC> {
pub fn to_file(&self) -> File<IO, TP, OCC> {
assert!(!self.is_dir(), "Not a file entry");
File::new(self.first_cluster(), Some(self.editor()), self.fs)
File::new(self.first_cluster(), Some(self.editor()), self.fs.clone())
}

/// Returns `Dir` struct for this entry.
Expand All @@ -658,14 +659,14 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC: OemCpConverter> DirEntry<'a,
///
/// Will panic if this is not a directory.
#[must_use]
pub fn to_dir(&self) -> Dir<'a, IO, TP, OCC> {
pub fn to_dir(&self) -> Dir<IO, TP, OCC> {
assert!(self.is_dir(), "Not a directory entry");
match self.first_cluster() {
Some(n) => {
let file = File::new(Some(n), Some(self.editor()), self.fs);
Dir::new(DirRawStream::File(file), self.fs)
let file = File::new(Some(n), Some(self.editor()), self.fs.clone());
Dir::new(DirRawStream::File(file), self.fs.clone())
}
None => self.fs.root_dir(),
None => FileSystem::root_dir(&self.fs),
}
}

Expand Down Expand Up @@ -740,7 +741,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC: OemCpConverter> DirEntry<'a,
}
}

impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> fmt::Debug for DirEntry<'_, IO, TP, OCC> {
impl<IO: ReadWriteSeek + Send + Sync, TP, OCC> fmt::Debug for DirEntry<IO, TP, OCC> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.data.fmt(f)
}
Expand Down
Loading