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