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