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