mountpoint_s3_fs/metablock/
stat.rs1use std::time::Duration;
3
4use time::OffsetDateTime;
5
6use super::Expiry;
7
8pub type InodeNo = u64;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum InodeKind {
12 File,
13 Directory,
14}
15
16impl InodeKind {
17 pub fn as_str(&self) -> &'static str {
18 match self {
19 InodeKind::File => "file",
20 InodeKind::Directory => "directory",
21 }
22 }
23}
24
25impl From<InodeKind> for fuser::FileType {
26 fn from(kind: InodeKind) -> Self {
27 match kind {
28 InodeKind::File => fuser::FileType::RegularFile,
29 InodeKind::Directory => fuser::FileType::Directory,
30 }
31 }
32}
33
34#[derive(Debug, Clone)]
35pub struct InodeStat {
36 pub expiry: Expiry,
38
39 pub size: usize,
41
42 pub mtime: OffsetDateTime,
44 pub ctime: OffsetDateTime,
46 pub atime: OffsetDateTime,
48 pub etag: Option<Box<str>>,
50 pub is_readable: bool,
54}
55
56impl InodeStat {
57 pub fn is_valid(&self) -> bool {
58 !self.expiry.is_expired()
59 }
60
61 pub fn update_validity(&mut self, validity: Duration) {
62 self.expiry = Expiry::from_now(validity);
63 }
64
65 fn is_readable(
70 storage_class: Option<&str>,
71 restore_status: Option<mountpoint_s3_client::types::RestoreStatus>,
72 ) -> bool {
73 use crate::sync::atomic::{AtomicBool, Ordering};
74 use std::time::SystemTime;
75
76 static HAS_SENT_WARNING: AtomicBool = AtomicBool::new(false);
77 match storage_class {
78 Some("GLACIER") | Some("DEEP_ARCHIVE") => {
79 let restored = matches!(restore_status, Some(mountpoint_s3_client::types::RestoreStatus::Restored { expiry }) if expiry > SystemTime::now());
80 if !restored && !HAS_SENT_WARNING.swap(true, Ordering::SeqCst) {
81 tracing::warn!(
82 "objects in the GLACIER and DEEP_ARCHIVE storage classes are only accessible if restored"
83 );
84 }
85 restored
86 }
87 _ => true,
88 }
89 }
90
91 pub fn for_file(
93 size: usize,
94 datetime: OffsetDateTime,
95 etag: Option<Box<str>>,
96 storage_class: Option<&str>,
97 restore_status: Option<mountpoint_s3_client::types::RestoreStatus>,
98 validity: Duration,
99 ) -> InodeStat {
100 let is_readable = Self::is_readable(storage_class, restore_status);
101 InodeStat {
102 expiry: Expiry::from_now(validity),
103 size,
104 atime: datetime,
105 ctime: datetime,
106 mtime: datetime,
107 etag,
108 is_readable,
109 }
110 }
111
112 pub fn for_directory(datetime: OffsetDateTime, validity: Duration) -> InodeStat {
114 InodeStat {
115 expiry: Expiry::from_now(validity),
116 size: 0,
117 atime: datetime,
118 ctime: datetime,
119 mtime: datetime,
120 etag: None,
121 is_readable: true,
122 }
123 }
124}