|
4 | 4 |
|
5 | 5 | #![stable(feature = "metadata_ext", since = "1.1.0")] |
6 | 6 |
|
| 7 | +use core::mem; |
| 8 | + |
7 | 9 | use crate::fs::Metadata; |
8 | 10 | #[allow(deprecated)] |
9 | 11 | use crate::os::linux::raw; |
| 12 | +use crate::os::raw::c_void; |
10 | 13 | use crate::sys::AsInner; |
| 14 | +use crate::sys::fs::cfg_has_statx; |
| 15 | +cfg_has_statx! {{ |
| 16 | + use crate::sys::fs::{FileAttr, StatxExtraFields}; |
| 17 | + use crate::sys::FromInner; |
| 18 | +} else { |
| 19 | + use crate::sys::unsupported; |
| 20 | +}} |
11 | 21 |
|
12 | 22 | /// OS-specific extensions to [`fs::Metadata`]. |
13 | 23 | /// |
@@ -41,6 +51,45 @@ pub trait MetadataExt { |
41 | 51 | #[allow(deprecated)] |
42 | 52 | fn as_raw_stat(&self) -> &raw::stat; |
43 | 53 |
|
| 54 | + /// Creates a [`Metadata`] from a const void pointer populated by the [`statx`] syscall. |
| 55 | + /// |
| 56 | + /// # Safety |
| 57 | + /// |
| 58 | + /// The caller must take care to provide a valid const void pointer containing information |
| 59 | + /// populated by the [`statx`] syscall. |
| 60 | + /// |
| 61 | + /// [`Metadata`]: crate::fs::Metadata |
| 62 | + /// [`statx`]: https://docs.rs/libc/latest/libc/struct.statx.html |
| 63 | + /// |
| 64 | + /// ```no_run |
| 65 | + /// #![feature(metadata_statx)] |
| 66 | + /// use libc::statx; |
| 67 | + /// use std::ffi::c_void; |
| 68 | + /// use std::fs::{write, Metadata}; |
| 69 | + /// use std::io; |
| 70 | + /// use std::os::linux::fs::MetadataExt; |
| 71 | + /// |
| 72 | + /// fn main() -> io::Result<()> { |
| 73 | + /// write("hello.txt", "Hello World!")?; |
| 74 | + /// let mut buf = Box::<statx>::new_uninit(); |
| 75 | + /// unsafe { |
| 76 | + /// libc::statx( |
| 77 | + /// libc::AT_FDCWD, |
| 78 | + /// "hello.txt".as_ptr().cast(), |
| 79 | + /// libc::AT_STATX_SYNC_AS_STAT, |
| 80 | + /// libc::STATX_BASIC_STATS, |
| 81 | + /// buf.as_mut_ptr().cast() |
| 82 | + /// ); |
| 83 | + /// } |
| 84 | + /// let statxbuf: Box<statx> = unsafe { buf.assume_init() }; |
| 85 | + /// let metadata = unsafe { Metadata::from_statx(&*statxbuf as *const statx as *const c_void) }; |
| 86 | + /// assert_eq!(metadata.len(), 12); // "Hello World!" is 12 bytes |
| 87 | + /// Ok(()) |
| 88 | + /// } |
| 89 | + /// ``` |
| 90 | + #[unstable(feature = "metadata_statx", issue = "156268")] |
| 91 | + unsafe fn from_statx(statxbuf: *const c_void) -> Self; |
| 92 | + |
44 | 93 | /// Returns the device ID on which this file resides. |
45 | 94 | /// |
46 | 95 | /// # Examples |
@@ -337,6 +386,39 @@ impl MetadataExt for Metadata { |
337 | 386 | &*(self.as_inner().as_inner() as *const libc::stat64 as *const raw::stat) |
338 | 387 | } |
339 | 388 | } |
| 389 | + cfg_has_statx! {{ |
| 390 | + unsafe fn from_statx(statxbuf: *const c_void) -> Metadata { |
| 391 | + let buf = statxbuf as *const libc::statx; |
| 392 | + |
| 393 | + // We cannot fill `stat64` exhaustively because of private padding fields. |
| 394 | + let mut stat: libc::stat64 = mem::zeroed(); |
| 395 | + // `c_ulong` on gnu-mips, `dev_t` otherwise |
| 396 | + stat.st_dev = libc::makedev((*buf).stx_dev_major, (*buf).stx_dev_minor) as _; |
| 397 | + stat.st_ino = (*buf).stx_ino as libc::ino64_t; |
| 398 | + stat.st_nlink = (*buf).stx_nlink as libc::nlink_t; |
| 399 | + stat.st_mode = (*buf).stx_mode as libc::mode_t; |
| 400 | + stat.st_uid = (*buf).stx_uid as libc::uid_t; |
| 401 | + stat.st_gid = (*buf).stx_gid as libc::gid_t; |
| 402 | + stat.st_rdev = libc::makedev((*buf).stx_rdev_major, (*buf).stx_rdev_minor) as _; |
| 403 | + stat.st_size = (*buf).stx_size as libc::off64_t; |
| 404 | + stat.st_blksize = (*buf).stx_blksize as libc::blksize_t; |
| 405 | + stat.st_blocks = (*buf).stx_blocks as libc::blkcnt64_t; |
| 406 | + stat.st_atime = (*buf).stx_atime.tv_sec as libc::time_t; |
| 407 | + // `i64` on gnu-x86_64-x32, `c_ulong` otherwise. |
| 408 | + stat.st_atime_nsec = (*buf).stx_atime.tv_nsec as _; |
| 409 | + stat.st_mtime = (*buf).stx_mtime.tv_sec as libc::time_t; |
| 410 | + stat.st_mtime_nsec = (*buf).stx_mtime.tv_nsec as _; |
| 411 | + stat.st_ctime = (*buf).stx_ctime.tv_sec as libc::time_t; |
| 412 | + stat.st_ctime_nsec = (*buf).stx_ctime.tv_nsec as _; |
| 413 | + |
| 414 | + let extra = StatxExtraFields::from_statx(statxbuf); |
| 415 | + |
| 416 | + Metadata::from_inner(FileAttr::from_statx(stat, Some(extra))) |
| 417 | + }} else { |
| 418 | + unsafe fn from_statx(statxbuf: *const c_void) -> Self { |
| 419 | + unsupported(); |
| 420 | + } |
| 421 | + }} |
340 | 422 | fn st_dev(&self) -> u64 { |
341 | 423 | self.as_inner().as_inner().st_dev as u64 |
342 | 424 | } |
|
0 commit comments