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