diff options
Diffstat (limited to 'third_party/rust/nix/src/sys/stat.rs')
-rw-r--r-- | third_party/rust/nix/src/sys/stat.rs | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/third_party/rust/nix/src/sys/stat.rs b/third_party/rust/nix/src/sys/stat.rs new file mode 100644 index 0000000000..78203bfbe3 --- /dev/null +++ b/third_party/rust/nix/src/sys/stat.rs @@ -0,0 +1,480 @@ +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] +pub use libc::c_uint; +#[cfg(any( + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly" +))] +pub use libc::c_ulong; +pub use libc::stat as FileStat; +pub use libc::{dev_t, mode_t}; + +#[cfg(not(target_os = "redox"))] +use crate::fcntl::{at_rawfd, AtFlags}; +use crate::sys::time::{TimeSpec, TimeVal}; +use crate::{errno::Errno, NixPath, Result}; +use std::mem; +use std::os::unix::io::RawFd; + +libc_bitflags!( + /// "File type" flags for `mknod` and related functions. + pub struct SFlag: mode_t { + S_IFIFO; + S_IFCHR; + S_IFDIR; + S_IFBLK; + S_IFREG; + S_IFLNK; + S_IFSOCK; + S_IFMT; + } +); + +libc_bitflags! { + /// "File mode / permissions" flags. + pub struct Mode: mode_t { + /// Read, write and execute for owner. + S_IRWXU; + /// Read for owner. + S_IRUSR; + /// Write for owner. + S_IWUSR; + /// Execute for owner. + S_IXUSR; + /// Read write and execute for group. + S_IRWXG; + /// Read fr group. + S_IRGRP; + /// Write for group. + S_IWGRP; + /// Execute for group. + S_IXGRP; + /// Read, write and execute for other. + S_IRWXO; + /// Read for other. + S_IROTH; + /// Write for other. + S_IWOTH; + /// Execute for other. + S_IXOTH; + /// Set user id on execution. + S_ISUID as mode_t; + /// Set group id on execution. + S_ISGID as mode_t; + S_ISVTX as mode_t; + } +} + +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] +pub type type_of_file_flag = c_uint; +#[cfg(any( + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly" +))] +pub type type_of_file_flag = c_ulong; + +#[cfg(any( + target_os = "openbsd", + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios" +))] +libc_bitflags! { + /// File flags. + #[cfg_attr(docsrs, doc(cfg(all())))] + pub struct FileFlag: type_of_file_flag { + /// The file may only be appended to. + SF_APPEND; + /// The file has been archived. + SF_ARCHIVED; + #[cfg(any(target_os = "dragonfly"))] + SF_CACHE; + /// The file may not be changed. + SF_IMMUTABLE; + /// Indicates a WAPBL journal file. + #[cfg(any(target_os = "netbsd"))] + SF_LOG; + /// Do not retain history for file + #[cfg(any(target_os = "dragonfly"))] + SF_NOHISTORY; + /// The file may not be renamed or deleted. + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + SF_NOUNLINK; + /// Mask of superuser changeable flags + SF_SETTABLE; + /// Snapshot is invalid. + #[cfg(any(target_os = "netbsd"))] + SF_SNAPINVAL; + /// The file is a snapshot file. + #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] + SF_SNAPSHOT; + #[cfg(any(target_os = "dragonfly"))] + SF_XLINK; + /// The file may only be appended to. + UF_APPEND; + /// The file needs to be archived. + #[cfg(any(target_os = "freebsd"))] + UF_ARCHIVE; + #[cfg(any(target_os = "dragonfly"))] + UF_CACHE; + /// File is compressed at the file system level. + #[cfg(any(target_os = "macos", target_os = "ios"))] + UF_COMPRESSED; + /// The file may be hidden from directory listings at the application's + /// discretion. + #[cfg(any( + target_os = "freebsd", + target_os = "macos", + target_os = "ios", + ))] + UF_HIDDEN; + /// The file may not be changed. + UF_IMMUTABLE; + /// Do not dump the file. + UF_NODUMP; + #[cfg(any(target_os = "dragonfly"))] + UF_NOHISTORY; + /// The file may not be renamed or deleted. + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + UF_NOUNLINK; + /// The file is offline, or has the Windows and CIFS + /// `FILE_ATTRIBUTE_OFFLINE` attribute. + #[cfg(any(target_os = "freebsd"))] + UF_OFFLINE; + /// The directory is opaque when viewed through a union stack. + UF_OPAQUE; + /// The file is read only, and may not be written or appended. + #[cfg(any(target_os = "freebsd"))] + UF_READONLY; + /// The file contains a Windows reparse point. + #[cfg(any(target_os = "freebsd"))] + UF_REPARSE; + /// Mask of owner changeable flags. + UF_SETTABLE; + /// The file has the Windows `FILE_ATTRIBUTE_SPARSE_FILE` attribute. + #[cfg(any(target_os = "freebsd"))] + UF_SPARSE; + /// The file has the DOS, Windows and CIFS `FILE_ATTRIBUTE_SYSTEM` + /// attribute. + #[cfg(any(target_os = "freebsd"))] + UF_SYSTEM; + /// File renames and deletes are tracked. + #[cfg(any(target_os = "macos", target_os = "ios"))] + UF_TRACKED; + #[cfg(any(target_os = "dragonfly"))] + UF_XLINK; + } +} + +/// Create a special or ordinary file, by pathname. +pub fn mknod<P: ?Sized + NixPath>( + path: &P, + kind: SFlag, + perm: Mode, + dev: dev_t, +) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) + })?; + + Errno::result(res).map(drop) +} + +/// Create a special or ordinary file, relative to a given directory. +#[cfg(not(any( + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "haiku" +)))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn mknodat<P: ?Sized + NixPath>( + dirfd: RawFd, + path: &P, + kind: SFlag, + perm: Mode, + dev: dev_t, +) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::mknodat( + dirfd, + cstr.as_ptr(), + kind.bits | perm.bits() as mode_t, + dev, + ) + })?; + + Errno::result(res).map(drop) +} + +#[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub const fn major(dev: dev_t) -> u64 { + ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff) +} + +#[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub const fn minor(dev: dev_t) -> u64 { + ((dev >> 12) & 0xffff_ff00) | ((dev) & 0x0000_00ff) +} + +#[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub const fn makedev(major: u64, minor: u64) -> dev_t { + ((major & 0xffff_f000) << 32) + | ((major & 0x0000_0fff) << 8) + | ((minor & 0xffff_ff00) << 12) + | (minor & 0x0000_00ff) +} + +pub fn umask(mode: Mode) -> Mode { + let prev = unsafe { libc::umask(mode.bits() as mode_t) }; + Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode") +} + +pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> { + let mut dst = mem::MaybeUninit::uninit(); + let res = path.with_nix_path(|cstr| unsafe { + libc::stat(cstr.as_ptr(), dst.as_mut_ptr()) + })?; + + Errno::result(res)?; + + Ok(unsafe { dst.assume_init() }) +} + +pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> { + let mut dst = mem::MaybeUninit::uninit(); + let res = path.with_nix_path(|cstr| unsafe { + libc::lstat(cstr.as_ptr(), dst.as_mut_ptr()) + })?; + + Errno::result(res)?; + + Ok(unsafe { dst.assume_init() }) +} + +pub fn fstat(fd: RawFd) -> Result<FileStat> { + let mut dst = mem::MaybeUninit::uninit(); + let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) }; + + Errno::result(res)?; + + Ok(unsafe { dst.assume_init() }) +} + +#[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn fstatat<P: ?Sized + NixPath>( + dirfd: RawFd, + pathname: &P, + f: AtFlags, +) -> Result<FileStat> { + let mut dst = mem::MaybeUninit::uninit(); + let res = pathname.with_nix_path(|cstr| unsafe { + libc::fstatat( + dirfd, + cstr.as_ptr(), + dst.as_mut_ptr(), + f.bits() as libc::c_int, + ) + })?; + + Errno::result(res)?; + + Ok(unsafe { dst.assume_init() }) +} + +/// Change the file permission bits of the file specified by a file descriptor. +/// +/// # References +/// +/// [fchmod(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html). +pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> { + let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) }; + + Errno::result(res).map(drop) +} + +/// Flags for `fchmodat` function. +#[derive(Clone, Copy, Debug)] +pub enum FchmodatFlags { + FollowSymlink, + NoFollowSymlink, +} + +/// Change the file permission bits. +/// +/// The file to be changed is determined relative to the directory associated +/// with the file descriptor `dirfd` or the current working directory +/// if `dirfd` is `None`. +/// +/// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link, +/// then the mode of the symbolic link is changed. +/// +/// `fchmodat(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to +/// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented +/// in the `nix` crate. +/// +/// # References +/// +/// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html). +#[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn fchmodat<P: ?Sized + NixPath>( + dirfd: Option<RawFd>, + path: &P, + mode: Mode, + flag: FchmodatFlags, +) -> Result<()> { + let atflag = match flag { + FchmodatFlags::FollowSymlink => AtFlags::empty(), + FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, + }; + let res = path.with_nix_path(|cstr| unsafe { + libc::fchmodat( + at_rawfd(dirfd), + cstr.as_ptr(), + mode.bits() as mode_t, + atflag.bits() as libc::c_int, + ) + })?; + + Errno::result(res).map(drop) +} + +/// Change the access and modification times of a file. +/// +/// `utimes(path, times)` is identical to +/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former +/// is a deprecated API so prefer using the latter if the platforms you care +/// about support it. +/// +/// # References +/// +/// [utimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html). +pub fn utimes<P: ?Sized + NixPath>( + path: &P, + atime: &TimeVal, + mtime: &TimeVal, +) -> Result<()> { + let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; + let res = path.with_nix_path(|cstr| unsafe { + libc::utimes(cstr.as_ptr(), ×[0]) + })?; + + Errno::result(res).map(drop) +} + +/// Change the access and modification times of a file without following symlinks. +/// +/// `lutimes(path, times)` is identical to +/// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former +/// is a deprecated API so prefer using the latter if the platforms you care +/// about support it. +/// +/// # References +/// +/// [lutimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html). +#[cfg(any( + target_os = "linux", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd" +))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn lutimes<P: ?Sized + NixPath>( + path: &P, + atime: &TimeVal, + mtime: &TimeVal, +) -> Result<()> { + let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; + let res = path.with_nix_path(|cstr| unsafe { + libc::lutimes(cstr.as_ptr(), ×[0]) + })?; + + Errno::result(res).map(drop) +} + +/// Change the access and modification times of the file specified by a file descriptor. +/// +/// # References +/// +/// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). +#[inline] +pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> { + let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; + let res = unsafe { libc::futimens(fd, ×[0]) }; + + Errno::result(res).map(drop) +} + +/// Flags for `utimensat` function. +// TODO: replace with fcntl::AtFlags +#[derive(Clone, Copy, Debug)] +pub enum UtimensatFlags { + FollowSymlink, + NoFollowSymlink, +} + +/// Change the access and modification times of a file. +/// +/// The file to be changed is determined relative to the directory associated +/// with the file descriptor `dirfd` or the current working directory +/// if `dirfd` is `None`. +/// +/// If `flag` is `UtimensatFlags::NoFollowSymlink` and `path` names a symbolic link, +/// then the mode of the symbolic link is changed. +/// +/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to +/// `utimes(path, times)`. The latter is a deprecated API so prefer using the +/// former if the platforms you care about support it. +/// +/// # References +/// +/// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html). +#[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn utimensat<P: ?Sized + NixPath>( + dirfd: Option<RawFd>, + path: &P, + atime: &TimeSpec, + mtime: &TimeSpec, + flag: UtimensatFlags, +) -> Result<()> { + let atflag = match flag { + UtimensatFlags::FollowSymlink => AtFlags::empty(), + UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, + }; + let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; + let res = path.with_nix_path(|cstr| unsafe { + libc::utimensat( + at_rawfd(dirfd), + cstr.as_ptr(), + ×[0], + atflag.bits() as libc::c_int, + ) + })?; + + Errno::result(res).map(drop) +} + +#[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn mkdirat<P: ?Sized + NixPath>( + fd: RawFd, + path: &P, + mode: Mode, +) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) + })?; + + Errno::result(res).map(drop) +} |