[go: up one dir, main page]

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 Rust's options.
412    ///
413    /// Custom flags can only set flags, not remove flags set by Rust's options.
414    /// This function overwrites any previously-set custom flags.
415    ///
416    /// # Examples
417    ///
418    /// ```no_run
419    /// # mod libc { pub const O_NOFOLLOW: i32 = 0; }
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    /// options.custom_flags(libc::O_NOFOLLOW);
427    /// let file = options.open("foo.txt");
428    /// # }
429    /// ```
430    #[stable(feature = "open_options_ext", since = "1.10.0")]
431    fn custom_flags(&mut self, flags: i32) -> &mut Self;
432}
433
434#[stable(feature = "fs_ext", since = "1.1.0")]
435impl OpenOptionsExt for OpenOptions {
436    fn mode(&mut self, mode: u32) -> &mut OpenOptions {
437        self.as_inner_mut().mode(mode);
438        self
439    }
440
441    fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
442        self.as_inner_mut().custom_flags(flags);
443        self
444    }
445}
446
447/// Unix-specific extensions to [`fs::Metadata`].
448#[stable(feature = "metadata_ext", since = "1.1.0")]
449pub trait MetadataExt {
450    /// Returns the ID of the device containing the file.
451    ///
452    /// # Examples
453    ///
454    /// ```no_run
455    /// use std::io;
456    /// use std::fs;
457    /// use std::os::unix::fs::MetadataExt;
458    ///
459    /// fn main() -> io::Result<()> {
460    ///     let meta = fs::metadata("some_file")?;
461    ///     let dev_id = meta.dev();
462    ///     Ok(())
463    /// }
464    /// ```
465    #[stable(feature = "metadata_ext", since = "1.1.0")]
466    fn dev(&self) -> u64;
467    /// Returns the inode number.
468    ///
469    /// # Examples
470    ///
471    /// ```no_run
472    /// use std::fs;
473    /// use std::os::unix::fs::MetadataExt;
474    /// use std::io;
475    ///
476    /// fn main() -> io::Result<()> {
477    ///     let meta = fs::metadata("some_file")?;
478    ///     let inode = meta.ino();
479    ///     Ok(())
480    /// }
481    /// ```
482    #[stable(feature = "metadata_ext", since = "1.1.0")]
483    fn ino(&self) -> u64;
484    /// Returns the rights applied to this file.
485    ///
486    /// # Examples
487    ///
488    /// ```no_run
489    /// use std::fs;
490    /// use std::os::unix::fs::MetadataExt;
491    /// use std::io;
492    ///
493    /// fn main() -> io::Result<()> {
494    ///     let meta = fs::metadata("some_file")?;
495    ///     let mode = meta.mode();
496    ///     let user_has_write_access      = mode & 0o200;
497    ///     let user_has_read_write_access = mode & 0o600;
498    ///     let group_has_read_access      = mode & 0o040;
499    ///     let others_have_exec_access    = mode & 0o001;
500    ///     Ok(())
501    /// }
502    /// ```
503    #[stable(feature = "metadata_ext", since = "1.1.0")]
504    fn mode(&self) -> u32;
505    /// Returns the number of hard links pointing to this file.
506    ///
507    /// # Examples
508    ///
509    /// ```no_run
510    /// use std::fs;
511    /// use std::os::unix::fs::MetadataExt;
512    /// use std::io;
513    ///
514    /// fn main() -> io::Result<()> {
515    ///     let meta = fs::metadata("some_file")?;
516    ///     let nb_hard_links = meta.nlink();
517    ///     Ok(())
518    /// }
519    /// ```
520    #[stable(feature = "metadata_ext", since = "1.1.0")]
521    fn nlink(&self) -> u64;
522    /// Returns the user ID of the owner of this file.
523    ///
524    /// # Examples
525    ///
526    /// ```no_run
527    /// use std::fs;
528    /// use std::os::unix::fs::MetadataExt;
529    /// use std::io;
530    ///
531    /// fn main() -> io::Result<()> {
532    ///     let meta = fs::metadata("some_file")?;
533    ///     let user_id = meta.uid();
534    ///     Ok(())
535    /// }
536    /// ```
537    #[stable(feature = "metadata_ext", since = "1.1.0")]
538    fn uid(&self) -> u32;
539    /// Returns the group ID of the owner of this file.
540    ///
541    /// # Examples
542    ///
543    /// ```no_run
544    /// use std::fs;
545    /// use std::os::unix::fs::MetadataExt;
546    /// use std::io;
547    ///
548    /// fn main() -> io::Result<()> {
549    ///     let meta = fs::metadata("some_file")?;
550    ///     let group_id = meta.gid();
551    ///     Ok(())
552    /// }
553    /// ```
554    #[stable(feature = "metadata_ext", since = "1.1.0")]
555    fn gid(&self) -> u32;
556    /// Returns the device ID of this file (if it is a special one).
557    ///
558    /// # Examples
559    ///
560    /// ```no_run
561    /// use std::fs;
562    /// use std::os::unix::fs::MetadataExt;
563    /// use std::io;
564    ///
565    /// fn main() -> io::Result<()> {
566    ///     let meta = fs::metadata("some_file")?;
567    ///     let device_id = meta.rdev();
568    ///     Ok(())
569    /// }
570    /// ```
571    #[stable(feature = "metadata_ext", since = "1.1.0")]
572    fn rdev(&self) -> u64;
573    /// Returns the total size of this file in bytes.
574    ///
575    /// # Examples
576    ///
577    /// ```no_run
578    /// use std::fs;
579    /// use std::os::unix::fs::MetadataExt;
580    /// use std::io;
581    ///
582    /// fn main() -> io::Result<()> {
583    ///     let meta = fs::metadata("some_file")?;
584    ///     let file_size = meta.size();
585    ///     Ok(())
586    /// }
587    /// ```
588    #[stable(feature = "metadata_ext", since = "1.1.0")]
589    fn size(&self) -> u64;
590    /// Returns the last access time of the file, in seconds since Unix Epoch.
591    ///
592    /// # Examples
593    ///
594    /// ```no_run
595    /// use std::fs;
596    /// use std::os::unix::fs::MetadataExt;
597    /// use std::io;
598    ///
599    /// fn main() -> io::Result<()> {
600    ///     let meta = fs::metadata("some_file")?;
601    ///     let last_access_time = meta.atime();
602    ///     Ok(())
603    /// }
604    /// ```
605    #[stable(feature = "metadata_ext", since = "1.1.0")]
606    fn atime(&self) -> i64;
607    /// Returns the last access time of the file, in nanoseconds since [`atime`].
608    ///
609    /// [`atime`]: MetadataExt::atime
610    ///
611    /// # Examples
612    ///
613    /// ```no_run
614    /// use std::fs;
615    /// use std::os::unix::fs::MetadataExt;
616    /// use std::io;
617    ///
618    /// fn main() -> io::Result<()> {
619    ///     let meta = fs::metadata("some_file")?;
620    ///     let nano_last_access_time = meta.atime_nsec();
621    ///     Ok(())
622    /// }
623    /// ```
624    #[stable(feature = "metadata_ext", since = "1.1.0")]
625    fn atime_nsec(&self) -> i64;
626    /// Returns the last modification time of the file, in seconds since Unix Epoch.
627    ///
628    /// # Examples
629    ///
630    /// ```no_run
631    /// use std::fs;
632    /// use std::os::unix::fs::MetadataExt;
633    /// use std::io;
634    ///
635    /// fn main() -> io::Result<()> {
636    ///     let meta = fs::metadata("some_file")?;
637    ///     let last_modification_time = meta.mtime();
638    ///     Ok(())
639    /// }
640    /// ```
641    #[stable(feature = "metadata_ext", since = "1.1.0")]
642    fn mtime(&self) -> i64;
643    /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
644    ///
645    /// [`mtime`]: MetadataExt::mtime
646    ///
647    /// # Examples
648    ///
649    /// ```no_run
650    /// use std::fs;
651    /// use std::os::unix::fs::MetadataExt;
652    /// use std::io;
653    ///
654    /// fn main() -> io::Result<()> {
655    ///     let meta = fs::metadata("some_file")?;
656    ///     let nano_last_modification_time = meta.mtime_nsec();
657    ///     Ok(())
658    /// }
659    /// ```
660    #[stable(feature = "metadata_ext", since = "1.1.0")]
661    fn mtime_nsec(&self) -> i64;
662    /// Returns the last status change time of the file, in seconds since Unix Epoch.
663    ///
664    /// # Examples
665    ///
666    /// ```no_run
667    /// use std::fs;
668    /// use std::os::unix::fs::MetadataExt;
669    /// use std::io;
670    ///
671    /// fn main() -> io::Result<()> {
672    ///     let meta = fs::metadata("some_file")?;
673    ///     let last_status_change_time = meta.ctime();
674    ///     Ok(())
675    /// }
676    /// ```
677    #[stable(feature = "metadata_ext", since = "1.1.0")]
678    fn ctime(&self) -> i64;
679    /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
680    ///
681    /// [`ctime`]: MetadataExt::ctime
682    ///
683    /// # Examples
684    ///
685    /// ```no_run
686    /// use std::fs;
687    /// use std::os::unix::fs::MetadataExt;
688    /// use std::io;
689    ///
690    /// fn main() -> io::Result<()> {
691    ///     let meta = fs::metadata("some_file")?;
692    ///     let nano_last_status_change_time = meta.ctime_nsec();
693    ///     Ok(())
694    /// }
695    /// ```
696    #[stable(feature = "metadata_ext", since = "1.1.0")]
697    fn ctime_nsec(&self) -> i64;
698    /// Returns the block size for filesystem I/O.
699    ///
700    /// # Examples
701    ///
702    /// ```no_run
703    /// use std::fs;
704    /// use std::os::unix::fs::MetadataExt;
705    /// use std::io;
706    ///
707    /// fn main() -> io::Result<()> {
708    ///     let meta = fs::metadata("some_file")?;
709    ///     let block_size = meta.blksize();
710    ///     Ok(())
711    /// }
712    /// ```
713    #[stable(feature = "metadata_ext", since = "1.1.0")]
714    fn blksize(&self) -> u64;
715    /// Returns the number of blocks allocated to the file, in 512-byte units.
716    ///
717    /// Please note that this may be smaller than `st_size / 512` when the file has holes.
718    ///
719    /// # Examples
720    ///
721    /// ```no_run
722    /// use std::fs;
723    /// use std::os::unix::fs::MetadataExt;
724    /// use std::io;
725    ///
726    /// fn main() -> io::Result<()> {
727    ///     let meta = fs::metadata("some_file")?;
728    ///     let blocks = meta.blocks();
729    ///     Ok(())
730    /// }
731    /// ```
732    #[stable(feature = "metadata_ext", since = "1.1.0")]
733    fn blocks(&self) -> u64;
734    #[cfg(target_os = "vxworks")]
735    #[stable(feature = "metadata_ext", since = "1.1.0")]
736    fn attrib(&self) -> u8;
737}
738
739#[stable(feature = "metadata_ext", since = "1.1.0")]
740impl MetadataExt for fs::Metadata {
741    fn dev(&self) -> u64 {
742        self.st_dev()
743    }
744    fn ino(&self) -> u64 {
745        self.st_ino()
746    }
747    fn mode(&self) -> u32 {
748        self.st_mode()
749    }
750    fn nlink(&self) -> u64 {
751        self.st_nlink()
752    }
753    fn uid(&self) -> u32 {
754        self.st_uid()
755    }
756    fn gid(&self) -> u32 {
757        self.st_gid()
758    }
759    fn rdev(&self) -> u64 {
760        self.st_rdev()
761    }
762    fn size(&self) -> u64 {
763        self.st_size()
764    }
765    fn atime(&self) -> i64 {
766        self.st_atime()
767    }
768    fn atime_nsec(&self) -> i64 {
769        self.st_atime_nsec()
770    }
771    fn mtime(&self) -> i64 {
772        self.st_mtime()
773    }
774    fn mtime_nsec(&self) -> i64 {
775        self.st_mtime_nsec()
776    }
777    fn ctime(&self) -> i64 {
778        self.st_ctime()
779    }
780    fn ctime_nsec(&self) -> i64 {
781        self.st_ctime_nsec()
782    }
783    fn blksize(&self) -> u64 {
784        self.st_blksize()
785    }
786    fn blocks(&self) -> u64 {
787        self.st_blocks()
788    }
789    #[cfg(target_os = "vxworks")]
790    fn attrib(&self) -> u8 {
791        self.st_attrib()
792    }
793}
794
795/// Unix-specific extensions for [`fs::FileType`].
796///
797/// Adds support for special Unix file types such as block/character devices,
798/// pipes, and sockets.
799#[stable(feature = "file_type_ext", since = "1.5.0")]
800pub trait FileTypeExt {
801    /// Returns `true` if this file type is a block device.
802    ///
803    /// # Examples
804    ///
805    /// ```no_run
806    /// use std::fs;
807    /// use std::os::unix::fs::FileTypeExt;
808    /// use std::io;
809    ///
810    /// fn main() -> io::Result<()> {
811    ///     let meta = fs::metadata("block_device_file")?;
812    ///     let file_type = meta.file_type();
813    ///     assert!(file_type.is_block_device());
814    ///     Ok(())
815    /// }
816    /// ```
817    #[stable(feature = "file_type_ext", since = "1.5.0")]
818    fn is_block_device(&self) -> bool;
819    /// Returns `true` if this file type is a char device.
820    ///
821    /// # Examples
822    ///
823    /// ```no_run
824    /// use std::fs;
825    /// use std::os::unix::fs::FileTypeExt;
826    /// use std::io;
827    ///
828    /// fn main() -> io::Result<()> {
829    ///     let meta = fs::metadata("char_device_file")?;
830    ///     let file_type = meta.file_type();
831    ///     assert!(file_type.is_char_device());
832    ///     Ok(())
833    /// }
834    /// ```
835    #[stable(feature = "file_type_ext", since = "1.5.0")]
836    fn is_char_device(&self) -> bool;
837    /// Returns `true` if this file type is a fifo.
838    ///
839    /// # Examples
840    ///
841    /// ```no_run
842    /// use std::fs;
843    /// use std::os::unix::fs::FileTypeExt;
844    /// use std::io;
845    ///
846    /// fn main() -> io::Result<()> {
847    ///     let meta = fs::metadata("fifo_file")?;
848    ///     let file_type = meta.file_type();
849    ///     assert!(file_type.is_fifo());
850    ///     Ok(())
851    /// }
852    /// ```
853    #[stable(feature = "file_type_ext", since = "1.5.0")]
854    fn is_fifo(&self) -> bool;
855    /// Returns `true` if this file type is a socket.
856    ///
857    /// # Examples
858    ///
859    /// ```no_run
860    /// use std::fs;
861    /// use std::os::unix::fs::FileTypeExt;
862    /// use std::io;
863    ///
864    /// fn main() -> io::Result<()> {
865    ///     let meta = fs::metadata("unix.socket")?;
866    ///     let file_type = meta.file_type();
867    ///     assert!(file_type.is_socket());
868    ///     Ok(())
869    /// }
870    /// ```
871    #[stable(feature = "file_type_ext", since = "1.5.0")]
872    fn is_socket(&self) -> bool;
873}
874
875#[stable(feature = "file_type_ext", since = "1.5.0")]
876impl FileTypeExt for fs::FileType {
877    fn is_block_device(&self) -> bool {
878        self.as_inner().is(libc::S_IFBLK)
879    }
880    fn is_char_device(&self) -> bool {
881        self.as_inner().is(libc::S_IFCHR)
882    }
883    fn is_fifo(&self) -> bool {
884        self.as_inner().is(libc::S_IFIFO)
885    }
886    fn is_socket(&self) -> bool {
887        self.as_inner().is(libc::S_IFSOCK)
888    }
889}
890
891/// Unix-specific extension methods for [`fs::DirEntry`].
892#[stable(feature = "dir_entry_ext", since = "1.1.0")]
893pub trait DirEntryExt {
894    /// Returns the underlying `d_ino` field in the contained `dirent`
895    /// structure.
896    ///
897    /// # Examples
898    ///
899    /// ```
900    /// use std::fs;
901    /// use std::os::unix::fs::DirEntryExt;
902    ///
903    /// if let Ok(entries) = fs::read_dir(".") {
904    ///     for entry in entries {
905    ///         if let Ok(entry) = entry {
906    ///             // Here, `entry` is a `DirEntry`.
907    ///             println!("{:?}: {}", entry.file_name(), entry.ino());
908    ///         }
909    ///     }
910    /// }
911    /// ```
912    #[stable(feature = "dir_entry_ext", since = "1.1.0")]
913    fn ino(&self) -> u64;
914}
915
916#[stable(feature = "dir_entry_ext", since = "1.1.0")]
917impl DirEntryExt for fs::DirEntry {
918    fn ino(&self) -> u64 {
919        self.as_inner().ino()
920    }
921}
922
923/// Sealed Unix-specific extension methods for [`fs::DirEntry`].
924#[unstable(feature = "dir_entry_ext2", issue = "85573")]
925pub trait DirEntryExt2: Sealed {
926    /// Returns a reference to the underlying `OsStr` of this entry's filename.
927    ///
928    /// # Examples
929    ///
930    /// ```
931    /// #![feature(dir_entry_ext2)]
932    /// use std::os::unix::fs::DirEntryExt2;
933    /// use std::{fs, io};
934    ///
935    /// fn main() -> io::Result<()> {
936    ///     let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?;
937    ///     entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));
938    ///
939    ///     for p in entries {
940    ///         println!("{p:?}");
941    ///     }
942    ///
943    ///     Ok(())
944    /// }
945    /// ```
946    fn file_name_ref(&self) -> &OsStr;
947}
948
949/// Allows extension traits within `std`.
950#[unstable(feature = "sealed", issue = "none")]
951impl Sealed for fs::DirEntry {}
952
953#[unstable(feature = "dir_entry_ext2", issue = "85573")]
954impl DirEntryExt2 for fs::DirEntry {
955    fn file_name_ref(&self) -> &OsStr {
956        self.as_inner().file_name_os_str()
957    }
958}
959
960/// Creates a new symbolic link on the filesystem.
961///
962/// The `link` path will be a symbolic link pointing to the `original` path.
963///
964/// # Examples
965///
966/// ```no_run
967/// use std::os::unix::fs;
968///
969/// fn main() -> std::io::Result<()> {
970///     fs::symlink("a.txt", "b.txt")?;
971///     Ok(())
972/// }
973/// ```
974#[stable(feature = "symlink", since = "1.1.0")]
975pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
976    sys::fs::symlink(original.as_ref(), link.as_ref())
977}
978
979/// Unix-specific extensions to [`fs::DirBuilder`].
980#[stable(feature = "dir_builder", since = "1.6.0")]
981pub trait DirBuilderExt {
982    /// Sets the mode to create new directories with. This option defaults to
983    /// 0o777.
984    ///
985    /// # Examples
986    ///
987    /// ```no_run
988    /// use std::fs::DirBuilder;
989    /// use std::os::unix::fs::DirBuilderExt;
990    ///
991    /// let mut builder = DirBuilder::new();
992    /// builder.mode(0o755);
993    /// ```
994    #[stable(feature = "dir_builder", since = "1.6.0")]
995    fn mode(&mut self, mode: u32) -> &mut Self;
996}
997
998#[stable(feature = "dir_builder", since = "1.6.0")]
999impl DirBuilderExt for fs::DirBuilder {
1000    fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
1001        self.as_inner_mut().set_mode(mode);
1002        self
1003    }
1004}
1005
1006/// Change the owner and group of the specified path.
1007///
1008/// Specifying either the uid or gid as `None` will leave it unchanged.
1009///
1010/// Changing the owner typically requires privileges, such as root or a specific capability.
1011/// Changing the group typically requires either being the owner and a member of the group, or
1012/// having privileges.
1013///
1014/// Be aware that changing owner clears the `suid` and `sgid` permission bits in most cases
1015/// according to POSIX, usually even if the user is root. The sgid is not cleared when
1016/// the file is non-group-executable. See: <https://www.man7.org/linux/man-pages/man2/chown.2.html>
1017/// This call may also clear file capabilities, if there was any.
1018///
1019/// If called on a symbolic link, this will change the owner and group of the link target. To
1020/// change the owner and group of the link itself, see [`lchown`].
1021///
1022/// # Examples
1023///
1024/// ```no_run
1025/// use std::os::unix::fs;
1026///
1027/// fn main() -> std::io::Result<()> {
1028///     fs::chown("/sandbox", Some(0), Some(0))?;
1029///     Ok(())
1030/// }
1031/// ```
1032#[stable(feature = "unix_chown", since = "1.73.0")]
1033pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1034    sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
1035}
1036
1037/// Change the owner and group of the file referenced by the specified open file descriptor.
1038///
1039/// For semantics and required privileges, see [`chown`].
1040///
1041/// # Examples
1042///
1043/// ```no_run
1044/// use std::os::unix::fs;
1045///
1046/// fn main() -> std::io::Result<()> {
1047///     let f = std::fs::File::open("/file")?;
1048///     fs::fchown(&f, Some(0), Some(0))?;
1049///     Ok(())
1050/// }
1051/// ```
1052#[stable(feature = "unix_chown", since = "1.73.0")]
1053pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1054    sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
1055}
1056
1057/// Change the owner and group of the specified path, without dereferencing symbolic links.
1058///
1059/// Identical to [`chown`], except that if called on a symbolic link, this will change the owner
1060/// and group of the link itself rather than the owner and group of the link target.
1061///
1062/// # Examples
1063///
1064/// ```no_run
1065/// use std::os::unix::fs;
1066///
1067/// fn main() -> std::io::Result<()> {
1068///     fs::lchown("/symlink", Some(0), Some(0))?;
1069///     Ok(())
1070/// }
1071/// ```
1072#[stable(feature = "unix_chown", since = "1.73.0")]
1073pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1074    sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
1075}
1076
1077/// Change the root directory of the current process to the specified path.
1078///
1079/// This typically requires privileges, such as root or a specific capability.
1080///
1081/// This does not change the current working directory; you should call
1082/// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards.
1083///
1084/// # Examples
1085///
1086/// ```no_run
1087/// use std::os::unix::fs;
1088///
1089/// fn main() -> std::io::Result<()> {
1090///     fs::chroot("/sandbox")?;
1091///     std::env::set_current_dir("/")?;
1092///     // continue working in sandbox
1093///     Ok(())
1094/// }
1095/// ```
1096#[stable(feature = "unix_chroot", since = "1.56.0")]
1097#[cfg(not(target_os = "fuchsia"))]
1098pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
1099    sys::fs::chroot(dir.as_ref())
1100}
1101
1102/// Create a FIFO special file at the specified path with the specified mode.
1103///
1104/// # Examples
1105///
1106/// ```no_run
1107/// # #![feature(unix_mkfifo)]
1108/// # #[cfg(not(unix))]
1109/// # fn main() {}
1110/// # #[cfg(unix)]
1111/// # fn main() -> std::io::Result<()> {
1112/// # use std::{
1113/// #     os::unix::fs::{mkfifo, PermissionsExt},
1114/// #     fs::{File, Permissions, remove_file},
1115/// #     io::{Write, Read},
1116/// # };
1117/// # let _ = remove_file("/tmp/fifo");
1118/// mkfifo("/tmp/fifo", Permissions::from_mode(0o774))?;
1119///
1120/// let mut wx = File::options().read(true).write(true).open("/tmp/fifo")?;
1121/// let mut rx = File::open("/tmp/fifo")?;
1122///
1123/// wx.write_all(b"hello, world!")?;
1124/// drop(wx);
1125///
1126/// let mut s = String::new();
1127/// rx.read_to_string(&mut s)?;
1128///
1129/// assert_eq!(s, "hello, world!");
1130/// # Ok(())
1131/// # }
1132/// ```
1133#[unstable(feature = "unix_mkfifo", issue = "139324")]
1134pub fn mkfifo<P: AsRef<Path>>(path: P, permissions: Permissions) -> io::Result<()> {
1135    sys::fs::mkfifo(path.as_ref(), permissions.mode())
1136}