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 use super::platform::fs::MetadataExt as _;
8 use crate::fs::{self, OpenOptions, Permissions};
9 use crate::io;
10 use crate::os::unix::io::{AsFd, AsRawFd};
11 use crate::path::Path;
12 use crate::sys;
13 use crate::sys_common::{AsInner, AsInnerMut, FromInner};
14 // Used for `File::read` on intra-doc links
15 use crate::ffi::OsStr;
16 use crate::sealed::Sealed;
17 #[allow(unused_imports)]
18 use io::{Read, Write};
19
20 // Tests for this module
21 #[cfg(test)]
22 mod tests;
23
24 /// Unix-specific extensions to [`fs::File`].
25 #[stable(feature = "file_offset", since = "1.15.0")]
26 pub 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")]
read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>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")]
read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize>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 byte 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")]
read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()>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.kind() == io::ErrorKind::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 /// [`File::write`]: fs::File::write
153 ///
154 /// # Examples
155 ///
156 /// ```no_run
157 /// use std::fs::File;
158 /// use std::io;
159 /// use std::os::unix::prelude::FileExt;
160 ///
161 /// fn main() -> io::Result<()> {
162 /// let file = File::open("foo.txt")?;
163 ///
164 /// // We now write at the offset 10.
165 /// file.write_at(b"sushi", 10)?;
166 /// Ok(())
167 /// }
168 /// ```
169 #[stable(feature = "file_offset", since = "1.15.0")]
write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>170 fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
171
172 /// Like `write_at`, except that it writes from a slice of buffers.
173 ///
174 /// Data is copied from each buffer in order, with the final buffer read
175 /// from possibly being only partially consumed. This method must behave as
176 /// a call to `write_at` with the buffers concatenated would.
177 #[unstable(feature = "unix_file_vectored_at", issue = "89517")]
write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize>178 fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> {
179 io::default_write_vectored(|b| self.write_at(b, offset), bufs)
180 }
181
182 /// Attempts to write an entire buffer starting from a given offset.
183 ///
184 /// The offset is relative to the start of the file and thus independent
185 /// from the current cursor.
186 ///
187 /// The current file cursor is not affected by this function.
188 ///
189 /// This method will continuously call [`write_at`] until there is no more data
190 /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
191 /// returned. This method will not return until the entire buffer has been
192 /// successfully written or such an error occurs. The first error that is
193 /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
194 /// returned.
195 ///
196 /// # Errors
197 ///
198 /// This function will return the first error of
199 /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
200 ///
201 /// [`write_at`]: FileExt::write_at
202 ///
203 /// # Examples
204 ///
205 /// ```no_run
206 /// use std::fs::File;
207 /// use std::io;
208 /// use std::os::unix::prelude::FileExt;
209 ///
210 /// fn main() -> io::Result<()> {
211 /// let file = File::open("foo.txt")?;
212 ///
213 /// // We now write at the offset 10.
214 /// file.write_all_at(b"sushi", 10)?;
215 /// Ok(())
216 /// }
217 /// ```
218 #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()>219 fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
220 while !buf.is_empty() {
221 match self.write_at(buf, offset) {
222 Ok(0) => {
223 return Err(io::const_io_error!(
224 io::ErrorKind::WriteZero,
225 "failed to write whole buffer",
226 ));
227 }
228 Ok(n) => {
229 buf = &buf[n..];
230 offset += n as u64
231 }
232 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
233 Err(e) => return Err(e),
234 }
235 }
236 Ok(())
237 }
238 }
239
240 #[stable(feature = "file_offset", since = "1.15.0")]
241 impl FileExt for fs::File {
read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>242 fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
243 self.as_inner().read_at(buf, offset)
244 }
read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize>245 fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
246 self.as_inner().read_vectored_at(bufs, offset)
247 }
write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>248 fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
249 self.as_inner().write_at(buf, offset)
250 }
write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize>251 fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> {
252 self.as_inner().write_vectored_at(bufs, offset)
253 }
254 }
255
256 /// Unix-specific extensions to [`fs::Permissions`].
257 #[stable(feature = "fs_ext", since = "1.1.0")]
258 pub trait PermissionsExt {
259 /// Returns the underlying raw `st_mode` bits that contain the standard
260 /// Unix permissions for this file.
261 ///
262 /// # Examples
263 ///
264 /// ```no_run
265 /// use std::fs::File;
266 /// use std::os::unix::fs::PermissionsExt;
267 ///
268 /// fn main() -> std::io::Result<()> {
269 /// let f = File::create("foo.txt")?;
270 /// let metadata = f.metadata()?;
271 /// let permissions = metadata.permissions();
272 ///
273 /// println!("permissions: {:o}", permissions.mode());
274 /// Ok(())
275 /// }
276 /// ```
277 #[stable(feature = "fs_ext", since = "1.1.0")]
mode(&self) -> u32278 fn mode(&self) -> u32;
279
280 /// Sets the underlying raw bits for this set of permissions.
281 ///
282 /// # Examples
283 ///
284 /// ```no_run
285 /// use std::fs::File;
286 /// use std::os::unix::fs::PermissionsExt;
287 ///
288 /// fn main() -> std::io::Result<()> {
289 /// let f = File::create("foo.txt")?;
290 /// let metadata = f.metadata()?;
291 /// let mut permissions = metadata.permissions();
292 ///
293 /// permissions.set_mode(0o644); // Read/write for owner and read for others.
294 /// assert_eq!(permissions.mode(), 0o644);
295 /// Ok(())
296 /// }
297 /// ```
298 #[stable(feature = "fs_ext", since = "1.1.0")]
set_mode(&mut self, mode: u32)299 fn set_mode(&mut self, mode: u32);
300
301 /// Creates a new instance of `Permissions` from the given set of Unix
302 /// permission bits.
303 ///
304 /// # Examples
305 ///
306 /// ```
307 /// use std::fs::Permissions;
308 /// use std::os::unix::fs::PermissionsExt;
309 ///
310 /// // Read/write for owner and read for others.
311 /// let permissions = Permissions::from_mode(0o644);
312 /// assert_eq!(permissions.mode(), 0o644);
313 /// ```
314 #[stable(feature = "fs_ext", since = "1.1.0")]
from_mode(mode: u32) -> Self315 fn from_mode(mode: u32) -> Self;
316 }
317
318 #[stable(feature = "fs_ext", since = "1.1.0")]
319 impl PermissionsExt for Permissions {
mode(&self) -> u32320 fn mode(&self) -> u32 {
321 self.as_inner().mode()
322 }
323
set_mode(&mut self, mode: u32)324 fn set_mode(&mut self, mode: u32) {
325 *self = Permissions::from_inner(FromInner::from_inner(mode));
326 }
327
from_mode(mode: u32) -> Permissions328 fn from_mode(mode: u32) -> Permissions {
329 Permissions::from_inner(FromInner::from_inner(mode))
330 }
331 }
332
333 /// Unix-specific extensions to [`fs::OpenOptions`].
334 #[stable(feature = "fs_ext", since = "1.1.0")]
335 pub trait OpenOptionsExt {
336 /// Sets the mode bits that a new file will be created with.
337 ///
338 /// If a new file is created as part of an `OpenOptions::open` call then this
339 /// specified `mode` will be used as the permission bits for the new file.
340 /// If no `mode` is set, the default of `0o666` will be used.
341 /// The operating system masks out bits with the system's `umask`, to produce
342 /// the final permissions.
343 ///
344 /// # Examples
345 ///
346 /// ```no_run
347 /// use std::fs::OpenOptions;
348 /// use std::os::unix::fs::OpenOptionsExt;
349 ///
350 /// # fn main() {
351 /// let mut options = OpenOptions::new();
352 /// options.mode(0o644); // Give read/write for owner and read for others.
353 /// let file = options.open("foo.txt");
354 /// # }
355 /// ```
356 #[stable(feature = "fs_ext", since = "1.1.0")]
mode(&mut self, mode: u32) -> &mut Self357 fn mode(&mut self, mode: u32) -> &mut Self;
358
359 /// Pass custom flags to the `flags` argument of `open`.
360 ///
361 /// The bits that define the access mode are masked out with `O_ACCMODE`, to
362 /// ensure they do not interfere with the access mode set by Rusts options.
363 ///
364 /// Custom flags can only set flags, not remove flags set by Rusts options.
365 /// This options overwrites any previously set custom flags.
366 ///
367 /// # Examples
368 ///
369 /// ```no_run
370 /// # #![feature(rustc_private)]
371 /// use libc;
372 /// use std::fs::OpenOptions;
373 /// use std::os::unix::fs::OpenOptionsExt;
374 ///
375 /// # fn main() {
376 /// let mut options = OpenOptions::new();
377 /// options.write(true);
378 /// if cfg!(unix) {
379 /// options.custom_flags(libc::O_NOFOLLOW);
380 /// }
381 /// let file = options.open("foo.txt");
382 /// # }
383 /// ```
384 #[stable(feature = "open_options_ext", since = "1.10.0")]
custom_flags(&mut self, flags: i32) -> &mut Self385 fn custom_flags(&mut self, flags: i32) -> &mut Self;
386 }
387
388 #[stable(feature = "fs_ext", since = "1.1.0")]
389 impl OpenOptionsExt for OpenOptions {
mode(&mut self, mode: u32) -> &mut OpenOptions390 fn mode(&mut self, mode: u32) -> &mut OpenOptions {
391 self.as_inner_mut().mode(mode);
392 self
393 }
394
custom_flags(&mut self, flags: i32) -> &mut OpenOptions395 fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
396 self.as_inner_mut().custom_flags(flags);
397 self
398 }
399 }
400
401 /// Unix-specific extensions to [`fs::Metadata`].
402 #[stable(feature = "metadata_ext", since = "1.1.0")]
403 pub trait MetadataExt {
404 /// Returns the ID of the device containing the file.
405 ///
406 /// # Examples
407 ///
408 /// ```no_run
409 /// use std::io;
410 /// use std::fs;
411 /// use std::os::unix::fs::MetadataExt;
412 ///
413 /// fn main() -> io::Result<()> {
414 /// let meta = fs::metadata("some_file")?;
415 /// let dev_id = meta.dev();
416 /// Ok(())
417 /// }
418 /// ```
419 #[stable(feature = "metadata_ext", since = "1.1.0")]
dev(&self) -> u64420 fn dev(&self) -> u64;
421 /// Returns the inode number.
422 ///
423 /// # Examples
424 ///
425 /// ```no_run
426 /// use std::fs;
427 /// use std::os::unix::fs::MetadataExt;
428 /// use std::io;
429 ///
430 /// fn main() -> io::Result<()> {
431 /// let meta = fs::metadata("some_file")?;
432 /// let inode = meta.ino();
433 /// Ok(())
434 /// }
435 /// ```
436 #[stable(feature = "metadata_ext", since = "1.1.0")]
ino(&self) -> u64437 fn ino(&self) -> u64;
438 /// Returns the rights applied to this file.
439 ///
440 /// # Examples
441 ///
442 /// ```no_run
443 /// use std::fs;
444 /// use std::os::unix::fs::MetadataExt;
445 /// use std::io;
446 ///
447 /// fn main() -> io::Result<()> {
448 /// let meta = fs::metadata("some_file")?;
449 /// let mode = meta.mode();
450 /// let user_has_write_access = mode & 0o200;
451 /// let user_has_read_write_access = mode & 0o600;
452 /// let group_has_read_access = mode & 0o040;
453 /// let others_have_exec_access = mode & 0o001;
454 /// Ok(())
455 /// }
456 /// ```
457 #[stable(feature = "metadata_ext", since = "1.1.0")]
mode(&self) -> u32458 fn mode(&self) -> u32;
459 /// Returns the number of hard links pointing 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 nb_hard_links = meta.nlink();
471 /// Ok(())
472 /// }
473 /// ```
474 #[stable(feature = "metadata_ext", since = "1.1.0")]
nlink(&self) -> u64475 fn nlink(&self) -> u64;
476 /// Returns the user ID of the owner of this file.
477 ///
478 /// # Examples
479 ///
480 /// ```no_run
481 /// use std::fs;
482 /// use std::os::unix::fs::MetadataExt;
483 /// use std::io;
484 ///
485 /// fn main() -> io::Result<()> {
486 /// let meta = fs::metadata("some_file")?;
487 /// let user_id = meta.uid();
488 /// Ok(())
489 /// }
490 /// ```
491 #[stable(feature = "metadata_ext", since = "1.1.0")]
uid(&self) -> u32492 fn uid(&self) -> u32;
493 /// Returns the group ID of the owner of this file.
494 ///
495 /// # Examples
496 ///
497 /// ```no_run
498 /// use std::fs;
499 /// use std::os::unix::fs::MetadataExt;
500 /// use std::io;
501 ///
502 /// fn main() -> io::Result<()> {
503 /// let meta = fs::metadata("some_file")?;
504 /// let group_id = meta.gid();
505 /// Ok(())
506 /// }
507 /// ```
508 #[stable(feature = "metadata_ext", since = "1.1.0")]
gid(&self) -> u32509 fn gid(&self) -> u32;
510 /// Returns the device ID of this file (if it is a special one).
511 ///
512 /// # Examples
513 ///
514 /// ```no_run
515 /// use std::fs;
516 /// use std::os::unix::fs::MetadataExt;
517 /// use std::io;
518 ///
519 /// fn main() -> io::Result<()> {
520 /// let meta = fs::metadata("some_file")?;
521 /// let device_id = meta.rdev();
522 /// Ok(())
523 /// }
524 /// ```
525 #[stable(feature = "metadata_ext", since = "1.1.0")]
rdev(&self) -> u64526 fn rdev(&self) -> u64;
527 /// Returns the total size of this file in bytes.
528 ///
529 /// # Examples
530 ///
531 /// ```no_run
532 /// use std::fs;
533 /// use std::os::unix::fs::MetadataExt;
534 /// use std::io;
535 ///
536 /// fn main() -> io::Result<()> {
537 /// let meta = fs::metadata("some_file")?;
538 /// let file_size = meta.size();
539 /// Ok(())
540 /// }
541 /// ```
542 #[stable(feature = "metadata_ext", since = "1.1.0")]
size(&self) -> u64543 fn size(&self) -> u64;
544 /// Returns the last access time of the file, in seconds since Unix Epoch.
545 ///
546 /// # Examples
547 ///
548 /// ```no_run
549 /// use std::fs;
550 /// use std::os::unix::fs::MetadataExt;
551 /// use std::io;
552 ///
553 /// fn main() -> io::Result<()> {
554 /// let meta = fs::metadata("some_file")?;
555 /// let last_access_time = meta.atime();
556 /// Ok(())
557 /// }
558 /// ```
559 #[stable(feature = "metadata_ext", since = "1.1.0")]
atime(&self) -> i64560 fn atime(&self) -> i64;
561 /// Returns the last access time of the file, in nanoseconds since [`atime`].
562 ///
563 /// [`atime`]: MetadataExt::atime
564 ///
565 /// # Examples
566 ///
567 /// ```no_run
568 /// use std::fs;
569 /// use std::os::unix::fs::MetadataExt;
570 /// use std::io;
571 ///
572 /// fn main() -> io::Result<()> {
573 /// let meta = fs::metadata("some_file")?;
574 /// let nano_last_access_time = meta.atime_nsec();
575 /// Ok(())
576 /// }
577 /// ```
578 #[stable(feature = "metadata_ext", since = "1.1.0")]
atime_nsec(&self) -> i64579 fn atime_nsec(&self) -> i64;
580 /// Returns the last modification time of the file, in seconds since Unix Epoch.
581 ///
582 /// # Examples
583 ///
584 /// ```no_run
585 /// use std::fs;
586 /// use std::os::unix::fs::MetadataExt;
587 /// use std::io;
588 ///
589 /// fn main() -> io::Result<()> {
590 /// let meta = fs::metadata("some_file")?;
591 /// let last_modification_time = meta.mtime();
592 /// Ok(())
593 /// }
594 /// ```
595 #[stable(feature = "metadata_ext", since = "1.1.0")]
mtime(&self) -> i64596 fn mtime(&self) -> i64;
597 /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
598 ///
599 /// [`mtime`]: MetadataExt::mtime
600 ///
601 /// # Examples
602 ///
603 /// ```no_run
604 /// use std::fs;
605 /// use std::os::unix::fs::MetadataExt;
606 /// use std::io;
607 ///
608 /// fn main() -> io::Result<()> {
609 /// let meta = fs::metadata("some_file")?;
610 /// let nano_last_modification_time = meta.mtime_nsec();
611 /// Ok(())
612 /// }
613 /// ```
614 #[stable(feature = "metadata_ext", since = "1.1.0")]
mtime_nsec(&self) -> i64615 fn mtime_nsec(&self) -> i64;
616 /// Returns the last status change time of the file, in seconds since Unix Epoch.
617 ///
618 /// # Examples
619 ///
620 /// ```no_run
621 /// use std::fs;
622 /// use std::os::unix::fs::MetadataExt;
623 /// use std::io;
624 ///
625 /// fn main() -> io::Result<()> {
626 /// let meta = fs::metadata("some_file")?;
627 /// let last_status_change_time = meta.ctime();
628 /// Ok(())
629 /// }
630 /// ```
631 #[stable(feature = "metadata_ext", since = "1.1.0")]
ctime(&self) -> i64632 fn ctime(&self) -> i64;
633 /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
634 ///
635 /// [`ctime`]: MetadataExt::ctime
636 ///
637 /// # Examples
638 ///
639 /// ```no_run
640 /// use std::fs;
641 /// use std::os::unix::fs::MetadataExt;
642 /// use std::io;
643 ///
644 /// fn main() -> io::Result<()> {
645 /// let meta = fs::metadata("some_file")?;
646 /// let nano_last_status_change_time = meta.ctime_nsec();
647 /// Ok(())
648 /// }
649 /// ```
650 #[stable(feature = "metadata_ext", since = "1.1.0")]
ctime_nsec(&self) -> i64651 fn ctime_nsec(&self) -> i64;
652 /// Returns the block size for filesystem I/O.
653 ///
654 /// # Examples
655 ///
656 /// ```no_run
657 /// use std::fs;
658 /// use std::os::unix::fs::MetadataExt;
659 /// use std::io;
660 ///
661 /// fn main() -> io::Result<()> {
662 /// let meta = fs::metadata("some_file")?;
663 /// let block_size = meta.blksize();
664 /// Ok(())
665 /// }
666 /// ```
667 #[stable(feature = "metadata_ext", since = "1.1.0")]
blksize(&self) -> u64668 fn blksize(&self) -> u64;
669 /// Returns the number of blocks allocated to the file, in 512-byte units.
670 ///
671 /// Please note that this may be smaller than `st_size / 512` when the file has holes.
672 ///
673 /// # Examples
674 ///
675 /// ```no_run
676 /// use std::fs;
677 /// use std::os::unix::fs::MetadataExt;
678 /// use std::io;
679 ///
680 /// fn main() -> io::Result<()> {
681 /// let meta = fs::metadata("some_file")?;
682 /// let blocks = meta.blocks();
683 /// Ok(())
684 /// }
685 /// ```
686 #[stable(feature = "metadata_ext", since = "1.1.0")]
blocks(&self) -> u64687 fn blocks(&self) -> u64;
688 #[cfg(target_os = "vxworks")]
689 #[stable(feature = "metadata_ext", since = "1.1.0")]
attrib(&self) -> u8690 fn attrib(&self) -> u8;
691 }
692
693 #[stable(feature = "metadata_ext", since = "1.1.0")]
694 impl MetadataExt for fs::Metadata {
dev(&self) -> u64695 fn dev(&self) -> u64 {
696 self.st_dev()
697 }
ino(&self) -> u64698 fn ino(&self) -> u64 {
699 self.st_ino()
700 }
mode(&self) -> u32701 fn mode(&self) -> u32 {
702 self.st_mode()
703 }
nlink(&self) -> u64704 fn nlink(&self) -> u64 {
705 self.st_nlink()
706 }
uid(&self) -> u32707 fn uid(&self) -> u32 {
708 self.st_uid()
709 }
gid(&self) -> u32710 fn gid(&self) -> u32 {
711 self.st_gid()
712 }
rdev(&self) -> u64713 fn rdev(&self) -> u64 {
714 self.st_rdev()
715 }
size(&self) -> u64716 fn size(&self) -> u64 {
717 self.st_size()
718 }
atime(&self) -> i64719 fn atime(&self) -> i64 {
720 self.st_atime()
721 }
atime_nsec(&self) -> i64722 fn atime_nsec(&self) -> i64 {
723 self.st_atime_nsec()
724 }
mtime(&self) -> i64725 fn mtime(&self) -> i64 {
726 self.st_mtime()
727 }
mtime_nsec(&self) -> i64728 fn mtime_nsec(&self) -> i64 {
729 self.st_mtime_nsec()
730 }
ctime(&self) -> i64731 fn ctime(&self) -> i64 {
732 self.st_ctime()
733 }
ctime_nsec(&self) -> i64734 fn ctime_nsec(&self) -> i64 {
735 self.st_ctime_nsec()
736 }
blksize(&self) -> u64737 fn blksize(&self) -> u64 {
738 self.st_blksize()
739 }
blocks(&self) -> u64740 fn blocks(&self) -> u64 {
741 self.st_blocks()
742 }
743 #[cfg(target_os = "vxworks")]
attrib(&self) -> u8744 fn attrib(&self) -> u8 {
745 self.st_attrib()
746 }
747 }
748
749 /// Unix-specific extensions for [`fs::FileType`].
750 ///
751 /// Adds support for special Unix file types such as block/character devices,
752 /// pipes, and sockets.
753 #[stable(feature = "file_type_ext", since = "1.5.0")]
754 pub trait FileTypeExt {
755 /// Returns `true` if this file type is a block device.
756 ///
757 /// # Examples
758 ///
759 /// ```no_run
760 /// use std::fs;
761 /// use std::os::unix::fs::FileTypeExt;
762 /// use std::io;
763 ///
764 /// fn main() -> io::Result<()> {
765 /// let meta = fs::metadata("block_device_file")?;
766 /// let file_type = meta.file_type();
767 /// assert!(file_type.is_block_device());
768 /// Ok(())
769 /// }
770 /// ```
771 #[stable(feature = "file_type_ext", since = "1.5.0")]
is_block_device(&self) -> bool772 fn is_block_device(&self) -> bool;
773 /// Returns `true` if this file type is a char device.
774 ///
775 /// # Examples
776 ///
777 /// ```no_run
778 /// use std::fs;
779 /// use std::os::unix::fs::FileTypeExt;
780 /// use std::io;
781 ///
782 /// fn main() -> io::Result<()> {
783 /// let meta = fs::metadata("char_device_file")?;
784 /// let file_type = meta.file_type();
785 /// assert!(file_type.is_char_device());
786 /// Ok(())
787 /// }
788 /// ```
789 #[stable(feature = "file_type_ext", since = "1.5.0")]
is_char_device(&self) -> bool790 fn is_char_device(&self) -> bool;
791 /// Returns `true` if this file type is a fifo.
792 ///
793 /// # Examples
794 ///
795 /// ```no_run
796 /// use std::fs;
797 /// use std::os::unix::fs::FileTypeExt;
798 /// use std::io;
799 ///
800 /// fn main() -> io::Result<()> {
801 /// let meta = fs::metadata("fifo_file")?;
802 /// let file_type = meta.file_type();
803 /// assert!(file_type.is_fifo());
804 /// Ok(())
805 /// }
806 /// ```
807 #[stable(feature = "file_type_ext", since = "1.5.0")]
is_fifo(&self) -> bool808 fn is_fifo(&self) -> bool;
809 /// Returns `true` if this file type is a socket.
810 ///
811 /// # Examples
812 ///
813 /// ```no_run
814 /// use std::fs;
815 /// use std::os::unix::fs::FileTypeExt;
816 /// use std::io;
817 ///
818 /// fn main() -> io::Result<()> {
819 /// let meta = fs::metadata("unix.socket")?;
820 /// let file_type = meta.file_type();
821 /// assert!(file_type.is_socket());
822 /// Ok(())
823 /// }
824 /// ```
825 #[stable(feature = "file_type_ext", since = "1.5.0")]
is_socket(&self) -> bool826 fn is_socket(&self) -> bool;
827 }
828
829 #[stable(feature = "file_type_ext", since = "1.5.0")]
830 impl FileTypeExt for fs::FileType {
is_block_device(&self) -> bool831 fn is_block_device(&self) -> bool {
832 self.as_inner().is(libc::S_IFBLK)
833 }
is_char_device(&self) -> bool834 fn is_char_device(&self) -> bool {
835 self.as_inner().is(libc::S_IFCHR)
836 }
is_fifo(&self) -> bool837 fn is_fifo(&self) -> bool {
838 self.as_inner().is(libc::S_IFIFO)
839 }
is_socket(&self) -> bool840 fn is_socket(&self) -> bool {
841 self.as_inner().is(libc::S_IFSOCK)
842 }
843 }
844
845 /// Unix-specific extension methods for [`fs::DirEntry`].
846 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
847 pub trait DirEntryExt {
848 /// Returns the underlying `d_ino` field in the contained `dirent`
849 /// structure.
850 ///
851 /// # Examples
852 ///
853 /// ```
854 /// use std::fs;
855 /// use std::os::unix::fs::DirEntryExt;
856 ///
857 /// if let Ok(entries) = fs::read_dir(".") {
858 /// for entry in entries {
859 /// if let Ok(entry) = entry {
860 /// // Here, `entry` is a `DirEntry`.
861 /// println!("{:?}: {}", entry.file_name(), entry.ino());
862 /// }
863 /// }
864 /// }
865 /// ```
866 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
ino(&self) -> u64867 fn ino(&self) -> u64;
868 }
869
870 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
871 impl DirEntryExt for fs::DirEntry {
ino(&self) -> u64872 fn ino(&self) -> u64 {
873 self.as_inner().ino()
874 }
875 }
876
877 /// Sealed Unix-specific extension methods for [`fs::DirEntry`].
878 #[unstable(feature = "dir_entry_ext2", issue = "85573")]
879 pub trait DirEntryExt2: Sealed {
880 /// Returns a reference to the underlying `OsStr` of this entry's filename.
881 ///
882 /// # Examples
883 ///
884 /// ```
885 /// #![feature(dir_entry_ext2)]
886 /// use std::os::unix::fs::DirEntryExt2;
887 /// use std::{fs, io};
888 ///
889 /// fn main() -> io::Result<()> {
890 /// let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?;
891 /// entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));
892 ///
893 /// for p in entries {
894 /// println!("{p:?}");
895 /// }
896 ///
897 /// Ok(())
898 /// }
899 /// ```
file_name_ref(&self) -> &OsStr900 fn file_name_ref(&self) -> &OsStr;
901 }
902
903 /// Allows extension traits within `std`.
904 #[unstable(feature = "sealed", issue = "none")]
905 impl Sealed for fs::DirEntry {}
906
907 #[unstable(feature = "dir_entry_ext2", issue = "85573")]
908 impl DirEntryExt2 for fs::DirEntry {
file_name_ref(&self) -> &OsStr909 fn file_name_ref(&self) -> &OsStr {
910 self.as_inner().file_name_os_str()
911 }
912 }
913
914 /// Creates a new symbolic link on the filesystem.
915 ///
916 /// The `link` path will be a symbolic link pointing to the `original` path.
917 ///
918 /// # Examples
919 ///
920 /// ```no_run
921 /// use std::os::unix::fs;
922 ///
923 /// fn main() -> std::io::Result<()> {
924 /// fs::symlink("a.txt", "b.txt")?;
925 /// Ok(())
926 /// }
927 /// ```
928 #[stable(feature = "symlink", since = "1.1.0")]
symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()>929 pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
930 sys::fs::symlink(original.as_ref(), link.as_ref())
931 }
932
933 /// Unix-specific extensions to [`fs::DirBuilder`].
934 #[stable(feature = "dir_builder", since = "1.6.0")]
935 pub trait DirBuilderExt {
936 /// Sets the mode to create new directories with. This option defaults to
937 /// 0o777.
938 ///
939 /// # Examples
940 ///
941 /// ```no_run
942 /// use std::fs::DirBuilder;
943 /// use std::os::unix::fs::DirBuilderExt;
944 ///
945 /// let mut builder = DirBuilder::new();
946 /// builder.mode(0o755);
947 /// ```
948 #[stable(feature = "dir_builder", since = "1.6.0")]
mode(&mut self, mode: u32) -> &mut Self949 fn mode(&mut self, mode: u32) -> &mut Self;
950 }
951
952 #[stable(feature = "dir_builder", since = "1.6.0")]
953 impl DirBuilderExt for fs::DirBuilder {
mode(&mut self, mode: u32) -> &mut fs::DirBuilder954 fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
955 self.as_inner_mut().set_mode(mode);
956 self
957 }
958 }
959
960 /// Change the owner and group of the specified path.
961 ///
962 /// Specifying either the uid or gid as `None` will leave it unchanged.
963 ///
964 /// Changing the owner typically requires privileges, such as root or a specific capability.
965 /// Changing the group typically requires either being the owner and a member of the group, or
966 /// having privileges.
967 ///
968 /// If called on a symbolic link, this will change the owner and group of the link target. To
969 /// change the owner and group of the link itself, see [`lchown`].
970 ///
971 /// # Examples
972 ///
973 /// ```no_run
974 /// #![feature(unix_chown)]
975 /// use std::os::unix::fs;
976 ///
977 /// fn main() -> std::io::Result<()> {
978 /// fs::chown("/sandbox", Some(0), Some(0))?;
979 /// Ok(())
980 /// }
981 /// ```
982 #[unstable(feature = "unix_chown", issue = "88989")]
chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()>983 pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
984 sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
985 }
986
987 /// Change the owner and group of the file referenced by the specified open file descriptor.
988 ///
989 /// For semantics and required privileges, see [`chown`].
990 ///
991 /// # Examples
992 ///
993 /// ```no_run
994 /// #![feature(unix_chown)]
995 /// use std::os::unix::fs;
996 ///
997 /// fn main() -> std::io::Result<()> {
998 /// let f = std::fs::File::open("/file")?;
999 /// fs::fchown(&f, Some(0), Some(0))?;
1000 /// Ok(())
1001 /// }
1002 /// ```
1003 #[unstable(feature = "unix_chown", issue = "88989")]
fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()>1004 pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1005 sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
1006 }
1007
1008 /// Change the owner and group of the specified path, without dereferencing symbolic links.
1009 ///
1010 /// Identical to [`chown`], except that if called on a symbolic link, this will change the owner
1011 /// and group of the link itself rather than the owner and group of the link target.
1012 ///
1013 /// # Examples
1014 ///
1015 /// ```no_run
1016 /// #![feature(unix_chown)]
1017 /// use std::os::unix::fs;
1018 ///
1019 /// fn main() -> std::io::Result<()> {
1020 /// fs::lchown("/symlink", Some(0), Some(0))?;
1021 /// Ok(())
1022 /// }
1023 /// ```
1024 #[unstable(feature = "unix_chown", issue = "88989")]
lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()>1025 pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
1026 sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
1027 }
1028
1029 /// Change the root directory of the current process to the specified path.
1030 ///
1031 /// This typically requires privileges, such as root or a specific capability.
1032 ///
1033 /// This does not change the current working directory; you should call
1034 /// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards.
1035 ///
1036 /// # Examples
1037 ///
1038 /// ```no_run
1039 /// use std::os::unix::fs;
1040 ///
1041 /// fn main() -> std::io::Result<()> {
1042 /// fs::chroot("/sandbox")?;
1043 /// std::env::set_current_dir("/")?;
1044 /// // continue working in sandbox
1045 /// Ok(())
1046 /// }
1047 /// ```
1048 #[stable(feature = "unix_chroot", since = "1.56.0")]
1049 #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
chroot<P: AsRef<Path>>(dir: P) -> io::Result<()>1050 pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
1051 sys::fs::chroot(dir.as_ref())
1052 }
1053