]> git.lizzy.rs Git - rust.git/blob - library/std/src/sys/unix/ext/fs.rs
f174a59b49a6ba51b01a1bc50f720ee2a6e4dd37
[rust.git] / library / std / src / sys / unix / ext / 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 crate::fs::{self, OpenOptions, Permissions};
6 use crate::io;
7 use crate::path::Path;
8 use crate::sys;
9 use crate::sys::platform::fs::MetadataExt as UnixMetadataExt;
10 use crate::sys_common::{AsInner, AsInnerMut, FromInner};
11
12 /// Unix-specific extensions to [`File`].
13 ///
14 /// [`File`]: ../../../../std/fs/struct.File.html
15 #[stable(feature = "file_offset", since = "1.15.0")]
16 pub trait FileExt {
17     /// Reads a number of bytes starting from a given offset.
18     ///
19     /// Returns the number of bytes read.
20     ///
21     /// The offset is relative to the start of the file and thus independent
22     /// from the current cursor.
23     ///
24     /// The current file cursor is not affected by this function.
25     ///
26     /// Note that similar to [`File::read`], it is not an error to return with a
27     /// short read.
28     ///
29     /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read
30     ///
31     /// # Examples
32     ///
33     /// ```no_run
34     /// use std::io;
35     /// use std::fs::File;
36     /// use std::os::unix::prelude::FileExt;
37     ///
38     /// fn main() -> io::Result<()> {
39     ///     let mut buf = [0u8; 8];
40     ///     let file = File::open("foo.txt")?;
41     ///
42     ///     // We now read 8 bytes from the offset 10.
43     ///     let num_bytes_read = file.read_at(&mut buf, 10)?;
44     ///     println!("read {} bytes: {:?}", num_bytes_read, buf);
45     ///     Ok(())
46     /// }
47     /// ```
48     #[stable(feature = "file_offset", since = "1.15.0")]
49     fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
50
51     /// Reads the exact number of byte required to fill `buf` from the given offset.
52     ///
53     /// The offset is relative to the start of the file and thus independent
54     /// from the current cursor.
55     ///
56     /// The current file cursor is not affected by this function.
57     ///
58     /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
59     ///
60     /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact
61     /// [`read_at`]: #tymethod.read_at
62     ///
63     /// # Errors
64     ///
65     /// If this function encounters an error of the kind
66     /// [`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 [`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     /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
81     /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
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(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`]: ../../../../std/fs/struct.File.html#method.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-[`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 [`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-[`ErrorKind::Interrupted`] kind that [`write_at`] returns.
174     ///
175     /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
176     /// [`write_at`]: #tymethod.write_at
177     ///
178     /// # Examples
179     ///
180     /// ```no_run
181     /// use std::fs::File;
182     /// use std::io;
183     /// use std::os::unix::prelude::FileExt;
184     ///
185     /// fn main() -> io::Result<()> {
186     ///     let file = File::open("foo.txt")?;
187     ///
188     ///     // We now write at the offset 10.
189     ///     file.write_all_at(b"sushi", 10)?;
190     ///     Ok(())
191     /// }
192     /// ```
193     #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
194     fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
195         while !buf.is_empty() {
196             match self.write_at(buf, offset) {
197                 Ok(0) => {
198                     return Err(io::Error::new(
199                         io::ErrorKind::WriteZero,
200                         "failed to write whole buffer",
201                     ));
202                 }
203                 Ok(n) => {
204                     buf = &buf[n..];
205                     offset += n as u64
206                 }
207                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
208                 Err(e) => return Err(e),
209             }
210         }
211         Ok(())
212     }
213 }
214
215 #[stable(feature = "file_offset", since = "1.15.0")]
216 impl FileExt for fs::File {
217     fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
218         self.as_inner().read_at(buf, offset)
219     }
220     fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
221         self.as_inner().write_at(buf, offset)
222     }
223 }
224
225 /// Unix-specific extensions to [`fs::Permissions`].
226 ///
227 /// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
228 #[stable(feature = "fs_ext", since = "1.1.0")]
229 pub trait PermissionsExt {
230     /// Returns the underlying raw `st_mode` bits that contain the standard
231     /// Unix permissions for this file.
232     ///
233     /// # Examples
234     ///
235     /// ```no_run
236     /// use std::fs::File;
237     /// use std::os::unix::fs::PermissionsExt;
238     ///
239     /// fn main() -> std::io::Result<()> {
240     ///     let f = File::create("foo.txt")?;
241     ///     let metadata = f.metadata()?;
242     ///     let permissions = metadata.permissions();
243     ///
244     ///     println!("permissions: {:o}", permissions.mode());
245     ///     Ok(())
246     /// }
247     /// ```
248     #[stable(feature = "fs_ext", since = "1.1.0")]
249     fn mode(&self) -> u32;
250
251     /// Sets the underlying raw bits for this set of permissions.
252     ///
253     /// # Examples
254     ///
255     /// ```no_run
256     /// use std::fs::File;
257     /// use std::os::unix::fs::PermissionsExt;
258     ///
259     /// fn main() -> std::io::Result<()> {
260     ///     let f = File::create("foo.txt")?;
261     ///     let metadata = f.metadata()?;
262     ///     let mut permissions = metadata.permissions();
263     ///
264     ///     permissions.set_mode(0o644); // Read/write for owner and read for others.
265     ///     assert_eq!(permissions.mode(), 0o644);
266     ///     Ok(())
267     /// }
268     /// ```
269     #[stable(feature = "fs_ext", since = "1.1.0")]
270     fn set_mode(&mut self, mode: u32);
271
272     /// Creates a new instance of `Permissions` from the given set of Unix
273     /// permission bits.
274     ///
275     /// # Examples
276     ///
277     /// ```
278     /// use std::fs::Permissions;
279     /// use std::os::unix::fs::PermissionsExt;
280     ///
281     /// // Read/write for owner and read for others.
282     /// let permissions = Permissions::from_mode(0o644);
283     /// assert_eq!(permissions.mode(), 0o644);
284     /// ```
285     #[stable(feature = "fs_ext", since = "1.1.0")]
286     fn from_mode(mode: u32) -> Self;
287 }
288
289 #[stable(feature = "fs_ext", since = "1.1.0")]
290 impl PermissionsExt for Permissions {
291     fn mode(&self) -> u32 {
292         self.as_inner().mode()
293     }
294
295     fn set_mode(&mut self, mode: u32) {
296         *self = Permissions::from_inner(FromInner::from_inner(mode));
297     }
298
299     fn from_mode(mode: u32) -> Permissions {
300         Permissions::from_inner(FromInner::from_inner(mode))
301     }
302 }
303
304 /// Unix-specific extensions to [`fs::OpenOptions`].
305 ///
306 /// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
307 #[stable(feature = "fs_ext", since = "1.1.0")]
308 pub trait OpenOptionsExt {
309     /// Sets the mode bits that a new file will be created with.
310     ///
311     /// If a new file is created as part of an `OpenOptions::open` call then this
312     /// specified `mode` will be used as the permission bits for the new file.
313     /// If no `mode` is set, the default of `0o666` will be used.
314     /// The operating system masks out bits with the system's `umask`, to produce
315     /// the final permissions.
316     ///
317     /// # Examples
318     ///
319     /// ```no_run
320     /// use std::fs::OpenOptions;
321     /// use std::os::unix::fs::OpenOptionsExt;
322     ///
323     /// # fn main() {
324     /// let mut options = OpenOptions::new();
325     /// options.mode(0o644); // Give read/write for owner and read for others.
326     /// let file = options.open("foo.txt");
327     /// # }
328     /// ```
329     #[stable(feature = "fs_ext", since = "1.1.0")]
330     fn mode(&mut self, mode: u32) -> &mut Self;
331
332     /// Pass custom flags to the `flags` argument of `open`.
333     ///
334     /// The bits that define the access mode are masked out with `O_ACCMODE`, to
335     /// ensure they do not interfere with the access mode set by Rusts options.
336     ///
337     /// Custom flags can only set flags, not remove flags set by Rusts options.
338     /// This options overwrites any previously set custom flags.
339     ///
340     /// # Examples
341     ///
342     /// ```no_run
343     /// # #![feature(rustc_private)]
344     /// extern crate libc;
345     /// use std::fs::OpenOptions;
346     /// use std::os::unix::fs::OpenOptionsExt;
347     ///
348     /// # fn main() {
349     /// let mut options = OpenOptions::new();
350     /// options.write(true);
351     /// if cfg!(unix) {
352     ///     options.custom_flags(libc::O_NOFOLLOW);
353     /// }
354     /// let file = options.open("foo.txt");
355     /// # }
356     /// ```
357     #[stable(feature = "open_options_ext", since = "1.10.0")]
358     fn custom_flags(&mut self, flags: i32) -> &mut Self;
359 }
360
361 #[stable(feature = "fs_ext", since = "1.1.0")]
362 impl OpenOptionsExt for OpenOptions {
363     fn mode(&mut self, mode: u32) -> &mut OpenOptions {
364         self.as_inner_mut().mode(mode);
365         self
366     }
367
368     fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
369         self.as_inner_mut().custom_flags(flags);
370         self
371     }
372 }
373
374 /// Unix-specific extensions to [`fs::Metadata`].
375 ///
376 /// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
377 #[stable(feature = "metadata_ext", since = "1.1.0")]
378 pub trait MetadataExt {
379     /// Returns the ID of the device containing the file.
380     ///
381     /// # Examples
382     ///
383     /// ```no_run
384     /// use std::io;
385     /// use std::fs;
386     /// use std::os::unix::fs::MetadataExt;
387     ///
388     /// fn main() -> io::Result<()> {
389     ///     let meta = fs::metadata("some_file")?;
390     ///     let dev_id = meta.dev();
391     ///     Ok(())
392     /// }
393     /// ```
394     #[stable(feature = "metadata_ext", since = "1.1.0")]
395     fn dev(&self) -> u64;
396     /// Returns the inode number.
397     ///
398     /// # Examples
399     ///
400     /// ```no_run
401     /// use std::fs;
402     /// use std::os::unix::fs::MetadataExt;
403     /// use std::io;
404     ///
405     /// fn main() -> io::Result<()> {
406     ///     let meta = fs::metadata("some_file")?;
407     ///     let inode = meta.ino();
408     ///     Ok(())
409     /// }
410     /// ```
411     #[stable(feature = "metadata_ext", since = "1.1.0")]
412     fn ino(&self) -> u64;
413     /// Returns the rights applied to this file.
414     ///
415     /// # Examples
416     ///
417     /// ```no_run
418     /// use std::fs;
419     /// use std::os::unix::fs::MetadataExt;
420     /// use std::io;
421     ///
422     /// fn main() -> io::Result<()> {
423     ///     let meta = fs::metadata("some_file")?;
424     ///     let mode = meta.mode();
425     ///     let user_has_write_access      = mode & 0o200;
426     ///     let user_has_read_write_access = mode & 0o600;
427     ///     let group_has_read_access      = mode & 0o040;
428     ///     let others_have_exec_access    = mode & 0o001;
429     ///     Ok(())
430     /// }
431     /// ```
432     #[stable(feature = "metadata_ext", since = "1.1.0")]
433     fn mode(&self) -> u32;
434     /// Returns the number of hard links pointing to this file.
435     ///
436     /// # Examples
437     ///
438     /// ```no_run
439     /// use std::fs;
440     /// use std::os::unix::fs::MetadataExt;
441     ///  use std::io;
442     ///
443     /// fn main() -> io::Result<()> {
444     ///     let meta = fs::metadata("some_file")?;
445     ///     let nb_hard_links = meta.nlink();
446     ///     Ok(())
447     /// }
448     /// ```
449     #[stable(feature = "metadata_ext", since = "1.1.0")]
450     fn nlink(&self) -> u64;
451     /// Returns the user ID of the owner of this file.
452     ///
453     /// # Examples
454     ///
455     /// ```no_run
456     /// use std::fs;
457     /// use std::os::unix::fs::MetadataExt;
458     /// use std::io;
459     ///
460     /// fn main() -> io::Result<()> {
461     ///     let meta = fs::metadata("some_file")?;
462     ///     let user_id = meta.uid();
463     ///     Ok(())
464     /// }
465     /// ```
466     #[stable(feature = "metadata_ext", since = "1.1.0")]
467     fn uid(&self) -> u32;
468     /// Returns the group ID of the owner of this file.
469     ///
470     /// # Examples
471     ///
472     /// ```no_run
473     /// use std::fs;
474     /// use std::os::unix::fs::MetadataExt;
475     /// use std::io;
476     ///
477     /// fn main() -> io::Result<()> {
478     ///     let meta = fs::metadata("some_file")?;
479     ///     let group_id = meta.gid();
480     ///     Ok(())
481     /// }
482     /// ```
483     #[stable(feature = "metadata_ext", since = "1.1.0")]
484     fn gid(&self) -> u32;
485     /// Returns the device ID of this file (if it is a special one).
486     ///
487     /// # Examples
488     ///
489     /// ```no_run
490     /// use std::fs;
491     /// use std::os::unix::fs::MetadataExt;
492     /// use std::io;
493     ///
494     /// fn main() -> io::Result<()> {
495     ///     let meta = fs::metadata("some_file")?;
496     ///     let device_id = meta.rdev();
497     ///     Ok(())
498     /// }
499     /// ```
500     #[stable(feature = "metadata_ext", since = "1.1.0")]
501     fn rdev(&self) -> u64;
502     /// Returns the total size of this file in bytes.
503     ///
504     /// # Examples
505     ///
506     /// ```no_run
507     /// use std::fs;
508     /// use std::os::unix::fs::MetadataExt;
509     /// use std::io;
510     ///
511     /// fn main() -> io::Result<()> {
512     ///     let meta = fs::metadata("some_file")?;
513     ///     let file_size = meta.size();
514     ///     Ok(())
515     /// }
516     /// ```
517     #[stable(feature = "metadata_ext", since = "1.1.0")]
518     fn size(&self) -> u64;
519     /// Returns the last access time of the file, in seconds since Unix Epoch.
520     ///
521     /// # Examples
522     ///
523     /// ```no_run
524     /// use std::fs;
525     /// use std::os::unix::fs::MetadataExt;
526     /// use std::io;
527     ///
528     /// fn main() -> io::Result<()> {
529     ///     let meta = fs::metadata("some_file")?;
530     ///     let last_access_time = meta.atime();
531     ///     Ok(())
532     /// }
533     /// ```
534     #[stable(feature = "metadata_ext", since = "1.1.0")]
535     fn atime(&self) -> i64;
536     /// Returns the last access time of the file, in nanoseconds since [`atime`].
537     ///
538     /// [`atime`]: #tymethod.atime
539     ///
540     /// # Examples
541     ///
542     /// ```no_run
543     /// use std::fs;
544     /// use std::os::unix::fs::MetadataExt;
545     /// use std::io;
546     ///
547     /// fn main() -> io::Result<()> {
548     ///     let meta = fs::metadata("some_file")?;
549     ///     let nano_last_access_time = meta.atime_nsec();
550     ///     Ok(())
551     /// }
552     /// ```
553     #[stable(feature = "metadata_ext", since = "1.1.0")]
554     fn atime_nsec(&self) -> i64;
555     /// Returns the last modification time of the file, in seconds since Unix Epoch.
556     ///
557     /// # Examples
558     ///
559     /// ```no_run
560     /// use std::fs;
561     /// use std::os::unix::fs::MetadataExt;
562     /// use std::io;
563     ///
564     /// fn main() -> io::Result<()> {
565     ///     let meta = fs::metadata("some_file")?;
566     ///     let last_modification_time = meta.mtime();
567     ///     Ok(())
568     /// }
569     /// ```
570     #[stable(feature = "metadata_ext", since = "1.1.0")]
571     fn mtime(&self) -> i64;
572     /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
573     ///
574     /// [`mtime`]: #tymethod.mtime
575     ///
576     /// # Examples
577     ///
578     /// ```no_run
579     /// use std::fs;
580     /// use std::os::unix::fs::MetadataExt;
581     /// use std::io;
582     ///
583     /// fn main() -> io::Result<()> {
584     ///     let meta = fs::metadata("some_file")?;
585     ///     let nano_last_modification_time = meta.mtime_nsec();
586     ///     Ok(())
587     /// }
588     /// ```
589     #[stable(feature = "metadata_ext", since = "1.1.0")]
590     fn mtime_nsec(&self) -> i64;
591     /// Returns the last status change time of the file, in seconds since Unix Epoch.
592     ///
593     /// # Examples
594     ///
595     /// ```no_run
596     /// use std::fs;
597     /// use std::os::unix::fs::MetadataExt;
598     /// use std::io;
599     ///
600     /// fn main() -> io::Result<()> {
601     ///     let meta = fs::metadata("some_file")?;
602     ///     let last_status_change_time = meta.ctime();
603     ///     Ok(())
604     /// }
605     /// ```
606     #[stable(feature = "metadata_ext", since = "1.1.0")]
607     fn ctime(&self) -> i64;
608     /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
609     ///
610     /// [`ctime`]: #tymethod.ctime
611     ///
612     /// # Examples
613     ///
614     /// ```no_run
615     /// use std::fs;
616     /// use std::os::unix::fs::MetadataExt;
617     /// use std::io;
618     ///
619     /// fn main() -> io::Result<()> {
620     ///     let meta = fs::metadata("some_file")?;
621     ///     let nano_last_status_change_time = meta.ctime_nsec();
622     ///     Ok(())
623     /// }
624     /// ```
625     #[stable(feature = "metadata_ext", since = "1.1.0")]
626     fn ctime_nsec(&self) -> i64;
627     /// Returns the block size for filesystem I/O.
628     ///
629     /// # Examples
630     ///
631     /// ```no_run
632     /// use std::fs;
633     /// use std::os::unix::fs::MetadataExt;
634     /// use std::io;
635     ///
636     /// fn main() -> io::Result<()> {
637     ///     let meta = fs::metadata("some_file")?;
638     ///     let block_size = meta.blksize();
639     ///     Ok(())
640     /// }
641     /// ```
642     #[stable(feature = "metadata_ext", since = "1.1.0")]
643     fn blksize(&self) -> u64;
644     /// Returns the number of blocks allocated to the file, in 512-byte units.
645     ///
646     /// Please note that this may be smaller than `st_size / 512` when the file has holes.
647     ///
648     /// # Examples
649     ///
650     /// ```no_run
651     /// use std::fs;
652     /// use std::os::unix::fs::MetadataExt;
653     /// use std::io;
654     ///
655     /// fn main() -> io::Result<()> {
656     ///     let meta = fs::metadata("some_file")?;
657     ///     let blocks = meta.blocks();
658     ///     Ok(())
659     /// }
660     /// ```
661     #[stable(feature = "metadata_ext", since = "1.1.0")]
662     fn blocks(&self) -> u64;
663 }
664
665 #[stable(feature = "metadata_ext", since = "1.1.0")]
666 impl MetadataExt for fs::Metadata {
667     fn dev(&self) -> u64 {
668         self.st_dev()
669     }
670     fn ino(&self) -> u64 {
671         self.st_ino()
672     }
673     fn mode(&self) -> u32 {
674         self.st_mode()
675     }
676     fn nlink(&self) -> u64 {
677         self.st_nlink()
678     }
679     fn uid(&self) -> u32 {
680         self.st_uid()
681     }
682     fn gid(&self) -> u32 {
683         self.st_gid()
684     }
685     fn rdev(&self) -> u64 {
686         self.st_rdev()
687     }
688     fn size(&self) -> u64 {
689         self.st_size()
690     }
691     fn atime(&self) -> i64 {
692         self.st_atime()
693     }
694     fn atime_nsec(&self) -> i64 {
695         self.st_atime_nsec()
696     }
697     fn mtime(&self) -> i64 {
698         self.st_mtime()
699     }
700     fn mtime_nsec(&self) -> i64 {
701         self.st_mtime_nsec()
702     }
703     fn ctime(&self) -> i64 {
704         self.st_ctime()
705     }
706     fn ctime_nsec(&self) -> i64 {
707         self.st_ctime_nsec()
708     }
709     fn blksize(&self) -> u64 {
710         self.st_blksize()
711     }
712     fn blocks(&self) -> u64 {
713         self.st_blocks()
714     }
715 }
716
717 /// Unix-specific extensions for [`FileType`].
718 ///
719 /// Adds support for special Unix file types such as block/character devices,
720 /// pipes, and sockets.
721 ///
722 /// [`FileType`]: ../../../../std/fs/struct.FileType.html
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 ///
817 /// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html
818 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
819 pub trait DirEntryExt {
820     /// Returns the underlying `d_ino` field in the contained `dirent`
821     /// structure.
822     ///
823     /// # Examples
824     ///
825     /// ```
826     /// use std::fs;
827     /// use std::os::unix::fs::DirEntryExt;
828     ///
829     /// if let Ok(entries) = fs::read_dir(".") {
830     ///     for entry in entries {
831     ///         if let Ok(entry) = entry {
832     ///             // Here, `entry` is a `DirEntry`.
833     ///             println!("{:?}: {}", entry.file_name(), entry.ino());
834     ///         }
835     ///     }
836     /// }
837     /// ```
838     #[stable(feature = "dir_entry_ext", since = "1.1.0")]
839     fn ino(&self) -> u64;
840 }
841
842 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
843 impl DirEntryExt for fs::DirEntry {
844     fn ino(&self) -> u64 {
845         self.as_inner().ino()
846     }
847 }
848
849 /// Creates a new symbolic link on the filesystem.
850 ///
851 /// The `dst` path will be a symbolic link pointing to the `src` path.
852 ///
853 /// # Note
854 ///
855 /// On Windows, you must specify whether a symbolic link points to a file
856 /// or directory. Use `os::windows::fs::symlink_file` to create a
857 /// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
858 /// symbolic link to a directory. Additionally, the process must have
859 /// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
860 /// symbolic link.
861 ///
862 /// # Examples
863 ///
864 /// ```no_run
865 /// use std::os::unix::fs;
866 ///
867 /// fn main() -> std::io::Result<()> {
868 ///     fs::symlink("a.txt", "b.txt")?;
869 ///     Ok(())
870 /// }
871 /// ```
872 #[stable(feature = "symlink", since = "1.1.0")]
873 pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
874     sys::fs::symlink(src.as_ref(), dst.as_ref())
875 }
876
877 /// Unix-specific extensions to [`fs::DirBuilder`].
878 ///
879 /// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
880 #[stable(feature = "dir_builder", since = "1.6.0")]
881 pub trait DirBuilderExt {
882     /// Sets the mode to create new directories with. This option defaults to
883     /// 0o777.
884     ///
885     /// # Examples
886     ///
887     /// ```no_run
888     /// use std::fs::DirBuilder;
889     /// use std::os::unix::fs::DirBuilderExt;
890     ///
891     /// let mut builder = DirBuilder::new();
892     /// builder.mode(0o755);
893     /// ```
894     #[stable(feature = "dir_builder", since = "1.6.0")]
895     fn mode(&mut self, mode: u32) -> &mut Self;
896 }
897
898 #[stable(feature = "dir_builder", since = "1.6.0")]
899 impl DirBuilderExt for fs::DirBuilder {
900     fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
901         self.as_inner_mut().set_mode(mode);
902         self
903     }
904 }