Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/walkdir.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/os/unix/stat.rs')
-rw-r--r--src/os/unix/stat.rs297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/os/unix/stat.rs b/src/os/unix/stat.rs
new file mode 100644
index 0000000..a367ed1
--- /dev/null
+++ b/src/os/unix/stat.rs
@@ -0,0 +1,297 @@
+use std::ffi::{CStr, CString, OsString};
+use std::fmt;
+use std::io;
+use std::mem;
+use std::os::unix::ffi::OsStringExt;
+use std::os::unix::io::RawFd;
+use std::path::PathBuf;
+use std::time::{Duration, SystemTime};
+
+use libc;
+
+#[cfg(not(any(target_os = "linux", target_os = "android",)))]
+use libc::{fstatat as fstatat64, lstat as lstat64, stat as stat64};
+#[cfg(any(target_os = "linux", target_os = "android",))]
+use libc::{fstatat64, lstat64, stat64};
+
+pub struct Metadata {
+ stat: stat64,
+}
+
+impl Metadata {
+ pub fn file_type(&self) -> FileType {
+ FileType::from_stat_mode(self.stat.st_mode as u64)
+ }
+
+ pub fn len(&self) -> u64 {
+ self.stat.st_size as u64
+ }
+
+ pub fn dev(&self) -> u64 {
+ self.stat.st_dev
+ }
+
+ pub fn ino(&self) -> u64 {
+ self.stat.st_ino
+ }
+
+ pub fn mode(&self) -> u64 {
+ self.stat.st_mode as u64
+ }
+
+ pub fn permissions(&self) -> ! {
+ unimplemented!()
+ }
+}
+
+#[cfg(target_os = "netbsd")]
+impl Metadata {
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ let dur = Duration::new(
+ self.stat.st_mtime as u64,
+ self.stat.st_mtimensec as u32,
+ );
+ Ok(SystemTime::UNIX_EPOCH + dur)
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ let dur = Duration::new(
+ self.stat.st_atime as u64,
+ self.stat.st_atimensec as u32,
+ );
+ Ok(SystemTime::UNIX_EPOCH + dur)
+ }
+
+ pub fn created(&self) -> io::Result<SystemTime> {
+ let dur = Duration::new(
+ self.stat.st_birthtime as u64,
+ self.stat.st_birthtimensec as u32,
+ );
+ Ok(SystemTime::UNIX_EPOCH + dur)
+ }
+}
+
+#[cfg(not(target_os = "netbsd"))]
+impl Metadata {
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ let dur = Duration::new(
+ self.stat.st_mtime as u64,
+ self.stat.st_mtime_nsec as u32,
+ );
+ Ok(SystemTime::UNIX_EPOCH + dur)
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ let dur = Duration::new(
+ self.stat.st_atime as u64,
+ self.stat.st_atime_nsec as u32,
+ );
+ Ok(SystemTime::UNIX_EPOCH + dur)
+ }
+
+ #[cfg(any(
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "macos",
+ target_os = "ios"
+ ))]
+ pub fn created(&self) -> io::Result<SystemTime> {
+ let dur = Duration::new(
+ self.stat.st_birthtime as u64,
+ self.stat.st_birthtime_nsec as u32,
+ );
+ Ok(SystemTime::UNIX_EPOCH + dur)
+ }
+
+ #[cfg(not(any(
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "macos",
+ target_os = "ios"
+ )))]
+ pub fn created(&self) -> io::Result<SystemTime> {
+ Err(io::Error::new(
+ io::ErrorKind::Other,
+ "creation time is not available on this platform currently",
+ ))
+ }
+}
+
+/// One of seven possible file types on Unix.
+#[derive(Clone, Copy)]
+pub struct FileType(libc::mode_t);
+
+impl fmt::Debug for FileType {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let human = if self.is_file() {
+ "File"
+ } else if self.is_dir() {
+ "Directory"
+ } else if self.is_symlink() {
+ "Symbolic Link"
+ } else if self.is_block_device() {
+ "Block Device"
+ } else if self.is_char_device() {
+ "Char Device"
+ } else if self.is_fifo() {
+ "FIFO"
+ } else if self.is_socket() {
+ "Socket"
+ } else {
+ "Unknown"
+ };
+ write!(f, "FileType({})", human)
+ }
+}
+
+impl FileType {
+ /// Create a new file type from a directory entry's type field.
+ ///
+ /// If the given type is not recognized or is `DT_UNKNOWN`, then `None`
+ /// is returned.
+ pub fn from_dirent_type(d_type: u8) -> Option<FileType> {
+ Some(FileType(match d_type {
+ libc::DT_REG => libc::S_IFREG,
+ libc::DT_DIR => libc::S_IFDIR,
+ libc::DT_LNK => libc::S_IFLNK,
+ libc::DT_BLK => libc::S_IFBLK,
+ libc::DT_CHR => libc::S_IFCHR,
+ libc::DT_FIFO => libc::S_IFIFO,
+ libc::DT_SOCK => libc::S_IFSOCK,
+ libc::DT_UNKNOWN => return None,
+ _ => return None, // wat?
+ }))
+ }
+
+ /// Create a new file type from a stat's `st_mode` field.
+ pub fn from_stat_mode(st_mode: u64) -> FileType {
+ FileType(st_mode as libc::mode_t)
+ }
+
+ /// Convert this file type to the platform independent file type.
+ pub fn into_api(self) -> crate::FileType {
+ crate::FileType::from(self)
+ }
+
+ /// Returns true if this file type is a regular file.
+ ///
+ /// This corresponds to the `S_IFREG` value on Unix.
+ pub fn is_file(&self) -> bool {
+ self.0 & libc::S_IFMT == libc::S_IFREG
+ }
+
+ /// Returns true if this file type is a directory.
+ ///
+ /// This corresponds to the `S_IFDIR` value on Unix.
+ pub fn is_dir(&self) -> bool {
+ self.0 & libc::S_IFMT == libc::S_IFDIR
+ }
+
+ /// Returns true if this file type is a symbolic link.
+ ///
+ /// This corresponds to the `S_IFLNK` value on Unix.
+ pub fn is_symlink(&self) -> bool {
+ self.0 & libc::S_IFMT == libc::S_IFLNK
+ }
+
+ /// Returns true if this file type is a block device.
+ ///
+ /// This corresponds to the `S_IFBLK` value on Unix.
+ pub fn is_block_device(&self) -> bool {
+ self.0 & libc::S_IFMT == libc::S_IFBLK
+ }
+
+ /// Returns true if this file type is a character device.
+ ///
+ /// This corresponds to the `S_IFCHR` value on Unix.
+ pub fn is_char_device(&self) -> bool {
+ self.0 & libc::S_IFMT == libc::S_IFCHR
+ }
+
+ /// Returns true if this file type is a FIFO.
+ ///
+ /// This corresponds to the `S_IFIFO` value on Unix.
+ pub fn is_fifo(&self) -> bool {
+ self.0 & libc::S_IFMT == libc::S_IFIFO
+ }
+
+ /// Returns true if this file type is a socket.
+ ///
+ /// This corresponds to the `S_IFSOCK` value on Unix.
+ pub fn is_socket(&self) -> bool {
+ self.0 & libc::S_IFMT == libc::S_IFSOCK
+ }
+}
+
+pub fn stat<P: Into<PathBuf>>(path: P) -> io::Result<Metadata> {
+ let bytes = path.into().into_os_string().into_vec();
+ stat_c(&CString::new(bytes)?)
+}
+
+pub fn stat_c(path: &CStr) -> io::Result<Metadata> {
+ let mut stat: stat64 = unsafe { mem::zeroed() };
+ let res = unsafe { stat64(path.as_ptr(), &mut stat) };
+ if res < 0 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(Metadata { stat })
+ }
+}
+
+pub fn lstat<P: Into<PathBuf>>(path: P) -> io::Result<Metadata> {
+ let bytes = path.into().into_os_string().into_vec();
+ lstat_c(&CString::new(bytes)?)
+}
+
+pub fn lstat_c(path: &CStr) -> io::Result<Metadata> {
+ let mut stat: stat64 = unsafe { mem::zeroed() };
+ let res = unsafe { lstat64(path.as_ptr(), &mut stat) };
+ if res < 0 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(Metadata { stat })
+ }
+}
+
+pub fn statat<N: Into<OsString>>(
+ parent_dirfd: RawFd,
+ name: N,
+) -> io::Result<Metadata> {
+ let bytes = name.into().into_vec();
+ statat_c(parent_dirfd, &CString::new(bytes)?)
+}
+
+pub fn statat_c(parent_dirfd: RawFd, name: &CStr) -> io::Result<Metadata> {
+ let mut stat: stat64 = unsafe { mem::zeroed() };
+ let res = unsafe { fstatat64(parent_dirfd, name.as_ptr(), &mut stat, 0) };
+ if res < 0 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(Metadata { stat })
+ }
+}
+
+pub fn lstatat<N: Into<OsString>>(
+ parent_dirfd: RawFd,
+ name: N,
+) -> io::Result<Metadata> {
+ let bytes = name.into().into_vec();
+ lstatat_c(parent_dirfd, &CString::new(bytes)?)
+}
+
+pub fn lstatat_c(parent_dirfd: RawFd, name: &CStr) -> io::Result<Metadata> {
+ let mut stat: stat64 = unsafe { mem::zeroed() };
+ let res = unsafe {
+ fstatat64(
+ parent_dirfd,
+ name.as_ptr(),
+ &mut stat,
+ libc::AT_SYMLINK_NOFOLLOW,
+ )
+ };
+ if res < 0 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(Metadata { stat })
+ }
+}