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}