monoio/fs/metadata/
mod.rs1mod unix;
2mod windows;
3
4use std::{os::unix::fs::MetadataExt, path::Path, time::SystemTime};
5
6use super::{file_type::FileType, permissions::Permissions};
7use crate::driver::op::Op;
8
9pub async fn metadata<P: AsRef<Path>>(path: P) -> std::io::Result<Metadata> {
42 #[cfg(target_os = "linux")]
43 let flags = libc::AT_STATX_SYNC_AS_STAT;
44
45 #[cfg(target_os = "linux")]
46 let op = Op::statx_using_path(path, flags)?;
47
48 #[cfg(any(target_os = "macos", target_os = "freebsd"))]
49 let op = Op::statx_using_path(path, true)?;
50
51 op.result().await.map(FileAttr::from).map(Metadata)
52}
53
54pub async fn symlink_metadata<P: AsRef<Path>>(path: P) -> std::io::Result<Metadata> {
82 #[cfg(target_os = "linux")]
83 let flags = libc::AT_STATX_SYNC_AS_STAT | libc::AT_SYMLINK_NOFOLLOW;
84
85 #[cfg(target_os = "linux")]
86 let op = Op::statx_using_path(path, flags)?;
87
88 #[cfg(any(target_os = "macos", target_os = "freebsd"))]
89 let op = Op::statx_using_path(path, false)?;
90
91 op.result().await.map(FileAttr::from).map(Metadata)
92}
93
94#[cfg(unix)]
95pub(crate) use unix::FileAttr;
96
97#[cfg(unix)]
104pub struct Metadata(pub(crate) FileAttr);
105
106impl Metadata {
107 pub fn is_dir(&self) -> bool {
123 self.0.stat.st_mode & libc::S_IFMT == libc::S_IFDIR
124 }
125
126 pub fn is_file(&self) -> bool {
142 self.0.stat.st_mode & libc::S_IFMT == libc::S_IFREG
143 }
144
145 pub fn is_symlink(&self) -> bool {
161 self.0.stat.st_mode & libc::S_IFMT == libc::S_IFLNK
162 }
163
164 #[allow(clippy::len_without_is_empty)]
180 pub fn len(&self) -> u64 {
181 self.0.size()
182 }
183
184 pub fn modified(&self) -> std::io::Result<SystemTime> {
199 let mtime = self.0.stat.st_mtime;
200 let mtime_nsec = self.0.stat.st_mtime_nsec as u32;
201
202 Ok(SystemTime::UNIX_EPOCH + std::time::Duration::new(mtime as u64, mtime_nsec))
203 }
204
205 pub fn accessed(&self) -> std::io::Result<SystemTime> {
221 let atime = self.0.stat.st_atime;
222 let atime_nsec = self.0.stat.st_atime_nsec as u32;
223
224 Ok(SystemTime::UNIX_EPOCH + std::time::Duration::new(atime as u64, atime_nsec))
225 }
226
227 #[cfg(target_os = "linux")]
243 pub fn created(&self) -> std::io::Result<SystemTime> {
244 if let Some(extra) = self.0.statx_extra_fields.as_ref() {
245 return if extra.stx_mask & libc::STATX_BTIME != 0 {
246 let btime = extra.stx_btime.tv_sec;
247 let btime_nsec = extra.stx_btime.tv_nsec;
248
249 Ok(SystemTime::UNIX_EPOCH + std::time::Duration::new(btime as u64, btime_nsec))
250 } else {
251 Err(std::io::Error::other("Creation time is not available"))
252 };
253 }
254
255 Err(std::io::Error::other("Creation time is not available"))
256 }
257
258 #[cfg(unix)]
274 pub fn permissions(&self) -> Permissions {
275 use super::permissions::Permissions;
276
277 Permissions(self.0.perm())
278 }
279
280 #[cfg(unix)]
296 pub fn file_type(&self) -> FileType {
297 self.0.file_type()
298 }
299}
300
301impl std::fmt::Debug for Metadata {
302 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
303 let mut debug = f.debug_struct("Metadata");
304 debug.field("permissions", &self.permissions());
306 debug.field("len", &self.len());
307 if let Ok(modified) = self.modified() {
308 debug.field("modified", &modified);
309 }
310 if let Ok(accessed) = self.accessed() {
311 debug.field("accessed", &accessed);
312 }
313 #[cfg(target_os = "linux")]
314 if let Ok(created) = self.created() {
315 debug.field("created", &created);
316 }
317 debug.finish_non_exhaustive()
318 }
319}
320
321#[cfg(all(target_os = "linux", not(target_pointer_width = "32")))]
322impl MetadataExt for Metadata {
323 fn dev(&self) -> u64 {
324 self.0.stat.st_dev
325 }
326
327 fn ino(&self) -> u64 {
328 self.0.stat.st_ino
329 }
330
331 fn mode(&self) -> u32 {
332 self.0.stat.st_mode
333 }
334
335 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
336 fn nlink(&self) -> u64 {
337 self.0.stat.st_nlink.into()
338 }
339
340 #[allow(clippy::useless_conversion)]
342 #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
343 fn nlink(&self) -> u64 {
344 self.0.stat.st_nlink.into()
345 }
346
347 fn uid(&self) -> u32 {
348 self.0.stat.st_uid
349 }
350
351 fn gid(&self) -> u32 {
352 self.0.stat.st_gid
353 }
354
355 fn rdev(&self) -> u64 {
356 self.0.stat.st_rdev
357 }
358
359 fn size(&self) -> u64 {
360 self.0.stat.st_size as u64
361 }
362
363 fn atime(&self) -> i64 {
364 self.0.stat.st_atime
365 }
366
367 fn atime_nsec(&self) -> i64 {
368 self.0.stat.st_atime_nsec
369 }
370
371 fn mtime(&self) -> i64 {
372 self.0.stat.st_mtime
373 }
374
375 fn mtime_nsec(&self) -> i64 {
376 self.0.stat.st_mtime_nsec
377 }
378
379 fn ctime(&self) -> i64 {
380 self.0.stat.st_ctime
381 }
382
383 fn ctime_nsec(&self) -> i64 {
384 self.0.stat.st_ctime_nsec
385 }
386
387 fn blksize(&self) -> u64 {
388 self.0.stat.st_blksize as u64
389 }
390
391 fn blocks(&self) -> u64 {
392 self.0.stat.st_blocks as u64
393 }
394}
395
396#[cfg(all(
397 any(target_os = "macos", target_os = "freebsd"),
398 not(target_pointer_width = "32")
399))]
400impl MetadataExt for Metadata {
401 fn dev(&self) -> u64 {
402 self.0.stat.st_dev as u64
403 }
404
405 fn ino(&self) -> u64 {
406 self.0.stat.st_ino.into()
407 }
408
409 fn mode(&self) -> u32 {
410 self.0.stat.st_mode as u32
411 }
412
413 fn nlink(&self) -> u64 {
414 self.0.stat.st_nlink.into()
415 }
416
417 fn uid(&self) -> u32 {
418 self.0.stat.st_uid
419 }
420
421 fn gid(&self) -> u32 {
422 self.0.stat.st_gid
423 }
424
425 fn rdev(&self) -> u64 {
426 self.0.stat.st_rdev as u64
427 }
428
429 fn size(&self) -> u64 {
430 self.0.stat.st_size as u64
431 }
432
433 fn atime(&self) -> i64 {
434 self.0.stat.st_atime
435 }
436
437 fn atime_nsec(&self) -> i64 {
438 self.0.stat.st_atime_nsec
439 }
440
441 fn mtime(&self) -> i64 {
442 self.0.stat.st_mtime
443 }
444
445 fn mtime_nsec(&self) -> i64 {
446 self.0.stat.st_mtime_nsec
447 }
448
449 fn ctime(&self) -> i64 {
450 self.0.stat.st_ctime
451 }
452
453 fn ctime_nsec(&self) -> i64 {
454 self.0.stat.st_ctime_nsec
455 }
456
457 fn blksize(&self) -> u64 {
458 self.0.stat.st_blksize as u64
459 }
460
461 fn blocks(&self) -> u64 {
462 self.0.stat.st_blocks as u64
463 }
464}
465
466#[cfg(all(unix, target_pointer_width = "32"))]
467impl MetadataExt for Metadata {
468 fn dev(&self) -> u64 {
469 self.0.stat.st_dev.into()
470 }
471
472 fn ino(&self) -> u64 {
473 self.0.stat.st_ino.into()
474 }
475
476 fn mode(&self) -> u32 {
477 self.0.stat.st_mode
478 }
479
480 fn nlink(&self) -> u64 {
481 self.0.stat.st_nlink.into()
482 }
483
484 fn uid(&self) -> u32 {
485 self.0.stat.st_uid
486 }
487
488 fn gid(&self) -> u32 {
489 self.0.stat.st_gid
490 }
491
492 fn rdev(&self) -> u64 {
493 self.0.stat.st_rdev.into()
494 }
495
496 fn size(&self) -> u64 {
497 self.0.stat.st_size as u64
498 }
499
500 fn atime(&self) -> i64 {
501 self.0.stat.st_atime.into()
502 }
503
504 fn atime_nsec(&self) -> i64 {
505 self.0.stat.st_atime_nsec.into()
506 }
507
508 fn mtime(&self) -> i64 {
509 self.0.stat.st_mtime.into()
510 }
511
512 fn mtime_nsec(&self) -> i64 {
513 self.0.stat.st_mtime_nsec.into()
514 }
515
516 fn ctime(&self) -> i64 {
517 self.0.stat.st_ctime.into()
518 }
519
520 fn ctime_nsec(&self) -> i64 {
521 self.0.stat.st_ctime_nsec.into()
522 }
523
524 fn blksize(&self) -> u64 {
525 self.0.stat.st_blksize as u64
526 }
527
528 fn blocks(&self) -> u64 {
529 self.0.stat.st_blocks as u64
530 }
531}