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