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
7use super::platform::fs::MetadataExt as _;
8use crate::fs::{self, OpenOptions, Permissions};
9use crate::io;
10use crate::os::unix::io::{AsFd, AsRawFd};
11use crate::path::Path;
12use crate::sys;
13use crate::sys_common::{AsInner, AsInnerMut, FromInner};
14// Used for `File::read` on intra-doc links
15use crate::ffi::OsStr;
16use crate::sealed::Sealed;
17#[allow(unused_imports)]
18use io::{Read, Write};
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 behaviour.
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#[stable(feature = "fs_ext", since = "1.1.0")]
280pub trait PermissionsExt {
281 /// Returns the underlying raw `st_mode` bits that contain the standard
282 /// Unix permissions for this file.
283 ///
284 /// # Examples
285 ///
286 /// ```no_run
287 /// use std::fs::File;
288 /// use std::os::unix::fs::PermissionsExt;
289 ///
290 /// fn main() -> std::io::Result<()> {
291 /// let f = File::create("foo.txt")?;
292 /// let metadata = f.metadata()?;
293 /// let permissions = metadata.permissions();
294 ///
295 /// println!("permissions: {:o}", permissions.mode());
296 /// Ok(())
297 /// }
298 /// ```
299 #[stable(feature = "fs_ext", since = "1.1.0")]
300 fn mode(&self) -> u32;
301
302 /// Sets the underlying raw bits for this set of permissions.
303 ///
304 /// # Examples
305 ///
306 /// ```no_run
307 /// use std::fs::File;
308 /// use std::os::unix::fs::PermissionsExt;
309 ///
310 /// fn main() -> std::io::Result<()> {
311 /// let f = File::create("foo.txt")?;
312 /// let metadata = f.metadata()?;
313 /// let mut permissions = metadata.permissions();
314 ///
315 /// permissions.set_mode(0o644); // Read/write for owner and read for others.
316 /// assert_eq!(permissions.mode(), 0o644);
317 /// Ok(())
318 /// }
319 /// ```
320 #[stable(feature = "fs_ext", since = "1.1.0")]
321 fn set_mode(&mut self, mode: u32);
322
323 /// Creates a new instance of `Permissions` from the given set of Unix
324 /// permission bits.
325 ///
326 /// # Examples
327 ///
328 /// ```
329 /// use std::fs::Permissions;
330 /// use std::os::unix::fs::PermissionsExt;
331 ///
332 /// // Read/write for owner and read for others.
333 /// let permissions = Permissions::from_mode(0o644);
334 /// assert_eq!(permissions.mode(), 0o644);
335 /// ```
336 #[stable(feature = "fs_ext", since = "1.1.0")]
337 fn from_mode(mode: u32) -> Self;
338}
339
340#[stable(feature = "fs_ext", since = "1.1.0")]
341impl PermissionsExt for Permissions {
342 fn mode(&self) -> u32 {
343 self.as_inner().mode()
344 }
345
346 fn set_mode(&mut self, mode: u32) {
347 *self = Permissions::from_inner(FromInner::from_inner(mode));
348 }
349
350 fn from_mode(mode: u32) -> Permissions {
351 Permissions::from_inner(FromInner::from_inner(mode))
352 }
353}
354
355/// Unix-specific extensions to [`fs::OpenOptions`].
356#[stable(feature = "fs_ext", since = "1.1.0")]
357pub trait OpenOptionsExt {
358 /// Sets the mode bits that a new file will be created with.
359 ///
360 /// If a new file is created as part of an `OpenOptions::open` call then this
361 /// specified `mode` will be used as the permission bits for the new file.
362 /// If no `mode` is set, the default of `0o666` will be used.
363 /// The operating system masks out bits with the system's `umask`, to produce
364 /// the final permissions.
365 ///
366 /// # Examples
367 ///
368 /// ```no_run
369 /// use std::fs::OpenOptions;
370 /// use std::os::unix::fs::OpenOptionsExt;
371 ///
372 /// # fn main() {
373 /// let mut options = OpenOptions::new();
374 /// options.mode(0o644); // Give read/write for owner and read for others.
375 /// let file = options.open("foo.txt");
376 /// # }
377 /// ```
378 #[stable(feature = "fs_ext", since = "1.1.0")]
379 fn mode(&mut self, mode: u32) -> &mut Self;
380
381 /// Pass custom flags to the `flags` argument of `open`.
382 ///
383 /// The bits that define the access mode are masked out with `O_ACCMODE`, to
384 /// ensure they do not interfere with the access mode set by Rusts options.
385 ///
386 /// Custom flags can only set flags, not remove flags set by Rusts options.
387 /// This options overwrites any previously set custom flags.
388 ///
389 /// # Examples
390 ///
391 /// ```no_run
392 /// # #![feature(rustc_private)]
393 /// use std::fs::OpenOptions;
394 /// use std::os::unix::fs::OpenOptionsExt;
395 ///
396 /// # fn main() {
397 /// let mut options = OpenOptions::new();
398 /// options.write(true);
399 /// if cfg!(unix) {
400 /// options.custom_flags(libc::O_NOFOLLOW);
401 /// }
402 /// let file = options.open("foo.txt");
403 /// # }
404 /// ```
405 #[stable(feature = "open_options_ext", since = "1.10.0")]
406 fn custom_flags(&mut self, flags: i32) -> &mut Self;
407}
408
409#[stable(feature = "fs_ext", since = "1.1.0")]
410impl OpenOptionsExt for OpenOptions {
411 fn mode(&mut self, mode: u32) -> &mut OpenOptions {
412 self.as_inner_mut().mode(mode);
413 self
414 }
415
416 fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
417 self.as_inner_mut().custom_flags(flags);
418 self
419 }
420}
421
422/// Unix-specific extensions to [`fs::Metadata`].
423#[stable(feature = "metadata_ext", since = "1.1.0")]
424pub trait MetadataExt {
425 /// Returns the ID of the device containing the file.
426 ///
427 /// # Examples
428 ///
429 /// ```no_run
430 /// use std::io;
431 /// use std::fs;
432 /// use std::os::unix::fs::MetadataExt;
433 ///
434 /// fn main() -> io::Result<()> {
435 /// let meta = fs::metadata("some_file")?;
436 /// let dev_id = meta.dev();
437 /// Ok(())
438 /// }
439 /// ```
440 #[stable(feature = "metadata_ext", since = "1.1.0")]
441 fn dev(&self) -> u64;
442 /// Returns the inode number.
443 ///
444 /// # Examples
445 ///
446 /// ```no_run
447 /// use std::fs;
448 /// use std::os::unix::fs::MetadataExt;
449 /// use std::io;
450 ///
451 /// fn main() -> io::Result<()> {
452 /// let meta = fs::metadata("some_file")?;
453 /// let inode = meta.ino();
454 /// Ok(())
455 /// }
456 /// ```
457 #[stable(feature = "metadata_ext", since = "1.1.0")]
458 fn ino(&self) -> u64;
459 /// Returns the rights applied to this file.
460 ///
461 /// # Examples
462 ///
463 /// ```no_run
464 /// use std::fs;
465 /// use std::os::unix::fs::MetadataExt;
466 /// use std::io;
467 ///
468 /// fn main() -> io::Result<()> {
469 /// let meta = fs::metadata("some_file")?;
470 /// let mode = meta.mode();
471 /// let user_has_write_access = mode & 0o200;
472 /// let user_has_read_write_access = mode & 0o600;
473 /// let group_has_read_access = mode & 0o040;
474 /// let others_have_exec_access = mode & 0o001;
475 /// Ok(())
476 /// }
477 /// ```
478 #[stable(feature = "metadata_ext", since = "1.1.0")]
479 fn mode(&self) -> u32;
480 /// Returns the number of hard links pointing to this file.
481 ///
482 /// # Examples
483 ///
484 /// ```no_run
485 /// use std::fs;
486 /// use std::os::unix::fs::MetadataExt;
487 /// use std::io;
488 ///
489 /// fn main() -> io::Result<()> {
490 /// let meta = fs::metadata("some_file")?;
491 /// let nb_hard_links = meta.nlink();
492 /// Ok(())
493 /// }
494 /// ```
495 #[stable(feature = "metadata_ext", since = "1.1.0")]
496 fn nlink(&self) -> u64;
497 /// Returns the user ID of the owner of this file.
498 ///
499 /// # Examples
500 ///
501 /// ```no_run
502 /// use std::fs;
503 /// use std::os::unix::fs::MetadataExt;
504 /// use std::io;
505 ///
506 /// fn main() -> io::Result<()> {
507 /// let meta = fs::metadata("some_file")?;
508 /// let user_id = meta.uid();
509 /// Ok(())
510 /// }
511 /// ```
512 #[stable(feature = "metadata_ext", since = "1.1.0")]
513 fn uid(&self) -> u32;
514 /// Returns the group ID of the owner of this file.
515 ///
516 /// # Examples
517 ///
518 /// ```no_run
519 /// use std::fs;
520 /// use std::os::unix::fs::MetadataExt;
521 /// use std::io;
522 ///
523 /// fn main() -> io::Result<()> {
524 /// let meta = fs::metadata("some_file")?;
525 /// let group_id = meta.gid();
526 /// Ok(())
527 /// }
528 /// ```
529 #[stable(feature = "metadata_ext", since = "1.1.0")]
530 fn gid(&self) -> u32;
531 /// Returns the device ID of this file (if it is a special one).
532 ///
533 /// # Examples
534 ///
535 /// ```no_run
536 /// use std::fs;
537 /// use std::os::unix::fs::MetadataExt;
538 /// use std::io;
539 ///
540 /// fn main() -> io::Result<()> {
541 /// let meta = fs::metadata("some_file")?;
542 /// let device_id = meta.rdev();
543 /// Ok(())
544 /// }
545 /// ```
546 #[stable(feature = "metadata_ext", since = "1.1.0")]
547 fn rdev(&self) -> u64;
548 /// Returns the total size of this file in bytes.
549 ///
550 /// # Examples
551 ///
552 /// ```no_run
553 /// use std::fs;
554 /// use std::os::unix::fs::MetadataExt;
555 /// use std::io;
556 ///
557 /// fn main() -> io::Result<()> {
558 /// let meta = fs::metadata("some_file")?;
559 /// let file_size = meta.size();
560 /// Ok(())
561 /// }
562 /// ```
563 #[stable(feature = "metadata_ext", since = "1.1.0")]
564 fn size(&self) -> u64;
565 /// Returns the last access time of the file, in seconds since Unix Epoch.
566 ///
567 /// # Examples
568 ///
569 /// ```no_run
570 /// use std::fs;
571 /// use std::os::unix::fs::MetadataExt;
572 /// use std::io;
573 ///
574 /// fn main() -> io::Result<()> {
575 /// let meta = fs::metadata("some_file")?;
576 /// let last_access_time = meta.atime();
577 /// Ok(())
578 /// }
579 /// ```
580 #[stable(feature = "metadata_ext", since = "1.1.0")]
581 fn atime(&self) -> i64;
582 /// Returns the last access time of the file, in nanoseconds since [`atime`].
583 ///
584 /// [`atime`]: MetadataExt::atime
585 ///
586 /// # Examples
587 ///
588 /// ```no_run
589 /// use std::fs;
590 /// use std::os::unix::fs::MetadataExt;
591 /// use std::io;
592 ///
593 /// fn main() -> io::Result<()> {
594 /// let meta = fs::metadata("some_file")?;
595 /// let nano_last_access_time = meta.atime_nsec();
596 /// Ok(())
597 /// }
598 /// ```
599 #[stable(feature = "metadata_ext", since = "1.1.0")]
600 fn atime_nsec(&self) -> i64;
601 /// Returns the last modification time of the file, in seconds since Unix Epoch.
602 ///
603 /// # Examples
604 ///
605 /// ```no_run
606 /// use std::fs;
607 /// use std::os::unix::fs::MetadataExt;
608 /// use std::io;
609 ///
610 /// fn main() -> io::Result<()> {
611 /// let meta = fs::metadata("some_file")?;
612 /// let last_modification_time = meta.mtime();
613 /// Ok(())
614 /// }
615 /// ```
616 #[stable(feature = "metadata_ext", since = "1.1.0")]
617 fn mtime(&self) -> i64;
618 /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
619 ///
620 /// [`mtime`]: MetadataExt::mtime
621 ///
622 /// # Examples
623 ///
624 /// ```no_run
625 /// use std::fs;
626 /// use std::os::unix::fs::MetadataExt;
627 /// use std::io;
628 ///
629 /// fn main() -> io::Result<()> {
630 /// let meta = fs::metadata("some_file")?;
631 /// let nano_last_modification_time = meta.mtime_nsec();
632 /// Ok(())
633 /// }
634 /// ```
635 #[stable(feature = "metadata_ext", since = "1.1.0")]
636 fn mtime_nsec(&self) -> i64;
637 /// Returns the last status change time of the file, in seconds since Unix Epoch.
638 ///
639 /// # Examples
640 ///
641 /// ```no_run
642 /// use std::fs;
643 /// use std::os::unix::fs::MetadataExt;
644 /// use std::io;
645 ///
646 /// fn main() -> io::Result<()> {
647 /// let meta = fs::metadata("some_file")?;
648 /// let last_status_change_time = meta.ctime();
649 /// Ok(())
650 /// }
651 /// ```
652 #[stable(feature = "metadata_ext", since = "1.1.0")]
653 fn ctime(&self) -> i64;
654 /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
655 ///
656 /// [`ctime`]: MetadataExt::ctime
657 ///
658 /// # Examples
659 ///
660 /// ```no_run
661 /// use std::fs;
662 /// use std::os::unix::fs::MetadataExt;
663 /// use std::io;
664 ///
665 /// fn main() -> io::Result<()> {
666 /// let meta = fs::metadata("some_file")?;
667 /// let nano_last_status_change_time = meta.ctime_nsec();
668 /// Ok(())
669 /// }
670 /// ```
671 #[stable(feature = "metadata_ext", since = "1.1.0")]
672 fn ctime_nsec(&self) -> i64;
673 /// Returns the block size for filesystem I/O.
674 ///
675 /// # Examples
676 ///
677 /// ```no_run
678 /// use std::fs;
679 /// use std::os::unix::fs::MetadataExt;
680 /// use std::io;
681 ///
682 /// fn main() -> io::Result<()> {
683 /// let meta = fs::metadata("some_file")?;
684 /// let block_size = meta.blksize();
685 /// Ok(())
686 /// }
687 /// ```
688 #[stable(feature = "metadata_ext", since = "1.1.0")]
689 fn blksize(&self) -> u64;
690 /// Returns the number of blocks allocated to the file, in 512-byte units.
691 ///
692 /// Please note that this may be smaller than `st_size / 512` when the file has holes.
693 ///
694 /// # Examples
695 ///
696 /// ```no_run
697 /// use std::fs;
698 /// use std::os::unix::fs::MetadataExt;
699 /// use std::io;
700 ///
701 /// fn main() -> io::Result<()> {
702 /// let meta = fs::metadata("some_file")?;
703 /// let blocks = meta.blocks();
704 /// Ok(())
705 /// }
706 /// ```
707 #[stable(feature = "metadata_ext", since = "1.1.0")]
708 fn blocks(&self) -> u64;
709 #[cfg(target_os = "vxworks")]
710 #[stable(feature = "metadata_ext", since = "1.1.0")]
711 fn attrib(&self) -> u8;
712}
713
714#[stable(feature = "metadata_ext", since = "1.1.0")]
715impl MetadataExt for fs::Metadata {
716 fn dev(&self) -> u64 {
717 self.st_dev()
718 }
719 fn ino(&self) -> u64 {
720 self.st_ino()
721 }
722 fn mode(&self) -> u32 {
723 self.st_mode()
724 }
725 fn nlink(&self) -> u64 {
726 self.st_nlink()
727 }
728 fn uid(&self) -> u32 {
729 self.st_uid()
730 }
731 fn gid(&self) -> u32 {
732 self.st_gid()
733 }
734 fn rdev(&self) -> u64 {
735 self.st_rdev()
736 }
737 fn size(&self) -> u64 {
738 self.st_size()
739 }
740 fn atime(&self) -> i64 {
741 self.st_atime()
742 }
743 fn atime_nsec(&self) -> i64 {
744 self.st_atime_nsec()
745 }
746 fn mtime(&self) -> i64 {
747 self.st_mtime()
748 }
749 fn mtime_nsec(&self) -> i64 {
750 self.st_mtime_nsec()
751 }
752 fn ctime(&self) -> i64 {
753 self.st_ctime()
754 }
755 fn ctime_nsec(&self) -> i64 {
756 self.st_ctime_nsec()
757 }
758 fn blksize(&self) -> u64 {
759 self.st_blksize()
760 }
761 fn blocks(&self) -> u64 {
762 self.st_blocks()
763 }
764 #[cfg(target_os = "vxworks")]
765 fn attrib(&self) -> u8 {
766 self.st_attrib()
767 }
768}
769
770/// Unix-specific extensions for [`fs::FileType`].
771///
772/// Adds support for special Unix file types such as block/character devices,
773/// pipes, and sockets.
774#[stable(feature = "file_type_ext", since = "1.5.0")]
775pub trait FileTypeExt {
776 /// Returns `true` if this file type is a block device.
777 ///
778 /// # Examples
779 ///
780 /// ```no_run
781 /// use std::fs;
782 /// use std::os::unix::fs::FileTypeExt;
783 /// use std::io;
784 ///
785 /// fn main() -> io::Result<()> {
786 /// let meta = fs::metadata("block_device_file")?;
787 /// let file_type = meta.file_type();
788 /// assert!(file_type.is_block_device());
789 /// Ok(())
790 /// }
791 /// ```
792 #[stable(feature = "file_type_ext", since = "1.5.0")]
793 fn is_block_device(&self) -> bool;
794 /// Returns `true` if this file type is a char device.
795 ///
796 /// # Examples
797 ///
798 /// ```no_run
799 /// use std::fs;
800 /// use std::os::unix::fs::FileTypeExt;
801 /// use std::io;
802 ///
803 /// fn main() -> io::Result<()> {
804 /// let meta = fs::metadata("char_device_file")?;
805 /// let file_type = meta.file_type();
806 /// assert!(file_type.is_char_device());
807 /// Ok(())
808 /// }
809 /// ```
810 #[stable(feature = "file_type_ext", since = "1.5.0")]
811 fn is_char_device(&self) -> bool;
812 /// Returns `true` if this file type is a fifo.
813 ///
814 /// # Examples
815 ///
816 /// ```no_run
817 /// use std::fs;
818 /// use std::os::unix::fs::FileTypeExt;
819 /// use std::io;
820 ///
821 /// fn main() -> io::Result<()> {
822 /// let meta = fs::metadata("fifo_file")?;
823 /// let file_type = meta.file_type();
824 /// assert!(file_type.is_fifo());
825 /// Ok(())
826 /// }
827 /// ```
828 #[stable(feature = "file_type_ext", since = "1.5.0")]
829 fn is_fifo(&self) -> bool;
830 /// Returns `true` if this file type is a socket.
831 ///
832 /// # Examples
833 ///
834 /// ```no_run
835 /// use std::fs;
836 /// use std::os::unix::fs::FileTypeExt;
837 /// use std::io;
838 ///
839 /// fn main() -> io::Result<()> {
840 /// let meta = fs::metadata("unix.socket")?;
841 /// let file_type = meta.file_type();
842 /// assert!(file_type.is_socket());
843 /// Ok(())
844 /// }
845 /// ```
846 #[stable(feature = "file_type_ext", since = "1.5.0")]
847 fn is_socket(&self) -> bool;
848}
849
850#[stable(feature = "file_type_ext", since = "1.5.0")]
851impl FileTypeExt for fs::FileType {
852 fn is_block_device(&self) -> bool {
853 self.as_inner().is(mode:libc::S_IFBLK)
854 }
855 fn is_char_device(&self) -> bool {
856 self.as_inner().is(mode:libc::S_IFCHR)
857 }
858 fn is_fifo(&self) -> bool {
859 self.as_inner().is(mode:libc::S_IFIFO)
860 }
861 fn is_socket(&self) -> bool {
862 self.as_inner().is(mode:libc::S_IFSOCK)
863 }
864}
865
866/// Unix-specific extension methods for [`fs::DirEntry`].
867#[stable(feature = "dir_entry_ext", since = "1.1.0")]
868pub trait DirEntryExt {
869 /// Returns the underlying `d_ino` field in the contained `dirent`
870 /// structure.
871 ///
872 /// # Examples
873 ///
874 /// ```
875 /// use std::fs;
876 /// use std::os::unix::fs::DirEntryExt;
877 ///
878 /// if let Ok(entries) = fs::read_dir(".") {
879 /// for entry in entries {
880 /// if let Ok(entry) = entry {
881 /// // Here, `entry` is a `DirEntry`.
882 /// println!("{:?}: {}", entry.file_name(), entry.ino());
883 /// }
884 /// }
885 /// }
886 /// ```
887 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
888 fn ino(&self) -> u64;
889}
890
891#[stable(feature = "dir_entry_ext", since = "1.1.0")]
892impl DirEntryExt for fs::DirEntry {
893 fn ino(&self) -> u64 {
894 self.as_inner().ino()
895 }
896}
897
898/// Sealed Unix-specific extension methods for [`fs::DirEntry`].
899#[unstable(feature = "dir_entry_ext2", issue = "85573")]
900pub trait DirEntryExt2: Sealed {
901 /// Returns a reference to the underlying `OsStr` of this entry's filename.
902 ///
903 /// # Examples
904 ///
905 /// ```
906 /// #![feature(dir_entry_ext2)]
907 /// use std::os::unix::fs::DirEntryExt2;
908 /// use std::{fs, io};
909 ///
910 /// fn main() -> io::Result<()> {
911 /// let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?;
912 /// entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));
913 ///
914 /// for p in entries {
915 /// println!("{p:?}");
916 /// }
917 ///
918 /// Ok(())
919 /// }
920 /// ```
921 fn file_name_ref(&self) -> &OsStr;
922}
923
924/// Allows extension traits within `std`.
925#[unstable(feature = "sealed", issue = "none")]
926impl Sealed for fs::DirEntry {}
927
928#[unstable(feature = "dir_entry_ext2", issue = "85573")]
929impl DirEntryExt2 for fs::DirEntry {
930 fn file_name_ref(&self) -> &OsStr {
931 self.as_inner().file_name_os_str()
932 }
933}
934
935/// Creates a new symbolic link on the filesystem.
936///
937/// The `link` path will be a symbolic link pointing to the `original` path.
938///
939/// # Examples
940///
941/// ```no_run
942/// use std::os::unix::fs;
943///
944/// fn main() -> std::io::Result<()> {
945/// fs::symlink("a.txt", "b.txt")?;
946/// Ok(())
947/// }
948/// ```
949#[stable(feature = "symlink", since = "1.1.0")]
950pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
951 sys::fs::symlink(original.as_ref(), link.as_ref())
952}
953
954/// Unix-specific extensions to [`fs::DirBuilder`].
955#[stable(feature = "dir_builder", since = "1.6.0")]
956pub trait DirBuilderExt {
957 /// Sets the mode to create new directories with. This option defaults to
958 /// 0o777.
959 ///
960 /// # Examples
961 ///
962 /// ```no_run
963 /// use std::fs::DirBuilder;
964 /// use std::os::unix::fs::DirBuilderExt;
965 ///
966 /// let mut builder = DirBuilder::new();
967 /// builder.mode(0o755);
968 /// ```
969 #[stable(feature = "dir_builder", since = "1.6.0")]
970 fn mode(&mut self, mode: u32) -> &mut Self;
971}
972
973#[stable(feature = "dir_builder", since = "1.6.0")]
974impl DirBuilderExt for fs::DirBuilder {
975 fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
976 self.as_inner_mut().set_mode(mode);
977 self
978 }
979}
980
981/// Change the owner and group of the specified path.
982///
983/// Specifying either the uid or gid as `None` will leave it unchanged.
984///
985/// Changing the owner typically requires privileges, such as root or a specific capability.
986/// Changing the group typically requires either being the owner and a member of the group, or
987/// having privileges.
988///
989/// If called on a symbolic link, this will change the owner and group of the link target. To
990/// change the owner and group of the link itself, see [`lchown`].
991///
992/// # Examples
993///
994/// ```no_run
995/// use std::os::unix::fs;
996///
997/// fn main() -> std::io::Result<()> {
998/// fs::chown("/sandbox", Some(0), Some(0))?;
999/// Ok(())
1000/// }
1001/// ```
1002#[stable(feature = "unix_chown", since = "1.73.0")]
1003pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1004 sys::fs::chown(path:dir.as_ref(), uid:uid.unwrap_or(u32::MAX), gid:gid.unwrap_or(default:u32::MAX))
1005}
1006
1007/// Change the owner and group of the file referenced by the specified open file descriptor.
1008///
1009/// For semantics and required privileges, see [`chown`].
1010///
1011/// # Examples
1012///
1013/// ```no_run
1014/// use std::os::unix::fs;
1015///
1016/// fn main() -> std::io::Result<()> {
1017/// let f = std::fs::File::open("/file")?;
1018/// fs::fchown(&f, Some(0), Some(0))?;
1019/// Ok(())
1020/// }
1021/// ```
1022#[stable(feature = "unix_chown", since = "1.73.0")]
1023pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1024 sys::fs::fchown(fd.as_fd().as_raw_fd(), uid:uid.unwrap_or(u32::MAX), gid:gid.unwrap_or(default:u32::MAX))
1025}
1026
1027/// Change the owner and group of the specified path, without dereferencing symbolic links.
1028///
1029/// Identical to [`chown`], except that if called on a symbolic link, this will change the owner
1030/// and group of the link itself rather than the owner and group of the link target.
1031///
1032/// # Examples
1033///
1034/// ```no_run
1035/// use std::os::unix::fs;
1036///
1037/// fn main() -> std::io::Result<()> {
1038/// fs::lchown("/symlink", Some(0), Some(0))?;
1039/// Ok(())
1040/// }
1041/// ```
1042#[stable(feature = "unix_chown", since = "1.73.0")]
1043pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1044 sys::fs::lchown(path:dir.as_ref(), uid:uid.unwrap_or(u32::MAX), gid:gid.unwrap_or(default:u32::MAX))
1045}
1046
1047/// Change the root directory of the current process to the specified path.
1048///
1049/// This typically requires privileges, such as root or a specific capability.
1050///
1051/// This does not change the current working directory; you should call
1052/// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards.
1053///
1054/// # Examples
1055///
1056/// ```no_run
1057/// use std::os::unix::fs;
1058///
1059/// fn main() -> std::io::Result<()> {
1060/// fs::chroot("/sandbox")?;
1061/// std::env::set_current_dir("/")?;
1062/// // continue working in sandbox
1063/// Ok(())
1064/// }
1065/// ```
1066#[stable(feature = "unix_chroot", since = "1.56.0")]
1067#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
1068pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
1069 sys::fs::chroot(dir.as_ref())
1070}
1071