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