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 Rust's options.
412 ///
413 /// Custom flags can only set flags, not remove flags set by Rust's options.
414 /// This function overwrites any previously-set custom flags.
415 ///
416 /// # Examples
417 ///
418 /// ```no_run
419 /// # mod libc { pub const O_NOFOLLOW: i32 = 0; }
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 /// options.custom_flags(libc::O_NOFOLLOW);
427 /// let file = options.open("foo.txt");
428 /// # }
429 /// ```
430 #[stable(feature = "open_options_ext", since = "1.10.0")]
431 fn custom_flags(&mut self, flags: i32) -> &mut Self;
432}
433
434#[stable(feature = "fs_ext", since = "1.1.0")]
435impl OpenOptionsExt for OpenOptions {
436 fn mode(&mut self, mode: u32) -> &mut OpenOptions {
437 self.as_inner_mut().mode(mode);
438 self
439 }
440
441 fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
442 self.as_inner_mut().custom_flags(flags);
443 self
444 }
445}
446
447/// Unix-specific extensions to [`fs::Metadata`].
448#[stable(feature = "metadata_ext", since = "1.1.0")]
449pub trait MetadataExt {
450 /// Returns the ID of the device containing the file.
451 ///
452 /// # Examples
453 ///
454 /// ```no_run
455 /// use std::io;
456 /// use std::fs;
457 /// use std::os::unix::fs::MetadataExt;
458 ///
459 /// fn main() -> io::Result<()> {
460 /// let meta = fs::metadata("some_file")?;
461 /// let dev_id = meta.dev();
462 /// Ok(())
463 /// }
464 /// ```
465 #[stable(feature = "metadata_ext", since = "1.1.0")]
466 fn dev(&self) -> u64;
467 /// Returns the inode number.
468 ///
469 /// # Examples
470 ///
471 /// ```no_run
472 /// use std::fs;
473 /// use std::os::unix::fs::MetadataExt;
474 /// use std::io;
475 ///
476 /// fn main() -> io::Result<()> {
477 /// let meta = fs::metadata("some_file")?;
478 /// let inode = meta.ino();
479 /// Ok(())
480 /// }
481 /// ```
482 #[stable(feature = "metadata_ext", since = "1.1.0")]
483 fn ino(&self) -> u64;
484 /// Returns the rights applied to this file.
485 ///
486 /// # Examples
487 ///
488 /// ```no_run
489 /// use std::fs;
490 /// use std::os::unix::fs::MetadataExt;
491 /// use std::io;
492 ///
493 /// fn main() -> io::Result<()> {
494 /// let meta = fs::metadata("some_file")?;
495 /// let mode = meta.mode();
496 /// let user_has_write_access = mode & 0o200;
497 /// let user_has_read_write_access = mode & 0o600;
498 /// let group_has_read_access = mode & 0o040;
499 /// let others_have_exec_access = mode & 0o001;
500 /// Ok(())
501 /// }
502 /// ```
503 #[stable(feature = "metadata_ext", since = "1.1.0")]
504 fn mode(&self) -> u32;
505 /// Returns the number of hard links pointing to this file.
506 ///
507 /// # Examples
508 ///
509 /// ```no_run
510 /// use std::fs;
511 /// use std::os::unix::fs::MetadataExt;
512 /// use std::io;
513 ///
514 /// fn main() -> io::Result<()> {
515 /// let meta = fs::metadata("some_file")?;
516 /// let nb_hard_links = meta.nlink();
517 /// Ok(())
518 /// }
519 /// ```
520 #[stable(feature = "metadata_ext", since = "1.1.0")]
521 fn nlink(&self) -> u64;
522 /// Returns the user ID of the owner of this file.
523 ///
524 /// # Examples
525 ///
526 /// ```no_run
527 /// use std::fs;
528 /// use std::os::unix::fs::MetadataExt;
529 /// use std::io;
530 ///
531 /// fn main() -> io::Result<()> {
532 /// let meta = fs::metadata("some_file")?;
533 /// let user_id = meta.uid();
534 /// Ok(())
535 /// }
536 /// ```
537 #[stable(feature = "metadata_ext", since = "1.1.0")]
538 fn uid(&self) -> u32;
539 /// Returns the group ID of the owner of this file.
540 ///
541 /// # Examples
542 ///
543 /// ```no_run
544 /// use std::fs;
545 /// use std::os::unix::fs::MetadataExt;
546 /// use std::io;
547 ///
548 /// fn main() -> io::Result<()> {
549 /// let meta = fs::metadata("some_file")?;
550 /// let group_id = meta.gid();
551 /// Ok(())
552 /// }
553 /// ```
554 #[stable(feature = "metadata_ext", since = "1.1.0")]
555 fn gid(&self) -> u32;
556 /// Returns the device ID of this file (if it is a special one).
557 ///
558 /// # Examples
559 ///
560 /// ```no_run
561 /// use std::fs;
562 /// use std::os::unix::fs::MetadataExt;
563 /// use std::io;
564 ///
565 /// fn main() -> io::Result<()> {
566 /// let meta = fs::metadata("some_file")?;
567 /// let device_id = meta.rdev();
568 /// Ok(())
569 /// }
570 /// ```
571 #[stable(feature = "metadata_ext", since = "1.1.0")]
572 fn rdev(&self) -> u64;
573 /// Returns the total size of this file in bytes.
574 ///
575 /// # Examples
576 ///
577 /// ```no_run
578 /// use std::fs;
579 /// use std::os::unix::fs::MetadataExt;
580 /// use std::io;
581 ///
582 /// fn main() -> io::Result<()> {
583 /// let meta = fs::metadata("some_file")?;
584 /// let file_size = meta.size();
585 /// Ok(())
586 /// }
587 /// ```
588 #[stable(feature = "metadata_ext", since = "1.1.0")]
589 fn size(&self) -> u64;
590 /// Returns the last access time of the file, in seconds since Unix Epoch.
591 ///
592 /// # Examples
593 ///
594 /// ```no_run
595 /// use std::fs;
596 /// use std::os::unix::fs::MetadataExt;
597 /// use std::io;
598 ///
599 /// fn main() -> io::Result<()> {
600 /// let meta = fs::metadata("some_file")?;
601 /// let last_access_time = meta.atime();
602 /// Ok(())
603 /// }
604 /// ```
605 #[stable(feature = "metadata_ext", since = "1.1.0")]
606 fn atime(&self) -> i64;
607 /// Returns the last access time of the file, in nanoseconds since [`atime`].
608 ///
609 /// [`atime`]: MetadataExt::atime
610 ///
611 /// # Examples
612 ///
613 /// ```no_run
614 /// use std::fs;
615 /// use std::os::unix::fs::MetadataExt;
616 /// use std::io;
617 ///
618 /// fn main() -> io::Result<()> {
619 /// let meta = fs::metadata("some_file")?;
620 /// let nano_last_access_time = meta.atime_nsec();
621 /// Ok(())
622 /// }
623 /// ```
624 #[stable(feature = "metadata_ext", since = "1.1.0")]
625 fn atime_nsec(&self) -> i64;
626 /// Returns the last modification time of the file, in seconds since Unix Epoch.
627 ///
628 /// # Examples
629 ///
630 /// ```no_run
631 /// use std::fs;
632 /// use std::os::unix::fs::MetadataExt;
633 /// use std::io;
634 ///
635 /// fn main() -> io::Result<()> {
636 /// let meta = fs::metadata("some_file")?;
637 /// let last_modification_time = meta.mtime();
638 /// Ok(())
639 /// }
640 /// ```
641 #[stable(feature = "metadata_ext", since = "1.1.0")]
642 fn mtime(&self) -> i64;
643 /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
644 ///
645 /// [`mtime`]: MetadataExt::mtime
646 ///
647 /// # Examples
648 ///
649 /// ```no_run
650 /// use std::fs;
651 /// use std::os::unix::fs::MetadataExt;
652 /// use std::io;
653 ///
654 /// fn main() -> io::Result<()> {
655 /// let meta = fs::metadata("some_file")?;
656 /// let nano_last_modification_time = meta.mtime_nsec();
657 /// Ok(())
658 /// }
659 /// ```
660 #[stable(feature = "metadata_ext", since = "1.1.0")]
661 fn mtime_nsec(&self) -> i64;
662 /// Returns the last status change time of the file, in seconds since Unix Epoch.
663 ///
664 /// # Examples
665 ///
666 /// ```no_run
667 /// use std::fs;
668 /// use std::os::unix::fs::MetadataExt;
669 /// use std::io;
670 ///
671 /// fn main() -> io::Result<()> {
672 /// let meta = fs::metadata("some_file")?;
673 /// let last_status_change_time = meta.ctime();
674 /// Ok(())
675 /// }
676 /// ```
677 #[stable(feature = "metadata_ext", since = "1.1.0")]
678 fn ctime(&self) -> i64;
679 /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
680 ///
681 /// [`ctime`]: MetadataExt::ctime
682 ///
683 /// # Examples
684 ///
685 /// ```no_run
686 /// use std::fs;
687 /// use std::os::unix::fs::MetadataExt;
688 /// use std::io;
689 ///
690 /// fn main() -> io::Result<()> {
691 /// let meta = fs::metadata("some_file")?;
692 /// let nano_last_status_change_time = meta.ctime_nsec();
693 /// Ok(())
694 /// }
695 /// ```
696 #[stable(feature = "metadata_ext", since = "1.1.0")]
697 fn ctime_nsec(&self) -> i64;
698 /// Returns the block size for filesystem I/O.
699 ///
700 /// # Examples
701 ///
702 /// ```no_run
703 /// use std::fs;
704 /// use std::os::unix::fs::MetadataExt;
705 /// use std::io;
706 ///
707 /// fn main() -> io::Result<()> {
708 /// let meta = fs::metadata("some_file")?;
709 /// let block_size = meta.blksize();
710 /// Ok(())
711 /// }
712 /// ```
713 #[stable(feature = "metadata_ext", since = "1.1.0")]
714 fn blksize(&self) -> u64;
715 /// Returns the number of blocks allocated to the file, in 512-byte units.
716 ///
717 /// Please note that this may be smaller than `st_size / 512` when the file has holes.
718 ///
719 /// # Examples
720 ///
721 /// ```no_run
722 /// use std::fs;
723 /// use std::os::unix::fs::MetadataExt;
724 /// use std::io;
725 ///
726 /// fn main() -> io::Result<()> {
727 /// let meta = fs::metadata("some_file")?;
728 /// let blocks = meta.blocks();
729 /// Ok(())
730 /// }
731 /// ```
732 #[stable(feature = "metadata_ext", since = "1.1.0")]
733 fn blocks(&self) -> u64;
734 #[cfg(target_os = "vxworks")]
735 #[stable(feature = "metadata_ext", since = "1.1.0")]
736 fn attrib(&self) -> u8;
737}
738
739#[stable(feature = "metadata_ext", since = "1.1.0")]
740impl MetadataExt for fs::Metadata {
741 fn dev(&self) -> u64 {
742 self.st_dev()
743 }
744 fn ino(&self) -> u64 {
745 self.st_ino()
746 }
747 fn mode(&self) -> u32 {
748 self.st_mode()
749 }
750 fn nlink(&self) -> u64 {
751 self.st_nlink()
752 }
753 fn uid(&self) -> u32 {
754 self.st_uid()
755 }
756 fn gid(&self) -> u32 {
757 self.st_gid()
758 }
759 fn rdev(&self) -> u64 {
760 self.st_rdev()
761 }
762 fn size(&self) -> u64 {
763 self.st_size()
764 }
765 fn atime(&self) -> i64 {
766 self.st_atime()
767 }
768 fn atime_nsec(&self) -> i64 {
769 self.st_atime_nsec()
770 }
771 fn mtime(&self) -> i64 {
772 self.st_mtime()
773 }
774 fn mtime_nsec(&self) -> i64 {
775 self.st_mtime_nsec()
776 }
777 fn ctime(&self) -> i64 {
778 self.st_ctime()
779 }
780 fn ctime_nsec(&self) -> i64 {
781 self.st_ctime_nsec()
782 }
783 fn blksize(&self) -> u64 {
784 self.st_blksize()
785 }
786 fn blocks(&self) -> u64 {
787 self.st_blocks()
788 }
789 #[cfg(target_os = "vxworks")]
790 fn attrib(&self) -> u8 {
791 self.st_attrib()
792 }
793}
794
795/// Unix-specific extensions for [`fs::FileType`].
796///
797/// Adds support for special Unix file types such as block/character devices,
798/// pipes, and sockets.
799#[stable(feature = "file_type_ext", since = "1.5.0")]
800pub trait FileTypeExt {
801 /// Returns `true` if this file type is a block device.
802 ///
803 /// # Examples
804 ///
805 /// ```no_run
806 /// use std::fs;
807 /// use std::os::unix::fs::FileTypeExt;
808 /// use std::io;
809 ///
810 /// fn main() -> io::Result<()> {
811 /// let meta = fs::metadata("block_device_file")?;
812 /// let file_type = meta.file_type();
813 /// assert!(file_type.is_block_device());
814 /// Ok(())
815 /// }
816 /// ```
817 #[stable(feature = "file_type_ext", since = "1.5.0")]
818 fn is_block_device(&self) -> bool;
819 /// Returns `true` if this file type is a char device.
820 ///
821 /// # Examples
822 ///
823 /// ```no_run
824 /// use std::fs;
825 /// use std::os::unix::fs::FileTypeExt;
826 /// use std::io;
827 ///
828 /// fn main() -> io::Result<()> {
829 /// let meta = fs::metadata("char_device_file")?;
830 /// let file_type = meta.file_type();
831 /// assert!(file_type.is_char_device());
832 /// Ok(())
833 /// }
834 /// ```
835 #[stable(feature = "file_type_ext", since = "1.5.0")]
836 fn is_char_device(&self) -> bool;
837 /// Returns `true` if this file type is a fifo.
838 ///
839 /// # Examples
840 ///
841 /// ```no_run
842 /// use std::fs;
843 /// use std::os::unix::fs::FileTypeExt;
844 /// use std::io;
845 ///
846 /// fn main() -> io::Result<()> {
847 /// let meta = fs::metadata("fifo_file")?;
848 /// let file_type = meta.file_type();
849 /// assert!(file_type.is_fifo());
850 /// Ok(())
851 /// }
852 /// ```
853 #[stable(feature = "file_type_ext", since = "1.5.0")]
854 fn is_fifo(&self) -> bool;
855 /// Returns `true` if this file type is a socket.
856 ///
857 /// # Examples
858 ///
859 /// ```no_run
860 /// use std::fs;
861 /// use std::os::unix::fs::FileTypeExt;
862 /// use std::io;
863 ///
864 /// fn main() -> io::Result<()> {
865 /// let meta = fs::metadata("unix.socket")?;
866 /// let file_type = meta.file_type();
867 /// assert!(file_type.is_socket());
868 /// Ok(())
869 /// }
870 /// ```
871 #[stable(feature = "file_type_ext", since = "1.5.0")]
872 fn is_socket(&self) -> bool;
873}
874
875#[stable(feature = "file_type_ext", since = "1.5.0")]
876impl FileTypeExt for fs::FileType {
877 fn is_block_device(&self) -> bool {
878 self.as_inner().is(libc::S_IFBLK)
879 }
880 fn is_char_device(&self) -> bool {
881 self.as_inner().is(libc::S_IFCHR)
882 }
883 fn is_fifo(&self) -> bool {
884 self.as_inner().is(libc::S_IFIFO)
885 }
886 fn is_socket(&self) -> bool {
887 self.as_inner().is(libc::S_IFSOCK)
888 }
889}
890
891/// Unix-specific extension methods for [`fs::DirEntry`].
892#[stable(feature = "dir_entry_ext", since = "1.1.0")]
893pub trait DirEntryExt {
894 /// Returns the underlying `d_ino` field in the contained `dirent`
895 /// structure.
896 ///
897 /// # Examples
898 ///
899 /// ```
900 /// use std::fs;
901 /// use std::os::unix::fs::DirEntryExt;
902 ///
903 /// if let Ok(entries) = fs::read_dir(".") {
904 /// for entry in entries {
905 /// if let Ok(entry) = entry {
906 /// // Here, `entry` is a `DirEntry`.
907 /// println!("{:?}: {}", entry.file_name(), entry.ino());
908 /// }
909 /// }
910 /// }
911 /// ```
912 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
913 fn ino(&self) -> u64;
914}
915
916#[stable(feature = "dir_entry_ext", since = "1.1.0")]
917impl DirEntryExt for fs::DirEntry {
918 fn ino(&self) -> u64 {
919 self.as_inner().ino()
920 }
921}
922
923/// Sealed Unix-specific extension methods for [`fs::DirEntry`].
924#[unstable(feature = "dir_entry_ext2", issue = "85573")]
925pub trait DirEntryExt2: Sealed {
926 /// Returns a reference to the underlying `OsStr` of this entry's filename.
927 ///
928 /// # Examples
929 ///
930 /// ```
931 /// #![feature(dir_entry_ext2)]
932 /// use std::os::unix::fs::DirEntryExt2;
933 /// use std::{fs, io};
934 ///
935 /// fn main() -> io::Result<()> {
936 /// let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?;
937 /// entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));
938 ///
939 /// for p in entries {
940 /// println!("{p:?}");
941 /// }
942 ///
943 /// Ok(())
944 /// }
945 /// ```
946 fn file_name_ref(&self) -> &OsStr;
947}
948
949/// Allows extension traits within `std`.
950#[unstable(feature = "sealed", issue = "none")]
951impl Sealed for fs::DirEntry {}
952
953#[unstable(feature = "dir_entry_ext2", issue = "85573")]
954impl DirEntryExt2 for fs::DirEntry {
955 fn file_name_ref(&self) -> &OsStr {
956 self.as_inner().file_name_os_str()
957 }
958}
959
960/// Creates a new symbolic link on the filesystem.
961///
962/// The `link` path will be a symbolic link pointing to the `original` path.
963///
964/// # Examples
965///
966/// ```no_run
967/// use std::os::unix::fs;
968///
969/// fn main() -> std::io::Result<()> {
970/// fs::symlink("a.txt", "b.txt")?;
971/// Ok(())
972/// }
973/// ```
974#[stable(feature = "symlink", since = "1.1.0")]
975pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
976 sys::fs::symlink(original.as_ref(), link.as_ref())
977}
978
979/// Unix-specific extensions to [`fs::DirBuilder`].
980#[stable(feature = "dir_builder", since = "1.6.0")]
981pub trait DirBuilderExt {
982 /// Sets the mode to create new directories with. This option defaults to
983 /// 0o777.
984 ///
985 /// # Examples
986 ///
987 /// ```no_run
988 /// use std::fs::DirBuilder;
989 /// use std::os::unix::fs::DirBuilderExt;
990 ///
991 /// let mut builder = DirBuilder::new();
992 /// builder.mode(0o755);
993 /// ```
994 #[stable(feature = "dir_builder", since = "1.6.0")]
995 fn mode(&mut self, mode: u32) -> &mut Self;
996}
997
998#[stable(feature = "dir_builder", since = "1.6.0")]
999impl DirBuilderExt for fs::DirBuilder {
1000 fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
1001 self.as_inner_mut().set_mode(mode);
1002 self
1003 }
1004}
1005
1006/// Change the owner and group of the specified path.
1007///
1008/// Specifying either the uid or gid as `None` will leave it unchanged.
1009///
1010/// Changing the owner typically requires privileges, such as root or a specific capability.
1011/// Changing the group typically requires either being the owner and a member of the group, or
1012/// having privileges.
1013///
1014/// Be aware that changing owner clears the `suid` and `sgid` permission bits in most cases
1015/// according to POSIX, usually even if the user is root. The sgid is not cleared when
1016/// the file is non-group-executable. See: <https://www.man7.org/linux/man-pages/man2/chown.2.html>
1017/// This call may also clear file capabilities, if there was any.
1018///
1019/// If called on a symbolic link, this will change the owner and group of the link target. To
1020/// change the owner and group of the link itself, see [`lchown`].
1021///
1022/// # Examples
1023///
1024/// ```no_run
1025/// use std::os::unix::fs;
1026///
1027/// fn main() -> std::io::Result<()> {
1028/// fs::chown("/sandbox", Some(0), Some(0))?;
1029/// Ok(())
1030/// }
1031/// ```
1032#[stable(feature = "unix_chown", since = "1.73.0")]
1033pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1034 sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
1035}
1036
1037/// Change the owner and group of the file referenced by the specified open file descriptor.
1038///
1039/// For semantics and required privileges, see [`chown`].
1040///
1041/// # Examples
1042///
1043/// ```no_run
1044/// use std::os::unix::fs;
1045///
1046/// fn main() -> std::io::Result<()> {
1047/// let f = std::fs::File::open("/file")?;
1048/// fs::fchown(&f, Some(0), Some(0))?;
1049/// Ok(())
1050/// }
1051/// ```
1052#[stable(feature = "unix_chown", since = "1.73.0")]
1053pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1054 sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
1055}
1056
1057/// Change the owner and group of the specified path, without dereferencing symbolic links.
1058///
1059/// Identical to [`chown`], except that if called on a symbolic link, this will change the owner
1060/// and group of the link itself rather than the owner and group of the link target.
1061///
1062/// # Examples
1063///
1064/// ```no_run
1065/// use std::os::unix::fs;
1066///
1067/// fn main() -> std::io::Result<()> {
1068/// fs::lchown("/symlink", Some(0), Some(0))?;
1069/// Ok(())
1070/// }
1071/// ```
1072#[stable(feature = "unix_chown", since = "1.73.0")]
1073pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1074 sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
1075}
1076
1077/// Change the root directory of the current process to the specified path.
1078///
1079/// This typically requires privileges, such as root or a specific capability.
1080///
1081/// This does not change the current working directory; you should call
1082/// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards.
1083///
1084/// # Examples
1085///
1086/// ```no_run
1087/// use std::os::unix::fs;
1088///
1089/// fn main() -> std::io::Result<()> {
1090/// fs::chroot("/sandbox")?;
1091/// std::env::set_current_dir("/")?;
1092/// // continue working in sandbox
1093/// Ok(())
1094/// }
1095/// ```
1096#[stable(feature = "unix_chroot", since = "1.56.0")]
1097#[cfg(not(target_os = "fuchsia"))]
1098pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
1099 sys::fs::chroot(dir.as_ref())
1100}
1101
1102/// Create a FIFO special file at the specified path with the specified mode.
1103///
1104/// # Examples
1105///
1106/// ```no_run
1107/// # #![feature(unix_mkfifo)]
1108/// # #[cfg(not(unix))]
1109/// # fn main() {}
1110/// # #[cfg(unix)]
1111/// # fn main() -> std::io::Result<()> {
1112/// # use std::{
1113/// # os::unix::fs::{mkfifo, PermissionsExt},
1114/// # fs::{File, Permissions, remove_file},
1115/// # io::{Write, Read},
1116/// # };
1117/// # let _ = remove_file("/tmp/fifo");
1118/// mkfifo("/tmp/fifo", Permissions::from_mode(0o774))?;
1119///
1120/// let mut wx = File::options().read(true).write(true).open("/tmp/fifo")?;
1121/// let mut rx = File::open("/tmp/fifo")?;
1122///
1123/// wx.write_all(b"hello, world!")?;
1124/// drop(wx);
1125///
1126/// let mut s = String::new();
1127/// rx.read_to_string(&mut s)?;
1128///
1129/// assert_eq!(s, "hello, world!");
1130/// # Ok(())
1131/// # }
1132/// ```
1133#[unstable(feature = "unix_mkfifo", issue = "139324")]
1134pub fn mkfifo<P: AsRef<Path>>(path: P, permissions: Permissions) -> io::Result<()> {
1135 sys::fs::mkfifo(path.as_ref(), permissions.mode())
1136}