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