use std::time::Duration;
use time::OffsetDateTime;
use super::Expiry;
pub type InodeNo = u64;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InodeKind {
File,
Directory,
}
impl InodeKind {
pub fn as_str(&self) -> &'static str {
match self {
InodeKind::File => "file",
InodeKind::Directory => "directory",
}
}
}
impl From<InodeKind> for fuser::FileType {
fn from(kind: InodeKind) -> Self {
match kind {
InodeKind::File => fuser::FileType::RegularFile,
InodeKind::Directory => fuser::FileType::Directory,
}
}
}
#[derive(Debug, Clone)]
pub struct InodeStat {
pub expiry: Expiry,
pub size: usize,
pub mtime: OffsetDateTime,
pub ctime: OffsetDateTime,
pub atime: OffsetDateTime,
pub etag: Option<Box<str>>,
pub is_readable: bool,
}
impl InodeStat {
pub fn is_valid(&self) -> bool {
!self.expiry.is_expired()
}
pub fn update_validity(&mut self, validity: Duration) {
self.expiry = Expiry::from_now(validity);
}
fn is_readable(
storage_class: Option<&str>,
restore_status: Option<mountpoint_s3_client::types::RestoreStatus>,
) -> bool {
use crate::sync::atomic::{AtomicBool, Ordering};
use std::time::SystemTime;
static HAS_SENT_WARNING: AtomicBool = AtomicBool::new(false);
match storage_class {
Some("GLACIER") | Some("DEEP_ARCHIVE") => {
let restored = matches!(restore_status, Some(mountpoint_s3_client::types::RestoreStatus::Restored { expiry }) if expiry > SystemTime::now());
if !restored && !HAS_SENT_WARNING.swap(true, Ordering::SeqCst) {
tracing::warn!(
"objects in the GLACIER and DEEP_ARCHIVE storage classes are only accessible if restored"
);
}
restored
}
_ => true,
}
}
pub fn for_file(
size: usize,
datetime: OffsetDateTime,
etag: Option<Box<str>>,
storage_class: Option<&str>,
restore_status: Option<mountpoint_s3_client::types::RestoreStatus>,
validity: Duration,
) -> InodeStat {
let is_readable = Self::is_readable(storage_class, restore_status);
InodeStat {
expiry: Expiry::from_now(validity),
size,
atime: datetime,
ctime: datetime,
mtime: datetime,
etag,
is_readable,
}
}
pub fn for_directory(datetime: OffsetDateTime, validity: Duration) -> InodeStat {
InodeStat {
expiry: Expiry::from_now(validity),
size: 0,
atime: datetime,
ctime: datetime,
mtime: datetime,
etag: None,
is_readable: true,
}
}
}