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