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}