use crate::KernelConfig;
use std::ffi::{OsStr, OsString};
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::{Duration, SystemTime};
pub type Inode = u64;
#[derive(Clone, Copy, Debug)]
pub struct RequestInfo {
pub unique: u64,
pub uid: u32,
pub gid: u32,
pub pid: u32,
}
#[derive(Clone, Debug)]
pub struct DirectoryEntry {
pub name: OsString,
pub kind: crate::FileType,
}
#[derive(Clone, Copy, Debug)]
pub struct Statfs {
pub blocks: u64,
pub bfree: u64,
pub bavail: u64,
pub files: u64,
pub ffree: u64,
pub bsize: u32,
pub namelen: u32,
pub frsize: u32,
}
#[derive(Clone, Copy, Debug)]
pub struct FileAttr {
pub size: u64,
pub blocks: u64,
pub atime: SystemTime,
pub mtime: SystemTime,
pub ctime: SystemTime,
pub crtime: SystemTime,
pub kind: crate::FileType,
pub perm: u16,
pub nlink: u32,
pub uid: u32,
pub gid: u32,
pub rdev: u32,
pub blksize: u32,
pub flags: u32,
}
#[derive(Clone, Debug)]
pub struct CreatedEntry {
pub ttl: Duration,
pub attr: FileAttr,
pub fh: u64,
pub flags: u32,
}
#[derive(Clone, Debug)]
pub enum Xattr {
Size(u32),
Data(Vec<u8>),
}
#[cfg(target_os = "macos")]
#[derive(Clone, Debug)]
pub struct XTimes {
pub bkuptime: SystemTime,
pub crtime: SystemTime,
}
pub type ResultEmpty = std::io::Result<()>;
pub type ResultEntry = std::io::Result<(Duration, FileAttr)>;
pub type ResultOpen = std::io::Result<(u64, u32)>;
pub type ResultReaddir = std::io::Result<Vec<DirectoryEntry>>;
pub type ResultData = std::io::Result<Vec<u8>>;
pub type ResultSlice<'a> = std::io::Result<&'a [u8]>;
pub type ResultWrite = std::io::Result<u32>;
pub type ResultStatfs = std::io::Result<Statfs>;
pub type ResultCreate = std::io::Result<CreatedEntry>;
pub type ResultXattr = std::io::Result<Xattr>;
#[cfg(target_os = "macos")]
pub type ResultXTimes = std::io::Result<XTimes>;
pub struct CallbackResult {
pub(crate) _private: std::marker::PhantomData<()>,
}
#[derive(Debug, Clone)]
pub struct ResolvedPath {
parent: Arc<PathBuf>,
name: Arc<OsStr>,
ino: Inode,
}
impl ResolvedPath {
pub fn full_path(&self) -> PathBuf {
self.parent.join(self.name.as_ref())
}
pub fn name(&self) -> &OsStr {
&self.name
}
pub fn ino(&self) -> Inode {
self.ino
}
pub fn parent_path(&self) -> Arc<PathBuf> {
self.parent.clone()
}
}
#[derive(Debug, Clone)]
pub struct EntryName {
parent: Arc<PathBuf>,
name: Arc<OsStr>,
}
impl EntryName {
pub(crate) fn with(self, ino: Inode) -> ResolvedPath {
ResolvedPath {
parent: self.parent,
name: self.name,
ino,
}
}
pub(crate) fn new(parent: FolderPath, name: Arc<OsStr>) -> Self {
Self {
parent: parent.0,
name,
}
}
pub fn full_path(&self) -> PathBuf {
self.parent.join(self.name.as_ref())
}
pub fn name(&self) -> &OsStr {
&self.name
}
pub fn parent_path(&self) -> Arc<PathBuf> {
self.parent.clone()
}
}
#[derive(Debug, Clone)]
pub enum EntryRef {
Lookup(EntryName),
Resolved(ResolvedPath),
}
impl EntryRef {
pub fn full_path(&self) -> PathBuf {
match self {
EntryRef::Lookup(this) => this.full_path(),
EntryRef::Resolved(this) => this.full_path(),
}
}
pub fn name(&self) -> &OsStr {
match self {
EntryRef::Lookup(this) => this.name(),
EntryRef::Resolved(this) => this.name(),
}
}
pub fn parent_path(&self) -> Arc<PathBuf> {
match self {
EntryRef::Lookup(this) => this.parent_path(),
EntryRef::Resolved(this) => this.parent_path(),
}
}
}
#[repr(transparent)]
#[derive(Debug)]
pub(crate) struct FolderPath(Arc<PathBuf>);
impl From<Arc<PathBuf>> for FolderPath {
fn from(value: Arc<PathBuf>) -> Self {
Self(value)
}
}
impl From<&OsStr> for FolderPath {
fn from(value: &OsStr) -> Self {
Self(Arc::new(value.into()))
}
}
impl Deref for FolderPath {
type Target = Arc<PathBuf>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
fn enosys_error<T>() -> std::io::Result<T> {
Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
}
#[allow(unused_variables)]
pub trait Filesystem {
fn init(&self, req: RequestInfo, config: &mut KernelConfig) -> ResultEmpty {
Ok(())
}
fn destroy(&self) {
}
fn getattr(&self, req: RequestInfo, path: &EntryRef, fh: Option<u64>) -> ResultEntry {
enosys_error()
}
fn chmod(
&self,
req: RequestInfo,
path: &ResolvedPath,
fh: Option<u64>,
mode: u32,
) -> ResultEmpty {
enosys_error()
}
fn chown(
&self,
req: RequestInfo,
path: &ResolvedPath,
fh: Option<u64>,
uid: Option<u32>,
gid: Option<u32>,
) -> ResultEmpty {
enosys_error()
}
fn truncate(
&self,
req: RequestInfo,
path: &ResolvedPath,
fh: Option<u64>,
size: u64,
) -> ResultEmpty {
enosys_error()
}
fn utimens(
&self,
req: RequestInfo,
path: &ResolvedPath,
fh: Option<u64>,
atime: Option<SystemTime>,
mtime: Option<SystemTime>,
) -> ResultEmpty {
enosys_error()
}
#[allow(clippy::too_many_arguments)]
fn utimens_macos(
&self,
req: RequestInfo,
path: &ResolvedPath,
fh: Option<u64>,
crtime: Option<SystemTime>,
chgtime: Option<SystemTime>,
bkuptime: Option<SystemTime>,
flags: Option<u32>,
) -> ResultEmpty {
enosys_error()
}
fn readlink(&self, req: RequestInfo, path: &ResolvedPath) -> ResultData {
enosys_error()
}
fn mknod(&self, req: RequestInfo, entry: &EntryName, mode: u32, rdev: u32) -> ResultEntry {
enosys_error()
}
fn mkdir(&self, req: RequestInfo, entry: &EntryName, mode: u32) -> ResultEntry {
enosys_error()
}
fn unlink(&self, req: RequestInfo, entry: &EntryName) -> ResultEmpty {
enosys_error()
}
fn rmdir(&self, req: RequestInfo, entry: &EntryName) -> ResultEmpty {
enosys_error()
}
fn symlink(&self, req: RequestInfo, entry: &EntryName, target: &Path) -> ResultEntry {
enosys_error()
}
fn rename(&self, req: RequestInfo, entry: &EntryName, new_entry: &EntryName) -> ResultEmpty {
enosys_error()
}
fn link(&self, req: RequestInfo, path: &ResolvedPath, new_entry: &EntryName) -> ResultEntry {
enosys_error()
}
fn open(&self, req: RequestInfo, path: &ResolvedPath, flags: u32) -> ResultOpen {
enosys_error()
}
fn read(
&self,
req: RequestInfo,
path: &ResolvedPath,
fh: u64,
offset: u64,
size: u32,
callback: impl FnOnce(ResultSlice<'_>) -> CallbackResult,
) -> CallbackResult {
callback(enosys_error())
}
fn write(
&self,
req: RequestInfo,
path: &ResolvedPath,
fh: u64,
offset: u64,
data: Vec<u8>,
flags: u32,
) -> ResultWrite {
enosys_error()
}
fn flush(
&self,
req: RequestInfo,
path: &ResolvedPath,
fh: u64,
lock_owner: u64,
) -> ResultEmpty {
enosys_error()
}
fn release(
&self,
req: RequestInfo,
path: &ResolvedPath,
fh: u64,
flags: u32,
lock_owner: u64,
flush: bool,
) -> ResultEmpty {
enosys_error()
}
fn fsync(&self, req: RequestInfo, path: &ResolvedPath, fh: u64, datasync: bool) -> ResultEmpty {
enosys_error()
}
fn opendir(&self, req: RequestInfo, path: &ResolvedPath, flags: u32) -> ResultOpen {
enosys_error()
}
fn readdir(&self, req: RequestInfo, path: &ResolvedPath, fh: u64) -> ResultReaddir {
enosys_error()
}
fn releasedir(
&self,
req: RequestInfo,
path: &ResolvedPath,
fh: u64,
flags: u32,
) -> ResultEmpty {
enosys_error()
}
fn fsyncdir(
&self,
req: RequestInfo,
path: &ResolvedPath,
fh: u64,
datasync: bool,
) -> ResultEmpty {
enosys_error()
}
fn statfs(&self, req: RequestInfo, path: &ResolvedPath) -> ResultStatfs {
enosys_error()
}
fn setxattr(
&self,
req: RequestInfo,
path: &ResolvedPath,
name: &OsStr,
value: &[u8],
flags: u32,
position: u32,
) -> ResultEmpty {
enosys_error()
}
fn getxattr(
&self,
req: RequestInfo,
path: &ResolvedPath,
name: &OsStr,
size: u32,
) -> ResultXattr {
enosys_error()
}
fn listxattr(&self, req: RequestInfo, path: &ResolvedPath, size: u32) -> ResultXattr {
enosys_error()
}
fn removexattr(&self, req: RequestInfo, path: &ResolvedPath, name: &OsStr) -> ResultEmpty {
enosys_error()
}
fn access(&self, req: RequestInfo, path: &ResolvedPath, mask: u32) -> ResultEmpty {
enosys_error()
}
fn create(&self, req: RequestInfo, path: &ResolvedPath, mode: u32, flags: u32) -> ResultCreate {
enosys_error()
}
#[cfg(target_os = "macos")]
fn setvolname(&self, req: RequestInfo, name: &OsStr) -> ResultEmpty {
enosys_error()
}
#[cfg(target_os = "macos")]
fn getxtimes(&self, req: RequestInfo, path: &ResolvedPath) -> ResultXTimes {
Err(libc::ENOSYS)
}
}