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