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