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