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