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() {
131 Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer",))
132 } else {
133 Ok(())
134 }
135 }
136
137 /// Writes a number of bytes starting from a given offset.
138 ///
139 /// Returns the number of bytes written.
140 ///
141 /// The offset is relative to the start of the file and thus independent
142 /// from the current cursor.
143 ///
144 /// The current file cursor is not affected by this function.
145 ///
146 /// When writing beyond the end of the file, the file is appropriately
147 /// extended and the intermediate bytes are initialized with the value 0.
148 ///
149 /// Note that similar to [`File::write`], it is not an error to return a
150 /// short write.
151 ///
152 /// # Bug
153 /// On some systems, `write_at` utilises [`pwrite64`] to write to files.
154 /// However, this syscall has a [bug] where files opened with the `O_APPEND`
155 /// flag fail to respect the offset parameter, always appending to the end
156 /// of the file instead.
157 ///
158 /// It is possible to inadvertently set this flag, like in the example below.
159 /// Therefore, it is important to be vigilant while changing options to mitigate
160 /// unexpected behaviour.
161 ///
162 /// ```no_run
163 /// use std::fs::File;
164 /// use std::io;
165 /// use std::os::unix::prelude::FileExt;
166 ///
167 /// fn main() -> io::Result<()> {
168 /// // Open a file with the append option (sets the `O_APPEND` flag)
169 /// let file = File::options().append(true).open("foo.txt")?;
170 ///
171 /// // We attempt to write at offset 10; instead appended to EOF
172 /// file.write_at(b"sushi", 10)?;
173 ///
174 /// // foo.txt is 5 bytes long instead of 15
175 /// Ok(())
176 /// }
177 /// ```
178 ///
179 /// [`File::write`]: fs::File::write
180 /// [`pwrite64`]: https://man7.org/linux/man-pages/man2/pwrite.2.html
181 /// [bug]: https://man7.org/linux/man-pages/man2/pwrite.2.html#BUGS
182 ///
183 /// # Examples
184 ///
185 /// ```no_run
186 /// use std::fs::File;
187 /// use std::io;
188 /// use std::os::unix::prelude::FileExt;
189 ///
190 /// fn main() -> io::Result<()> {
191 /// let file = File::create("foo.txt")?;
192 ///
193 /// // We now write at the offset 10.
194 /// file.write_at(b"sushi", 10)?;
195 /// Ok(())
196 /// }
197 /// ```
198 #[stable(feature = "file_offset", since = "1.15.0")]
199 fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
200
201 /// Like `write_at`, except that it writes from a slice of buffers.
202 ///
203 /// Data is copied from each buffer in order, with the final buffer read
204 /// from possibly being only partially consumed. This method must behave as
205 /// a call to `write_at` with the buffers concatenated would.
206 #[unstable(feature = "unix_file_vectored_at", issue = "89517")]
207 fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> {
208 io::default_write_vectored(|b| self.write_at(b, offset), bufs)
209 }
210
211 /// Attempts to write an entire buffer starting from a given offset.
212 ///
213 /// The offset is relative to the start of the file and thus independent
214 /// from the current cursor.
215 ///
216 /// The current file cursor is not affected by this function.
217 ///
218 /// This method will continuously call [`write_at`] until there is no more data
219 /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
220 /// returned. This method will not return until the entire buffer has been
221 /// successfully written or such an error occurs. The first error that is
222 /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
223 /// returned.
224 ///
225 /// # Errors
226 ///
227 /// This function will return the first error of
228 /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
229 ///
230 /// [`write_at`]: FileExt::write_at
231 ///
232 /// # Examples
233 ///
234 /// ```no_run
235 /// use std::fs::File;
236 /// use std::io;
237 /// use std::os::unix::prelude::FileExt;
238 ///
239 /// fn main() -> io::Result<()> {
240 /// let file = File::open("foo.txt")?;
241 ///
242 /// // We now write at the offset 10.
243 /// file.write_all_at(b"sushi", 10)?;
244 /// Ok(())
245 /// }
246 /// ```
247 #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
248 fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
249 while !buf.is_empty() {
250 match self.write_at(buf, offset) {
251 Ok(0) => {
252 return Err(io::const_io_error!(
253 io::ErrorKind::WriteZero,
254 "failed to write whole buffer",
255 ));
256 }
257 Ok(n) => {
258 buf = &buf[n..];
259 offset += n as u64
260 }
261 Err(ref e) if e.is_interrupted() => {}
262 Err(e) => return Err(e),
263 }
264 }
265 Ok(())
266 }
267}
268
269#[stable(feature = "file_offset", since = "1.15.0")]
270impl FileExt for fs::File {
271 fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
272 self.as_inner().read_at(buf, offset)
273 }
274 fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
275 self.as_inner().read_vectored_at(bufs, offset)
276 }
277 fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
278 self.as_inner().write_at(buf, offset)
279 }
280 fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> {
281 self.as_inner().write_vectored_at(bufs, offset)
282 }
283}
284
285/// Unix-specific extensions to [`fs::Permissions`].
286#[stable(feature = "fs_ext", since = "1.1.0")]
287pub trait PermissionsExt {
288 /// Returns the underlying raw `st_mode` bits that contain the standard
289 /// Unix permissions for this file.
290 ///
291 /// # Examples
292 ///
293 /// ```no_run
294 /// use std::fs::File;
295 /// use std::os::unix::fs::PermissionsExt;
296 ///
297 /// fn main() -> std::io::Result<()> {
298 /// let f = File::create("foo.txt")?;
299 /// let metadata = f.metadata()?;
300 /// let permissions = metadata.permissions();
301 ///
302 /// println!("permissions: {:o}", permissions.mode());
303 /// Ok(())
304 /// }
305 /// ```
306 #[stable(feature = "fs_ext", since = "1.1.0")]
307 fn mode(&self) -> u32;
308
309 /// Sets the underlying raw bits for this set of permissions.
310 ///
311 /// # Examples
312 ///
313 /// ```no_run
314 /// use std::fs::File;
315 /// use std::os::unix::fs::PermissionsExt;
316 ///
317 /// fn main() -> std::io::Result<()> {
318 /// let f = File::create("foo.txt")?;
319 /// let metadata = f.metadata()?;
320 /// let mut permissions = metadata.permissions();
321 ///
322 /// permissions.set_mode(0o644); // Read/write for owner and read for others.
323 /// assert_eq!(permissions.mode(), 0o644);
324 /// Ok(())
325 /// }
326 /// ```
327 #[stable(feature = "fs_ext", since = "1.1.0")]
328 fn set_mode(&mut self, mode: u32);
329
330 /// Creates a new instance of `Permissions` from the given set of Unix
331 /// permission bits.
332 ///
333 /// # Examples
334 ///
335 /// ```
336 /// use std::fs::Permissions;
337 /// use std::os::unix::fs::PermissionsExt;
338 ///
339 /// // Read/write for owner and read for others.
340 /// let permissions = Permissions::from_mode(0o644);
341 /// assert_eq!(permissions.mode(), 0o644);
342 /// ```
343 #[stable(feature = "fs_ext", since = "1.1.0")]
344 fn from_mode(mode: u32) -> Self;
345}
346
347#[stable(feature = "fs_ext", since = "1.1.0")]
348impl PermissionsExt for Permissions {
349 fn mode(&self) -> u32 {
350 self.as_inner().mode()
351 }
352
353 fn set_mode(&mut self, mode: u32) {
354 *self = Permissions::from_inner(FromInner::from_inner(mode));
355 }
356
357 fn from_mode(mode: u32) -> Permissions {
358 Permissions::from_inner(FromInner::from_inner(mode))
359 }
360}
361
362/// Unix-specific extensions to [`fs::OpenOptions`].
363#[stable(feature = "fs_ext", since = "1.1.0")]
364pub trait OpenOptionsExt {
365 /// Sets the mode bits that a new file will be created with.
366 ///
367 /// If a new file is created as part of an `OpenOptions::open` call then this
368 /// specified `mode` will be used as the permission bits for the new file.
369 /// If no `mode` is set, the default of `0o666` will be used.
370 /// The operating system masks out bits with the system's `umask`, to produce
371 /// the final permissions.
372 ///
373 /// # Examples
374 ///
375 /// ```no_run
376 /// use std::fs::OpenOptions;
377 /// use std::os::unix::fs::OpenOptionsExt;
378 ///
379 /// # fn main() {
380 /// let mut options = OpenOptions::new();
381 /// options.mode(0o644); // Give read/write for owner and read for others.
382 /// let file = options.open("foo.txt");
383 /// # }
384 /// ```
385 #[stable(feature = "fs_ext", since = "1.1.0")]
386 fn mode(&mut self, mode: u32) -> &mut Self;
387
388 /// Pass custom flags to the `flags` argument of `open`.
389 ///
390 /// The bits that define the access mode are masked out with `O_ACCMODE`, to
391 /// ensure they do not interfere with the access mode set by Rusts options.
392 ///
393 /// Custom flags can only set flags, not remove flags set by Rusts options.
394 /// This options overwrites any previously set custom flags.
395 ///
396 /// # Examples
397 ///
398 /// ```no_run
399 /// # #![feature(rustc_private)]
400 /// use libc;
401 /// use std::fs::OpenOptions;
402 /// use std::os::unix::fs::OpenOptionsExt;
403 ///
404 /// # fn main() {
405 /// let mut options = OpenOptions::new();
406 /// options.write(true);
407 /// if cfg!(unix) {
408 /// options.custom_flags(libc::O_NOFOLLOW);
409 /// }
410 /// let file = options.open("foo.txt");
411 /// # }
412 /// ```
413 #[stable(feature = "open_options_ext", since = "1.10.0")]
414 fn custom_flags(&mut self, flags: i32) -> &mut Self;
415}
416
417#[stable(feature = "fs_ext", since = "1.1.0")]
418impl OpenOptionsExt for OpenOptions {
419 fn mode(&mut self, mode: u32) -> &mut OpenOptions {
420 self.as_inner_mut().mode(mode);
421 self
422 }
423
424 fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
425 self.as_inner_mut().custom_flags(flags);
426 self
427 }
428}
429
430/// Unix-specific extensions to [`fs::Metadata`].
431#[stable(feature = "metadata_ext", since = "1.1.0")]
432pub trait MetadataExt {
433 /// Returns the ID of the device containing the file.
434 ///
435 /// # Examples
436 ///
437 /// ```no_run
438 /// use std::io;
439 /// use std::fs;
440 /// use std::os::unix::fs::MetadataExt;
441 ///
442 /// fn main() -> io::Result<()> {
443 /// let meta = fs::metadata("some_file")?;
444 /// let dev_id = meta.dev();
445 /// Ok(())
446 /// }
447 /// ```
448 #[stable(feature = "metadata_ext", since = "1.1.0")]
449 fn dev(&self) -> u64;
450 /// Returns the inode number.
451 ///
452 /// # Examples
453 ///
454 /// ```no_run
455 /// use std::fs;
456 /// use std::os::unix::fs::MetadataExt;
457 /// use std::io;
458 ///
459 /// fn main() -> io::Result<()> {
460 /// let meta = fs::metadata("some_file")?;
461 /// let inode = meta.ino();
462 /// Ok(())
463 /// }
464 /// ```
465 #[stable(feature = "metadata_ext", since = "1.1.0")]
466 fn ino(&self) -> u64;
467 /// Returns the rights applied to this file.
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 mode = meta.mode();
479 /// let user_has_write_access = mode & 0o200;
480 /// let user_has_read_write_access = mode & 0o600;
481 /// let group_has_read_access = mode & 0o040;
482 /// let others_have_exec_access = mode & 0o001;
483 /// Ok(())
484 /// }
485 /// ```
486 #[stable(feature = "metadata_ext", since = "1.1.0")]
487 fn mode(&self) -> u32;
488 /// Returns the number of hard links pointing to this file.
489 ///
490 /// # Examples
491 ///
492 /// ```no_run
493 /// use std::fs;
494 /// use std::os::unix::fs::MetadataExt;
495 /// use std::io;
496 ///
497 /// fn main() -> io::Result<()> {
498 /// let meta = fs::metadata("some_file")?;
499 /// let nb_hard_links = meta.nlink();
500 /// Ok(())
501 /// }
502 /// ```
503 #[stable(feature = "metadata_ext", since = "1.1.0")]
504 fn nlink(&self) -> u64;
505 /// Returns the user ID of the owner of 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 user_id = meta.uid();
517 /// Ok(())
518 /// }
519 /// ```
520 #[stable(feature = "metadata_ext", since = "1.1.0")]
521 fn uid(&self) -> u32;
522 /// Returns the group 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 group_id = meta.gid();
534 /// Ok(())
535 /// }
536 /// ```
537 #[stable(feature = "metadata_ext", since = "1.1.0")]
538 fn gid(&self) -> u32;
539 /// Returns the device ID of this file (if it is a special one).
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 device_id = meta.rdev();
551 /// Ok(())
552 /// }
553 /// ```
554 #[stable(feature = "metadata_ext", since = "1.1.0")]
555 fn rdev(&self) -> u64;
556 /// Returns the total size of this file in bytes.
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 file_size = meta.size();
568 /// Ok(())
569 /// }
570 /// ```
571 #[stable(feature = "metadata_ext", since = "1.1.0")]
572 fn size(&self) -> u64;
573 /// Returns the last access time of the file, in seconds since Unix Epoch.
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 last_access_time = meta.atime();
585 /// Ok(())
586 /// }
587 /// ```
588 #[stable(feature = "metadata_ext", since = "1.1.0")]
589 fn atime(&self) -> i64;
590 /// Returns the last access time of the file, in nanoseconds since [`atime`].
591 ///
592 /// [`atime`]: MetadataExt::atime
593 ///
594 /// # Examples
595 ///
596 /// ```no_run
597 /// use std::fs;
598 /// use std::os::unix::fs::MetadataExt;
599 /// use std::io;
600 ///
601 /// fn main() -> io::Result<()> {
602 /// let meta = fs::metadata("some_file")?;
603 /// let nano_last_access_time = meta.atime_nsec();
604 /// Ok(())
605 /// }
606 /// ```
607 #[stable(feature = "metadata_ext", since = "1.1.0")]
608 fn atime_nsec(&self) -> i64;
609 /// Returns the last modification time of the file, in seconds since Unix Epoch.
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 last_modification_time = meta.mtime();
621 /// Ok(())
622 /// }
623 /// ```
624 #[stable(feature = "metadata_ext", since = "1.1.0")]
625 fn mtime(&self) -> i64;
626 /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
627 ///
628 /// [`mtime`]: MetadataExt::mtime
629 ///
630 /// # Examples
631 ///
632 /// ```no_run
633 /// use std::fs;
634 /// use std::os::unix::fs::MetadataExt;
635 /// use std::io;
636 ///
637 /// fn main() -> io::Result<()> {
638 /// let meta = fs::metadata("some_file")?;
639 /// let nano_last_modification_time = meta.mtime_nsec();
640 /// Ok(())
641 /// }
642 /// ```
643 #[stable(feature = "metadata_ext", since = "1.1.0")]
644 fn mtime_nsec(&self) -> i64;
645 /// Returns the last status change time of the file, in seconds since Unix Epoch.
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 last_status_change_time = meta.ctime();
657 /// Ok(())
658 /// }
659 /// ```
660 #[stable(feature = "metadata_ext", since = "1.1.0")]
661 fn ctime(&self) -> i64;
662 /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
663 ///
664 /// [`ctime`]: MetadataExt::ctime
665 ///
666 /// # Examples
667 ///
668 /// ```no_run
669 /// use std::fs;
670 /// use std::os::unix::fs::MetadataExt;
671 /// use std::io;
672 ///
673 /// fn main() -> io::Result<()> {
674 /// let meta = fs::metadata("some_file")?;
675 /// let nano_last_status_change_time = meta.ctime_nsec();
676 /// Ok(())
677 /// }
678 /// ```
679 #[stable(feature = "metadata_ext", since = "1.1.0")]
680 fn ctime_nsec(&self) -> i64;
681 /// Returns the block size for filesystem I/O.
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 block_size = meta.blksize();
693 /// Ok(())
694 /// }
695 /// ```
696 #[stable(feature = "metadata_ext", since = "1.1.0")]
697 fn blksize(&self) -> u64;
698 /// Returns the number of blocks allocated to the file, in 512-byte units.
699 ///
700 /// Please note that this may be smaller than `st_size / 512` when the file has holes.
701 ///
702 /// # Examples
703 ///
704 /// ```no_run
705 /// use std::fs;
706 /// use std::os::unix::fs::MetadataExt;
707 /// use std::io;
708 ///
709 /// fn main() -> io::Result<()> {
710 /// let meta = fs::metadata("some_file")?;
711 /// let blocks = meta.blocks();
712 /// Ok(())
713 /// }
714 /// ```
715 #[stable(feature = "metadata_ext", since = "1.1.0")]
716 fn blocks(&self) -> u64;
717 #[cfg(target_os = "vxworks")]
718 #[stable(feature = "metadata_ext", since = "1.1.0")]
719 fn attrib(&self) -> u8;
720}
721
722#[stable(feature = "metadata_ext", since = "1.1.0")]
723impl MetadataExt for fs::Metadata {
724 fn dev(&self) -> u64 {
725 self.st_dev()
726 }
727 fn ino(&self) -> u64 {
728 self.st_ino()
729 }
730 fn mode(&self) -> u32 {
731 self.st_mode()
732 }
733 fn nlink(&self) -> u64 {
734 self.st_nlink()
735 }
736 fn uid(&self) -> u32 {
737 self.st_uid()
738 }
739 fn gid(&self) -> u32 {
740 self.st_gid()
741 }
742 fn rdev(&self) -> u64 {
743 self.st_rdev()
744 }
745 fn size(&self) -> u64 {
746 self.st_size()
747 }
748 fn atime(&self) -> i64 {
749 self.st_atime()
750 }
751 fn atime_nsec(&self) -> i64 {
752 self.st_atime_nsec()
753 }
754 fn mtime(&self) -> i64 {
755 self.st_mtime()
756 }
757 fn mtime_nsec(&self) -> i64 {
758 self.st_mtime_nsec()
759 }
760 fn ctime(&self) -> i64 {
761 self.st_ctime()
762 }
763 fn ctime_nsec(&self) -> i64 {
764 self.st_ctime_nsec()
765 }
766 fn blksize(&self) -> u64 {
767 self.st_blksize()
768 }
769 fn blocks(&self) -> u64 {
770 self.st_blocks()
771 }
772 #[cfg(target_os = "vxworks")]
773 fn attrib(&self) -> u8 {
774 self.st_attrib()
775 }
776}
777
778/// Unix-specific extensions for [`fs::FileType`].
779///
780/// Adds support for special Unix file types such as block/character devices,
781/// pipes, and sockets.
782#[stable(feature = "file_type_ext", since = "1.5.0")]
783pub trait FileTypeExt {
784 /// Returns `true` if this file type is a block device.
785 ///
786 /// # Examples
787 ///
788 /// ```no_run
789 /// use std::fs;
790 /// use std::os::unix::fs::FileTypeExt;
791 /// use std::io;
792 ///
793 /// fn main() -> io::Result<()> {
794 /// let meta = fs::metadata("block_device_file")?;
795 /// let file_type = meta.file_type();
796 /// assert!(file_type.is_block_device());
797 /// Ok(())
798 /// }
799 /// ```
800 #[stable(feature = "file_type_ext", since = "1.5.0")]
801 fn is_block_device(&self) -> bool;
802 /// Returns `true` if this file type is a char device.
803 ///
804 /// # Examples
805 ///
806 /// ```no_run
807 /// use std::fs;
808 /// use std::os::unix::fs::FileTypeExt;
809 /// use std::io;
810 ///
811 /// fn main() -> io::Result<()> {
812 /// let meta = fs::metadata("char_device_file")?;
813 /// let file_type = meta.file_type();
814 /// assert!(file_type.is_char_device());
815 /// Ok(())
816 /// }
817 /// ```
818 #[stable(feature = "file_type_ext", since = "1.5.0")]
819 fn is_char_device(&self) -> bool;
820 /// Returns `true` if this file type is a fifo.
821 ///
822 /// # Examples
823 ///
824 /// ```no_run
825 /// use std::fs;
826 /// use std::os::unix::fs::FileTypeExt;
827 /// use std::io;
828 ///
829 /// fn main() -> io::Result<()> {
830 /// let meta = fs::metadata("fifo_file")?;
831 /// let file_type = meta.file_type();
832 /// assert!(file_type.is_fifo());
833 /// Ok(())
834 /// }
835 /// ```
836 #[stable(feature = "file_type_ext", since = "1.5.0")]
837 fn is_fifo(&self) -> bool;
838 /// Returns `true` if this file type is a socket.
839 ///
840 /// # Examples
841 ///
842 /// ```no_run
843 /// use std::fs;
844 /// use std::os::unix::fs::FileTypeExt;
845 /// use std::io;
846 ///
847 /// fn main() -> io::Result<()> {
848 /// let meta = fs::metadata("unix.socket")?;
849 /// let file_type = meta.file_type();
850 /// assert!(file_type.is_socket());
851 /// Ok(())
852 /// }
853 /// ```
854 #[stable(feature = "file_type_ext", since = "1.5.0")]
855 fn is_socket(&self) -> bool;
856}
857
858#[stable(feature = "file_type_ext", since = "1.5.0")]
859impl FileTypeExt for fs::FileType {
860 fn is_block_device(&self) -> bool {
861 self.as_inner().is(mode:libc::S_IFBLK)
862 }
863 fn is_char_device(&self) -> bool {
864 self.as_inner().is(mode:libc::S_IFCHR)
865 }
866 fn is_fifo(&self) -> bool {
867 self.as_inner().is(mode:libc::S_IFIFO)
868 }
869 fn is_socket(&self) -> bool {
870 self.as_inner().is(mode:libc::S_IFSOCK)
871 }
872}
873
874/// Unix-specific extension methods for [`fs::DirEntry`].
875#[stable(feature = "dir_entry_ext", since = "1.1.0")]
876pub trait DirEntryExt {
877 /// Returns the underlying `d_ino` field in the contained `dirent`
878 /// structure.
879 ///
880 /// # Examples
881 ///
882 /// ```
883 /// use std::fs;
884 /// use std::os::unix::fs::DirEntryExt;
885 ///
886 /// if let Ok(entries) = fs::read_dir(".") {
887 /// for entry in entries {
888 /// if let Ok(entry) = entry {
889 /// // Here, `entry` is a `DirEntry`.
890 /// println!("{:?}: {}", entry.file_name(), entry.ino());
891 /// }
892 /// }
893 /// }
894 /// ```
895 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
896 fn ino(&self) -> u64;
897}
898
899#[stable(feature = "dir_entry_ext", since = "1.1.0")]
900impl DirEntryExt for fs::DirEntry {
901 fn ino(&self) -> u64 {
902 self.as_inner().ino()
903 }
904}
905
906/// Sealed Unix-specific extension methods for [`fs::DirEntry`].
907#[unstable(feature = "dir_entry_ext2", issue = "85573")]
908pub trait DirEntryExt2: Sealed {
909 /// Returns a reference to the underlying `OsStr` of this entry's filename.
910 ///
911 /// # Examples
912 ///
913 /// ```
914 /// #![feature(dir_entry_ext2)]
915 /// use std::os::unix::fs::DirEntryExt2;
916 /// use std::{fs, io};
917 ///
918 /// fn main() -> io::Result<()> {
919 /// let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?;
920 /// entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));
921 ///
922 /// for p in entries {
923 /// println!("{p:?}");
924 /// }
925 ///
926 /// Ok(())
927 /// }
928 /// ```
929 fn file_name_ref(&self) -> &OsStr;
930}
931
932/// Allows extension traits within `std`.
933#[unstable(feature = "sealed", issue = "none")]
934impl Sealed for fs::DirEntry {}
935
936#[unstable(feature = "dir_entry_ext2", issue = "85573")]
937impl DirEntryExt2 for fs::DirEntry {
938 fn file_name_ref(&self) -> &OsStr {
939 self.as_inner().file_name_os_str()
940 }
941}
942
943/// Creates a new symbolic link on the filesystem.
944///
945/// The `link` path will be a symbolic link pointing to the `original` path.
946///
947/// # Examples
948///
949/// ```no_run
950/// use std::os::unix::fs;
951///
952/// fn main() -> std::io::Result<()> {
953/// fs::symlink("a.txt", "b.txt")?;
954/// Ok(())
955/// }
956/// ```
957#[stable(feature = "symlink", since = "1.1.0")]
958pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
959 sys::fs::symlink(original.as_ref(), link.as_ref())
960}
961
962/// Unix-specific extensions to [`fs::DirBuilder`].
963#[stable(feature = "dir_builder", since = "1.6.0")]
964pub trait DirBuilderExt {
965 /// Sets the mode to create new directories with. This option defaults to
966 /// 0o777.
967 ///
968 /// # Examples
969 ///
970 /// ```no_run
971 /// use std::fs::DirBuilder;
972 /// use std::os::unix::fs::DirBuilderExt;
973 ///
974 /// let mut builder = DirBuilder::new();
975 /// builder.mode(0o755);
976 /// ```
977 #[stable(feature = "dir_builder", since = "1.6.0")]
978 fn mode(&mut self, mode: u32) -> &mut Self;
979}
980
981#[stable(feature = "dir_builder", since = "1.6.0")]
982impl DirBuilderExt for fs::DirBuilder {
983 fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
984 self.as_inner_mut().set_mode(mode);
985 self
986 }
987}
988
989/// Change the owner and group of the specified path.
990///
991/// Specifying either the uid or gid as `None` will leave it unchanged.
992///
993/// Changing the owner typically requires privileges, such as root or a specific capability.
994/// Changing the group typically requires either being the owner and a member of the group, or
995/// having privileges.
996///
997/// If called on a symbolic link, this will change the owner and group of the link target. To
998/// change the owner and group of the link itself, see [`lchown`].
999///
1000/// # Examples
1001///
1002/// ```no_run
1003/// use std::os::unix::fs;
1004///
1005/// fn main() -> std::io::Result<()> {
1006/// fs::chown("/sandbox", Some(0), Some(0))?;
1007/// Ok(())
1008/// }
1009/// ```
1010#[stable(feature = "unix_chown", since = "1.73.0")]
1011pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1012 sys::fs::chown(path:dir.as_ref(), uid:uid.unwrap_or(u32::MAX), gid:gid.unwrap_or(default:u32::MAX))
1013}
1014
1015/// Change the owner and group of the file referenced by the specified open file descriptor.
1016///
1017/// For semantics and required privileges, see [`chown`].
1018///
1019/// # Examples
1020///
1021/// ```no_run
1022/// use std::os::unix::fs;
1023///
1024/// fn main() -> std::io::Result<()> {
1025/// let f = std::fs::File::open("/file")?;
1026/// fs::fchown(&f, Some(0), Some(0))?;
1027/// Ok(())
1028/// }
1029/// ```
1030#[stable(feature = "unix_chown", since = "1.73.0")]
1031pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1032 sys::fs::fchown(fd.as_fd().as_raw_fd(), uid:uid.unwrap_or(u32::MAX), gid:gid.unwrap_or(default:u32::MAX))
1033}
1034
1035/// Change the owner and group of the specified path, without dereferencing symbolic links.
1036///
1037/// Identical to [`chown`], except that if called on a symbolic link, this will change the owner
1038/// and group of the link itself rather than the owner and group of the link target.
1039///
1040/// # Examples
1041///
1042/// ```no_run
1043/// use std::os::unix::fs;
1044///
1045/// fn main() -> std::io::Result<()> {
1046/// fs::lchown("/symlink", Some(0), Some(0))?;
1047/// Ok(())
1048/// }
1049/// ```
1050#[stable(feature = "unix_chown", since = "1.73.0")]
1051pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1052 sys::fs::lchown(path:dir.as_ref(), uid:uid.unwrap_or(u32::MAX), gid:gid.unwrap_or(default:u32::MAX))
1053}
1054
1055/// Change the root directory of the current process to the specified path.
1056///
1057/// This typically requires privileges, such as root or a specific capability.
1058///
1059/// This does not change the current working directory; you should call
1060/// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards.
1061///
1062/// # Examples
1063///
1064/// ```no_run
1065/// use std::os::unix::fs;
1066///
1067/// fn main() -> std::io::Result<()> {
1068/// fs::chroot("/sandbox")?;
1069/// std::env::set_current_dir("/")?;
1070/// // continue working in sandbox
1071/// Ok(())
1072/// }
1073/// ```
1074#[stable(feature = "unix_chroot", since = "1.56.0")]
1075#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
1076pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
1077 sys::fs::chroot(dir.as_ref())
1078}
1079