use alloc::vec::Vec;
use deku::no_std_io::{Read, Seek, Write};
use crate::error::Error;
use crate::fs::permissions::Permissions;
use crate::fs::types::{Blkcnt, Blksize, Dev, Gid, Ino, Mode, Nlink, Off, Timespec, Uid};
use crate::path::{PARENT_DIR, UnixStr};
#[derive(Debug, Clone)]
pub struct Stat {
pub dev: Dev,
pub ino: Ino,
pub mode: Mode,
pub nlink: Nlink,
pub uid: Uid,
pub gid: Gid,
pub rdev: Dev,
pub size: Off,
pub atim: Timespec,
pub mtim: Timespec,
pub ctim: Timespec,
pub blksize: Blksize,
pub blkcnt: Blkcnt,
}
pub trait Base {
type FsError: core::error::Error;
}
pub trait FileRead: Base {
fn stat(&self) -> Stat;
fn get_type(&self) -> Type;
fn permissions(&self) -> Permissions {
self.stat().mode.into()
}
}
pub trait File: FileRead {
fn set_mode(&mut self, mode: Mode) -> Result<(), Error<Self::FsError>>;
fn set_uid(&mut self, uid: Uid) -> Result<(), Error<Self::FsError>>;
fn set_gid(&mut self, gid: Gid) -> Result<(), Error<Self::FsError>>;
fn set_atim(&mut self, atim: Timespec) -> Result<(), Error<Self::FsError>>;
fn set_mtim(&mut self, mtim: Timespec) -> Result<(), Error<Self::FsError>>;
fn set_ctim(&mut self, ctim: Timespec) -> Result<(), Error<Self::FsError>>;
}
pub trait RegularRead: FileRead + Read + Seek {}
pub trait Regular: File + RegularRead + Write {
fn truncate(&mut self, size: u64) -> Result<(), Error<<Self as Base>::FsError>>;
}
pub struct DirectoryEntry<'path, Dir: DirectoryRead> {
pub filename: UnixStr<'path>,
pub file: TypeWithFile<Dir>,
}
pub trait DirectoryRead: Sized + Base {
type Regular: RegularRead<FsError = <Self as Base>::FsError>;
type SymbolicLink: SymbolicLinkRead<FsError = <Self as Base>::FsError>;
type Fifo: FifoRead<FsError = <Self as Base>::FsError>;
type CharacterDevice: CharacterDeviceRead<FsError = <Self as Base>::FsError>;
type BlockDevice: BlockDeviceRead<FsError = <Self as Base>::FsError>;
type Socket: SocketRead<FsError = <Self as Base>::FsError>;
fn entries(&self) -> Result<Vec<DirectoryEntry<'_, Self>>, Error<Self::FsError>>;
fn entry(&self, name: UnixStr) -> Result<Option<TypeWithFile<Self>>, Error<Self::FsError>> {
let children = self.entries()?;
Ok(children.into_iter().find(|entry| entry.filename == name).map(|entry| entry.file))
}
fn parent(&self) -> Result<Self, Error<Self::FsError>> {
let Some(TypeWithFile::Directory(parent_entry)) = self.entry(PARENT_DIR.clone())? else {
unreachable!("`entries` must return `..` that corresponds to the parent directory.")
};
Ok(parent_entry)
}
}
pub trait Directory: File + DirectoryRead
where
<Self as DirectoryRead>::Regular: Regular<FsError = <Self as Base>::FsError>,
<Self as DirectoryRead>::SymbolicLink: SymbolicLink<FsError = <Self as Base>::FsError>,
<Self as DirectoryRead>::Fifo: Fifo<FsError = <Self as Base>::FsError>,
<Self as DirectoryRead>::CharacterDevice: CharacterDevice<FsError = <Self as Base>::FsError>,
<Self as DirectoryRead>::BlockDevice: BlockDevice<FsError = <Self as Base>::FsError>,
<Self as DirectoryRead>::Socket: Socket<FsError = <Self as Base>::FsError>,
{
fn add_entry(
&mut self,
name: UnixStr<'_>,
file_type: Type,
permissions: Permissions,
user_id: Uid,
group_id: Gid,
) -> Result<TypeWithFile<Self>, Error<Self::FsError>>;
fn remove_entry(&mut self, name: UnixStr) -> Result<(), Error<Self::FsError>>;
}
pub trait SymbolicLinkRead: FileRead {
fn get_pointed_file(&self) -> Result<&str, Error<Self::FsError>>;
}
pub trait SymbolicLink: File + SymbolicLinkRead {
fn set_pointed_file(&mut self, pointed_file: &str) -> Result<(), Error<Self::FsError>>;
}
pub trait FifoRead: FileRead {}
pub trait Fifo: File + FifoRead {}
pub trait CharacterDeviceRead: FileRead {}
pub trait CharacterDevice: File + CharacterDeviceRead {}
pub trait BlockDeviceRead: FileRead {}
pub trait BlockDevice: File + BlockDeviceRead {}
pub trait SocketRead: FileRead {}
pub trait Socket: File + SocketRead {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum Type {
Regular,
Directory,
SymbolicLink,
Fifo,
CharacterDevice,
BlockDevice,
Socket,
}
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, Clone)]
pub enum TypeWithFile<Dir: DirectoryRead> {
Regular(Dir::Regular),
Directory(Dir),
SymbolicLink(Dir::SymbolicLink),
Fifo(Dir::Fifo),
CharacterDevice(Dir::CharacterDevice),
BlockDevice(Dir::BlockDevice),
Socket(Dir::Socket),
}
impl<Dir: DirectoryRead> TypeWithFile<Dir> {
pub const fn is_regular(&self) -> bool {
match self {
Self::Regular(_) => true,
Self::Directory(_)
| Self::SymbolicLink(_)
| Self::Fifo(_)
| Self::CharacterDevice(_)
| Self::BlockDevice(_)
| Self::Socket(_) => false,
}
}
pub const fn is_directory(&self) -> bool {
match self {
Self::Directory(_) => true,
Self::Regular(_)
| Self::SymbolicLink(_)
| Self::Fifo(_)
| Self::CharacterDevice(_)
| Self::BlockDevice(_)
| Self::Socket(_) => false,
}
}
pub const fn is_symlink(&self) -> bool {
match self {
Self::SymbolicLink(_) => true,
Self::Regular(_)
| Self::Directory(_)
| Self::Fifo(_)
| Self::CharacterDevice(_)
| Self::BlockDevice(_)
| Self::Socket(_) => false,
}
}
pub const fn is_fifo(&self) -> bool {
match self {
Self::Fifo(_) => true,
Self::Regular(_)
| Self::Directory(_)
| Self::SymbolicLink(_)
| Self::CharacterDevice(_)
| Self::BlockDevice(_)
| Self::Socket(_) => false,
}
}
pub const fn is_character_device(&self) -> bool {
match self {
Self::CharacterDevice(_) => true,
Self::Regular(_)
| Self::Directory(_)
| Self::SymbolicLink(_)
| Self::Fifo(_)
| Self::BlockDevice(_)
| Self::Socket(_) => false,
}
}
pub const fn is_block_device(&self) -> bool {
match self {
Self::BlockDevice(_) => true,
Self::Regular(_)
| Self::Directory(_)
| Self::SymbolicLink(_)
| Self::Fifo(_)
| Self::CharacterDevice(_)
| Self::Socket(_) => false,
}
}
pub const fn is_socket(&self) -> bool {
match self {
Self::Socket(_) => true,
Self::Regular(_)
| Self::Directory(_)
| Self::SymbolicLink(_)
| Self::Fifo(_)
| Self::CharacterDevice(_)
| Self::BlockDevice(_) => false,
}
}
}
impl<Dir: DirectoryRead> From<&TypeWithFile<Dir>> for Type {
fn from(value: &TypeWithFile<Dir>) -> Self {
match value {
TypeWithFile::Regular(_) => Self::Regular,
TypeWithFile::Directory(_) => Self::Directory,
TypeWithFile::SymbolicLink(_) => Self::SymbolicLink,
TypeWithFile::Fifo(_) => Self::Fifo,
TypeWithFile::CharacterDevice(_) => Self::CharacterDevice,
TypeWithFile::BlockDevice(_) => Self::BlockDevice,
TypeWithFile::Socket(_) => Self::Socket,
}
}
}
impl<Dir: DirectoryRead> From<TypeWithFile<Dir>> for Type {
fn from(value: TypeWithFile<Dir>) -> Self {
match value {
TypeWithFile::Regular(_) => Self::Regular,
TypeWithFile::Directory(_) => Self::Directory,
TypeWithFile::SymbolicLink(_) => Self::SymbolicLink,
TypeWithFile::Fifo(_) => Self::Fifo,
TypeWithFile::CharacterDevice(_) => Self::CharacterDevice,
TypeWithFile::BlockDevice(_) => Self::BlockDevice,
TypeWithFile::Socket(_) => Self::Socket,
}
}
}