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