|  | //! Unix-specific extensions to primitives in the [`std::fs`] module. | 
|  | //! | 
|  | //! [`std::fs`]: crate::fs | 
|  |  | 
|  | #![stable(feature = "rust1", since = "1.0.0")] | 
|  |  | 
|  | #[allow(unused_imports)] | 
|  | use io::{Read, Write}; | 
|  |  | 
|  | use super::platform::fs::MetadataExt as _; | 
|  | // Used for `File::read` on intra-doc links | 
|  | use crate::ffi::OsStr; | 
|  | use crate::fs::{self, OpenOptions, Permissions}; | 
|  | use crate::io::BorrowedCursor; | 
|  | use crate::os::unix::io::{AsFd, AsRawFd}; | 
|  | use crate::path::Path; | 
|  | use crate::sealed::Sealed; | 
|  | use crate::sys_common::{AsInner, AsInnerMut, FromInner}; | 
|  | use crate::{io, sys}; | 
|  |  | 
|  | // Tests for this module | 
|  | #[cfg(test)] | 
|  | mod tests; | 
|  |  | 
|  | /// Unix-specific extensions to [`fs::File`]. | 
|  | #[stable(feature = "file_offset", since = "1.15.0")] | 
|  | pub trait FileExt { | 
|  | /// Reads a number of bytes starting from a given offset. | 
|  | /// | 
|  | /// Returns the number of bytes read. | 
|  | /// | 
|  | /// The offset is relative to the start of the file and thus independent | 
|  | /// from the current cursor. | 
|  | /// | 
|  | /// The current file cursor is not affected by this function. | 
|  | /// | 
|  | /// Note that similar to [`File::read`], it is not an error to return with a | 
|  | /// short read. | 
|  | /// | 
|  | /// [`File::read`]: fs::File::read | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::io; | 
|  | /// use std::fs::File; | 
|  | /// use std::os::unix::prelude::FileExt; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let mut buf = [0u8; 8]; | 
|  | ///     let file = File::open("foo.txt")?; | 
|  | /// | 
|  | ///     // We now read 8 bytes from the offset 10. | 
|  | ///     let num_bytes_read = file.read_at(&mut buf, 10)?; | 
|  | ///     println!("read {num_bytes_read} bytes: {buf:?}"); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "file_offset", since = "1.15.0")] | 
|  | fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; | 
|  |  | 
|  | /// Like `read_at`, except that it reads into a slice of buffers. | 
|  | /// | 
|  | /// Data is copied to fill each buffer in order, with the final buffer | 
|  | /// written to possibly being only partially filled. This method must behave | 
|  | /// equivalently to a single call to read with concatenated buffers. | 
|  | #[unstable(feature = "unix_file_vectored_at", issue = "89517")] | 
|  | fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> { | 
|  | io::default_read_vectored(|b| self.read_at(b, offset), bufs) | 
|  | } | 
|  |  | 
|  | /// Reads the exact number of bytes required to fill `buf` from the given offset. | 
|  | /// | 
|  | /// The offset is relative to the start of the file and thus independent | 
|  | /// from the current cursor. | 
|  | /// | 
|  | /// The current file cursor is not affected by this function. | 
|  | /// | 
|  | /// Similar to [`io::Read::read_exact`] but uses [`read_at`] instead of `read`. | 
|  | /// | 
|  | /// [`read_at`]: FileExt::read_at | 
|  | /// | 
|  | /// # Errors | 
|  | /// | 
|  | /// If this function encounters an error of the kind | 
|  | /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation | 
|  | /// will continue. | 
|  | /// | 
|  | /// If this function encounters an "end of file" before completely filling | 
|  | /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`]. | 
|  | /// The contents of `buf` are unspecified in this case. | 
|  | /// | 
|  | /// If any other read error is encountered then this function immediately | 
|  | /// returns. The contents of `buf` are unspecified in this case. | 
|  | /// | 
|  | /// If this function returns an error, it is unspecified how many bytes it | 
|  | /// has read, but it will never read more than would be necessary to | 
|  | /// completely fill the buffer. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::io; | 
|  | /// use std::fs::File; | 
|  | /// use std::os::unix::prelude::FileExt; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let mut buf = [0u8; 8]; | 
|  | ///     let file = File::open("foo.txt")?; | 
|  | /// | 
|  | ///     // We now read exactly 8 bytes from the offset 10. | 
|  | ///     file.read_exact_at(&mut buf, 10)?; | 
|  | ///     println!("read {} bytes: {:?}", buf.len(), buf); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "rw_exact_all_at", since = "1.33.0")] | 
|  | fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { | 
|  | while !buf.is_empty() { | 
|  | match self.read_at(buf, offset) { | 
|  | Ok(0) => break, | 
|  | Ok(n) => { | 
|  | let tmp = buf; | 
|  | buf = &mut tmp[n..]; | 
|  | offset += n as u64; | 
|  | } | 
|  | Err(ref e) if e.is_interrupted() => {} | 
|  | Err(e) => return Err(e), | 
|  | } | 
|  | } | 
|  | if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) } | 
|  | } | 
|  |  | 
|  | /// Reads some bytes starting from a given offset into the buffer. | 
|  | /// | 
|  | /// This equivalent to the [`read_at`](FileExt::read_at) method, except that it is passed a | 
|  | /// [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized buffers. The new | 
|  | /// data will be appended to any existing contents of `buf`. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// #![feature(core_io_borrowed_buf)] | 
|  | /// #![feature(read_buf_at)] | 
|  | /// | 
|  | /// use std::io; | 
|  | /// use std::io::BorrowedBuf; | 
|  | /// use std::fs::File; | 
|  | /// use std::mem::MaybeUninit; | 
|  | /// use std::os::unix::prelude::*; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let mut file = File::open("pi.txt")?; | 
|  | /// | 
|  | ///     // Read some bytes starting from offset 2 | 
|  | ///     let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10]; | 
|  | ///     let mut buf = BorrowedBuf::from(buf.as_mut_slice()); | 
|  | ///     file.read_buf_at(buf.unfilled(), 2)?; | 
|  | /// | 
|  | ///     assert!(buf.filled().starts_with(b"1")); | 
|  | /// | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[unstable(feature = "read_buf_at", issue = "140771")] | 
|  | fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { | 
|  | io::default_read_buf(|b| self.read_at(b, offset), buf) | 
|  | } | 
|  |  | 
|  | /// Reads the exact number of bytes required to fill the buffer from a given offset. | 
|  | /// | 
|  | /// This is equivalent to the [`read_exact_at`](FileExt::read_exact_at) method, except that it | 
|  | /// is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized | 
|  | /// buffers. The new data will be appended to any existing contents of `buf`. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// #![feature(core_io_borrowed_buf)] | 
|  | /// #![feature(read_buf_at)] | 
|  | /// | 
|  | /// use std::io; | 
|  | /// use std::io::BorrowedBuf; | 
|  | /// use std::fs::File; | 
|  | /// use std::mem::MaybeUninit; | 
|  | /// use std::os::unix::prelude::*; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let mut file = File::open("pi.txt")?; | 
|  | /// | 
|  | ///     // Read exactly 10 bytes starting from offset 2 | 
|  | ///     let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10]; | 
|  | ///     let mut buf = BorrowedBuf::from(buf.as_mut_slice()); | 
|  | ///     file.read_buf_exact_at(buf.unfilled(), 2)?; | 
|  | /// | 
|  | ///     assert_eq!(buf.filled(), b"1415926535"); | 
|  | /// | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[unstable(feature = "read_buf_at", issue = "140771")] | 
|  | fn read_buf_exact_at(&self, mut buf: BorrowedCursor<'_>, mut offset: u64) -> io::Result<()> { | 
|  | while buf.capacity() > 0 { | 
|  | let prev_written = buf.written(); | 
|  | match self.read_buf_at(buf.reborrow(), offset) { | 
|  | Ok(()) => {} | 
|  | Err(e) if e.is_interrupted() => {} | 
|  | Err(e) => return Err(e), | 
|  | } | 
|  | let n = buf.written() - prev_written; | 
|  | offset += n as u64; | 
|  | if n == 0 { | 
|  | return Err(io::Error::READ_EXACT_EOF); | 
|  | } | 
|  | } | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | /// Writes a number of bytes starting from a given offset. | 
|  | /// | 
|  | /// Returns the number of bytes written. | 
|  | /// | 
|  | /// The offset is relative to the start of the file and thus independent | 
|  | /// from the current cursor. | 
|  | /// | 
|  | /// The current file cursor is not affected by this function. | 
|  | /// | 
|  | /// When writing beyond the end of the file, the file is appropriately | 
|  | /// extended and the intermediate bytes are initialized with the value 0. | 
|  | /// | 
|  | /// Note that similar to [`File::write`], it is not an error to return a | 
|  | /// short write. | 
|  | /// | 
|  | /// # Bug | 
|  | /// On some systems, `write_at` utilises [`pwrite64`] to write to files. | 
|  | /// However, this syscall has a [bug] where files opened with the `O_APPEND` | 
|  | /// flag fail to respect the offset parameter, always appending to the end | 
|  | /// of the file instead. | 
|  | /// | 
|  | /// It is possible to inadvertently set this flag, like in the example below. | 
|  | /// Therefore, it is important to be vigilant while changing options to mitigate | 
|  | /// unexpected behavior. | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs::File; | 
|  | /// use std::io; | 
|  | /// use std::os::unix::prelude::FileExt; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     // Open a file with the append option (sets the `O_APPEND` flag) | 
|  | ///     let file = File::options().append(true).open("foo.txt")?; | 
|  | /// | 
|  | ///     // We attempt to write at offset 10; instead appended to EOF | 
|  | ///     file.write_at(b"sushi", 10)?; | 
|  | /// | 
|  | ///     // foo.txt is 5 bytes long instead of 15 | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | /// | 
|  | /// [`File::write`]: fs::File::write | 
|  | /// [`pwrite64`]: https://man7.org/linux/man-pages/man2/pwrite.2.html | 
|  | /// [bug]: https://man7.org/linux/man-pages/man2/pwrite.2.html#BUGS | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs::File; | 
|  | /// use std::io; | 
|  | /// use std::os::unix::prelude::FileExt; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let file = File::create("foo.txt")?; | 
|  | /// | 
|  | ///     // We now write at the offset 10. | 
|  | ///     file.write_at(b"sushi", 10)?; | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "file_offset", since = "1.15.0")] | 
|  | fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>; | 
|  |  | 
|  | /// Like `write_at`, except that it writes from a slice of buffers. | 
|  | /// | 
|  | /// Data is copied from each buffer in order, with the final buffer read | 
|  | /// from possibly being only partially consumed. This method must behave as | 
|  | /// a call to `write_at` with the buffers concatenated would. | 
|  | #[unstable(feature = "unix_file_vectored_at", issue = "89517")] | 
|  | fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> { | 
|  | io::default_write_vectored(|b| self.write_at(b, offset), bufs) | 
|  | } | 
|  |  | 
|  | /// Attempts to write an entire buffer starting from a given offset. | 
|  | /// | 
|  | /// The offset is relative to the start of the file and thus independent | 
|  | /// from the current cursor. | 
|  | /// | 
|  | /// The current file cursor is not affected by this function. | 
|  | /// | 
|  | /// This method will continuously call [`write_at`] until there is no more data | 
|  | /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is | 
|  | /// returned. This method will not return until the entire buffer has been | 
|  | /// successfully written or such an error occurs. The first error that is | 
|  | /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be | 
|  | /// returned. | 
|  | /// | 
|  | /// # Errors | 
|  | /// | 
|  | /// This function will return the first error of | 
|  | /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns. | 
|  | /// | 
|  | /// [`write_at`]: FileExt::write_at | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs::File; | 
|  | /// use std::io; | 
|  | /// use std::os::unix::prelude::FileExt; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let file = File::open("foo.txt")?; | 
|  | /// | 
|  | ///     // We now write at the offset 10. | 
|  | ///     file.write_all_at(b"sushi", 10)?; | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "rw_exact_all_at", since = "1.33.0")] | 
|  | fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { | 
|  | while !buf.is_empty() { | 
|  | match self.write_at(buf, offset) { | 
|  | Ok(0) => { | 
|  | return Err(io::Error::WRITE_ALL_EOF); | 
|  | } | 
|  | Ok(n) => { | 
|  | buf = &buf[n..]; | 
|  | offset += n as u64 | 
|  | } | 
|  | Err(ref e) if e.is_interrupted() => {} | 
|  | Err(e) => return Err(e), | 
|  | } | 
|  | } | 
|  | Ok(()) | 
|  | } | 
|  | } | 
|  |  | 
|  | #[stable(feature = "file_offset", since = "1.15.0")] | 
|  | impl FileExt for fs::File { | 
|  | fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { | 
|  | self.as_inner().read_at(buf, offset) | 
|  | } | 
|  | fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { | 
|  | self.as_inner().read_buf_at(buf, offset) | 
|  | } | 
|  | fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> { | 
|  | self.as_inner().read_vectored_at(bufs, offset) | 
|  | } | 
|  | fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { | 
|  | self.as_inner().write_at(buf, offset) | 
|  | } | 
|  | fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> { | 
|  | self.as_inner().write_vectored_at(bufs, offset) | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Unix-specific extensions to [`fs::Permissions`]. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs::{File, Permissions}; | 
|  | /// use std::io::{ErrorKind, Result as IoResult}; | 
|  | /// use std::os::unix::fs::PermissionsExt; | 
|  | /// | 
|  | /// fn main() -> IoResult<()> { | 
|  | ///     let name = "test_file_for_permissions"; | 
|  | /// | 
|  | ///     // make sure file does not exist | 
|  | ///     let _ = std::fs::remove_file(name); | 
|  | ///     assert_eq!( | 
|  | ///         File::open(name).unwrap_err().kind(), | 
|  | ///         ErrorKind::NotFound, | 
|  | ///         "file already exists" | 
|  | ///     ); | 
|  | /// | 
|  | ///     // full read/write/execute mode bits for owner of file | 
|  | ///     // that we want to add to existing mode bits | 
|  | ///     let my_mode = 0o700; | 
|  | /// | 
|  | ///     // create new file with specified permissions | 
|  | ///     { | 
|  | ///         let file = File::create(name)?; | 
|  | ///         let mut permissions = file.metadata()?.permissions(); | 
|  | ///         eprintln!("Current permissions: {:o}", permissions.mode()); | 
|  | /// | 
|  | ///         // make sure new permissions are not already set | 
|  | ///         assert!( | 
|  | ///             permissions.mode() & my_mode != my_mode, | 
|  | ///             "permissions already set" | 
|  | ///         ); | 
|  | /// | 
|  | ///         // either use `set_mode` to change an existing Permissions struct | 
|  | ///         permissions.set_mode(permissions.mode() | my_mode); | 
|  | /// | 
|  | ///         // or use `from_mode` to construct a new Permissions struct | 
|  | ///         permissions = Permissions::from_mode(permissions.mode() | my_mode); | 
|  | /// | 
|  | ///         // write new permissions to file | 
|  | ///         file.set_permissions(permissions)?; | 
|  | ///     } | 
|  | /// | 
|  | ///     let permissions = File::open(name)?.metadata()?.permissions(); | 
|  | ///     eprintln!("New permissions: {:o}", permissions.mode()); | 
|  | /// | 
|  | ///     // assert new permissions were set | 
|  | ///     assert_eq!( | 
|  | ///         permissions.mode() & my_mode, | 
|  | ///         my_mode, | 
|  | ///         "new permissions not set" | 
|  | ///     ); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs::Permissions; | 
|  | /// use std::os::unix::fs::PermissionsExt; | 
|  | /// | 
|  | /// // read/write for owner and read for others | 
|  | /// let my_mode = 0o644; | 
|  | /// let mut permissions = Permissions::from_mode(my_mode); | 
|  | /// assert_eq!(permissions.mode(), my_mode); | 
|  | /// | 
|  | /// // read/write/execute for owner | 
|  | /// let other_mode = 0o700; | 
|  | /// permissions.set_mode(other_mode); | 
|  | /// assert_eq!(permissions.mode(), other_mode); | 
|  | /// ``` | 
|  | #[stable(feature = "fs_ext", since = "1.1.0")] | 
|  | pub trait PermissionsExt { | 
|  | /// Returns the mode permission bits | 
|  | #[stable(feature = "fs_ext", since = "1.1.0")] | 
|  | fn mode(&self) -> u32; | 
|  |  | 
|  | /// Sets the mode permission bits. | 
|  | #[stable(feature = "fs_ext", since = "1.1.0")] | 
|  | fn set_mode(&mut self, mode: u32); | 
|  |  | 
|  | /// Creates a new instance from the given mode permission bits. | 
|  | #[stable(feature = "fs_ext", since = "1.1.0")] | 
|  | #[cfg_attr(not(test), rustc_diagnostic_item = "permissions_from_mode")] | 
|  | fn from_mode(mode: u32) -> Self; | 
|  | } | 
|  |  | 
|  | #[stable(feature = "fs_ext", since = "1.1.0")] | 
|  | impl PermissionsExt for Permissions { | 
|  | fn mode(&self) -> u32 { | 
|  | self.as_inner().mode() | 
|  | } | 
|  |  | 
|  | fn set_mode(&mut self, mode: u32) { | 
|  | *self = Permissions::from_inner(FromInner::from_inner(mode)); | 
|  | } | 
|  |  | 
|  | fn from_mode(mode: u32) -> Permissions { | 
|  | Permissions::from_inner(FromInner::from_inner(mode)) | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Unix-specific extensions to [`fs::OpenOptions`]. | 
|  | #[stable(feature = "fs_ext", since = "1.1.0")] | 
|  | pub trait OpenOptionsExt { | 
|  | /// Sets the mode bits that a new file will be created with. | 
|  | /// | 
|  | /// If a new file is created as part of an `OpenOptions::open` call then this | 
|  | /// specified `mode` will be used as the permission bits for the new file. | 
|  | /// If no `mode` is set, the default of `0o666` will be used. | 
|  | /// The operating system masks out bits with the system's `umask`, to produce | 
|  | /// the final permissions. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs::OpenOptions; | 
|  | /// use std::os::unix::fs::OpenOptionsExt; | 
|  | /// | 
|  | /// # fn main() { | 
|  | /// let mut options = OpenOptions::new(); | 
|  | /// options.mode(0o644); // Give read/write for owner and read for others. | 
|  | /// let file = options.open("foo.txt"); | 
|  | /// # } | 
|  | /// ``` | 
|  | #[stable(feature = "fs_ext", since = "1.1.0")] | 
|  | fn mode(&mut self, mode: u32) -> &mut Self; | 
|  |  | 
|  | /// Pass custom flags to the `flags` argument of `open`. | 
|  | /// | 
|  | /// The bits that define the access mode are masked out with `O_ACCMODE`, to | 
|  | /// ensure they do not interfere with the access mode set by Rust's options. | 
|  | /// | 
|  | /// Custom flags can only set flags, not remove flags set by Rust's options. | 
|  | /// This function overwrites any previously-set custom flags. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// # mod libc { pub const O_NOFOLLOW: i32 = 0; } | 
|  | /// use std::fs::OpenOptions; | 
|  | /// use std::os::unix::fs::OpenOptionsExt; | 
|  | /// | 
|  | /// # fn main() { | 
|  | /// let mut options = OpenOptions::new(); | 
|  | /// options.write(true); | 
|  | /// options.custom_flags(libc::O_NOFOLLOW); | 
|  | /// let file = options.open("foo.txt"); | 
|  | /// # } | 
|  | /// ``` | 
|  | #[stable(feature = "open_options_ext", since = "1.10.0")] | 
|  | fn custom_flags(&mut self, flags: i32) -> &mut Self; | 
|  | } | 
|  |  | 
|  | #[stable(feature = "fs_ext", since = "1.1.0")] | 
|  | impl OpenOptionsExt for OpenOptions { | 
|  | fn mode(&mut self, mode: u32) -> &mut OpenOptions { | 
|  | self.as_inner_mut().mode(mode); | 
|  | self | 
|  | } | 
|  |  | 
|  | fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { | 
|  | self.as_inner_mut().custom_flags(flags); | 
|  | self | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Unix-specific extensions to [`fs::Metadata`]. | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | pub trait MetadataExt { | 
|  | /// Returns the ID of the device containing the file. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::io; | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let dev_id = meta.dev(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn dev(&self) -> u64; | 
|  | /// Returns the inode number. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let inode = meta.ino(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn ino(&self) -> u64; | 
|  | /// Returns the rights applied to this file. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let mode = meta.mode(); | 
|  | ///     let user_has_write_access      = mode & 0o200; | 
|  | ///     let user_has_read_write_access = mode & 0o600; | 
|  | ///     let group_has_read_access      = mode & 0o040; | 
|  | ///     let others_have_exec_access    = mode & 0o001; | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn mode(&self) -> u32; | 
|  | /// Returns the number of hard links pointing to this file. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let nb_hard_links = meta.nlink(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn nlink(&self) -> u64; | 
|  | /// Returns the user ID of the owner of this file. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let user_id = meta.uid(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn uid(&self) -> u32; | 
|  | /// Returns the group ID of the owner of this file. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let group_id = meta.gid(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn gid(&self) -> u32; | 
|  | /// Returns the device ID of this file (if it is a special one). | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let device_id = meta.rdev(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn rdev(&self) -> u64; | 
|  | /// Returns the total size of this file in bytes. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let file_size = meta.size(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn size(&self) -> u64; | 
|  | /// Returns the last access time of the file, in seconds since Unix Epoch. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let last_access_time = meta.atime(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn atime(&self) -> i64; | 
|  | /// Returns the last access time of the file, in nanoseconds since [`atime`]. | 
|  | /// | 
|  | /// [`atime`]: MetadataExt::atime | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let nano_last_access_time = meta.atime_nsec(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn atime_nsec(&self) -> i64; | 
|  | /// Returns the last modification time of the file, in seconds since Unix Epoch. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let last_modification_time = meta.mtime(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn mtime(&self) -> i64; | 
|  | /// Returns the last modification time of the file, in nanoseconds since [`mtime`]. | 
|  | /// | 
|  | /// [`mtime`]: MetadataExt::mtime | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let nano_last_modification_time = meta.mtime_nsec(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn mtime_nsec(&self) -> i64; | 
|  | /// Returns the last status change time of the file, in seconds since Unix Epoch. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let last_status_change_time = meta.ctime(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn ctime(&self) -> i64; | 
|  | /// Returns the last status change time of the file, in nanoseconds since [`ctime`]. | 
|  | /// | 
|  | /// [`ctime`]: MetadataExt::ctime | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let nano_last_status_change_time = meta.ctime_nsec(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn ctime_nsec(&self) -> i64; | 
|  | /// Returns the block size for filesystem I/O. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let block_size = meta.blksize(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn blksize(&self) -> u64; | 
|  | /// Returns the number of blocks allocated to the file, in 512-byte units. | 
|  | /// | 
|  | /// Please note that this may be smaller than `st_size / 512` when the file has holes. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::MetadataExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("some_file")?; | 
|  | ///     let blocks = meta.blocks(); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn blocks(&self) -> u64; | 
|  | #[cfg(target_os = "vxworks")] | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | fn attrib(&self) -> u8; | 
|  | } | 
|  |  | 
|  | #[stable(feature = "metadata_ext", since = "1.1.0")] | 
|  | impl MetadataExt for fs::Metadata { | 
|  | fn dev(&self) -> u64 { | 
|  | self.st_dev() | 
|  | } | 
|  | fn ino(&self) -> u64 { | 
|  | self.st_ino() | 
|  | } | 
|  | fn mode(&self) -> u32 { | 
|  | self.st_mode() | 
|  | } | 
|  | fn nlink(&self) -> u64 { | 
|  | self.st_nlink() | 
|  | } | 
|  | fn uid(&self) -> u32 { | 
|  | self.st_uid() | 
|  | } | 
|  | fn gid(&self) -> u32 { | 
|  | self.st_gid() | 
|  | } | 
|  | fn rdev(&self) -> u64 { | 
|  | self.st_rdev() | 
|  | } | 
|  | fn size(&self) -> u64 { | 
|  | self.st_size() | 
|  | } | 
|  | fn atime(&self) -> i64 { | 
|  | self.st_atime() | 
|  | } | 
|  | fn atime_nsec(&self) -> i64 { | 
|  | self.st_atime_nsec() | 
|  | } | 
|  | fn mtime(&self) -> i64 { | 
|  | self.st_mtime() | 
|  | } | 
|  | fn mtime_nsec(&self) -> i64 { | 
|  | self.st_mtime_nsec() | 
|  | } | 
|  | fn ctime(&self) -> i64 { | 
|  | self.st_ctime() | 
|  | } | 
|  | fn ctime_nsec(&self) -> i64 { | 
|  | self.st_ctime_nsec() | 
|  | } | 
|  | fn blksize(&self) -> u64 { | 
|  | self.st_blksize() | 
|  | } | 
|  | fn blocks(&self) -> u64 { | 
|  | self.st_blocks() | 
|  | } | 
|  | #[cfg(target_os = "vxworks")] | 
|  | fn attrib(&self) -> u8 { | 
|  | self.st_attrib() | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Unix-specific extensions for [`fs::FileType`]. | 
|  | /// | 
|  | /// Adds support for special Unix file types such as block/character devices, | 
|  | /// pipes, and sockets. | 
|  | #[stable(feature = "file_type_ext", since = "1.5.0")] | 
|  | pub trait FileTypeExt { | 
|  | /// Returns `true` if this file type is a block device. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::FileTypeExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("block_device_file")?; | 
|  | ///     let file_type = meta.file_type(); | 
|  | ///     assert!(file_type.is_block_device()); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "file_type_ext", since = "1.5.0")] | 
|  | fn is_block_device(&self) -> bool; | 
|  | /// Returns `true` if this file type is a char device. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::FileTypeExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("char_device_file")?; | 
|  | ///     let file_type = meta.file_type(); | 
|  | ///     assert!(file_type.is_char_device()); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "file_type_ext", since = "1.5.0")] | 
|  | fn is_char_device(&self) -> bool; | 
|  | /// Returns `true` if this file type is a fifo. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::FileTypeExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("fifo_file")?; | 
|  | ///     let file_type = meta.file_type(); | 
|  | ///     assert!(file_type.is_fifo()); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "file_type_ext", since = "1.5.0")] | 
|  | fn is_fifo(&self) -> bool; | 
|  | /// Returns `true` if this file type is a socket. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::FileTypeExt; | 
|  | /// use std::io; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let meta = fs::metadata("unix.socket")?; | 
|  | ///     let file_type = meta.file_type(); | 
|  | ///     assert!(file_type.is_socket()); | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "file_type_ext", since = "1.5.0")] | 
|  | fn is_socket(&self) -> bool; | 
|  | } | 
|  |  | 
|  | #[stable(feature = "file_type_ext", since = "1.5.0")] | 
|  | impl FileTypeExt for fs::FileType { | 
|  | fn is_block_device(&self) -> bool { | 
|  | self.as_inner().is(libc::S_IFBLK) | 
|  | } | 
|  | fn is_char_device(&self) -> bool { | 
|  | self.as_inner().is(libc::S_IFCHR) | 
|  | } | 
|  | fn is_fifo(&self) -> bool { | 
|  | self.as_inner().is(libc::S_IFIFO) | 
|  | } | 
|  | fn is_socket(&self) -> bool { | 
|  | self.as_inner().is(libc::S_IFSOCK) | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Unix-specific extension methods for [`fs::DirEntry`]. | 
|  | #[stable(feature = "dir_entry_ext", since = "1.1.0")] | 
|  | pub trait DirEntryExt { | 
|  | /// Returns the underlying `d_ino` field in the contained `dirent` | 
|  | /// structure. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ``` | 
|  | /// use std::fs; | 
|  | /// use std::os::unix::fs::DirEntryExt; | 
|  | /// | 
|  | /// if let Ok(entries) = fs::read_dir(".") { | 
|  | ///     for entry in entries { | 
|  | ///         if let Ok(entry) = entry { | 
|  | ///             // Here, `entry` is a `DirEntry`. | 
|  | ///             println!("{:?}: {}", entry.file_name(), entry.ino()); | 
|  | ///         } | 
|  | ///     } | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "dir_entry_ext", since = "1.1.0")] | 
|  | fn ino(&self) -> u64; | 
|  | } | 
|  |  | 
|  | #[stable(feature = "dir_entry_ext", since = "1.1.0")] | 
|  | impl DirEntryExt for fs::DirEntry { | 
|  | fn ino(&self) -> u64 { | 
|  | self.as_inner().ino() | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Sealed Unix-specific extension methods for [`fs::DirEntry`]. | 
|  | #[unstable(feature = "dir_entry_ext2", issue = "85573")] | 
|  | pub trait DirEntryExt2: Sealed { | 
|  | /// Returns a reference to the underlying `OsStr` of this entry's filename. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ``` | 
|  | /// #![feature(dir_entry_ext2)] | 
|  | /// use std::os::unix::fs::DirEntryExt2; | 
|  | /// use std::{fs, io}; | 
|  | /// | 
|  | /// fn main() -> io::Result<()> { | 
|  | ///     let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?; | 
|  | ///     entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref())); | 
|  | /// | 
|  | ///     for p in entries { | 
|  | ///         println!("{p:?}"); | 
|  | ///     } | 
|  | /// | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | fn file_name_ref(&self) -> &OsStr; | 
|  | } | 
|  |  | 
|  | /// Allows extension traits within `std`. | 
|  | #[unstable(feature = "sealed", issue = "none")] | 
|  | impl Sealed for fs::DirEntry {} | 
|  |  | 
|  | #[unstable(feature = "dir_entry_ext2", issue = "85573")] | 
|  | impl DirEntryExt2 for fs::DirEntry { | 
|  | fn file_name_ref(&self) -> &OsStr { | 
|  | self.as_inner().file_name_os_str() | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Creates a new symbolic link on the filesystem. | 
|  | /// | 
|  | /// The `link` path will be a symbolic link pointing to the `original` path. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::os::unix::fs; | 
|  | /// | 
|  | /// fn main() -> std::io::Result<()> { | 
|  | ///     fs::symlink("a.txt", "b.txt")?; | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "symlink", since = "1.1.0")] | 
|  | pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> { | 
|  | sys::fs::symlink(original.as_ref(), link.as_ref()) | 
|  | } | 
|  |  | 
|  | /// Unix-specific extensions to [`fs::DirBuilder`]. | 
|  | #[stable(feature = "dir_builder", since = "1.6.0")] | 
|  | pub trait DirBuilderExt { | 
|  | /// Sets the mode to create new directories with. This option defaults to | 
|  | /// 0o777. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::fs::DirBuilder; | 
|  | /// use std::os::unix::fs::DirBuilderExt; | 
|  | /// | 
|  | /// let mut builder = DirBuilder::new(); | 
|  | /// builder.mode(0o755); | 
|  | /// ``` | 
|  | #[stable(feature = "dir_builder", since = "1.6.0")] | 
|  | fn mode(&mut self, mode: u32) -> &mut Self; | 
|  | } | 
|  |  | 
|  | #[stable(feature = "dir_builder", since = "1.6.0")] | 
|  | impl DirBuilderExt for fs::DirBuilder { | 
|  | fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { | 
|  | self.as_inner_mut().set_mode(mode); | 
|  | self | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Change the owner and group of the specified path. | 
|  | /// | 
|  | /// Specifying either the uid or gid as `None` will leave it unchanged. | 
|  | /// | 
|  | /// Changing the owner typically requires privileges, such as root or a specific capability. | 
|  | /// Changing the group typically requires either being the owner and a member of the group, or | 
|  | /// having privileges. | 
|  | /// | 
|  | /// Be aware that changing owner clears the `suid` and `sgid` permission bits in most cases | 
|  | /// according to POSIX, usually even if the user is root. The sgid is not cleared when | 
|  | /// the file is non-group-executable. See: <https://www.man7.org/linux/man-pages/man2/chown.2.html> | 
|  | /// This call may also clear file capabilities, if there was any. | 
|  | /// | 
|  | /// If called on a symbolic link, this will change the owner and group of the link target. To | 
|  | /// change the owner and group of the link itself, see [`lchown`]. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::os::unix::fs; | 
|  | /// | 
|  | /// fn main() -> std::io::Result<()> { | 
|  | ///     fs::chown("/sandbox", Some(0), Some(0))?; | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "unix_chown", since = "1.73.0")] | 
|  | pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> { | 
|  | sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) | 
|  | } | 
|  |  | 
|  | /// Change the owner and group of the file referenced by the specified open file descriptor. | 
|  | /// | 
|  | /// For semantics and required privileges, see [`chown`]. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::os::unix::fs; | 
|  | /// | 
|  | /// fn main() -> std::io::Result<()> { | 
|  | ///     let f = std::fs::File::open("/file")?; | 
|  | ///     fs::fchown(&f, Some(0), Some(0))?; | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "unix_chown", since = "1.73.0")] | 
|  | pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> { | 
|  | sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) | 
|  | } | 
|  |  | 
|  | /// Change the owner and group of the specified path, without dereferencing symbolic links. | 
|  | /// | 
|  | /// Identical to [`chown`], except that if called on a symbolic link, this will change the owner | 
|  | /// and group of the link itself rather than the owner and group of the link target. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::os::unix::fs; | 
|  | /// | 
|  | /// fn main() -> std::io::Result<()> { | 
|  | ///     fs::lchown("/symlink", Some(0), Some(0))?; | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "unix_chown", since = "1.73.0")] | 
|  | pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> { | 
|  | sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) | 
|  | } | 
|  |  | 
|  | /// Change the root directory of the current process to the specified path. | 
|  | /// | 
|  | /// This typically requires privileges, such as root or a specific capability. | 
|  | /// | 
|  | /// This does not change the current working directory; you should call | 
|  | /// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// use std::os::unix::fs; | 
|  | /// | 
|  | /// fn main() -> std::io::Result<()> { | 
|  | ///     fs::chroot("/sandbox")?; | 
|  | ///     std::env::set_current_dir("/")?; | 
|  | ///     // continue working in sandbox | 
|  | ///     Ok(()) | 
|  | /// } | 
|  | /// ``` | 
|  | #[stable(feature = "unix_chroot", since = "1.56.0")] | 
|  | #[cfg(not(target_os = "fuchsia"))] | 
|  | pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> { | 
|  | sys::fs::chroot(dir.as_ref()) | 
|  | } | 
|  |  | 
|  | /// Create a FIFO special file at the specified path with the specified mode. | 
|  | /// | 
|  | /// # Examples | 
|  | /// | 
|  | /// ```no_run | 
|  | /// # #![feature(unix_mkfifo)] | 
|  | /// # #[cfg(not(unix))] | 
|  | /// # fn main() {} | 
|  | /// # #[cfg(unix)] | 
|  | /// # fn main() -> std::io::Result<()> { | 
|  | /// # use std::{ | 
|  | /// #     os::unix::fs::{mkfifo, PermissionsExt}, | 
|  | /// #     fs::{File, Permissions, remove_file}, | 
|  | /// #     io::{Write, Read}, | 
|  | /// # }; | 
|  | /// # let _ = remove_file("/tmp/fifo"); | 
|  | /// mkfifo("/tmp/fifo", Permissions::from_mode(0o774))?; | 
|  | /// | 
|  | /// let mut wx = File::options().read(true).write(true).open("/tmp/fifo")?; | 
|  | /// let mut rx = File::open("/tmp/fifo")?; | 
|  | /// | 
|  | /// wx.write_all(b"hello, world!")?; | 
|  | /// drop(wx); | 
|  | /// | 
|  | /// let mut s = String::new(); | 
|  | /// rx.read_to_string(&mut s)?; | 
|  | /// | 
|  | /// assert_eq!(s, "hello, world!"); | 
|  | /// # Ok(()) | 
|  | /// # } | 
|  | /// ``` | 
|  | #[unstable(feature = "unix_mkfifo", issue = "139324")] | 
|  | pub fn mkfifo<P: AsRef<Path>>(path: P, permissions: Permissions) -> io::Result<()> { | 
|  | sys::fs::mkfifo(path.as_ref(), permissions.mode()) | 
|  | } |