Skip to main content

std/os/unix/
fs.rs

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