Skip to content
Merged
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
143 changes: 113 additions & 30 deletions awkernel_async_lib/src/file/filesystem.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,82 @@
//! The async filesystem trait definitions needed to implement new async virtual filesystems
use super::path::AsyncVfsPath;
use crate::time::Time;
use alloc::{boxed::Box, string::String};
use async_trait::async_trait;
use awkernel_lib::file::{
error::IoError,
io::SeekFrom,
vfs::error::{VfsError, VfsErrorKind, VfsResult},
vfs::path::VfsMetadata,
};
use futures::stream::Stream;

// NOTE: We're currently using our own AsyncSeekAndRead and AsyncSeekAndWrite traits. We might replace these with traits from embedded-io-async in the future. However, that change would involve many modifications, and embedded-io-async doesn't seem stable yet, so we're sticking with our current approach for now."
#[async_trait]
pub trait AsyncSeekAndRead<E: IoError>: Send + Unpin {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, VfsError<E>>;

use crate::async_vfs::{AsyncVfsPath, SeekAndRead};
use crate::error::VfsErrorKind;
use crate::{VfsError, VfsMetadata, VfsResult};
async fn seek(&mut self, pos: SeekFrom) -> Result<u64, VfsError<E>>;

use async_std::io::Write;
use async_std::stream::Stream;
use async_trait::async_trait;
use std::fmt::Debug;
use std::time::SystemTime;
async fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), VfsError<E>> {
while !buf.is_empty() {
match self.read(buf).await {
Ok(0) => return Ok(()),
Ok(n) => {
buf = &mut buf[n..];
}
Err(e) => return Err(e),
}
}

Ok(())
}
}

#[async_trait]
pub trait AsyncSeekAndWrite<E: IoError>: Send + Unpin {
async fn write(&mut self, buf: &[u8]) -> Result<usize, VfsError<E>>;

async fn write_all(&mut self, buf: &[u8]) -> Result<(), VfsError<E>>;

async fn flush(&mut self) -> Result<(), VfsError<E>>;

async fn seek(&mut self, pos: SeekFrom) -> Result<u64, VfsError<E>>;
}

#[async_trait]
impl<E: IoError + Send> AsyncSeekAndRead<E> for Box<dyn AsyncSeekAndRead<E> + Send + Unpin> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, VfsError<E>> {
(**self).read(buf).await
}

async fn seek(&mut self, pos: SeekFrom) -> Result<u64, VfsError<E>> {
(**self).seek(pos).await
}

async fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), VfsError<E>> {
(**self).read_exact(buf).await
}
}

#[async_trait]
impl<E: IoError + Send> AsyncSeekAndWrite<E> for Box<dyn AsyncSeekAndWrite<E> + Send + Unpin> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, VfsError<E>> {
(**self).write(buf).await
}

async fn write_all(&mut self, buf: &[u8]) -> Result<(), VfsError<E>> {
(**self).write_all(buf).await
}

async fn flush(&mut self) -> Result<(), VfsError<E>> {
(**self).flush().await
}

async fn seek(&mut self, pos: SeekFrom) -> Result<u64, VfsError<E>> {
(**self).seek(pos).await
}
}

/// File system implementations must implement this trait
/// All path parameters are absolute, starting with '/', except for the root directory
Expand All @@ -18,59 +86,74 @@ use std::time::SystemTime;
///
/// Please use the test_macros [test_macros::test_async_vfs!] and [test_macros::test_async_vfs_readonly!]
#[async_trait]
pub trait AsyncFileSystem: Debug + Sync + Send + 'static {
pub trait AsyncFileSystem: Sync + Send + 'static {
/// The error type that can be returned by this file system.
type Error: IoError + Clone + Send + Sync;

/// Iterates over all direct children of this directory path
/// NOTE: the returned String items denote the local bare filenames, i.e. they should not contain "/" anywhere
async fn read_dir(
&self,
path: &str,
) -> VfsResult<Box<dyn Unpin + Stream<Item = String> + Send>>;
) -> VfsResult<Box<dyn Unpin + Stream<Item = String> + Send>, Self::Error>;

