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}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy