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