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