Skip to main content

std/os/unix/
fs.rs

1//! Unix-specific extensions to primitives in the [`std::fs`] module.
2//!
3//! [`std::fs`]: crate::fs
4
5#![stable(feature = "rust1", since = "1.0.0")]
6
7#[allow(unused_imports)]
8use io::{Read, Write};
9
10use super::platform::fs::MetadataExt as _;
11// Used for `File::read` on intra-doc links
12use crate::ffi::OsStr;
13use crate::fs::{self, OpenOptions, Permissions};
14use crate::io::BorrowedCursor;
15use crate::macros::rustdoc_skip_body;
16use crate::os::unix::io::{AsFd, AsRawFd};
17use crate::path::Path;
18use crate::sys::{AsInner, AsInnerMut, FromInner};
19use crate::{io, sys};
20
21// Tests for this module
22#[cfg(not(target_os = "l4re"))]
23#[cfg(test)]
24mod tests;
25
26pub(crate) mod dirs;
27
28#[unstable(feature = "fs_media_dirs", issue = "162083")]
29pub use dirs::MediaDirsExt;
30#[unstable(feature = "fs_home_dirs", issue = "162082")]
31pub use dirs::{HomeDirsExt, XdgDirs};
32
33/// Unix-specific extensions to [`fs::File`].
34#[stable(feature = "file_offset", since = "1.15.0")]
35pub trait FileExt {
36    /// Reads a number of bytes starting from a given offset.
37    ///
38    /// Returns the number of bytes read.
39    ///
40    /// The offset is relative to the start of the file and thus independent
41    /// from the current cursor.
42    ///
43    /// The current file cursor is not affected by this function.
44    ///
45    /// Note that similar to [`File::read`], it is not an error to return with a
46    /// short read.
47    ///
48    /// [`File::read`]: fs::File::read
49    ///
50    /// # Examples
51    ///
52    #[cfg_attr(target_family = "unix", doc = "```no_run")]
53    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
54    /// use std::io;
55    /// use std::fs::File;
56    /// use std::os::unix::prelude::FileExt;
57    ///
58    /// fn main() -> io::Result<()> {
59    ///     let mut buf = [0u8; 8];
60    ///     let file = File::open("foo.txt")?;
61    ///
62    ///     // We now read 8 bytes from the offset 10.
63    ///     let num_bytes_read = file.read_at(&mut buf, 10)?;
64    ///     println!("read {num_bytes_read} bytes: {buf:?}");
65    ///     Ok(())
66    /// }
67    /// ```
68    #[stable(feature = "file_offset", since = "1.15.0")]
69    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
70
71    /// Like `read_at`, except that it reads into a slice of buffers.
72    ///
73    /// Data is copied to fill each buffer in order, with the final buffer
74    /// written to possibly being only partially filled. This method must behave
75    /// equivalently to a single call to read with concatenated buffers.
76    #[unstable(feature = "unix_file_vectored_at", issue = "89517")]
77    fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
78        io::default_read_vectored(|b| self.read_at(b, offset), bufs)
79    }
80
81    /// Reads the exact number of bytes required to fill `buf` from the given offset.
82    ///
83    /// The offset is relative to the start of the file and thus independent
84    /// from the current cursor.
85    ///
86    /// The current file cursor is not affected by this function.
87    ///
88    /// Similar to [`io::Read::read_exact`] but uses [`read_at`] instead of `read`.
89    ///
90    /// [`read_at`]: FileExt::read_at
91    ///
92    /// # Errors
93    ///
94    /// If this function encounters an error of the kind
95    /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
96    /// will continue.
97    ///
98    /// If this function encounters an "end of file" before completely filling
99    /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
100    /// The contents of `buf` are unspecified in this case.
101    ///
102    /// If any other read error is encountered then this function immediately
103    /// returns. The contents of `buf` are unspecified in this case.
104    ///
105    /// If this function returns an error, it is unspecified how many bytes it
106    /// has read, but it will never read more than would be necessary to
107    /// completely fill the buffer.
108    ///
109    /// # Examples
110    ///
111    #[cfg_attr(target_family = "unix", doc = "```no_run")]
112    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
113    /// use std::io;
114    /// use std::fs::File;
115    /// use std::os::unix::prelude::FileExt;
116    ///
117    /// fn main() -> io::Result<()> {
118    ///     let mut buf = [0u8; 8];
119    ///     let file = File::open("foo.txt")?;
120    ///
121    ///     // We now read exactly 8 bytes from the offset 10.
122    ///     file.read_exact_at(&mut buf, 10)?;
123    ///     println!("read {} bytes: {:?}", buf.len(), buf);
124    ///     Ok(())
125    /// }
126    /// ```
127    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
128    fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
129        while !buf.is_empty() {
130            match self.read_at(buf, offset) {
131                Ok(0) => break,
132                Ok(n) => {
133                    let tmp = buf;
134                    buf = &mut tmp[n..];
135                    offset += n as u64;
136                }
137                Err(ref e) if e.is_interrupted() => {}
138                Err(e) => return Err(e),
139            }
140        }
141        if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
142    }
143
144    /// Reads some bytes starting from a given offset into the buffer.
145    ///
146    /// This equivalent to the [`read_at`](FileExt::read_at) method, except that it is passed a
147    /// [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized buffers. The new
148    /// data will be appended to any existing contents of `buf`.
149    ///
150    /// # Examples
151    ///
152    #[cfg_attr(target_family = "unix", doc = "```no_run")]
153    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
154    /// #![feature(core_io_borrowed_buf)]
155    /// #![feature(read_buf_at)]
156    ///
157    /// use std::io;
158    /// use std::io::BorrowedBuf;
159    /// use std::fs::File;
160    /// use std::mem::MaybeUninit;
161    /// use std::os::unix::prelude::*;
162    ///
163    /// fn main() -> io::Result<()> {
164    ///     let mut file = File::open("pi.txt")?;
165    ///
166    ///     // Read some bytes starting from offset 2
167    ///     let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10];
168    ///     let mut buf = BorrowedBuf::from(buf.as_mut_slice());
169    ///     file.read_buf_at(buf.unfilled(), 2)?;
170    ///
171    ///     assert!(buf.filled().starts_with(b"1"));
172    ///
173    ///     Ok(())
174    /// }
175    /// ```
176    #[unstable(feature = "read_buf_at", issue = "140771")]
177    fn read_buf_at(&self, buf: BorrowedCursor<'_, u8>, offset: u64) -> io::Result<()> {
178        io::default_read_buf(|b| self.read_at(b, offset), buf)
179    }
180
181    /// Reads the exact number of bytes required to fill the buffer from a given offset.
182    ///
183    /// This is equivalent to the [`read_exact_at`](FileExt::read_exact_at) method, except that it
184    /// is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized
185    /// buffers. The new data will be appended to any existing contents of `buf`.
186    ///
187    /// # Examples
188    ///
189    #[cfg_attr(target_family = "unix", doc = "```no_run")]
190    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
191    /// #![feature(core_io_borrowed_buf)]
192    /// #![feature(read_buf_at)]
193    ///
194    /// use std::io;
195    /// use std::io::BorrowedBuf;
196    /// use std::fs::File;
197    /// use std::mem::MaybeUninit;
198    /// use std::os::unix::prelude::*;
199    ///
200    /// fn main() -> io::Result<()> {
201    ///     let mut file = File::open("pi.txt")?;
202    ///
203    ///     // Read exactly 10 bytes starting from offset 2
204    ///     let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10];
205    ///     let mut buf = BorrowedBuf::from(buf.as_mut_slice());
206    ///     file.read_buf_exact_at(buf.unfilled(), 2)?;
207    ///
208    ///     assert_eq!(buf.filled(), b"1415926535");
209    ///
210    ///     Ok(())
211    /// }
212    /// ```
213    #[unstable(feature = "read_buf_at", issue = "140771")]
214    #[doc(alias("read_exact_buf_at"))]
215    fn read_buf_exact_at(
216        &self,
217        mut buf: BorrowedCursor<'_, u8>,
218        mut offset: u64,
219    ) -> io::Result<()> {
220        while buf.capacity() > 0 {
221            let prev_written = buf.written();
222            match self.read_buf_at(buf.reborrow(), offset) {
223                Ok(()) => {}
224                Err(e) if e.is_interrupted() => continue,
225                Err(e) => return Err(e),
226            }
227            let n = buf.written() - prev_written;
228            offset += n as u64;
229            if n == 0 {
230                return Err(io::Error::READ_EXACT_EOF);
231            }
232        }
233        Ok(())
234    }
235
236    /// Writes a number of bytes starting from a given offset.
237    ///
238    /// Returns the number of bytes written.
239    ///
240    /// The offset is relative to the start of the file and thus independent
241    /// from the current cursor.
242    ///
243    /// The current file cursor is not affected by this function.
244    ///
245    /// When writing beyond the end of the file, the file is appropriately
246    /// extended and the intermediate bytes are initialized with the value 0.
247    ///
248    /// Note that similar to [`File::write`], it is not an error to return a
249    /// short write.
250    ///
251    /// # Bug
252    /// On some systems, `write_at` utilises [`pwrite64`] to write to files.
253    /// However, this syscall has a [bug] where files opened with the `O_APPEND`
254    /// flag fail to respect the offset parameter, always appending to the end
255    /// of the file instead.
256    ///
257    /// It is possible to inadvertently set this flag, like in the example below.
258    /// Therefore, it is important to be vigilant while changing options to mitigate
259    /// unexpected behavior.
260    ///
261    #[cfg_attr(target_family = "unix", doc = "```no_run")]
262    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
263    /// use std::fs::File;
264    /// use std::io;
265    /// use std::os::unix::prelude::FileExt;
266    ///
267    /// fn main() -> io::Result<()> {
268    ///     // Open a file with the append option (sets the `O_APPEND` flag)
269    ///     let file = File::options().append(true).open("foo.txt")?;
270    ///
271    ///     // We attempt to write at offset 10; instead appended to EOF
272    ///     file.write_at(b"sushi", 10)?;
273    ///
274    ///     // foo.txt is 5 bytes long instead of 15
275    ///     Ok(())
276    /// }
277    /// ```
278    ///
279    /// [`File::write`]: fs::File::write
280    /// [`pwrite64`]: https://man7.org/linux/man-pages/man2/pwrite.2.html
281    /// [bug]: https://man7.org/linux/man-pages/man2/pwrite.2.html#BUGS
282    ///
283    /// # Examples
284    ///
285    #[cfg_attr(target_family = "unix", doc = "```no_run")]
286    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
287    /// use std::fs::File;
288    /// use std::io;
289    /// use std::os::unix::prelude::FileExt;
290    ///
291    /// fn main() -> io::Result<()> {
292    ///     let file = File::create("foo.txt")?;
293    ///
294    ///     // We now write at the offset 10.
295    ///     file.write_at(b"sushi", 10)?;
296    ///     Ok(())
297    /// }
298    /// ```
299    #[stable(feature = "file_offset", since = "1.15.0")]
300    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
301
302    /// Like `write_at`, except that it writes from a slice of buffers.
303    ///
304    /// Data is copied from each buffer in order, with the final buffer read
305    /// from possibly being only partially consumed. This method must behave as
306    /// a call to `write_at` with the buffers concatenated would.
307    #[unstable(feature = "unix_file_vectored_at", issue = "89517")]
308    fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> {
309        io::default_write_vectored(|b| self.write_at(b, offset), bufs)
310    }
311
312    /// Attempts to write an entire buffer starting from a given offset.
313    ///
314    /// The offset is relative to the start of the file and thus independent
315    /// from the current cursor.
316    ///
317    /// The current file cursor is not affected by this function.
318    ///
319    /// This method will continuously call [`write_at`] until there is no more data
320    /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
321    /// returned. This method will not return until the entire buffer has been
322    /// successfully written or such an error occurs. The first error that is
323    /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
324    /// returned.
325    ///
326    /// # Errors
327    ///
328    /// This function will return the first error of
329    /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
330    ///
331    /// [`write_at`]: FileExt::write_at
332    ///
333    /// # Examples
334    ///
335    #[cfg_attr(target_family = "unix", doc = "```no_run")]
336    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
337    /// use std::fs::File;
338    /// use std::io;
339    /// use std::os::unix::prelude::FileExt;
340    ///
341    /// fn main() -> io::Result<()> {
342    ///     let file = File::open("foo.txt")?;
343    ///
344    ///     // We now write at the offset 10.
345    ///     file.write_all_at(b"sushi", 10)?;
346    ///     Ok(())
347    /// }
348    /// ```
349    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
350    fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
351        while !buf.is_empty() {
352            match self.write_at(buf, offset) {
353                Ok(0) => {
354                    return Err(io::Error::WRITE_ALL_EOF);
355                }
356                Ok(n) => {
357                    buf = &buf[n..];
358                    offset += n as u64
359                }
360                Err(ref e) if e.is_interrupted() => {}
361                Err(e) => return Err(e),
362            }
363        }
364        Ok(())
365    }
366}
367
368#[stable(feature = "file_offset", since = "1.15.0")]
369impl FileExt for fs::File {
370    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
371        self.as_inner().read_at(buf, offset)
372    }
373    fn read_buf_at(&self, buf: BorrowedCursor<'_, u8>, offset: u64) -> io::Result<()> {
374        self.as_inner().read_buf_at(buf, offset)
375    }
376    #[rustdoc_skip_body]
377    fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
378        self.as_inner().read_vectored_at(bufs, offset)
379    }
380    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
381        self.as_inner().write_at(buf, offset)
382    }
383    #[rustdoc_skip_body]
384    fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> {
385        self.as_inner().write_vectored_at(bufs, offset)
386    }
387}
388
389/// Unix-specific extensions to [`fs::Permissions`].
390///
391/// # Examples
392///
393#[cfg_attr(target_family = "unix", doc = "```no_run")]
394#[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
395/// use std::fs::{File, Permissions};
396/// use std::io::{ErrorKind, Result as IoResult};
397/// use std::os::unix::fs::PermissionsExt;
398///
399/// fn main() -> IoResult<()> {
400///     let name = "test_file_for_permissions";
401///
402///     // make sure file does not exist
403///     let _ = std::fs::remove_file(name);
404///     assert_eq!(
405///         File::open(name).unwrap_err().kind(),
406///         ErrorKind::NotFound,
407///         "file already exists"
408///     );
409///
410///     // full read/write/execute mode bits for owner of file
411///     // that we want to add to existing mode bits
412///     let my_mode = 0o700;
413///
414///     // create new file with specified permissions
415///     {
416///         let file = File::create(name)?;
417///         let mut permissions = file.metadata()?.permissions();
418///         eprintln!("Current permissions: {:o}", permissions.mode());
419///
420///         // make sure new permissions are not already set
421///         assert!(
422///             permissions.mode() & my_mode != my_mode,
423///             "permissions already set"
424///         );
425///
426///         // either use `set_mode` to change an existing Permissions struct
427///         permissions.set_mode(permissions.mode() | my_mode);
428///
429///         // or use `from_mode` to construct a new Permissions struct
430///         permissions = Permissions::from_mode(permissions.mode() | my_mode);
431///
432///         // write new permissions to file
433///         file.set_permissions(permissions)?;
434///     }
435///
436///     let permissions = File::open(name)?.metadata()?.permissions();
437///     eprintln!("New permissions: {:o}", permissions.mode());
438///
439///     // assert new permissions were set
440///     assert_eq!(
441///         permissions.mode() & my_mode,
442///         my_mode,
443///         "new permissions not set"
444///     );
445///     Ok(())
446/// }
447/// ```
448///
449#[cfg_attr(target_family = "unix", doc = "```no_run")]
450#[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
451/// use std::fs::Permissions;
452/// use std::os::unix::fs::PermissionsExt;
453///
454/// // read/write for owner and read for others
455/// let my_mode = 0o644;
456/// let mut permissions = Permissions::from_mode(my_mode);
457/// assert_eq!(permissions.mode(), my_mode);
458///
459/// // read/write/execute for owner
460/// let other_mode = 0o700;
461/// permissions.set_mode(other_mode);
462/// assert_eq!(permissions.mode(), other_mode);
463/// ```
464#[stable(feature = "fs_ext", since = "1.1.0")]
465pub trait PermissionsExt {
466    /// Returns the mode permission bits
467    #[stable(feature = "fs_ext", since = "1.1.0")]
468    fn mode(&self) -> u32;
469
470    /// Sets the mode permission bits.
471    #[stable(feature = "fs_ext", since = "1.1.0")]
472    fn set_mode(&mut self, mode: u32);
473
474    /// Creates a new instance from the given mode permission bits.
475    #[stable(feature = "fs_ext", since = "1.1.0")]
476    #[cfg_attr(not(test), rustc_diagnostic_item = "permissions_from_mode")]
477    fn from_mode(mode: u32) -> Self;
478}
479
480#[stable(feature = "fs_ext", since = "1.1.0")]
481impl PermissionsExt for Permissions {
482    #[rustdoc_skip_body]
483    fn mode(&self) -> u32 {
484        self.as_inner().mode()
485    }
486
487    fn set_mode(&mut self, mode: u32) {
488        *self = Permissions::from_inner(FromInner::from_inner(mode));
489    }
490
491    fn from_mode(mode: u32) -> Permissions {
492        Permissions::from_inner(FromInner::from_inner(mode))
493    }
494}
495
496/// Unix-specific extensions to [`fs::OpenOptions`].
497#[stable(feature = "fs_ext", since = "1.1.0")]
498pub trait OpenOptionsExt {
499    /// Sets the mode bits that a new file will be created with.
500    ///
501    /// If a new file is created as part of an `OpenOptions::open` call then this
502    /// specified `mode` will be used as the permission bits for the new file.
503    /// If no `mode` is set, the default of `0o666` will be used.
504    /// The operating system masks out bits with the system's `umask`, to produce
505    /// the final permissions.
506    ///
507    /// # Examples
508    ///
509    #[cfg_attr(target_family = "unix", doc = "```no_run")]
510    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
511    /// use std::fs::OpenOptions;
512    /// use std::os::unix::fs::OpenOptionsExt;
513    ///
514    /// # fn main() {
515    /// let mut options = OpenOptions::new();
516    /// options.mode(0o644); // Give read/write for owner and read for others.
517    /// let file = options.open("foo.txt");
518    /// # }
519    /// ```
520    #[stable(feature = "fs_ext", since = "1.1.0")]
521    fn mode(&mut self, mode: u32) -> &mut Self;
522
523    /// Pass custom flags to the `flags` argument of `open`.
524    ///
525    /// The bits that define the access mode are masked out with `O_ACCMODE`, to
526    /// ensure they do not interfere with the access mode set by Rust's options.
527    ///
528    /// Custom flags can only set flags, not remove flags set by Rust's options.
529    /// This function overwrites any previously-set custom flags.
530    ///
531    /// # Examples
532    ///
533    #[cfg_attr(target_family = "unix", doc = "```no_run")]
534    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
535    /// # mod libc { pub const O_NOFOLLOW: i32 = 0; }
536    /// use std::fs::OpenOptions;
537    /// use std::os::unix::fs::OpenOptionsExt;
538    ///
539    /// # fn main() {
540    /// let mut options = OpenOptions::new();
541    /// options.write(true);
542    /// options.custom_flags(libc::O_NOFOLLOW);
543    /// let file = options.open("foo.txt");
544    /// # }
545    /// ```
546    #[stable(feature = "open_options_ext", since = "1.10.0")]
547    fn custom_flags(&mut self, flags: i32) -> &mut Self;
548}
549
550#[stable(feature = "fs_ext", since = "1.1.0")]
551impl OpenOptionsExt for OpenOptions {
552    #[rustdoc_skip_body]
553    fn mode(&mut self, mode: u32) -> &mut OpenOptions {
554        self.as_inner_mut().mode(mode);
555        self
556    }
557
558    #[rustdoc_skip_body]
559    fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
560        self.as_inner_mut().custom_flags(flags);
561        self
562    }
563}
564
565/// Unix-specific extensions to [`fs::Metadata`].
566#[stable(feature = "metadata_ext", since = "1.1.0")]
567pub trait MetadataExt {
568    /// Returns the ID of the device containing the file.
569    ///
570    /// # Examples
571    ///
572    #[cfg_attr(target_family = "unix", doc = "```no_run")]
573    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
574    /// use std::io;
575    /// use std::fs;
576    /// use std::os::unix::fs::MetadataExt;
577    ///
578    /// fn main() -> io::Result<()> {
579    ///     let meta = fs::metadata("some_file")?;
580    ///     let dev_id = meta.dev();
581    ///     Ok(())
582    /// }
583    /// ```
584    #[stable(feature = "metadata_ext", since = "1.1.0")]
585    fn dev(&self) -> u64;
586    /// Returns the inode number.
587    ///
588    /// # Examples
589    ///
590    #[cfg_attr(target_family = "unix", doc = "```no_run")]
591    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
592    /// use std::fs;
593    /// use std::os::unix::fs::MetadataExt;
594    /// use std::io;
595    ///
596    /// fn main() -> io::Result<()> {
597    ///     let meta = fs::metadata("some_file")?;
598    ///     let inode = meta.ino();
599    ///     Ok(())
600    /// }
601    /// ```
602    #[stable(feature = "metadata_ext", since = "1.1.0")]
603    fn ino(&self) -> u64;
604    /// Returns the rights applied to this file.
605    ///
606    /// # Examples
607    ///
608    #[cfg_attr(target_family = "unix", doc = "```no_run")]
609    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
610    /// use std::fs;
611    /// use std::os::unix::fs::MetadataExt;
612    /// use std::io;
613    ///
614    /// fn main() -> io::Result<()> {
615    ///     let meta = fs::metadata("some_file")?;
616    ///     let mode = meta.mode();
617    ///     let user_has_write_access      = mode & 0o200;
618    ///     let user_has_read_write_access = mode & 0o600;
619    ///     let group_has_read_access      = mode & 0o040;
620    ///     let others_have_exec_access    = mode & 0o001;
621    ///     Ok(())
622    /// }
623    /// ```
624    #[stable(feature = "metadata_ext", since = "1.1.0")]
625    fn mode(&self) -> u32;
626    /// Returns the number of hard links pointing to this file.
627    ///
628    /// # Examples
629    ///
630    #[cfg_attr(target_family = "unix", doc = "```no_run")]
631    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
632    /// use std::fs;
633    /// use std::os::unix::fs::MetadataExt;
634    /// use std::io;
635    ///
636    /// fn main() -> io::Result<()> {
637    ///     let meta = fs::metadata("some_file")?;
638    ///     let nb_hard_links = meta.nlink();
639    ///     Ok(())
640    /// }
641    /// ```
642    #[stable(feature = "metadata_ext", since = "1.1.0")]
643    fn nlink(&self) -> u64;
644    /// Returns the user ID of the owner of this file.
645    ///
646    /// # Examples
647    ///
648    #[cfg_attr(target_family = "unix", doc = "```no_run")]
649    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
650    /// use std::fs;
651    /// use std::os::unix::fs::MetadataExt;
652    /// use std::io;
653    ///
654    /// fn main() -> io::Result<()> {
655    ///     let meta = fs::metadata("some_file")?;
656    ///     let user_id = meta.uid();
657    ///     Ok(())
658    /// }
659    /// ```
660    #[stable(feature = "metadata_ext", since = "1.1.0")]
661    fn uid(&self) -> u32;
662    /// Returns the group ID of the owner of this file.
663    ///
664    /// # Examples
665    ///
666    #[cfg_attr(target_family = "unix", doc = "```no_run")]
667    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
668    /// use std::fs;
669    /// use std::os::unix::fs::MetadataExt;
670    /// use std::io;
671    ///
672    /// fn main() -> io::Result<()> {
673    ///     let meta = fs::metadata("some_file")?;
674    ///     let group_id = meta.gid();
675    ///     Ok(())
676    /// }
677    /// ```
678    #[stable(feature = "metadata_ext", since = "1.1.0")]
679    fn gid(&self) -> u32;
680    /// Returns the device ID of this file (if it is a special one).
681    ///
682    /// # Examples
683    ///
684    #[cfg_attr(target_family = "unix", doc = "```no_run")]
685    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
686    /// use std::fs;
687    /// use std::os::unix::fs::MetadataExt;
688    /// use std::io;
689    ///
690    /// fn main() -> io::Result<()> {
691    ///     let meta = fs::metadata("some_file")?;
692    ///     let device_id = meta.rdev();
693    ///     Ok(())
694    /// }
695    /// ```
696    #[stable(feature = "metadata_ext", since = "1.1.0")]
697    fn rdev(&self) -> u64;
698    /// Returns the total size of this file in bytes.
699    ///
700    /// # Examples
701    ///
702    #[cfg_attr(target_family = "unix", doc = "```no_run")]
703    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
704    /// use std::fs;
705    /// use std::os::unix::fs::MetadataExt;
706    /// use std::io;
707    ///
708    /// fn main() -> io::Result<()> {
709    ///     let meta = fs::metadata("some_file")?;
710    ///     let file_size = meta.size();
711    ///     Ok(())
712    /// }
713    /// ```
714    #[stable(feature = "metadata_ext", since = "1.1.0")]
715    fn size(&self) -> u64;
716    /// Returns the last access time of the file, in seconds since Unix Epoch.
717    ///
718    /// # Examples
719    ///
720    #[cfg_attr(target_family = "unix", doc = "```no_run")]
721    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
722    /// use std::fs;
723    /// use std::os::unix::fs::MetadataExt;
724    /// use std::io;
725    ///
726    /// fn main() -> io::Result<()> {
727    ///     let meta = fs::metadata("some_file")?;
728    ///     let last_access_time = meta.atime();
729    ///     Ok(())
730    /// }
731    /// ```
732    #[stable(feature = "metadata_ext", since = "1.1.0")]
733    fn atime(&self) -> i64;
734    /// Returns the last access time of the file, in nanoseconds since [`atime`].
735    ///
736    /// [`atime`]: MetadataExt::atime
737    ///
738    /// # Examples
739    ///
740    #[cfg_attr(target_family = "unix", doc = "```no_run")]
741    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
742    /// use std::fs;
743    /// use std::os::unix::fs::MetadataExt;
744    /// use std::io;
745    ///
746    /// fn main() -> io::Result<()> {
747    ///     let meta = fs::metadata("some_file")?;
748    ///     let nano_last_access_time = meta.atime_nsec();
749    ///     Ok(())
750    /// }
751    /// ```
752    #[stable(feature = "metadata_ext", since = "1.1.0")]
753    fn atime_nsec(&self) -> i64;
754    /// Returns the last modification time of the file, in seconds since Unix Epoch.
755    ///
756    /// # Examples
757    ///
758    #[cfg_attr(target_family = "unix", doc = "```no_run")]
759    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
760    /// use std::fs;
761    /// use std::os::unix::fs::MetadataExt;
762    /// use std::io;
763    ///
764    /// fn main() -> io::Result<()> {
765    ///     let meta = fs::metadata("some_file")?;
766    ///     let last_modification_time = meta.mtime();
767    ///     Ok(())
768    /// }
769    /// ```
770    #[stable(feature = "metadata_ext", since = "1.1.0")]
771    fn mtime(&self) -> i64;
772    /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
773    ///
774    /// [`mtime`]: MetadataExt::mtime
775    ///
776    /// # Examples
777    ///
778    #[cfg_attr(target_family = "unix", doc = "```no_run")]
779    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
780    /// use std::fs;
781    /// use std::os::unix::fs::MetadataExt;
782    /// use std::io;
783    ///
784    /// fn main() -> io::Result<()> {
785    ///     let meta = fs::metadata("some_file")?;
786    ///     let nano_last_modification_time = meta.mtime_nsec();
787    ///     Ok(())
788    /// }
789    /// ```
790    #[stable(feature = "metadata_ext", since = "1.1.0")]
791    fn mtime_nsec(&self) -> i64;
792    /// Returns the last status change time of the file, in seconds since Unix Epoch.
793    ///
794    /// # Examples
795    ///
796    #[cfg_attr(target_family = "unix", doc = "```no_run")]
797    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
798    /// use std::fs;
799    /// use std::os::unix::fs::MetadataExt;
800    /// use std::io;
801    ///
802    /// fn main() -> io::Result<()> {
803    ///     let meta = fs::metadata("some_file")?;
804    ///     let last_status_change_time = meta.ctime();
805    ///     Ok(())
806    /// }
807    /// ```
808    #[stable(feature = "metadata_ext", since = "1.1.0")]
809    fn ctime(&self) -> i64;
810    /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
811    ///
812    /// [`ctime`]: MetadataExt::ctime
813    ///
814    /// # Examples
815    ///
816    #[cfg_attr(target_family = "unix", doc = "```no_run")]
817    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
818    /// use std::fs;
819    /// use std::os::unix::fs::MetadataExt;
820    /// use std::io;
821    ///
822    /// fn main() -> io::Result<()> {
823    ///     let meta = fs::metadata("some_file")?;
824    ///     let nano_last_status_change_time = meta.ctime_nsec();
825    ///     Ok(())
826    /// }
827    /// ```
828    #[stable(feature = "metadata_ext", since = "1.1.0")]
829    fn ctime_nsec(&self) -> i64;
830    /// Returns the block size for filesystem I/O.
831    ///
832    /// # Examples
833    ///
834    #[cfg_attr(target_family = "unix", doc = "```no_run")]
835    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
836    /// use std::fs;
837    /// use std::os::unix::fs::MetadataExt;
838    /// use std::io;
839    ///
840    /// fn main() -> io::Result<()> {
841    ///     let meta = fs::metadata("some_file")?;
842    ///     let block_size = meta.blksize();
843    ///     Ok(())
844    /// }
845    /// ```
846    #[stable(feature = "metadata_ext", since = "1.1.0")]
847    fn blksize(&self) -> u64;
848    /// Returns the number of blocks allocated to the file, in 512-byte units.
849    ///
850    /// Please note that this may be smaller than `st_size / 512` when the file has holes.
851    ///
852    /// # Examples
853    ///
854    #[cfg_attr(target_family = "unix", doc = "```no_run")]
855    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
856    /// use std::fs;
857    /// use std::os::unix::fs::MetadataExt;
858    /// use std::io;
859    ///
860    /// fn main() -> io::Result<()> {
861    ///     let meta = fs::metadata("some_file")?;
862    ///     let blocks = meta.blocks();
863    ///     Ok(())
864    /// }
865    /// ```
866    #[stable(feature = "metadata_ext", since = "1.1.0")]
867    fn blocks(&self) -> u64;
868    #[cfg(target_os = "vxworks")]
869    #[stable(feature = "metadata_ext", since = "1.1.0")]
870    fn attrib(&self) -> u8;
871}
872
873#[stable(feature = "metadata_ext", since = "1.1.0")]
874impl MetadataExt for fs::Metadata {
875    fn dev(&self) -> u64 {
876        self.st_dev()
877    }
878    fn ino(&self) -> u64 {
879        self.st_ino()
880    }
881    fn mode(&self) -> u32 {
882        self.st_mode()
883    }
884    fn nlink(&self) -> u64 {
885        self.st_nlink()
886    }
887    fn uid(&self) -> u32 {
888        self.st_uid()
889    }
890    fn gid(&self) -> u32 {
891        self.st_gid()
892    }
893    fn rdev(&self) -> u64 {
894        self.st_rdev()
895    }
896    fn size(&self) -> u64 {
897        self.st_size()
898    }
899    fn atime(&self) -> i64 {
900        self.st_atime()
901    }
902    fn atime_nsec(&self) -> i64 {
903        self.st_atime_nsec()
904    }
905    fn mtime(&self) -> i64 {
906        self.st_mtime()
907    }
908    fn mtime_nsec(&self) -> i64 {
909        self.st_mtime_nsec()
910    }
911    fn ctime(&self) -> i64 {
912        self.st_ctime()
913    }
914    fn ctime_nsec(&self) -> i64 {
915        self.st_ctime_nsec()
916    }
917    fn blksize(&self) -> u64 {
918        self.st_blksize()
919    }
920    fn blocks(&self) -> u64 {
921        self.st_blocks()
922    }
923    #[cfg(target_os = "vxworks")]
924    fn attrib(&self) -> u8 {
925        self.st_attrib()
926    }
927}
928
929/// Unix-specific extensions for [`fs::FileType`].
930///
931/// Adds support for special Unix file types such as block/character devices,
932/// pipes, and sockets.
933#[stable(feature = "file_type_ext", since = "1.5.0")]
934pub trait FileTypeExt {
935    /// Returns `true` if this file type is a block device.
936    ///
937    /// # Examples
938    ///
939    #[cfg_attr(target_family = "unix", doc = "```no_run")]
940    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
941    /// use std::fs;
942    /// use std::os::unix::fs::FileTypeExt;
943    /// use std::io;
944    ///
945    /// fn main() -> io::Result<()> {
946    ///     let meta = fs::metadata("block_device_file")?;
947    ///     let file_type = meta.file_type();
948    ///     assert!(file_type.is_block_device());
949    ///     Ok(())
950    /// }
951    /// ```
952    #[stable(feature = "file_type_ext", since = "1.5.0")]
953    fn is_block_device(&self) -> bool;
954    /// Returns `true` if this file type is a char device.
955    ///
956    /// # Examples
957    ///
958    #[cfg_attr(target_family = "unix", doc = "```no_run")]
959    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
960    /// use std::fs;
961    /// use std::os::unix::fs::FileTypeExt;
962    /// use std::io;
963    ///
964    /// fn main() -> io::Result<()> {
965    ///     let meta = fs::metadata("char_device_file")?;
966    ///     let file_type = meta.file_type();
967    ///     assert!(file_type.is_char_device());
968    ///     Ok(())
969    /// }
970    /// ```
971    #[stable(feature = "file_type_ext", since = "1.5.0")]
972    fn is_char_device(&self) -> bool;
973    /// Returns `true` if this file type is a fifo.
974    ///
975    /// # Examples
976    ///
977    #[cfg_attr(target_family = "unix", doc = "```no_run")]
978    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
979    /// use std::fs;
980    /// use std::os::unix::fs::FileTypeExt;
981    /// use std::io;
982    ///
983    /// fn main() -> io::Result<()> {
984    ///     let meta = fs::metadata("fifo_file")?;
985    ///     let file_type = meta.file_type();
986    ///     assert!(file_type.is_fifo());
987    ///     Ok(())
988    /// }
989    /// ```
990    #[stable(feature = "file_type_ext", since = "1.5.0")]
991    fn is_fifo(&self) -> bool;
992    /// Returns `true` if this file type is a socket.
993    ///
994    /// # Examples
995    ///
996    #[cfg_attr(target_family = "unix", doc = "```no_run")]
997    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
998    /// use std::fs;
999    /// use std::os::unix::fs::FileTypeExt;
1000    /// use std::io;
1001    ///
1002    /// fn main() -> io::Result<()> {
1003    ///     let meta = fs::metadata("unix.socket")?;
1004    ///     let file_type = meta.file_type();
1005    ///     assert!(file_type.is_socket());
1006    ///     Ok(())
1007    /// }
1008    /// ```
1009    #[stable(feature = "file_type_ext", since = "1.5.0")]
1010    fn is_socket(&self) -> bool;
1011}
1012
1013#[stable(feature = "file_type_ext", since = "1.5.0")]
1014impl FileTypeExt for fs::FileType {
1015    #[rustdoc_skip_body]
1016    fn is_block_device(&self) -> bool {
1017        self.as_inner().is(libc::S_IFBLK)
1018    }
1019    #[rustdoc_skip_body]
1020    fn is_char_device(&self) -> bool {
1021        self.as_inner().is(libc::S_IFCHR)
1022    }
1023    #[rustdoc_skip_body]
1024    fn is_fifo(&self) -> bool {
1025        self.as_inner().is(libc::S_IFIFO)
1026    }
1027    #[rustdoc_skip_body]
1028    fn is_socket(&self) -> bool {
1029        self.as_inner().is(libc::S_IFSOCK)
1030    }
1031}
1032
1033/// Unix-specific extension methods for [`fs::DirEntry`].
1034#[stable(feature = "dir_entry_ext", since = "1.1.0")]
1035pub trait DirEntryExt {
1036    /// Returns the underlying `d_ino` field in the contained `dirent`
1037    /// structure.
1038    ///
1039    /// # Examples
1040    ///
1041    #[cfg_attr(target_family = "unix", doc = "```no_run")]
1042    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
1043    /// use std::fs;
1044    /// use std::os::unix::fs::DirEntryExt;
1045    ///
1046    /// if let Ok(entries) = fs::read_dir(".") {
1047    ///     for entry in entries {
1048    ///         if let Ok(entry) = entry {
1049    ///             // Here, `entry` is a `DirEntry`.
1050    ///             println!("{:?}: {}", entry.file_name(), entry.ino());
1051    ///         }
1052    ///     }
1053    /// }
1054    /// ```
1055    #[stable(feature = "dir_entry_ext", since = "1.1.0")]
1056    fn ino(&self) -> u64;
1057}
1058
1059#[stable(feature = "dir_entry_ext", since = "1.1.0")]
1060impl DirEntryExt for fs::DirEntry {
1061    #[rustdoc_skip_body]
1062    fn ino(&self) -> u64 {
1063        self.as_inner().ino()
1064    }
1065}
1066
1067/// Unix-specific extension methods for [`fs::DirEntry`].
1068#[unstable(feature = "dir_entry_ext2", issue = "85573")]
1069pub impl(self) trait DirEntryExt2 {
1070    /// Returns a reference to the underlying `OsStr` of this entry's filename.
1071    ///
1072    /// # Examples
1073    ///
1074    #[cfg_attr(target_family = "unix", doc = "```no_run")]
1075    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
1076    /// #![feature(dir_entry_ext2)]
1077    /// use std::os::unix::fs::DirEntryExt2;
1078    /// use std::{fs, io};
1079    ///
1080    /// fn main() -> io::Result<()> {
1081    ///     let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?;
1082    ///     entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));
1083    ///
1084    ///     for p in entries {
1085    ///         println!("{p:?}");
1086    ///     }
1087    ///
1088    ///     Ok(())
1089    /// }
1090    /// ```
1091    fn file_name_ref(&self) -> &OsStr;
1092}
1093
1094#[unstable(feature = "dir_entry_ext2", issue = "85573")]
1095impl DirEntryExt2 for fs::DirEntry {
1096    #[rustdoc_skip_body]
1097    fn file_name_ref(&self) -> &OsStr {
1098        self.as_inner().file_name_os_str()
1099    }
1100}
1101
1102/// Creates a new symbolic link on the filesystem.
1103///
1104/// The `link` path will be a symbolic link pointing to the `original` path.
1105///
1106/// # Examples
1107///
1108#[cfg_attr(target_family = "unix", doc = "```no_run")]
1109#[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
1110/// use std::os::unix::fs;
1111///
1112/// fn main() -> std::io::Result<()> {
1113///     fs::symlink("a.txt", "b.txt")?;
1114///     Ok(())
1115/// }
1116/// ```
1117#[stable(feature = "symlink", since = "1.1.0")]
1118#[cfg_attr(not(test), rustc_diagnostic_item = "fs_symlink")]
1119pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
1120    sys::fs::symlink(original.as_ref(), link.as_ref())
1121}
1122
1123/// Unix-specific extensions to [`fs::DirBuilder`].
1124#[stable(feature = "dir_builder", since = "1.6.0")]
1125pub trait DirBuilderExt {
1126    /// Sets the mode to create new directories with. This option defaults to
1127    /// 0o777.
1128    ///
1129    /// # Examples
1130    ///
1131    #[cfg_attr(target_family = "unix", doc = "```no_run")]
1132    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
1133    /// use std::fs::DirBuilder;
1134    /// use std::os::unix::fs::DirBuilderExt;
1135    ///
1136    /// let mut builder = DirBuilder::new();
1137    /// builder.mode(0o755);
1138    /// ```
1139    #[stable(feature = "dir_builder", since = "1.6.0")]
1140    fn mode(&mut self, mode: u32) -> &mut Self;
1141}
1142
1143#[stable(feature = "dir_builder", since = "1.6.0")]
1144impl DirBuilderExt for fs::DirBuilder {
1145    #[rustdoc_skip_body]
1146    fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
1147        self.as_inner_mut().set_mode(mode);
1148        self
1149    }
1150}
1151
1152/// Change the owner and group of the specified path.
1153///
1154/// Specifying either the uid or gid as `None` will leave it unchanged.
1155///
1156/// Changing the owner typically requires privileges, such as root or a specific capability.
1157/// Changing the group typically requires either being the owner and a member of the group, or
1158/// having privileges.
1159///
1160/// Be aware that changing owner clears the `suid` and `sgid` permission bits in most cases
1161/// according to POSIX, usually even if the user is root. The sgid is not cleared when
1162/// the file is non-group-executable. See: <https://www.man7.org/linux/man-pages/man2/chown.2.html>
1163/// This call may also clear file capabilities, if there was any.
1164///
1165/// If called on a symbolic link, this will change the owner and group of the link target. To
1166/// change the owner and group of the link itself, see [`lchown`].
1167///
1168/// # Examples
1169///
1170#[cfg_attr(target_family = "unix", doc = "```no_run")]
1171#[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
1172/// use std::os::unix::fs;
1173///
1174/// fn main() -> std::io::Result<()> {
1175///     fs::chown("/sandbox", Some(0), Some(0))?;
1176///     Ok(())
1177/// }
1178/// ```
1179#[stable(feature = "unix_chown", since = "1.73.0")]
1180#[rustdoc_skip_body]
1181pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1182    sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
1183}
1184
1185/// Change the owner and group of the file referenced by the specified open file descriptor.
1186///
1187/// For semantics and required privileges, see [`chown`].
1188///
1189/// # Examples
1190///
1191#[cfg_attr(target_family = "unix", doc = "```no_run")]
1192#[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
1193/// use std::os::unix::fs;
1194///
1195/// fn main() -> std::io::Result<()> {
1196///     let f = std::fs::File::open("/file")?;
1197///     fs::fchown(&f, Some(0), Some(0))?;
1198///     Ok(())
1199/// }
1200/// ```
1201#[stable(feature = "unix_chown", since = "1.73.0")]
1202#[rustdoc_skip_body]
1203pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1204    sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
1205}
1206
1207/// Change the owner and group of the specified path, without dereferencing symbolic links.
1208///
1209/// Identical to [`chown`], except that if called on a symbolic link, this will change the owner
1210/// and group of the link itself rather than the owner and group of the link target.
1211///
1212/// # Examples
1213///
1214#[cfg_attr(target_family = "unix", doc = "```no_run")]
1215#[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
1216/// use std::os::unix::fs;
1217///
1218/// fn main() -> std::io::Result<()> {
1219///     fs::lchown("/symlink", Some(0), Some(0))?;
1220///     Ok(())
1221/// }
1222/// ```
1223#[stable(feature = "unix_chown", since = "1.73.0")]
1224#[rustdoc_skip_body]
1225pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1226    sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
1227}
1228
1229/// Change the root directory of the current process to the specified path.
1230///
1231/// This typically requires privileges, such as root or a specific capability.
1232///
1233/// This does not change the current working directory; you should call
1234/// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards.
1235///
1236/// # Examples
1237///
1238#[cfg_attr(target_family = "unix", doc = "```no_run")]
1239#[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
1240/// use std::os::unix::fs;
1241///
1242/// fn main() -> std::io::Result<()> {
1243///     fs::chroot("/sandbox")?;
1244///     std::env::set_current_dir("/")?;
1245///     // continue working in sandbox
1246///     Ok(())
1247/// }
1248/// ```
1249#[stable(feature = "unix_chroot", since = "1.56.0")]
1250#[cfg(not(target_os = "fuchsia"))]
1251#[rustdoc_skip_body]
1252pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
1253    sys::fs::chroot(dir.as_ref())
1254}
1255
1256/// Create a FIFO special file at the specified path with the specified mode.
1257///
1258/// # Examples
1259///
1260#[cfg_attr(target_family = "unix", doc = "```no_run")]
1261#[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
1262/// # #![feature(unix_mkfifo)]
1263/// # #[cfg(not(unix))]
1264/// # fn main() {}
1265/// # #[cfg(unix)]
1266/// # fn main() -> std::io::Result<()> {
1267/// # use std::{
1268/// #     os::unix::fs::{mkfifo, PermissionsExt},
1269/// #     fs::{File, Permissions, remove_file},
1270/// #     io::{Write, Read},
1271/// # };
1272/// # let _ = remove_file("/tmp/fifo");
1273/// mkfifo("/tmp/fifo", Permissions::from_mode(0o774))?;
1274///
1275/// let mut wx = File::options().read(true).write(true).open("/tmp/fifo")?;
1276/// let mut rx = File::open("/tmp/fifo")?;
1277///
1278/// wx.write_all(b"hello, world!")?;
1279/// drop(wx);
1280///
1281/// let mut s = String::new();
1282/// rx.read_to_string(&mut s)?;
1283///
1284/// assert_eq!(s, "hello, world!");
1285/// # Ok(())
1286/// # }
1287/// ```
1288#[unstable(feature = "unix_mkfifo", issue = "139324")]
1289#[rustdoc_skip_body]
1290pub fn mkfifo<P: AsRef<Path>>(path: P, permissions: Permissions) -> io::Result<()> {
1291    sys::fs::mkfifo(path.as_ref(), permissions.mode())
1292}