/// Creates the directory at this path
///
/// Note that the parent directory must already exist.
async fn create_dir(&self, path: &str) -> VfsResult<()>;
async fn create_dir(&self, path: &str) -> VfsResult<(), Self::Error>;

/// Opens the file at this path for reading
async fn open_file(&self, path: &str) -> VfsResult<Box<dyn SeekAndRead + Send + Unpin>>;
async fn open_file(
&self,
path: &str,
) -> VfsResult<Box<dyn AsyncSeekAndRead<Self::Error> + Send + Unpin>, Self::Error>;

/// Creates a file at this path for writing
async fn create_file(&self, path: &str) -> VfsResult<Box<dyn Write + Send + Unpin>>;
async fn create_file(
&self,
path: &str,
) -> VfsResult<Box<dyn AsyncSeekAndWrite<Self::Error> + Send + Unpin>, Self::Error>;

/// Opens the file at this path for appending
async fn append_file(&self, path: &str) -> VfsResult<Box<dyn Write + Send + Unpin>>;
async fn append_file(
&self,
path: &str,
) -> VfsResult<Box<dyn AsyncSeekAndWrite<Self::Error> + Send + Unpin>, Self::Error>;

/// Returns the file metadata for the file at this path
async fn metadata(&self, path: &str) -> VfsResult<VfsMetadata>;
async fn metadata(&self, path: &str) -> VfsResult<VfsMetadata, Self::Error>;

/// Sets the files creation timestamp, if the implementation supports it
async fn set_creation_time(&self, _path: &str, _time: SystemTime) -> VfsResult<()> {
async fn set_creation_time(&self, _path: &str, _time: Time) -> VfsResult<(), Self::Error> {
Err(VfsError::from(VfsErrorKind::NotSupported))
}
/// Sets the files modification timestamp, if the implementation supports it
async fn set_modification_time(&self, _path: &str, _time: SystemTime) -> VfsResult<()> {
async fn set_modification_time(&self, _path: &str, _time: Time) -> VfsResult<(), Self::Error> {
Err(VfsError::from(VfsErrorKind::NotSupported))
}
/// Sets the files access timestamp, if the implementation supports it
async fn set_access_time(&self, _path: &str, _time: SystemTime) -> VfsResult<()> {
async fn set_access_time(&self, _path: &str, _time: Time) -> VfsResult<(), Self::Error> {
Err(VfsError::from(VfsErrorKind::NotSupported))
}
/// Returns true if a file or directory at path exists, false otherwise
async fn exists(&self, path: &str) -> VfsResult<bool>;
async fn exists(&self, path: &str) -> VfsResult<bool, Self::Error>;

/// Removes the file at this path
async fn remove_file(&self, path: &str) -> VfsResult<()>;
async fn remove_file(&self, path: &str) -> VfsResult<(), Self::Error>;

/// Removes the directory at this path
async fn remove_dir(&self, path: &str) -> VfsResult<()>;
async fn remove_dir(&self, path: &str) -> VfsResult<(), Self::Error>;

/// Copies the src path to the destination path within the same filesystem (optional)
async fn copy_file(&self, _src: &str, _dest: &str) -> VfsResult<()> {
async fn copy_file(&self, _src: &str, _dest: &str) -> VfsResult<(), Self::Error> {
Err(VfsErrorKind::NotSupported.into())
}
/// Moves the src path to the destination path within the same filesystem (optional)
async fn move_file(&self, _src: &str, _dest: &str) -> VfsResult<()> {
async fn move_file(&self, _src: &str, _dest: &str) -> VfsResult<(), Self::Error> {
Err(VfsErrorKind::NotSupported.into())
}
/// Moves the src directory to the destination path within the same filesystem (optional)
async fn move_dir(&self, _src: &str, _dest: &str) -> VfsResult<()> {
async fn move_dir(&self, _src: &str, _dest: &str) -> VfsResult<(), Self::Error> {
Err(VfsErrorKind::NotSupported.into())
}
}

impl<T: AsyncFileSystem> From<T> for AsyncVfsPath {
fn from(filesystem: T) -> Self {
AsyncVfsPath::new(filesystem)
}
}