1#[cfg(feature = "alloc")]
7extern crate alloc;
8
9#[cfg(feature = "alloc")]
10use alloc::string::String;
11#[cfg(feature = "std")]
12use std::time::SystemTime;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18#[repr(u8)]
19pub enum VfsFileType {
20 RegularFile = 1,
22 Directory = 2,
24 Symlink = 3,
26 BlockDevice = 4,
28 CharDevice = 5,
30 Fifo = 6,
32 Socket = 7,
34 Unknown = 0,
36}
37
38impl VfsFileType {
39 pub const fn from_mode(mode: u32) -> Self {
41 match mode & 0o170000 {
42 0o100000 => VfsFileType::RegularFile,
43 0o040000 => VfsFileType::Directory,
44 0o120000 => VfsFileType::Symlink,
45 0o060000 => VfsFileType::BlockDevice,
46 0o020000 => VfsFileType::CharDevice,
47 0o010000 => VfsFileType::Fifo,
48 0o140000 => VfsFileType::Socket,
49 _ => VfsFileType::Unknown,
50 }
51 }
52
53 pub const fn to_mode_bits(self) -> u32 {
55 match self {
56 VfsFileType::RegularFile => 0o100000,
57 VfsFileType::Directory => 0o040000,
58 VfsFileType::Symlink => 0o120000,
59 VfsFileType::BlockDevice => 0o060000,
60 VfsFileType::CharDevice => 0o020000,
61 VfsFileType::Fifo => 0o010000,
62 VfsFileType::Socket => 0o140000,
63 VfsFileType::Unknown => 0,
64 }
65 }
66
67 pub const fn is_file(self) -> bool {
69 matches!(self, VfsFileType::RegularFile)
70 }
71
72 pub const fn is_dir(self) -> bool {
74 matches!(self, VfsFileType::Directory)
75 }
76
77 pub const fn is_symlink(self) -> bool {
79 matches!(self, VfsFileType::Symlink)
80 }
81}
82
83impl Default for VfsFileType {
84 fn default() -> Self {
86 VfsFileType::Unknown
87 }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
94pub struct VfsTimestamp {
95 pub secs: i64,
97 pub nsecs: u32,
99}
100
101impl VfsTimestamp {
102 pub const fn new(secs: i64, nsecs: u32) -> Self {
104 Self { secs, nsecs }
105 }
106
107 pub const fn from_secs(secs: i64) -> Self {
109 Self { secs, nsecs: 0 }
110 }
111
112 pub const fn to_filetime(&self) -> u64 {
114 const WINDOWS_EPOCH_OFFSET: i64 = 11644473600;
116 let windows_secs = self.secs + WINDOWS_EPOCH_OFFSET;
117 if windows_secs < 0 {
118 return 0;
119 }
120 (windows_secs as u64) * 10_000_000 + (self.nsecs / 100) as u64
121 }
122
123 pub const fn from_filetime(ft: u64) -> Self {
125 const WINDOWS_EPOCH_OFFSET: i64 = 11644473600;
126 let secs = (ft / 10_000_000) as i64 - WINDOWS_EPOCH_OFFSET;
127 let nsecs = ((ft % 10_000_000) * 100) as u32;
128 Self { secs, nsecs }
129 }
130}
131
132#[cfg(feature = "std")]
133impl From<SystemTime> for VfsTimestamp {
134 fn from(time: SystemTime) -> Self {
136 match time.duration_since(SystemTime::UNIX_EPOCH) {
137 Ok(duration) => Self {
138 secs: duration.as_secs() as i64,
139 nsecs: duration.subsec_nanos(),
140 },
141 Err(e) => {
142 let duration = e.duration();
143 Self {
144 secs: -(duration.as_secs() as i64),
145 nsecs: duration.subsec_nanos(),
146 }
147 }
148 }
149 }
150}
151
152#[cfg(feature = "std")]
153impl From<VfsTimestamp> for SystemTime {
154 fn from(ts: VfsTimestamp) -> Self {
156 use std::time::Duration;
157 if ts.secs >= 0 {
158 SystemTime::UNIX_EPOCH + Duration::new(ts.secs as u64, ts.nsecs)
159 } else {
160 SystemTime::UNIX_EPOCH - Duration::new((-ts.secs) as u64, ts.nsecs)
161 }
162 }
163}
164
165#[derive(Debug, Clone)]
170pub struct VfsFileInfo {
171 pub ino: u64,
173 pub size: u64,
175 pub blocks: u64,
177 pub block_size: u32,
179 pub mode: u32,
181 pub file_type: VfsFileType,
183 pub nlink: u32,
185 pub uid: u32,
187 pub gid: u32,
189 pub rdev: u64,
191 pub atime: VfsTimestamp,
193 pub mtime: VfsTimestamp,
195 pub ctime: VfsTimestamp,
197 pub crtime: Option<VfsTimestamp>,
199}
200
201impl VfsFileInfo {
202 pub const fn is_file(&self) -> bool {
204 self.file_type.is_file()
205 }
206
207 pub const fn is_dir(&self) -> bool {
209 self.file_type.is_dir()
210 }
211
212 pub const fn is_symlink(&self) -> bool {
214 self.file_type.is_symlink()
215 }
216
217 pub const fn permissions(&self) -> u32 {
219 self.mode & 0o7777
220 }
221}
222
223impl Default for VfsFileInfo {
224 fn default() -> Self {
226 Self {
227 ino: 0,
228 size: 0,
229 blocks: 0,
230 block_size: 4096,
231 mode: 0,
232 file_type: VfsFileType::Unknown,
233 nlink: 1,
234 uid: 0,
235 gid: 0,
236 rdev: 0,
237 atime: VfsTimestamp::default(),
238 mtime: VfsTimestamp::default(),
239 ctime: VfsTimestamp::default(),
240 crtime: None,
241 }
242 }
243}
244
245#[derive(Debug, Clone)]
249#[cfg(feature = "alloc")]
250pub struct VfsDirEntry {
251 pub name: String,
253 pub ino: u64,
255 pub file_type: VfsFileType,
257 pub offset: u64,
259}
260
261#[cfg(feature = "alloc")]
262impl VfsDirEntry {
263 pub fn new(name: impl Into<String>, ino: u64, file_type: VfsFileType) -> Self {
265 Self {
266 name: name.into(),
267 ino,
268 file_type,
269 offset: 0,
270 }
271 }
272
273 pub fn with_offset(
275 name: impl Into<String>,
276 ino: u64,
277 file_type: VfsFileType,
278 offset: u64,
279 ) -> Self {
280 Self {
281 name: name.into(),
282 ino,
283 file_type,
284 offset,
285 }
286 }
287}
288
289#[derive(Debug, Clone)]
293#[cfg(feature = "alloc")]
294pub struct VfsVolumeInfo {
295 pub total_bytes: u64,
297 pub free_bytes: u64,
299 pub available_bytes: u64,
301 pub total_inodes: u64,
303 pub free_inodes: u64,
305 pub block_size: u32,
307 pub max_filename_len: u32,
309 pub fs_type: String,
311 pub volume_label: Option<String>,
313 pub uuid: Option<[u8; 16]>,
315}
316
317#[cfg(feature = "alloc")]
318impl Default for VfsVolumeInfo {
319 fn default() -> Self {
321 Self {
322 total_bytes: 0,
323 free_bytes: 0,
324 available_bytes: 0,
325 total_inodes: 0,
326 free_inodes: 0,
327 block_size: 4096,
328 max_filename_len: 255,
329 fs_type: String::new(),
330 volume_label: None,
331 uuid: None,
332 }
333 }
334}
335
336#[derive(Debug, Clone, Copy, Default)]
338pub struct RenameFlags {
339 pub replace_if_exists: bool,
341 pub exchange: bool,
343 pub no_replace: bool,
345}
346
347#[derive(Debug, Clone, Copy, Default)]
349pub struct OpenFlags {
350 pub read: bool,
352 pub write: bool,
354 pub create: bool,
356 pub exclusive: bool,
358 pub truncate: bool,
360 pub append: bool,
362 pub directory: bool,
364}