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