Files
rust/library/std/src/os/unix/fs.rs
T-O-R-U-S 72a25d05bf Use implicit capture syntax in format_args
This updates the standard library's documentation to use the new syntax. The
documentation is worthwhile to update as it should be more idiomatic
(particularly for features like this, which are nice for users to get acquainted
with). The general codebase is likely more hassle than benefit to update: it'll
hurt git blame, and generally updates can be done by folks updating the code if
(and when) that makes things more readable with the new format.

A few places in the compiler and library code are updated (mostly just due to
already having been done when this commit was first authored).
2022-03-10 10:23:40 -05:00

1023 lines
30 KiB
Rust

//! Unix-specific extensions to primitives in the [`std::fs`] module.
//!
//! [`std::fs`]: crate::fs
#![stable(feature = "rust1", since = "1.0.0")]
use super::platform::fs::MetadataExt as _;
use crate::fs::{self, OpenOptions, Permissions};
use crate::io;
use crate::os::unix::io::{AsFd, AsRawFd};
use crate::path::Path;
use crate::sys;
use crate::sys_common::{AsInner, AsInnerMut, FromInner};
// Used for `File::read` on intra-doc links
use crate::ffi::OsStr;
use crate::sealed::Sealed;
#[allow(unused_imports)]
use io::{Read, Write};
/// 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>;
/// Reads the exact number of byte 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.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
if !buf.is_empty() {
Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer",))
} else {
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.
///
/// [`File::write`]: fs::File::write
///
/// # 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_at(b"sushi", 10)?;
/// Ok(())
/// }
/// ```
#[stable(feature = "file_offset", since = "1.15.0")]
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
/// 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::const_io_error!(
io::ErrorKind::WriteZero,
"failed to write whole buffer",
));
}
Ok(n) => {
buf = &buf[n..];
offset += n as u64
}
Err(ref e) if e.kind() == io::ErrorKind::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 write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
self.as_inner().write_at(buf, offset)
}
}
/// Unix-specific extensions to [`fs::Permissions`].
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait PermissionsExt {
/// Returns the underlying raw `st_mode` bits that contain the standard
/// Unix permissions for this file.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::os::unix::fs::PermissionsExt;
///
/// fn main() -> std::io::Result<()> {
/// let f = File::create("foo.txt")?;
/// let metadata = f.metadata()?;
/// let permissions = metadata.permissions();
///
/// println!("permissions: {:o}", permissions.mode());
/// Ok(())
/// }
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&self) -> u32;
/// Sets the underlying raw bits for this set of permissions.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::os::unix::fs::PermissionsExt;
///
/// fn main() -> std::io::Result<()> {
/// let f = File::create("foo.txt")?;
/// let metadata = f.metadata()?;
/// let mut permissions = metadata.permissions();
///
/// permissions.set_mode(0o644); // Read/write for owner and read for others.
/// assert_eq!(permissions.mode(), 0o644);
/// Ok(())
/// }
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn set_mode(&mut self, mode: u32);
/// Creates a new instance of `Permissions` from the given set of Unix
/// permission bits.
///
/// # Examples
///
/// ```
/// use std::fs::Permissions;
/// use std::os::unix::fs::PermissionsExt;
///
/// // Read/write for owner and read for others.
/// let permissions = Permissions::from_mode(0o644);
/// assert_eq!(permissions.mode(), 0o644);
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
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 Rusts options.
///
/// Custom flags can only set flags, not remove flags set by Rusts options.
/// This options overwrites any previously set custom flags.
///
/// # Examples
///
/// ```no_run
/// # #![feature(rustc_private)]
/// extern crate libc;
/// use std::fs::OpenOptions;
/// use std::os::unix::fs::OpenOptionsExt;
///
/// # fn main() {
/// let mut options = OpenOptions::new();
/// options.write(true);
/// if cfg!(unix) {
/// 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.
///
/// 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
/// #![feature(unix_chown)]
/// use std::os::unix::fs;
///
/// fn main() -> std::io::Result<()> {
/// fs::chown("/sandbox", Some(0), Some(0))?;
/// Ok(())
/// }
/// ```
#[unstable(feature = "unix_chown", issue = "88989")]
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
/// #![feature(unix_chown)]
/// 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(())
/// }
/// ```
#[unstable(feature = "unix_chown", issue = "88989")]
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
/// #![feature(unix_chown)]
/// use std::os::unix::fs;
///
/// fn main() -> std::io::Result<()> {
/// fs::lchown("/symlink", Some(0), Some(0))?;
/// Ok(())
/// }
/// ```
#[unstable(feature = "unix_chown", issue = "88989")]
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(any(target_os = "fuchsia", target_os = "vxworks")))]
pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
sys::fs::chroot(dir.as_ref())
}