]> git.lizzy.rs Git - rust.git/blob - library/std/src/os/unix/fs.rs
Auto merge of #107843 - bjorn3:sync_cg_clif-2023-02-09, r=bjorn3
[rust.git] / library / std / src / 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 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 /// Unix-specific extensions to [`fs::File`].
21 #[stable(feature = "file_offset", since = "1.15.0")]
22 pub trait FileExt {
23     /// Reads a number of bytes starting from a given offset.
24     ///
25     /// Returns the number of bytes read.
26     ///
27     /// The offset is relative to the start of the file and thus independent
28     /// from the current cursor.
29     ///
30     /// The current file cursor is not affected by this function.
31     ///
32     /// Note that similar to [`File::read`], it is not an error to return with a
33     /// short read.
34     ///
35     /// [`File::read`]: fs::File::read
36     ///
37     /// # Examples
38     ///
39     /// ```no_run
40     /// use std::io;
41     /// use std::fs::File;
42     /// use std::os::unix::prelude::FileExt;
43     ///
44     /// fn main() -> io::Result<()> {
45     ///     let mut buf = [0u8; 8];
46     ///     let file = File::open("foo.txt")?;
47     ///
48     ///     // We now read 8 bytes from the offset 10.
49     ///     let num_bytes_read = file.read_at(&mut buf, 10)?;
50     ///     println!("read {num_bytes_read} bytes: {buf:?}");
51     ///     Ok(())
52     /// }
53     /// ```
54     #[stable(feature = "file_offset", since = "1.15.0")]
55     fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
56
57     /// Reads the exact number of byte required to fill `buf` from the given offset.
58     ///
59     /// The offset is relative to the start of the file and thus independent
60     /// from the current cursor.
61     ///
62     /// The current file cursor is not affected by this function.
63     ///
64     /// Similar to [`io::Read::read_exact`] but uses [`read_at`] instead of `read`.
65     ///
66     /// [`read_at`]: FileExt::read_at
67     ///
68     /// # Errors
69     ///
70     /// If this function encounters an error of the kind
71     /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
72     /// will continue.
73     ///
74     /// If this function encounters an "end of file" before completely filling
75     /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
76     /// The contents of `buf` are unspecified in this case.
77     ///
78     /// If any other read error is encountered then this function immediately
79     /// returns. The contents of `buf` are unspecified in this case.
80     ///
81     /// If this function returns an error, it is unspecified how many bytes it
82     /// has read, but it will never read more than would be necessary to
83     /// completely fill the buffer.
84     ///
85     /// # Examples
86     ///
87     /// ```no_run
88     /// use std::io;
89     /// use std::fs::File;
90     /// use std::os::unix::prelude::FileExt;
91     ///
92     /// fn main() -> io::Result<()> {
93     ///     let mut buf = [0u8; 8];
94     ///     let file = File::open("foo.txt")?;
95     ///
96     ///     // We now read exactly 8 bytes from the offset 10.
97     ///     file.read_exact_at(&mut buf, 10)?;
98     ///     println!("read {} bytes: {:?}", buf.len(), buf);
99     ///     Ok(())
100     /// }
101     /// ```
102     #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
103     fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
104         while !buf.is_empty() {
105             match self.read_at(buf, offset) {
106                 Ok(0) => break,
107                 Ok(n) => {
108                     let tmp = buf;
109                     buf = &mut tmp[n..];
110                     offset += n as u64;
111                 }
112                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
113                 Err(e) => return Err(e),
114             }
115         }
116         if !buf.is_empty() {
117             Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer",))
118         } else {
119             Ok(())
120         }
121     }
122
123     /// Writes a number of bytes starting from a given offset.
124     ///
125     /// Returns the number of bytes written.
126     ///
127     /// The offset is relative to the start of the file and thus independent
128     /// from the current cursor.
129     ///
130     /// The current file cursor is not affected by this function.
131     ///
132     /// When writing beyond the end of the file, the file is appropriately
133     /// extended and the intermediate bytes are initialized with the value 0.
134     ///
135     /// Note that similar to [`File::write`], it is not an error to return a
136     /// short write.
137     ///
138     /// [`File::write`]: fs::File::write
139     ///
140     /// # Examples
141     ///
142     /// ```no_run
143     /// use std::fs::File;
144     /// use std::io;
145     /// use std::os::unix::prelude::FileExt;
146     ///
147     /// fn main() -> io::Result<()> {
148     ///     let file = File::open("foo.txt")?;
149     ///
150     ///     // We now write at the offset 10.
151     ///     file.write_at(b"sushi", 10)?;
152     ///     Ok(())
153     /// }
154     /// ```
155     #[stable(feature = "file_offset", since = "1.15.0")]
156     fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
157
158     /// Attempts to write an entire buffer starting from a given offset.
159     ///
160     /// The offset is relative to the start of the file and thus independent
161     /// from the current cursor.
162     ///
163     /// The current file cursor is not affected by this function.
164     ///
165     /// This method will continuously call [`write_at`] until there is no more data
166     /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
167     /// returned. This method will not return until the entire buffer has been
168     /// successfully written or such an error occurs. The first error that is
169     /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
170     /// returned.
171     ///
172     /// # Errors
173     ///
174     /// This function will return the first error of
175     /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
176     ///
177     /// [`write_at`]: FileExt::write_at
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::open("foo.txt")?;
188     ///
189     ///     // We now write at the offset 10.
190     ///     file.write_all_at(b"sushi", 10)?;
191     ///     Ok(())
192     /// }
193     /// ```
194     #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
195     fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
196         while !buf.is_empty() {
197             match self.write_at(buf, offset) {
198                 Ok(0) => {
199                     return Err(io::const_io_error!(
200                         io::ErrorKind::WriteZero,
201                         "failed to write whole buffer",
202                     ));
203                 }
204                 Ok(n) => {
205                     buf = &buf[n..];
206                     offset += n as u64
207                 }
208                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
209                 Err(e) => return Err(e),
210             }
211         }
212         Ok(())
213     }
214 }
215
216 #[stable(feature = "file_offset", since = "1.15.0")]
217 impl FileExt for fs::File {
218     fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
219         self.as_inner().read_at(buf, offset)
220     }
221     fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
222         self.as_inner().write_at(buf, offset)
223     }
224 }
225
226 /// Unix-specific extensions to [`fs::Permissions`].
227 #[stable(feature = "fs_ext", since = "1.1.0")]
228 pub trait PermissionsExt {
229     /// Returns the underlying raw `st_mode` bits that contain the standard
230     /// Unix permissions for this file.
231     ///
232     /// # Examples
233     ///
234     /// ```no_run
235     /// use std::fs::File;
236     /// use std::os::unix::fs::PermissionsExt;
237     ///
238     /// fn main() -> std::io::Result<()> {
239     ///     let f = File::create("foo.txt")?;
240     ///     let metadata = f.metadata()?;
241     ///     let permissions = metadata.permissions();
242     ///
243     ///     println!("permissions: {:o}", permissions.mode());
244     ///     Ok(())
245     /// }
246     /// ```
247     #[stable(feature = "fs_ext", since = "1.1.0")]
248     fn mode(&self) -> u32;
249
250     /// Sets the underlying raw bits for this set of permissions.
251     ///
252     /// # Examples
253     ///
254     /// ```no_run
255     /// use std::fs::File;
256     /// use std::os::unix::fs::PermissionsExt;
257     ///
258     /// fn main() -> std::io::Result<()> {
259     ///     let f = File::create("foo.txt")?;
260     ///     let metadata = f.metadata()?;
261     ///     let mut permissions = metadata.permissions();
262     ///
263     ///     permissions.set_mode(0o644); // Read/write for owner and read for others.
264     ///     assert_eq!(permissions.mode(), 0o644);
265     ///     Ok(())
266     /// }
267     /// ```
268     #[stable(feature = "fs_ext", since = "1.1.0")]
269     fn set_mode(&mut self, mode: u32);
270
271     /// Creates a new instance of `Permissions` from the given set of Unix
272     /// permission bits.
273     ///
274     /// # Examples
275     ///
276     /// ```
277     /// use std::fs::Permissions;
278     /// use std::os::unix::fs::PermissionsExt;
279     ///
280     /// // Read/write for owner and read for others.
281     /// let permissions = Permissions::from_mode(0o644);
282     /// assert_eq!(permissions.mode(), 0o644);
283     /// ```
284     #[stable(feature = "fs_ext", since = "1.1.0")]
285     fn from_mode(mode: u32) -> Self;
286 }
287
288 #[stable(feature = "fs_ext", since = "1.1.0")]
289 impl PermissionsExt for Permissions {
290     fn mode(&self) -> u32 {
291         self.as_inner().mode()
292     }
293
294     fn set_mode(&mut self, mode: u32) {
295         *self = Permissions::from_inner(FromInner::from_inner(mode));
296     }
297
298     fn from_mode(mode: u32) -> Permissions {
299         Permissions::from_inner(FromInner::from_inner(mode))
300     }
301 }
302
303 /// Unix-specific extensions to [`fs::OpenOptions`].
304 #[stable(feature = "fs_ext", since = "1.1.0")]
305 pub trait OpenOptionsExt {
306     /// Sets the mode bits that a new file will be created with.
307     ///
308     /// If a new file is created as part of an `OpenOptions::open` call then this
309     /// specified `mode` will be used as the permission bits for the new file.
310     /// If no `mode` is set, the default of `0o666` will be used.
311     /// The operating system masks out bits with the system's `umask`, to produce
312     /// the final permissions.
313     ///
314     /// # Examples
315     ///
316     /// ```no_run
317     /// use std::fs::OpenOptions;
318     /// use std::os::unix::fs::OpenOptionsExt;
319     ///
320     /// # fn main() {
321     /// let mut options = OpenOptions::new();
322     /// options.mode(0o644); // Give read/write for owner and read for others.
323     /// let file = options.open("foo.txt");
324     /// # }
325     /// ```
326     #[stable(feature = "fs_ext", since = "1.1.0")]
327     fn mode(&mut self, mode: u32) -> &mut Self;
328
329     /// Pass custom flags to the `flags` argument of `open`.
330     ///
331     /// The bits that define the access mode are masked out with `O_ACCMODE`, to
332     /// ensure they do not interfere with the access mode set by Rusts options.
333     ///
334     /// Custom flags can only set flags, not remove flags set by Rusts options.
335     /// This options overwrites any previously set custom flags.
336     ///
337     /// # Examples
338     ///
339     /// ```no_run
340     /// # #![feature(rustc_private)]
341     /// extern crate libc;
342     /// use std::fs::OpenOptions;
343     /// use std::os::unix::fs::OpenOptionsExt;
344     ///
345     /// # fn main() {
346     /// let mut options = OpenOptions::new();
347     /// options.write(true);
348     /// if cfg!(unix) {
349     ///     options.custom_flags(libc::O_NOFOLLOW);
350     /// }
351     /// let file = options.open("foo.txt");
352     /// # }
353     /// ```
354     #[stable(feature = "open_options_ext", since = "1.10.0")]
355     fn custom_flags(&mut self, flags: i32) -> &mut Self;
356 }
357
358 #[stable(feature = "fs_ext", since = "1.1.0")]
359 impl OpenOptionsExt for OpenOptions {
360     fn mode(&mut self, mode: u32) -> &mut OpenOptions {
361         self.as_inner_mut().mode(mode);
362         self
363     }
364
365     fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
366         self.as_inner_mut().custom_flags(flags);
367         self
368     }
369 }
370
371 /// Unix-specific extensions to [`fs::Metadata`].
372 #[stable(feature = "metadata_ext", since = "1.1.0")]
373 pub trait MetadataExt {
374     /// Returns the ID of the device containing the file.
375     ///
376     /// # Examples
377     ///
378     /// ```no_run
379     /// use std::io;
380     /// use std::fs;
381     /// use std::os::unix::fs::MetadataExt;
382     ///
383     /// fn main() -> io::Result<()> {
384     ///     let meta = fs::metadata("some_file")?;
385     ///     let dev_id = meta.dev();
386     ///     Ok(())
387     /// }
388     /// ```
389     #[stable(feature = "metadata_ext", since = "1.1.0")]
390     fn dev(&self) -> u64;
391     /// Returns the inode number.
392     ///
393     /// # Examples
394     ///
395     /// ```no_run
396     /// use std::fs;
397     /// use std::os::unix::fs::MetadataExt;
398     /// use std::io;
399     ///
400     /// fn main() -> io::Result<()> {
401     ///     let meta = fs::metadata("some_file")?;
402     ///     let inode = meta.ino();
403     ///     Ok(())
404     /// }
405     /// ```
406     #[stable(feature = "metadata_ext", since = "1.1.0")]
407     fn ino(&self) -> u64;
408     /// Returns the rights applied to this file.
409     ///
410     /// # Examples
411     ///
412     /// ```no_run
413     /// use std::fs;
414     /// use std::os::unix::fs::MetadataExt;
415     /// use std::io;
416     ///
417     /// fn main() -> io::Result<()> {
418     ///     let meta = fs::metadata("some_file")?;
419     ///     let mode = meta.mode();
420     ///     let user_has_write_access      = mode & 0o200;
421     ///     let user_has_read_write_access = mode & 0o600;
422     ///     let group_has_read_access      = mode & 0o040;
423     ///     let others_have_exec_access    = mode & 0o001;
424     ///     Ok(())
425     /// }
426     /// ```
427     #[stable(feature = "metadata_ext", since = "1.1.0")]
428     fn mode(&self) -> u32;
429     /// Returns the number of hard links pointing to this file.
430     ///
431     /// # Examples
432     ///
433     /// ```no_run
434     /// use std::fs;
435     /// use std::os::unix::fs::MetadataExt;
436     /// use std::io;
437     ///
438     /// fn main() -> io::Result<()> {
439     ///     let meta = fs::metadata("some_file")?;
440     ///     let nb_hard_links = meta.nlink();
441     ///     Ok(())
442     /// }
443     /// ```
444     #[stable(feature = "metadata_ext", since = "1.1.0")]
445     fn nlink(&self) -> u64;
446     /// Returns the user ID of the owner of this file.
447     ///
448     /// # Examples
449     ///
450     /// ```no_run
451     /// use std::fs;
452     /// use std::os::unix::fs::MetadataExt;
453     /// use std::io;
454     ///
455     /// fn main() -> io::Result<()> {
456     ///     let meta = fs::metadata("some_file")?;
457     ///     let user_id = meta.uid();
458     ///     Ok(())
459     /// }
460     /// ```
461     #[stable(feature = "metadata_ext", since = "1.1.0")]
462     fn uid(&self) -> u32;
463     /// Returns the group ID of the owner of this file.
464     ///
465     /// # Examples
466     ///
467     /// ```no_run
468     /// use std::fs;
469     /// use std::os::unix::fs::MetadataExt;
470     /// use std::io;
471     ///
472     /// fn main() -> io::Result<()> {
473     ///     let meta = fs::metadata("some_file")?;
474     ///     let group_id = meta.gid();
475     ///     Ok(())
476     /// }
477     /// ```
478     #[stable(feature = "metadata_ext", since = "1.1.0")]
479     fn gid(&self) -> u32;
480     /// Returns the device ID of this file (if it is a special one).
481     ///
482     /// # Examples
483     ///
484     /// ```no_run
485     /// use std::fs;
486     /// use std::os::unix::fs::MetadataExt;
487     /// use std::io;
488     ///
489     /// fn main() -> io::Result<()> {
490     ///     let meta = fs::metadata("some_file")?;
491     ///     let device_id = meta.rdev();
492     ///     Ok(())
493     /// }
494     /// ```
495     #[stable(feature = "metadata_ext", since = "1.1.0")]
496     fn rdev(&self) -> u64;
497     /// Returns the total size of this file in bytes.
498     ///
499     /// # Examples
500     ///
501     /// ```no_run
502     /// use std::fs;
503     /// use std::os::unix::fs::MetadataExt;
504     /// use std::io;
505     ///
506     /// fn main() -> io::Result<()> {
507     ///     let meta = fs::metadata("some_file")?;
508     ///     let file_size = meta.size();
509     ///     Ok(())
510     /// }
511     /// ```
512     #[stable(feature = "metadata_ext", since = "1.1.0")]
513     fn size(&self) -> u64;
514     /// Returns the last access time of the file, in seconds since Unix Epoch.
515     ///
516     /// # Examples
517     ///
518     /// ```no_run
519     /// use std::fs;
520     /// use std::os::unix::fs::MetadataExt;
521     /// use std::io;
522     ///
523     /// fn main() -> io::Result<()> {
524     ///     let meta = fs::metadata("some_file")?;
525     ///     let last_access_time = meta.atime();
526     ///     Ok(())
527     /// }
528     /// ```
529     #[stable(feature = "metadata_ext", since = "1.1.0")]
530     fn atime(&self) -> i64;
531     /// Returns the last access time of the file, in nanoseconds since [`atime`].
532     ///
533     /// [`atime`]: MetadataExt::atime
534     ///
535     /// # Examples
536     ///
537     /// ```no_run
538     /// use std::fs;
539     /// use std::os::unix::fs::MetadataExt;
540     /// use std::io;
541     ///
542     /// fn main() -> io::Result<()> {
543     ///     let meta = fs::metadata("some_file")?;
544     ///     let nano_last_access_time = meta.atime_nsec();
545     ///     Ok(())
546     /// }
547     /// ```
548     #[stable(feature = "metadata_ext", since = "1.1.0")]
549     fn atime_nsec(&self) -> i64;
550     /// Returns the last modification time of the file, in seconds since Unix Epoch.
551     ///
552     /// # Examples
553     ///
554     /// ```no_run
555     /// use std::fs;
556     /// use std::os::unix::fs::MetadataExt;
557     /// use std::io;
558     ///
559     /// fn main() -> io::Result<()> {
560     ///     let meta = fs::metadata("some_file")?;
561     ///     let last_modification_time = meta.mtime();
562     ///     Ok(())
563     /// }
564     /// ```
565     #[stable(feature = "metadata_ext", since = "1.1.0")]
566     fn mtime(&self) -> i64;
567     /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
568     ///
569     /// [`mtime`]: MetadataExt::mtime
570     ///
571     /// # Examples
572     ///
573     /// ```no_run
574     /// use std::fs;
575     /// use std::os::unix::fs::MetadataExt;
576     /// use std::io;
577     ///
578     /// fn main() -> io::Result<()> {
579     ///     let meta = fs::metadata("some_file")?;
580     ///     let nano_last_modification_time = meta.mtime_nsec();
581     ///     Ok(())
582     /// }
583     /// ```
584     #[stable(feature = "metadata_ext", since = "1.1.0")]
585     fn mtime_nsec(&self) -> i64;
586     /// Returns the last status change time of the file, in seconds since Unix Epoch.
587     ///
588     /// # Examples
589     ///
590     /// ```no_run
591     /// use std::fs;
592     /// use std::os::unix::fs::MetadataExt;
593     /// use std::io;
594     ///
595     /// fn main() -> io::Result<()> {
596     ///     let meta = fs::metadata("some_file")?;
597     ///     let last_status_change_time = meta.ctime();
598     ///     Ok(())
599     /// }
600     /// ```
601     #[stable(feature = "metadata_ext", since = "1.1.0")]
602     fn ctime(&self) -> i64;
603     /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
604     ///
605     /// [`ctime`]: MetadataExt::ctime
606     ///
607     /// # Examples
608     ///
609     /// ```no_run
610     /// use std::fs;
611     /// use std::os::unix::fs::MetadataExt;
612     /// use std::io;
613     ///
614     /// fn main() -> io::Result<()> {
615     ///     let meta = fs::metadata("some_file")?;
616     ///     let nano_last_status_change_time = meta.ctime_nsec();
617     ///     Ok(())
618     /// }
619     /// ```
620     #[stable(feature = "metadata_ext", since = "1.1.0")]
621     fn ctime_nsec(&self) -> i64;
622     /// Returns the block size for filesystem I/O.
623     ///
624     /// # Examples
625     ///
626     /// ```no_run
627     /// use std::fs;
628     /// use std::os::unix::fs::MetadataExt;
629     /// use std::io;
630     ///
631     /// fn main() -> io::Result<()> {
632     ///     let meta = fs::metadata("some_file")?;
633     ///     let block_size = meta.blksize();
634     ///     Ok(())
635     /// }
636     /// ```
637     #[stable(feature = "metadata_ext", since = "1.1.0")]
638     fn blksize(&self) -> u64;
639     /// Returns the number of blocks allocated to the file, in 512-byte units.
640     ///
641     /// Please note that this may be smaller than `st_size / 512` when the file has holes.
642     ///
643     /// # Examples
644     ///
645     /// ```no_run
646     /// use std::fs;
647     /// use std::os::unix::fs::MetadataExt;
648     /// use std::io;
649     ///
650     /// fn main() -> io::Result<()> {
651     ///     let meta = fs::metadata("some_file")?;
652     ///     let blocks = meta.blocks();
653     ///     Ok(())
654     /// }
655     /// ```
656     #[stable(feature = "metadata_ext", since = "1.1.0")]
657     fn blocks(&self) -> u64;
658     #[cfg(target_os = "vxworks")]
659     #[stable(feature = "metadata_ext", since = "1.1.0")]
660     fn attrib(&self) -> u8;
661 }
662
663 #[stable(feature = "metadata_ext", since = "1.1.0")]
664 impl MetadataExt for fs::Metadata {
665     fn dev(&self) -> u64 {
666         self.st_dev()
667     }
668     fn ino(&self) -> u64 {
669         self.st_ino()
670     }
671     fn mode(&self) -> u32 {
672         self.st_mode()
673     }
674     fn nlink(&self) -> u64 {
675         self.st_nlink()
676     }
677     fn uid(&self) -> u32 {
678         self.st_uid()
679     }
680     fn gid(&self) -> u32 {
681         self.st_gid()
682     }
683     fn rdev(&self) -> u64 {
684         self.st_rdev()
685     }
686     fn size(&self) -> u64 {
687         self.st_size()
688     }
689     fn atime(&self) -> i64 {
690         self.st_atime()
691     }
692     fn atime_nsec(&self) -> i64 {
693         self.st_atime_nsec()
694     }
695     fn mtime(&self) -> i64 {
696         self.st_mtime()
697     }
698     fn mtime_nsec(&self) -> i64 {
699         self.st_mtime_nsec()
700     }
701     fn ctime(&self) -> i64 {
702         self.st_ctime()
703     }
704     fn ctime_nsec(&self) -> i64 {
705         self.st_ctime_nsec()
706     }
707     fn blksize(&self) -> u64 {
708         self.st_blksize()
709     }
710     fn blocks(&self) -> u64 {
711         self.st_blocks()
712     }
713     #[cfg(target_os = "vxworks")]
714     fn attrib(&self) -> u8 {
715         self.st_attrib()
716     }
717 }
718
719 /// Unix-specific extensions for [`fs::FileType`].
720 ///
721 /// Adds support for special Unix file types such as block/character devices,
722 /// pipes, and sockets.
723 #[stable(feature = "file_type_ext", since = "1.5.0")]
724 pub trait FileTypeExt {
725     /// Returns `true` if this file type is a block device.
726     ///
727     /// # Examples
728     ///
729     /// ```no_run
730     /// use std::fs;
731     /// use std::os::unix::fs::FileTypeExt;
732     /// use std::io;
733     ///
734     /// fn main() -> io::Result<()> {
735     ///     let meta = fs::metadata("block_device_file")?;
736     ///     let file_type = meta.file_type();
737     ///     assert!(file_type.is_block_device());
738     ///     Ok(())
739     /// }
740     /// ```
741     #[stable(feature = "file_type_ext", since = "1.5.0")]
742     fn is_block_device(&self) -> bool;
743     /// Returns `true` if this file type is a char device.
744     ///
745     /// # Examples
746     ///
747     /// ```no_run
748     /// use std::fs;
749     /// use std::os::unix::fs::FileTypeExt;
750     /// use std::io;
751     ///
752     /// fn main() -> io::Result<()> {
753     ///     let meta = fs::metadata("char_device_file")?;
754     ///     let file_type = meta.file_type();
755     ///     assert!(file_type.is_char_device());
756     ///     Ok(())
757     /// }
758     /// ```
759     #[stable(feature = "file_type_ext", since = "1.5.0")]
760     fn is_char_device(&self) -> bool;
761     /// Returns `true` if this file type is a fifo.
762     ///
763     /// # Examples
764     ///
765     /// ```no_run
766     /// use std::fs;
767     /// use std::os::unix::fs::FileTypeExt;
768     /// use std::io;
769     ///
770     /// fn main() -> io::Result<()> {
771     ///     let meta = fs::metadata("fifo_file")?;
772     ///     let file_type = meta.file_type();
773     ///     assert!(file_type.is_fifo());
774     ///     Ok(())
775     /// }
776     /// ```
777     #[stable(feature = "file_type_ext", since = "1.5.0")]
778     fn is_fifo(&self) -> bool;
779     /// Returns `true` if this file type is a socket.
780     ///
781     /// # Examples
782     ///
783     /// ```no_run
784     /// use std::fs;
785     /// use std::os::unix::fs::FileTypeExt;
786     /// use std::io;
787     ///
788     /// fn main() -> io::Result<()> {
789     ///     let meta = fs::metadata("unix.socket")?;
790     ///     let file_type = meta.file_type();
791     ///     assert!(file_type.is_socket());
792     ///     Ok(())
793     /// }
794     /// ```
795     #[stable(feature = "file_type_ext", since = "1.5.0")]
796     fn is_socket(&self) -> bool;
797 }
798
799 #[stable(feature = "file_type_ext", since = "1.5.0")]
800 impl FileTypeExt for fs::FileType {
801     fn is_block_device(&self) -> bool {
802         self.as_inner().is(libc::S_IFBLK)
803     }
804     fn is_char_device(&self) -> bool {
805         self.as_inner().is(libc::S_IFCHR)
806     }
807     fn is_fifo(&self) -> bool {
808         self.as_inner().is(libc::S_IFIFO)
809     }
810     fn is_socket(&self) -> bool {
811         self.as_inner().is(libc::S_IFSOCK)
812     }
813 }
814
815 /// Unix-specific extension methods for [`fs::DirEntry`].
816 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
817 pub trait DirEntryExt {
818     /// Returns the underlying `d_ino` field in the contained `dirent`
819     /// structure.
820     ///
821     /// # Examples
822     ///
823     /// ```
824     /// use std::fs;
825     /// use std::os::unix::fs::DirEntryExt;
826     ///
827     /// if let Ok(entries) = fs::read_dir(".") {
828     ///     for entry in entries {
829     ///         if let Ok(entry) = entry {
830     ///             // Here, `entry` is a `DirEntry`.
831     ///             println!("{:?}: {}", entry.file_name(), entry.ino());
832     ///         }
833     ///     }
834     /// }
835     /// ```
836     #[stable(feature = "dir_entry_ext", since = "1.1.0")]
837     fn ino(&self) -> u64;
838 }
839
840 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
841 impl DirEntryExt for fs::DirEntry {
842     fn ino(&self) -> u64 {
843         self.as_inner().ino()
844     }
845 }
846
847 /// Sealed Unix-specific extension methods for [`fs::DirEntry`].
848 #[unstable(feature = "dir_entry_ext2", issue = "85573")]
849 pub trait DirEntryExt2: Sealed {
850     /// Returns a reference to the underlying `OsStr` of this entry's filename.
851     ///
852     /// # Examples
853     ///
854     /// ```
855     /// #![feature(dir_entry_ext2)]
856     /// use std::os::unix::fs::DirEntryExt2;
857     /// use std::{fs, io};
858     ///
859     /// fn main() -> io::Result<()> {
860     ///     let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?;
861     ///     entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));
862     ///
863     ///     for p in entries {
864     ///         println!("{p:?}");
865     ///     }
866     ///
867     ///     Ok(())
868     /// }
869     /// ```
870     fn file_name_ref(&self) -> &OsStr;
871 }
872
873 /// Allows extension traits within `std`.
874 #[unstable(feature = "sealed", issue = "none")]
875 impl Sealed for fs::DirEntry {}
876
877 #[unstable(feature = "dir_entry_ext2", issue = "85573")]
878 impl DirEntryExt2 for fs::DirEntry {
879     fn file_name_ref(&self) -> &OsStr {
880         self.as_inner().file_name_os_str()
881     }
882 }
883
884 /// Creates a new symbolic link on the filesystem.
885 ///
886 /// The `link` path will be a symbolic link pointing to the `original` path.
887 ///
888 /// # Examples
889 ///
890 /// ```no_run
891 /// use std::os::unix::fs;
892 ///
893 /// fn main() -> std::io::Result<()> {
894 ///     fs::symlink("a.txt", "b.txt")?;
895 ///     Ok(())
896 /// }
897 /// ```
898 #[stable(feature = "symlink", since = "1.1.0")]
899 pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
900     sys::fs::symlink(original.as_ref(), link.as_ref())
901 }
902
903 /// Unix-specific extensions to [`fs::DirBuilder`].
904 #[stable(feature = "dir_builder", since = "1.6.0")]
905 pub trait DirBuilderExt {
906     /// Sets the mode to create new directories with. This option defaults to
907     /// 0o777.
908     ///
909     /// # Examples
910     ///
911     /// ```no_run
912     /// use std::fs::DirBuilder;
913     /// use std::os::unix::fs::DirBuilderExt;
914     ///
915     /// let mut builder = DirBuilder::new();
916     /// builder.mode(0o755);
917     /// ```
918     #[stable(feature = "dir_builder", since = "1.6.0")]
919     fn mode(&mut self, mode: u32) -> &mut Self;
920 }
921
922 #[stable(feature = "dir_builder", since = "1.6.0")]
923 impl DirBuilderExt for fs::DirBuilder {
924     fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
925         self.as_inner_mut().set_mode(mode);
926         self
927     }
928 }
929
930 /// Change the owner and group of the specified path.
931 ///
932 /// Specifying either the uid or gid as `None` will leave it unchanged.
933 ///
934 /// Changing the owner typically requires privileges, such as root or a specific capability.
935 /// Changing the group typically requires either being the owner and a member of the group, or
936 /// having privileges.
937 ///
938 /// If called on a symbolic link, this will change the owner and group of the link target. To
939 /// change the owner and group of the link itself, see [`lchown`].
940 ///
941 /// # Examples
942 ///
943 /// ```no_run
944 /// #![feature(unix_chown)]
945 /// use std::os::unix::fs;
946 ///
947 /// fn main() -> std::io::Result<()> {
948 ///     fs::chown("/sandbox", Some(0), Some(0))?;
949 ///     Ok(())
950 /// }
951 /// ```
952 #[unstable(feature = "unix_chown", issue = "88989")]
953 pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
954     sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
955 }
956
957 /// Change the owner and group of the file referenced by the specified open file descriptor.
958 ///
959 /// For semantics and required privileges, see [`chown`].
960 ///
961 /// # Examples
962 ///
963 /// ```no_run
964 /// #![feature(unix_chown)]
965 /// use std::os::unix::fs;
966 ///
967 /// fn main() -> std::io::Result<()> {
968 ///     let f = std::fs::File::open("/file")?;
969 ///     fs::fchown(&f, Some(0), Some(0))?;
970 ///     Ok(())
971 /// }
972 /// ```
973 #[unstable(feature = "unix_chown", issue = "88989")]
974 pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
975     sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
976 }
977
978 /// Change the owner and group of the specified path, without dereferencing symbolic links.
979 ///
980 /// Identical to [`chown`], except that if called on a symbolic link, this will change the owner
981 /// and group of the link itself rather than the owner and group of the link target.
982 ///
983 /// # Examples
984 ///
985 /// ```no_run
986 /// #![feature(unix_chown)]
987 /// use std::os::unix::fs;
988 ///
989 /// fn main() -> std::io::Result<()> {
990 ///     fs::lchown("/symlink", Some(0), Some(0))?;
991 ///     Ok(())
992 /// }
993 /// ```
994 #[unstable(feature = "unix_chown", issue = "88989")]
995 pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
996     sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
997 }
998
999 /// Change the root directory of the current process to the specified path.
1000 ///
1001 /// This typically requires privileges, such as root or a specific capability.
1002 ///
1003 /// This does not change the current working directory; you should call
1004 /// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards.
1005 ///
1006 /// # Examples
1007 ///
1008 /// ```no_run
1009 /// use std::os::unix::fs;
1010 ///
1011 /// fn main() -> std::io::Result<()> {
1012 ///     fs::chroot("/sandbox")?;
1013 ///     std::env::set_current_dir("/")?;
1014 ///     // continue working in sandbox
1015 ///     Ok(())
1016 /// }
1017 /// ```
1018 #[stable(feature = "unix_chroot", since = "1.56.0")]
1019 #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
1020 pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
1021     sys::fs::chroot(dir.as_ref())
1022 }