use async_trait::async_trait;
use mountpoint_s3_client::types::ETag;
use std::ffi::{OsStr, OsString};
use time::OffsetDateTime;
mod error;
mod expiry;
mod lookup;
mod path;
mod pending_upload;
mod stat;
pub use error::{InodeError, InodeErrorInfo};
pub use expiry::{Expiry, NEVER_EXPIRE_TTL};
pub use lookup::{InodeInformation, Lookup};
pub use path::{S3Location, ValidKey, ValidKeyError, ValidName};
pub use pending_upload::PendingUploadHook;
pub use stat::{InodeKind, InodeNo, InodeStat};
use crate::fs::OpenFlags;
pub const ROOT_INODE_NO: InodeNo = crate::fs::FUSE_ROOT_INODE;
#[async_trait]
pub trait Metablock: Send + Sync {
async fn lookup(&self, parent_ino: InodeNo, name: &OsStr) -> Result<Lookup, InodeError>;
async fn getattr(&self, ino: InodeNo, force_revalidate_if_remote: bool) -> Result<Lookup, InodeError>;
async fn setattr(
&self,
ino: InodeNo,
atime: Option<OffsetDateTime>,
mtime: Option<OffsetDateTime>,
) -> Result<Lookup, InodeError>;
async fn create(&self, dir: InodeNo, name: &OsStr, kind: InodeKind) -> Result<Lookup, InodeError>;
async fn forget(&self, ino: InodeNo, n: u64);
async fn open_handle(
&self,
ino: InodeNo,
fh: u64,
write_mode: &WriteMode,
flags: OpenFlags,
) -> Result<NewHandle, InodeError>;
async fn inc_file_size(&self, ino: InodeNo, len: usize) -> Result<usize, InodeError>;
async fn finish_writing(&self, ino: InodeNo, etag: Option<ETag>, fh: u64) -> Result<Lookup, InodeError>;
async fn finish_reading(&self, ino: InodeNo, fh: u64) -> Result<(), InodeError>;
async fn flush_reader(&self, ino: InodeNo, fh: u64) -> Result<(), InodeError>;
async fn flush_writer(
&self,
ino: InodeNo,
fh: u64,
pending_upload_hook: PendingUploadHook,
) -> Result<Option<PendingUploadHook>, InodeError>;
async fn release_writer(
&self,
ino: InodeNo,
fh: u64,
pending_upload_hook: PendingUploadHook,
location: &S3Location,
) -> Result<(), InodeError>;
async fn try_reactivate_handle(&self, ino: InodeNo, fh: u64, mode: ReadWriteMode) -> Result<bool, InodeError>;
async fn new_readdir_handle(&self, dir_ino: InodeNo) -> Result<u64, InodeError>;
async fn readdir<'a>(
&self,
parent: InodeNo,
fh: u64,
offset: i64,
is_readdirplus: bool,
mut add: AddDirEntry<'a>,
) -> Result<(), InodeError>;
async fn releasedir(&self, fh: u64) -> Result<(), InodeError>;
async fn rename(
&self,
src_parent_ino: InodeNo,
src_name: &OsStr,
dst_parent_ino: InodeNo,
dst_name: &OsStr,
allow_overwrite: bool,
) -> Result<(), InodeError>;
async fn rmdir(&self, parent_ino: InodeNo, name: &OsStr) -> Result<(), InodeError>;
async fn unlink(&self, parent_ino: InodeNo, name: &OsStr) -> Result<(), InodeError>;
}
pub type AddDirEntry<'r> = Box<dyn FnMut(InodeInformation, OsString, i64, u64) -> AddDirEntryResult + Send + Sync + 'r>;
#[derive(Debug, PartialEq, Eq)]
pub enum AddDirEntryResult {
EntryAdded,
ReplyBufferFull,
}
#[derive(Debug, Default)]
pub struct WriteMode {
pub allow_overwrite: bool,
pub incremental_upload: bool,
}
impl WriteMode {
pub fn is_inode_writable(&self, is_truncate: bool) -> bool {
if self.incremental_upload || (self.allow_overwrite && is_truncate) {
true
} else {
if is_truncate {
tracing::warn!(
"file overwrite is disabled by default, you need to remount with --allow-overwrite flag to enable it"
);
} else {
tracing::warn!(
"modifying an existing file is disabled by default, you need to remount with the --allow-overwrite or the --incremental-upload flag to enable it"
);
}
false
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum ReadWriteMode {
Read,
Write,
}
#[derive(Debug)]
pub struct NewHandle {
pub lookup: Lookup,
pub mode: ReadWriteMode,
}
impl NewHandle {
pub fn read(lookup: Lookup) -> Self {
Self {
lookup,
mode: ReadWriteMode::Read,
}
}
pub fn write(lookup: Lookup) -> Self {
Self {
lookup,
mode: ReadWriteMode::Write,
}
}
}