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