]> git.lizzy.rs Git - rust.git/blob - src/libstd/fs.rs
Links and punctionaction fixes.
[rust.git] / src / libstd / fs.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Filesystem manipulation operations
12 //!
13 //! This module contains basic methods to manipulate the contents of the local
14 //! filesystem. All methods in this module represent cross-platform filesystem
15 //! operations. Extra platform-specific functionality can be found in the
16 //! extension traits of `std::os::$platform`.
17
18 #![stable(feature = "rust1", since = "1.0.0")]
19
20 use fmt;
21 use ffi::OsString;
22 use io::{self, SeekFrom, Seek, Read, Write};
23 use path::{Path, PathBuf};
24 use sys::fs as fs_imp;
25 use sys_common::io::read_to_end_uninitialized;
26 use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner};
27 use vec::Vec;
28
29 /// A reference to an open file on the filesystem.
30 ///
31 /// An instance of a `File` can be read and/or written depending on what options
32 /// it was opened with. Files also implement `Seek` to alter the logical cursor
33 /// that the file contains internally.
34 ///
35 /// # Examples
36 ///
37 /// ```no_run
38 /// use std::io::prelude::*;
39 /// use std::fs::File;
40 ///
41 /// # fn foo() -> std::io::Result<()> {
42 /// let mut f = try!(File::create("foo.txt"));
43 /// try!(f.write_all(b"Hello, world!"));
44 ///
45 /// let mut f = try!(File::open("foo.txt"));
46 /// let mut s = String::new();
47 /// try!(f.read_to_string(&mut s));
48 /// assert_eq!(s, "Hello, world!");
49 /// # Ok(())
50 /// # }
51 /// ```
52 #[stable(feature = "rust1", since = "1.0.0")]
53 pub struct File {
54     inner: fs_imp::File,
55 }
56
57 /// Metadata information about a file.
58 ///
59 /// This structure is returned from the `metadata` function or method and
60 /// represents known metadata about a file such as its permissions, size,
61 /// modification times, etc.
62 #[stable(feature = "rust1", since = "1.0.0")]
63 #[derive(Clone)]
64 pub struct Metadata(fs_imp::FileAttr);
65
66 /// Iterator over the entries in a directory.
67 ///
68 /// This iterator is returned from the `read_dir` function of this module and
69 /// will yield instances of `io::Result<DirEntry>`. Through a `DirEntry`
70 /// information like the entry's path and possibly other metadata can be
71 /// learned.
72 ///
73 /// # Failure
74 ///
75 /// This `io::Result` will be an `Err` if there's some sort of intermittent
76 /// IO error during iteration.
77 #[stable(feature = "rust1", since = "1.0.0")]
78 pub struct ReadDir(fs_imp::ReadDir);
79
80 /// Entries returned by the `ReadDir` iterator.
81 ///
82 /// An instance of `DirEntry` represents an entry inside of a directory on the
83 /// filesystem. Each entry can be inspected via methods to learn about the full
84 /// path or possibly other metadata through per-platform extension traits.
85 #[stable(feature = "rust1", since = "1.0.0")]
86 pub struct DirEntry(fs_imp::DirEntry);
87
88 /// An iterator that recursively walks over the contents of a directory.
89 #[unstable(feature = "fs_walk",
90            reason = "the precise semantics and defaults for a recursive walk \
91                      may change and this may end up accounting for files such \
92                      as symlinks differently",
93            issue = "27707")]
94 #[rustc_deprecated(reason = "superceded by the walkdir crate",
95                    since = "1.6.0")]
96 pub struct WalkDir {
97     cur: Option<ReadDir>,
98     stack: Vec<io::Result<ReadDir>>,
99 }
100
101 /// Options and flags which can be used to configure how a file is opened.
102 ///
103 /// This builder exposes the ability to configure how a `File` is opened and
104 /// what operations are permitted on the open file. The `File::open` and
105 /// `File::create` methods are aliases for commonly used options using this
106 /// builder.
107 ///
108 /// Generally speaking, when using `OpenOptions`, you'll first call `new()`,
109 /// then chain calls to methods to set each option, then call `open()`, passing
110 /// the path of the file you're trying to open. This will give you a
111 /// [`io::Result`][result] with a [`File`][file] inside that you can further
112 /// operate on.
113 ///
114 /// [result]: ../io/type.Result.html
115 /// [file]: struct.File.html
116 ///
117 /// # Examples
118 ///
119 /// Opening a file to read:
120 ///
121 /// ```no_run
122 /// use std::fs::OpenOptions;
123 ///
124 /// let file = OpenOptions::new().read(true).open("foo.txt");
125 /// ```
126 ///
127 /// Opening a file for both reading and writing, as well as creating it if it
128 /// doesn't exist:
129 ///
130 /// ```no_run
131 /// use std::fs::OpenOptions;
132 ///
133 /// let file = OpenOptions::new()
134 ///             .read(true)
135 ///             .write(true)
136 ///             .create(true)
137 ///             .open("foo.txt");
138 /// ```
139 #[derive(Clone)]
140 #[stable(feature = "rust1", since = "1.0.0")]
141 pub struct OpenOptions(fs_imp::OpenOptions);
142
143 /// Representation of the various permissions on a file.
144 ///
145 /// This module only currently provides one bit of information, `readonly`,
146 /// which is exposed on all currently supported platforms. Unix-specific
147 /// functionality, such as mode bits, is available through the
148 /// `os::unix::PermissionsExt` trait.
149 #[derive(Clone, PartialEq, Eq, Debug)]
150 #[stable(feature = "rust1", since = "1.0.0")]
151 pub struct Permissions(fs_imp::FilePermissions);
152
153 /// An structure representing a type of file with accessors for each file type.
154 #[stable(feature = "file_type", since = "1.1.0")]
155 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
156 pub struct FileType(fs_imp::FileType);
157
158 /// A builder used to create directories in various manners.
159 ///
160 /// This builder also supports platform-specific options.
161 #[stable(feature = "dir_builder", since = "1.6.0")]
162 pub struct DirBuilder {
163     inner: fs_imp::DirBuilder,
164     recursive: bool,
165 }
166
167 impl File {
168     /// Attempts to open a file in read-only mode.
169     ///
170     /// See the `OpenOptions::open` method for more details.
171     ///
172     /// # Errors
173     ///
174     /// This function will return an error if `path` does not already exist.
175     /// Other errors may also be returned according to `OpenOptions::open`.
176     ///
177     /// # Examples
178     ///
179     /// ```no_run
180     /// use std::fs::File;
181     ///
182     /// # fn foo() -> std::io::Result<()> {
183     /// let mut f = try!(File::open("foo.txt"));
184     /// # Ok(())
185     /// # }
186     /// ```
187     #[stable(feature = "rust1", since = "1.0.0")]
188     pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
189         OpenOptions::new().read(true).open(path.as_ref())
190     }
191
192     /// Opens a file in write-only mode.
193     ///
194     /// This function will create a file if it does not exist,
195     /// and will truncate it if it does.
196     ///
197     /// See the `OpenOptions::open` function for more details.
198     ///
199     /// # Examples
200     ///
201     /// ```no_run
202     /// use std::fs::File;
203     ///
204     /// # fn foo() -> std::io::Result<()> {
205     /// let mut f = try!(File::create("foo.txt"));
206     /// # Ok(())
207     /// # }
208     /// ```
209     #[stable(feature = "rust1", since = "1.0.0")]
210     pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
211         OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
212     }
213
214     /// Attempts to sync all OS-internal metadata to disk.
215     ///
216     /// This function will attempt to ensure that all in-core data reaches the
217     /// filesystem before returning.
218     ///
219     /// # Examples
220     ///
221     /// ```no_run
222     /// use std::fs::File;
223     /// use std::io::prelude::*;
224     ///
225     /// # fn foo() -> std::io::Result<()> {
226     /// let mut f = try!(File::create("foo.txt"));
227     /// try!(f.write_all(b"Hello, world!"));
228     ///
229     /// try!(f.sync_all());
230     /// # Ok(())
231     /// # }
232     /// ```
233     #[stable(feature = "rust1", since = "1.0.0")]
234     pub fn sync_all(&self) -> io::Result<()> {
235         self.inner.fsync()
236     }
237
238     /// This function is similar to `sync_all`, except that it may not
239     /// synchronize file metadata to the filesystem.
240     ///
241     /// This is intended for use cases that must synchronize content, but don't
242     /// need the metadata on disk. The goal of this method is to reduce disk
243     /// operations.
244     ///
245     /// Note that some platforms may simply implement this in terms of
246     /// `sync_all`.
247     ///
248     /// # Examples
249     ///
250     /// ```no_run
251     /// use std::fs::File;
252     /// use std::io::prelude::*;
253     ///
254     /// # fn foo() -> std::io::Result<()> {
255     /// let mut f = try!(File::create("foo.txt"));
256     /// try!(f.write_all(b"Hello, world!"));
257     ///
258     /// try!(f.sync_data());
259     /// # Ok(())
260     /// # }
261     /// ```
262     #[stable(feature = "rust1", since = "1.0.0")]
263     pub fn sync_data(&self) -> io::Result<()> {
264         self.inner.datasync()
265     }
266
267     /// Truncates or extends the underlying file, updating the size of
268     /// this file to become `size`.
269     ///
270     /// If the `size` is less than the current file's size, then the file will
271     /// be shrunk. If it is greater than the current file's size, then the file
272     /// will be extended to `size` and have all of the intermediate data filled
273     /// in with 0s.
274     ///
275     /// # Errors
276     ///
277     /// This function will return an error if the file is not opened for writing.
278     ///
279     /// # Examples
280     ///
281     /// ```no_run
282     /// use std::fs::File;
283     ///
284     /// # fn foo() -> std::io::Result<()> {
285     /// let mut f = try!(File::create("foo.txt"));
286     /// try!(f.set_len(10));
287     /// # Ok(())
288     /// # }
289     /// ```
290     #[stable(feature = "rust1", since = "1.0.0")]
291     pub fn set_len(&self, size: u64) -> io::Result<()> {
292         self.inner.truncate(size)
293     }
294
295     /// Queries metadata about the underlying file.
296     ///
297     /// # Examples
298     ///
299     /// ```no_run
300     /// use std::fs::File;
301     ///
302     /// # fn foo() -> std::io::Result<()> {
303     /// let mut f = try!(File::open("foo.txt"));
304     /// let metadata = try!(f.metadata());
305     /// # Ok(())
306     /// # }
307     /// ```
308     #[stable(feature = "rust1", since = "1.0.0")]
309     pub fn metadata(&self) -> io::Result<Metadata> {
310         self.inner.file_attr().map(Metadata)
311     }
312 }
313
314 impl AsInner<fs_imp::File> for File {
315     fn as_inner(&self) -> &fs_imp::File { &self.inner }
316 }
317 impl FromInner<fs_imp::File> for File {
318     fn from_inner(f: fs_imp::File) -> File {
319         File { inner: f }
320     }
321 }
322 impl IntoInner<fs_imp::File> for File {
323     fn into_inner(self) -> fs_imp::File {
324         self.inner
325     }
326 }
327
328 #[stable(feature = "rust1", since = "1.0.0")]
329 impl fmt::Debug for File {
330     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
331         self.inner.fmt(f)
332     }
333 }
334
335 #[stable(feature = "rust1", since = "1.0.0")]
336 impl Read for File {
337     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
338         self.inner.read(buf)
339     }
340     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
341         unsafe { read_to_end_uninitialized(self, buf) }
342     }
343 }
344 #[stable(feature = "rust1", since = "1.0.0")]
345 impl Write for File {
346     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
347         self.inner.write(buf)
348     }
349     fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
350 }
351 #[stable(feature = "rust1", since = "1.0.0")]
352 impl Seek for File {
353     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
354         self.inner.seek(pos)
355     }
356 }
357 #[stable(feature = "rust1", since = "1.0.0")]
358 impl<'a> Read for &'a File {
359     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
360         self.inner.read(buf)
361     }
362 }
363 #[stable(feature = "rust1", since = "1.0.0")]
364 impl<'a> Write for &'a File {
365     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
366         self.inner.write(buf)
367     }
368     fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
369 }
370 #[stable(feature = "rust1", since = "1.0.0")]
371 impl<'a> Seek for &'a File {
372     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
373         self.inner.seek(pos)
374     }
375 }
376
377 impl OpenOptions {
378     /// Creates a blank net set of options ready for configuration.
379     ///
380     /// All options are initially set to `false`.
381     ///
382     /// # Examples
383     ///
384     /// ```no_run
385     /// use std::fs::OpenOptions;
386     ///
387     /// let file = OpenOptions::new().open("foo.txt");
388     /// ```
389     #[stable(feature = "rust1", since = "1.0.0")]
390     pub fn new() -> OpenOptions {
391         OpenOptions(fs_imp::OpenOptions::new())
392     }
393
394     /// Sets the option for read access.
395     ///
396     /// This option, when true, will indicate that the file should be
397     /// `read`-able if opened.
398     ///
399     /// # Examples
400     ///
401     /// ```no_run
402     /// use std::fs::OpenOptions;
403     ///
404     /// let file = OpenOptions::new().read(true).open("foo.txt");
405     /// ```
406     #[stable(feature = "rust1", since = "1.0.0")]
407     pub fn read(&mut self, read: bool) -> &mut OpenOptions {
408         self.0.read(read); self
409     }
410
411     /// Sets the option for write access.
412     ///
413     /// This option, when true, will indicate that the file should be
414     /// `write`-able if opened.
415     ///
416     /// # Examples
417     ///
418     /// ```no_run
419     /// use std::fs::OpenOptions;
420     ///
421     /// let file = OpenOptions::new().write(true).open("foo.txt");
422     /// ```
423     #[stable(feature = "rust1", since = "1.0.0")]
424     pub fn write(&mut self, write: bool) -> &mut OpenOptions {
425         self.0.write(write); self
426     }
427
428     /// Sets the option for the append mode.
429     ///
430     /// This option, when true, means that writes will append to a file instead
431     /// of overwriting previous contents.
432     ///
433     /// # Examples
434     ///
435     /// ```no_run
436     /// use std::fs::OpenOptions;
437     ///
438     /// let file = OpenOptions::new().write(true).append(true).open("foo.txt");
439     /// ```
440     #[stable(feature = "rust1", since = "1.0.0")]
441     pub fn append(&mut self, append: bool) -> &mut OpenOptions {
442         self.0.append(append); self
443     }
444
445     /// Sets the option for truncating a previous file.
446     ///
447     /// If a file is successfully opened with this option set it will truncate
448     /// the file to 0 length if it already exists.
449     ///
450     /// # Examples
451     ///
452     /// ```no_run
453     /// use std::fs::OpenOptions;
454     ///
455     /// let file = OpenOptions::new().write(true).truncate(true).open("foo.txt");
456     /// ```
457     #[stable(feature = "rust1", since = "1.0.0")]
458     pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
459         self.0.truncate(truncate); self
460     }
461
462     /// Sets the option for creating a new file.
463     ///
464     /// This option indicates whether a new file will be created if the file
465     /// does not yet already exist.
466     ///
467     /// # Examples
468     ///
469     /// ```no_run
470     /// use std::fs::OpenOptions;
471     ///
472     /// let file = OpenOptions::new().create(true).open("foo.txt");
473     /// ```
474     #[stable(feature = "rust1", since = "1.0.0")]
475     pub fn create(&mut self, create: bool) -> &mut OpenOptions {
476         self.0.create(create); self
477     }
478
479     /// Opens a file at `path` with the options specified by `self`.
480     ///
481     /// # Errors
482     ///
483     /// This function will return an error under a number of different
484     /// circumstances, to include but not limited to:
485     ///
486     /// * Opening a file that does not exist with read access.
487     /// * Attempting to open a file with access that the user lacks
488     ///   permissions for
489     /// * Filesystem-level errors (full disk, etc)
490     ///
491     /// # Examples
492     ///
493     /// ```no_run
494     /// use std::fs::OpenOptions;
495     ///
496     /// let file = OpenOptions::new().open("foo.txt");
497     /// ```
498     #[stable(feature = "rust1", since = "1.0.0")]
499     pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
500         self._open(path.as_ref())
501     }
502
503     fn _open(&self, path: &Path) -> io::Result<File> {
504         let inner = try!(fs_imp::File::open(path, &self.0));
505         Ok(File { inner: inner })
506     }
507 }
508
509 impl AsInnerMut<fs_imp::OpenOptions> for OpenOptions {
510     fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 }
511 }
512
513 impl Metadata {
514     /// Returns the file type for this metadata.
515     #[stable(feature = "file_type", since = "1.1.0")]
516     pub fn file_type(&self) -> FileType {
517         FileType(self.0.file_type())
518     }
519
520     /// Returns whether this metadata is for a directory.
521     ///
522     /// # Examples
523     ///
524     /// ```
525     /// # fn foo() -> std::io::Result<()> {
526     /// use std::fs;
527     ///
528     /// let metadata = try!(fs::metadata("foo.txt"));
529     ///
530     /// assert!(!metadata.is_dir());
531     /// # Ok(())
532     /// # }
533     /// ```
534     #[stable(feature = "rust1", since = "1.0.0")]
535     pub fn is_dir(&self) -> bool { self.file_type().is_dir() }
536
537     /// Returns whether this metadata is for a regular file.
538     ///
539     /// # Examples
540     ///
541     /// ```
542     /// # fn foo() -> std::io::Result<()> {
543     /// use std::fs;
544     ///
545     /// let metadata = try!(fs::metadata("foo.txt"));
546     ///
547     /// assert!(metadata.is_file());
548     /// # Ok(())
549     /// # }
550     /// ```
551     #[stable(feature = "rust1", since = "1.0.0")]
552     pub fn is_file(&self) -> bool { self.file_type().is_file() }
553
554     /// Returns the size of the file, in bytes, this metadata is for.
555     ///
556     /// # Examples
557     ///
558     /// ```
559     /// # fn foo() -> std::io::Result<()> {
560     /// use std::fs;
561     ///
562     /// let metadata = try!(fs::metadata("foo.txt"));
563     ///
564     /// assert_eq!(0, metadata.len());
565     /// # Ok(())
566     /// # }
567     /// ```
568     #[stable(feature = "rust1", since = "1.0.0")]
569     pub fn len(&self) -> u64 { self.0.size() }
570
571     /// Returns the permissions of the file this metadata is for.
572     ///
573     /// # Examples
574     ///
575     /// ```
576     /// # fn foo() -> std::io::Result<()> {
577     /// use std::fs;
578     ///
579     /// let metadata = try!(fs::metadata("foo.txt"));
580     ///
581     /// assert!(!metadata.permissions().readonly());
582     /// # Ok(())
583     /// # }
584     /// ```
585     #[stable(feature = "rust1", since = "1.0.0")]
586     pub fn permissions(&self) -> Permissions {
587         Permissions(self.0.perm())
588     }
589 }
590
591 impl AsInner<fs_imp::FileAttr> for Metadata {
592     fn as_inner(&self) -> &fs_imp::FileAttr { &self.0 }
593 }
594
595 impl Permissions {
596     /// Returns whether these permissions describe a readonly file.
597     ///
598     /// # Examples
599     ///
600     /// ```
601     /// use std::fs::File;
602     ///
603     /// # fn foo() -> std::io::Result<()> {
604     /// let mut f = try!(File::create("foo.txt"));
605     /// let metadata = try!(f.metadata());
606     ///
607     /// assert_eq!(false, metadata.permissions().readonly());
608     /// # Ok(())
609     /// # }
610     /// ```
611     #[stable(feature = "rust1", since = "1.0.0")]
612     pub fn readonly(&self) -> bool { self.0.readonly() }
613
614     /// Modifies the readonly flag for this set of permissions.
615     ///
616     /// This operation does **not** modify the filesystem. To modify the
617     /// filesystem use the `fs::set_permissions` function.
618     ///
619     /// # Examples
620     ///
621     /// ```
622     /// use std::fs::File;
623     ///
624     /// # fn foo() -> std::io::Result<()> {
625     /// let f = try!(File::create("foo.txt"));
626     /// let metadata = try!(f.metadata());
627     /// let mut permissions = metadata.permissions();
628     ///
629     /// permissions.set_readonly(true);
630     ///
631     /// // filesystem doesn't change
632     /// assert_eq!(false, metadata.permissions().readonly());
633     ///
634     /// // just this particular `permissions`.
635     /// assert_eq!(true, permissions.readonly());
636     /// # Ok(())
637     /// # }
638     /// ```
639     #[stable(feature = "rust1", since = "1.0.0")]
640     pub fn set_readonly(&mut self, readonly: bool) {
641         self.0.set_readonly(readonly)
642     }
643 }
644
645 impl FileType {
646     /// Test whether this file type represents a directory.
647     #[stable(feature = "file_type", since = "1.1.0")]
648     pub fn is_dir(&self) -> bool { self.0.is_dir() }
649
650     /// Test whether this file type represents a regular file.
651     #[stable(feature = "file_type", since = "1.1.0")]
652     pub fn is_file(&self) -> bool { self.0.is_file() }
653
654     /// Test whether this file type represents a symbolic link.
655     #[stable(feature = "file_type", since = "1.1.0")]
656     pub fn is_symlink(&self) -> bool { self.0.is_symlink() }
657 }
658
659 impl AsInner<fs_imp::FileType> for FileType {
660     fn as_inner(&self) -> &fs_imp::FileType { &self.0 }
661 }
662
663 impl FromInner<fs_imp::FilePermissions> for Permissions {
664     fn from_inner(f: fs_imp::FilePermissions) -> Permissions {
665         Permissions(f)
666     }
667 }
668
669 impl AsInner<fs_imp::FilePermissions> for Permissions {
670     fn as_inner(&self) -> &fs_imp::FilePermissions { &self.0 }
671 }
672
673 #[stable(feature = "rust1", since = "1.0.0")]
674 impl Iterator for ReadDir {
675     type Item = io::Result<DirEntry>;
676
677     fn next(&mut self) -> Option<io::Result<DirEntry>> {
678         self.0.next().map(|entry| entry.map(DirEntry))
679     }
680 }
681
682 impl DirEntry {
683     /// Returns the full path to the file that this entry represents.
684     ///
685     /// The full path is created by joining the original path to `read_dir` or
686     /// `walk_dir` with the filename of this entry.
687     ///
688     /// # Examples
689     ///
690     /// ```
691     /// use std::fs;
692     /// # fn foo() -> std::io::Result<()> {
693     /// for entry in try!(fs::read_dir(".")) {
694     ///     let dir = try!(entry);
695     ///     println!("{:?}", dir.path());
696     /// }
697     /// # Ok(())
698     /// # }
699     /// ```
700     ///
701     /// This prints output like:
702     ///
703     /// ```text
704     /// "./whatever.txt"
705     /// "./foo.html"
706     /// "./hello_world.rs"
707     /// ```
708     ///
709     /// The exact text, of course, depends on what files you have in `.`.
710     #[stable(feature = "rust1", since = "1.0.0")]
711     pub fn path(&self) -> PathBuf { self.0.path() }
712
713     /// Return the metadata for the file that this entry points at.
714     ///
715     /// This function will not traverse symlinks if this entry points at a
716     /// symlink.
717     ///
718     /// # Platform behavior
719     ///
720     /// On Windows this function is cheap to call (no extra system calls
721     /// needed), but on Unix platforms this function is the equivalent of
722     /// calling `symlink_metadata` on the path.
723     #[stable(feature = "dir_entry_ext", since = "1.1.0")]
724     pub fn metadata(&self) -> io::Result<Metadata> {
725         self.0.metadata().map(Metadata)
726     }
727
728     /// Return the file type for the file that this entry points at.
729     ///
730     /// This function will not traverse symlinks if this entry points at a
731     /// symlink.
732     ///
733     /// # Platform behavior
734     ///
735     /// On Windows and most Unix platforms this function is free (no extra
736     /// system calls needed), but some Unix platforms may require the equivalent
737     /// call to `symlink_metadata` to learn about the target file type.
738     #[stable(feature = "dir_entry_ext", since = "1.1.0")]
739     pub fn file_type(&self) -> io::Result<FileType> {
740         self.0.file_type().map(FileType)
741     }
742
743     /// Returns the bare file name of this directory entry without any other
744     /// leading path component.
745     #[stable(feature = "dir_entry_ext", since = "1.1.0")]
746     pub fn file_name(&self) -> OsString {
747         self.0.file_name()
748     }
749 }
750
751 impl AsInner<fs_imp::DirEntry> for DirEntry {
752     fn as_inner(&self) -> &fs_imp::DirEntry { &self.0 }
753 }
754
755 /// Removes a file from the filesystem.
756 ///
757 /// Note that there is no
758 /// guarantee that the file is immediately deleted (e.g. depending on
759 /// platform, other open file descriptors may prevent immediate removal).
760 ///
761 /// # Platform behavior
762 ///
763 /// This function currently corresponds to the `unlink` function on Unix
764 /// and the `DeleteFile` function on Windows.
765 /// Note that, this [may change in the future][changes].
766 /// [changes]: https://github.com/rust-lang/rust/pull/28613
767 ///
768 /// # Errors
769 ///
770 /// This function will return an error in the following situations, but is not
771 /// limited to just these cases:
772 ///
773 /// * `path` points to a directory.
774 /// * The user lacks permissions to remove the file.
775 ///
776 /// # Examples
777 ///
778 /// ```
779 /// use std::fs;
780 ///
781 /// # fn foo() -> std::io::Result<()> {
782 /// try!(fs::remove_file("a.txt"));
783 /// # Ok(())
784 /// # }
785 /// ```
786 #[stable(feature = "rust1", since = "1.0.0")]
787 pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
788     fs_imp::unlink(path.as_ref())
789 }
790
791 /// Given a path, query the file system to get information about a file,
792 /// directory, etc.
793 ///
794 /// This function will traverse symbolic links to query information about the
795 /// destination file.
796 ///
797 /// # Platform behavior
798 ///
799 /// This function currently corresponds to the `stat` function on Unix
800 /// and the `GetFileAttributesEx` function on Windows.
801 /// Note that, this [may change in the future][changes].
802 /// [changes]: https://github.com/rust-lang/rust/pull/28613
803 ///
804 /// # Errors
805 ///
806 /// This function will return an error in the following situations, but is not
807 /// limited to just these cases:
808 ///
809 /// * The user lacks permissions to perform `metadata` call on `path`.
810 /// * `path` does not exist.
811 ///
812 /// # Examples
813 ///
814 /// ```rust
815 /// # fn foo() -> std::io::Result<()> {
816 /// use std::fs;
817 ///
818 /// let attr = try!(fs::metadata("/some/file/path.txt"));
819 /// // inspect attr ...
820 /// # Ok(())
821 /// # }
822 /// ```
823 #[stable(feature = "rust1", since = "1.0.0")]
824 pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
825     fs_imp::stat(path.as_ref()).map(Metadata)
826 }
827
828 /// Query the metadata about a file without following symlinks.
829 ///
830 /// # Platform behavior
831 ///
832 /// This function currently corresponds to the `lstat` function on Unix
833 /// and the `GetFileAttributesEx` function on Windows.
834 /// Note that, this [may change in the future][changes].
835 /// [changes]: https://github.com/rust-lang/rust/pull/28613
836 ///
837 /// # Errors
838 ///
839 /// This function will return an error in the following situations, but is not
840 /// limited to just these cases:
841 ///
842 /// * The user lacks permissions to perform `metadata` call on `path`.
843 /// * `path` does not exist.
844 ///
845 /// # Examples
846 ///
847 /// ```rust
848 /// # fn foo() -> std::io::Result<()> {
849 /// use std::fs;
850 ///
851 /// let attr = try!(fs::symlink_metadata("/some/file/path.txt"));
852 /// // inspect attr ...
853 /// # Ok(())
854 /// # }
855 /// ```
856 #[stable(feature = "symlink_metadata", since = "1.1.0")]
857 pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
858     fs_imp::lstat(path.as_ref()).map(Metadata)
859 }
860
861 /// Rename a file or directory to a new name.
862 ///
863 /// This will not work if the new name is on a different mount point.
864 ///
865 /// # Platform behavior
866 ///
867 /// This function currently corresponds to the `rename` function on Unix
868 /// and the `MoveFileEx` function with the `MOVEFILE_REPLACE_EXISTING` flag on Windows.
869 /// Note that, this [may change in the future][changes].
870 /// [changes]: https://github.com/rust-lang/rust/pull/28613
871 ///
872 /// # Errors
873 ///
874 /// This function will return an error in the following situations, but is not
875 /// limited to just these cases:
876 ///
877 /// * `from` does not exist.
878 /// * The user lacks permissions to view contents.
879 /// * `from` and `to` are on separate filesystems.
880 ///
881 /// # Examples
882 ///
883 /// ```
884 /// use std::fs;
885 ///
886 /// # fn foo() -> std::io::Result<()> {
887 /// try!(fs::rename("a.txt", "b.txt")); // Rename a.txt to b.txt
888 /// # Ok(())
889 /// # }
890 /// ```
891 #[stable(feature = "rust1", since = "1.0.0")]
892 pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
893     fs_imp::rename(from.as_ref(), to.as_ref())
894 }
895
896 /// Copies the contents of one file to another. This function will also
897 /// copy the permission bits of the original file to the destination file.
898 ///
899 /// This function will **overwrite** the contents of `to`.
900 ///
901 /// Note that if `from` and `to` both point to the same file, then the file
902 /// will likely get truncated by this operation.
903 ///
904 /// On success, the total number of bytes copied is returned.
905 ///
906 /// # Platform behavior
907 ///
908 /// This function currently corresponds to the `open` function in Unix
909 /// with `O_RDONLY` for `from` and `O_WRONLY`, `O_CREAT`, and `O_TRUNC` for `to`.
910 /// `O_CLOEXEC` is set for returned file descriptors.
911 /// On Windows, this function currently corresponds to `CopyFileEx`.
912 /// Note that, this [may change in the future][changes].
913 /// [changes]: https://github.com/rust-lang/rust/pull/28613
914 ///
915 /// # Errors
916 ///
917 /// This function will return an error in the following situations, but is not
918 /// limited to just these cases:
919 ///
920 /// * The `from` path is not a file.
921 /// * The `from` file does not exist.
922 /// * The current process does not have the permission rights to access
923 ///   `from` or write `to`.
924 ///
925 /// # Examples
926 ///
927 /// ```no_run
928 /// use std::fs;
929 ///
930 /// # fn foo() -> std::io::Result<()> {
931 /// try!(fs::copy("foo.txt", "bar.txt"));  // Copy foo.txt to bar.txt
932 /// # Ok(()) }
933 /// ```
934 #[stable(feature = "rust1", since = "1.0.0")]
935 pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
936     fs_imp::copy(from.as_ref(), to.as_ref())
937 }
938
939 /// Creates a new hard link on the filesystem.
940 ///
941 /// The `dst` path will be a link pointing to the `src` path. Note that systems
942 /// often require these two paths to both be located on the same filesystem.
943 ///
944 /// # Platform behavior
945 ///
946 /// This function currently corresponds to the `link` function on Unix
947 /// and the `CreateHardLink` function on Windows.
948 /// Note that, this [may change in the future][changes].
949 /// [changes]: https://github.com/rust-lang/rust/pull/28613
950 ///
951 /// # Errors
952 ///
953 /// This function will return an error in the following situations, but is not
954 /// limited to just these cases:
955 ///
956 /// * The `src` path is not a file or doesn't exist.
957 ///
958 /// # Examples
959 ///
960 /// ```
961 /// use std::fs;
962 ///
963 /// # fn foo() -> std::io::Result<()> {
964 /// try!(fs::hard_link("a.txt", "b.txt")); // Hard link a.txt to b.txt
965 /// # Ok(())
966 /// # }
967 /// ```
968 #[stable(feature = "rust1", since = "1.0.0")]
969 pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
970     fs_imp::link(src.as_ref(), dst.as_ref())
971 }
972
973 /// Creates a new symbolic link on the filesystem.
974 ///
975 /// The `dst` path will be a symbolic link pointing to the `src` path.
976 /// On Windows, this will be a file symlink, not a directory symlink;
977 /// for this reason, the platform-specific `std::os::unix::fs::symlink`
978 /// and `std::os::windows::fs::{symlink_file, symlink_dir}` should be
979 /// used instead to make the intent explicit.
980 ///
981 /// # Examples
982 ///
983 /// ```
984 /// use std::fs;
985 ///
986 /// # fn foo() -> std::io::Result<()> {
987 /// try!(fs::soft_link("a.txt", "b.txt"));
988 /// # Ok(())
989 /// # }
990 /// ```
991 #[stable(feature = "rust1", since = "1.0.0")]
992 #[rustc_deprecated(since = "1.1.0",
993              reason = "replaced with std::os::unix::fs::symlink and \
994                        std::os::windows::fs::{symlink_file, symlink_dir}")]
995 pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
996     fs_imp::symlink(src.as_ref(), dst.as_ref())
997 }
998
999 /// Reads a symbolic link, returning the file that the link points to.
1000 ///
1001 /// # Platform behavior
1002 ///
1003 /// This function currently corresponds to the `readlink` function on Unix
1004 /// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and
1005 /// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows.
1006 /// Note that, this [may change in the future][changes].
1007 /// [changes]: https://github.com/rust-lang/rust/pull/28613
1008 ///
1009 /// # Errors
1010 ///
1011 /// This function will return an error in the following situations, but is not
1012 /// limited to just these cases:
1013 ///
1014 /// * `path` is not a symbolic link.
1015 /// * `path` does not exist.
1016 ///
1017 /// # Examples
1018 ///
1019 /// ```
1020 /// use std::fs;
1021 ///
1022 /// # fn foo() -> std::io::Result<()> {
1023 /// let path = try!(fs::read_link("a.txt"));
1024 /// # Ok(())
1025 /// # }
1026 /// ```
1027 #[stable(feature = "rust1", since = "1.0.0")]
1028 pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
1029     fs_imp::readlink(path.as_ref())
1030 }
1031
1032 /// Returns the canonical form of a path with all intermediate components
1033 /// normalized and symbolic links resolved.
1034 ///
1035 /// # Platform behavior
1036 ///
1037 /// This function currently corresponds to the `realpath` function on Unix
1038 /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows.
1039 /// Note that, this [may change in the future][changes].
1040 /// [changes]: https://github.com/rust-lang/rust/pull/28613
1041 ///
1042 /// # Errors
1043 ///
1044 /// This function will return an error in the following situations, but is not
1045 /// limited to just these cases:
1046 ///
1047 /// * `path` does not exist.
1048 /// * A component in path is not a directory.
1049 ///
1050 /// # Examples
1051 ///
1052 /// ```
1053 /// use std::fs;
1054 ///
1055 /// # fn foo() -> std::io::Result<()> {
1056 /// let path = try!(fs::canonicalize("../a/../foo.txt"));
1057 /// # Ok(())
1058 /// # }
1059 /// ```
1060 #[stable(feature = "fs_canonicalize", since = "1.5.0")]
1061 pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
1062     fs_imp::canonicalize(path.as_ref())
1063 }
1064
1065 /// Creates a new, empty directory at the provided path
1066 ///
1067 /// # Platform behavior
1068 ///
1069 /// This function currently corresponds to the `mkdir` function on Unix
1070 /// and the `CreateDirectory` function on Windows.
1071 /// Note that, this [may change in the future][changes].
1072 /// [changes]: https://github.com/rust-lang/rust/pull/28613
1073 ///
1074 /// # Errors
1075 ///
1076 /// This function will return an error in the following situations, but is not
1077 /// limited to just these cases:
1078 ///
1079 /// * User lacks permissions to create directory at `path`.
1080 /// * `path` already exists.
1081 ///
1082 /// # Examples
1083 ///
1084 /// ```
1085 /// use std::fs;
1086 ///
1087 /// # fn foo() -> std::io::Result<()> {
1088 /// try!(fs::create_dir("/some/dir"));
1089 /// # Ok(())
1090 /// # }
1091 /// ```
1092 #[stable(feature = "rust1", since = "1.0.0")]
1093 pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
1094     DirBuilder::new().create(path.as_ref())
1095 }
1096
1097 /// Recursively create a directory and all of its parent components if they
1098 /// are missing.
1099 ///
1100 /// # Platform behavior
1101 ///
1102 /// This function currently corresponds to the `mkdir` function on Unix
1103 /// and the `CreateDirectory` function on Windows.
1104 /// Note that, this [may change in the future][changes].
1105 /// [changes]: https://github.com/rust-lang/rust/pull/28613
1106 ///
1107 /// # Errors
1108 ///
1109 /// This function will return an error in the following situations, but is not
1110 /// limited to just these cases:
1111 ///
1112 /// * If any directory in the path specified by `path`
1113 /// does not already exist and it could not be created otherwise. The specific
1114 /// error conditions for when a directory is being created (after it is
1115 /// determined to not exist) are outlined by `fs::create_dir`.
1116 ///
1117 /// # Examples
1118 ///
1119 /// ```
1120 /// use std::fs;
1121 ///
1122 /// # fn foo() -> std::io::Result<()> {
1123 /// try!(fs::create_dir_all("/some/dir"));
1124 /// # Ok(())
1125 /// # }
1126 /// ```
1127 #[stable(feature = "rust1", since = "1.0.0")]
1128 pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
1129     DirBuilder::new().recursive(true).create(path.as_ref())
1130 }
1131
1132 /// Removes an existing, empty directory.
1133 ///
1134 /// # Platform behavior
1135 ///
1136 /// This function currently corresponds to the `rmdir` function on Unix
1137 /// and the `RemoveDirectory` function on Windows.
1138 /// Note that, this [may change in the future][changes].
1139 /// [changes]: https://github.com/rust-lang/rust/pull/28613
1140 ///
1141 /// # Errors
1142 ///
1143 /// This function will return an error in the following situations, but is not
1144 /// limited to just these cases:
1145 ///
1146 /// * The user lacks permissions to remove the directory at the provided `path`.
1147 /// * The directory isn't empty.
1148 ///
1149 /// # Examples
1150 ///
1151 /// ```
1152 /// use std::fs;
1153 ///
1154 /// # fn foo() -> std::io::Result<()> {
1155 /// try!(fs::remove_dir("/some/dir"));
1156 /// # Ok(())
1157 /// # }
1158 /// ```
1159 #[stable(feature = "rust1", since = "1.0.0")]
1160 pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
1161     fs_imp::rmdir(path.as_ref())
1162 }
1163
1164 /// Removes a directory at this path, after removing all its contents. Use
1165 /// carefully!
1166 ///
1167 /// This function does **not** follow symbolic links and it will simply remove the
1168 /// symbolic link itself.
1169 ///
1170 /// # Platform behavior
1171 ///
1172 /// This function currently corresponds to `opendir`, `lstat`, `rm` and `rmdir` functions on Unix
1173 /// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions
1174 /// on Windows.
1175 /// Note that, this [may change in the future][changes].
1176 /// [changes]: https://github.com/rust-lang/rust/pull/28613
1177 ///
1178 /// # Errors
1179 ///
1180 /// See `file::remove_file` and `fs::remove_dir`.
1181 ///
1182 /// # Examples
1183 ///
1184 /// ```
1185 /// use std::fs;
1186 ///
1187 /// # fn foo() -> std::io::Result<()> {
1188 /// try!(fs::remove_dir_all("/some/dir"));
1189 /// # Ok(())
1190 /// # }
1191 /// ```
1192 #[stable(feature = "rust1", since = "1.0.0")]
1193 pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
1194     _remove_dir_all(path.as_ref())
1195 }
1196
1197 fn _remove_dir_all(path: &Path) -> io::Result<()> {
1198     for child in try!(read_dir(path)) {
1199         let child = try!(child).path();
1200         let stat = try!(symlink_metadata(&*child));
1201         if stat.is_dir() {
1202             try!(remove_dir_all(&*child));
1203         } else {
1204             try!(remove_file(&*child));
1205         }
1206     }
1207     remove_dir(path)
1208 }
1209
1210 /// Returns an iterator over the entries within a directory.
1211 ///
1212 /// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
1213 /// be encountered after an iterator is initially constructed.
1214 ///
1215 /// # Platform behavior
1216 ///
1217 /// This function currently corresponds to the `opendir` function on Unix
1218 /// and the `FindFirstFile` function on Windows.
1219 /// Note that, this [may change in the future][changes].
1220 /// [changes]: https://github.com/rust-lang/rust/pull/28613
1221 ///
1222 /// # Errors
1223 ///
1224 /// This function will return an error in the following situations, but is not
1225 /// limited to just these cases:
1226 ///
1227 /// * The provided `path` doesn't exist.
1228 /// * The process lacks permissions to view the contents.
1229 /// * The `path` points at a non-directory file.
1230 ///
1231 /// # Examples
1232 ///
1233 /// ```
1234 /// use std::io;
1235 /// use std::fs::{self, DirEntry};
1236 /// use std::path::Path;
1237 ///
1238 /// // one possible implementation of fs::walk_dir only visiting files
1239 /// fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
1240 ///     if try!(fs::metadata(dir)).is_dir() {
1241 ///         for entry in try!(fs::read_dir(dir)) {
1242 ///             let entry = try!(entry);
1243 ///             if try!(fs::metadata(entry.path())).is_dir() {
1244 ///                 try!(visit_dirs(&entry.path(), cb));
1245 ///             } else {
1246 ///                 cb(&entry);
1247 ///             }
1248 ///         }
1249 ///     }
1250 ///     Ok(())
1251 /// }
1252 /// ```
1253 #[stable(feature = "rust1", since = "1.0.0")]
1254 pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
1255     fs_imp::readdir(path.as_ref()).map(ReadDir)
1256 }
1257
1258 /// Returns an iterator that will recursively walk the directory structure
1259 /// rooted at `path`.
1260 ///
1261 /// The path given will not be iterated over, and this will perform iteration in
1262 /// some top-down order.  The contents of unreadable subdirectories are ignored.
1263 ///
1264 /// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
1265 /// be encountered after an iterator is initially constructed.
1266 #[unstable(feature = "fs_walk",
1267            reason = "the precise semantics and defaults for a recursive walk \
1268                      may change and this may end up accounting for files such \
1269                      as symlinks differently",
1270            issue = "27707")]
1271 #[rustc_deprecated(reason = "superceded by the walkdir crate",
1272                    since = "1.6.0")]
1273 #[allow(deprecated)]
1274 pub fn walk_dir<P: AsRef<Path>>(path: P) -> io::Result<WalkDir> {
1275     _walk_dir(path.as_ref())
1276 }
1277
1278 #[allow(deprecated)]
1279 fn _walk_dir(path: &Path) -> io::Result<WalkDir> {
1280     let start = try!(read_dir(path));
1281     Ok(WalkDir { cur: Some(start), stack: Vec::new() })
1282 }
1283
1284 #[unstable(feature = "fs_walk", issue = "27707")]
1285 #[rustc_deprecated(reason = "superceded by the walkdir crate",
1286                    since = "1.6.0")]
1287 #[allow(deprecated)]
1288 impl Iterator for WalkDir {
1289     type Item = io::Result<DirEntry>;
1290
1291     fn next(&mut self) -> Option<io::Result<DirEntry>> {
1292         loop {
1293             if let Some(ref mut cur) = self.cur {
1294                 match cur.next() {
1295                     Some(Err(e)) => return Some(Err(e)),
1296                     Some(Ok(next)) => {
1297                         let path = next.path();
1298                         if path.is_dir() {
1299                             self.stack.push(read_dir(&*path));
1300                         }
1301                         return Some(Ok(next))
1302                     }
1303                     None => {}
1304                 }
1305             }
1306             self.cur = None;
1307             match self.stack.pop() {
1308                 Some(Err(e)) => return Some(Err(e)),
1309                 Some(Ok(next)) => self.cur = Some(next),
1310                 None => return None,
1311             }
1312         }
1313     }
1314 }
1315
1316 /// Changes the permissions found on a file or a directory.
1317 ///
1318 /// # Platform behavior
1319 ///
1320 /// This function currently corresponds to the `chmod` function on Unix
1321 /// and the `SetFileAttributes` function on Windows.
1322 /// Note that, this [may change in the future][changes].
1323 /// [changes]: https://github.com/rust-lang/rust/pull/28613
1324 ///
1325 /// # Errors
1326 ///
1327 /// This function will return an error in the following situations, but is not
1328 /// limited to just these cases:
1329 ///
1330 /// * `path` does not exist.
1331 /// * The user lacks the permission to change attributes of the file.
1332 ///
1333 /// # Examples
1334 ///
1335 /// ```
1336 /// # fn foo() -> std::io::Result<()> {
1337 /// use std::fs;
1338 ///
1339 /// let mut perms = try!(fs::metadata("foo.txt")).permissions();
1340 /// perms.set_readonly(true);
1341 /// try!(fs::set_permissions("foo.txt", perms));
1342 /// # Ok(())
1343 /// # }
1344 /// ```
1345 #[stable(feature = "set_permissions", since = "1.1.0")]
1346 pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions)
1347                                        -> io::Result<()> {
1348     fs_imp::set_perm(path.as_ref(), perm.0)
1349 }
1350
1351 impl DirBuilder {
1352     /// Creates a new set of options with default mode/security settings for all
1353     /// platforms and also non-recursive.
1354     #[stable(feature = "dir_builder", since = "1.6.0")]
1355     pub fn new() -> DirBuilder {
1356         DirBuilder {
1357             inner: fs_imp::DirBuilder::new(),
1358             recursive: false,
1359         }
1360     }
1361
1362     /// Indicate that directories create should be created recursively, creating
1363     /// all parent directories if they do not exist with the same security and
1364     /// permissions settings.
1365     ///
1366     /// This option defaults to `false`
1367     #[stable(feature = "dir_builder", since = "1.6.0")]
1368     pub fn recursive(&mut self, recursive: bool) -> &mut Self {
1369         self.recursive = recursive;
1370         self
1371     }
1372
1373     /// Create the specified directory with the options configured in this
1374     /// builder.
1375     ///
1376     /// # Examples
1377     ///
1378     /// ```no_run
1379     /// use std::fs::{self, DirBuilder};
1380     ///
1381     /// let path = "/tmp/foo/bar/baz";
1382     /// DirBuilder::new()
1383     ///     .recursive(true)
1384     ///     .create(path).unwrap();
1385     ///
1386     /// assert!(fs::metadata(path).unwrap().is_dir());
1387     /// ```
1388     #[stable(feature = "dir_builder", since = "1.6.0")]
1389     pub fn create<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
1390         self._create(path.as_ref())
1391     }
1392
1393     fn _create(&self, path: &Path) -> io::Result<()> {
1394         if self.recursive {
1395             self.create_dir_all(path)
1396         } else {
1397             self.inner.mkdir(path)
1398         }
1399     }
1400
1401     fn create_dir_all(&self, path: &Path) -> io::Result<()> {
1402         if path == Path::new("") || path.is_dir() { return Ok(()) }
1403         if let Some(p) = path.parent() {
1404             try!(self.create_dir_all(p))
1405         }
1406         self.inner.mkdir(path)
1407     }
1408 }
1409
1410 impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
1411     fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder {
1412         &mut self.inner
1413     }
1414 }
1415
1416 #[cfg(test)]
1417 mod tests {
1418     #![allow(deprecated)] //rand
1419
1420     use prelude::v1::*;
1421     use io::prelude::*;
1422
1423     use env;
1424     use fs::{self, File, OpenOptions};
1425     use io::{ErrorKind, SeekFrom};
1426     use path::PathBuf;
1427     use path::Path as Path2;
1428     use rand::{self, StdRng, Rng};
1429     use str;
1430
1431     macro_rules! check { ($e:expr) => (
1432         match $e {
1433             Ok(t) => t,
1434             Err(e) => panic!("{} failed with: {}", stringify!($e), e),
1435         }
1436     ) }
1437
1438     macro_rules! error { ($e:expr, $s:expr) => (
1439         match $e {
1440             Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
1441             Err(ref err) => assert!(err.to_string().contains($s),
1442                                     format!("`{}` did not contain `{}`", err, $s))
1443         }
1444     ) }
1445
1446     pub struct TempDir(PathBuf);
1447
1448     impl TempDir {
1449         fn join(&self, path: &str) -> PathBuf {
1450             let TempDir(ref p) = *self;
1451             p.join(path)
1452         }
1453
1454         fn path<'a>(&'a self) -> &'a Path2 {
1455             let TempDir(ref p) = *self;
1456             p
1457         }
1458     }
1459
1460     impl Drop for TempDir {
1461         fn drop(&mut self) {
1462             // Gee, seeing how we're testing the fs module I sure hope that we
1463             // at least implement this correctly!
1464             let TempDir(ref p) = *self;
1465             check!(fs::remove_dir_all(p));
1466         }
1467     }
1468
1469     pub fn tmpdir() -> TempDir {
1470         let p = env::temp_dir();
1471         let mut r = rand::thread_rng();
1472         let ret = p.join(&format!("rust-{}", r.next_u32()));
1473         check!(fs::create_dir(&ret));
1474         TempDir(ret)
1475     }
1476
1477     #[test]
1478     fn file_test_io_smoke_test() {
1479         let message = "it's alright. have a good time";
1480         let tmpdir = tmpdir();
1481         let filename = &tmpdir.join("file_rt_io_file_test.txt");
1482         {
1483             let mut write_stream = check!(File::create(filename));
1484             check!(write_stream.write(message.as_bytes()));
1485         }
1486         {
1487             let mut read_stream = check!(File::open(filename));
1488             let mut read_buf = [0; 1028];
1489             let read_str = match check!(read_stream.read(&mut read_buf)) {
1490                 0 => panic!("shouldn't happen"),
1491                 n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
1492             };
1493             assert_eq!(read_str, message);
1494         }
1495         check!(fs::remove_file(filename));
1496     }
1497
1498     #[test]
1499     fn invalid_path_raises() {
1500         let tmpdir = tmpdir();
1501         let filename = &tmpdir.join("file_that_does_not_exist.txt");
1502         let result = File::open(filename);
1503
1504         if cfg!(unix) {
1505             error!(result, "o such file or directory");
1506         }
1507         // error!(result, "couldn't open path as file");
1508         // error!(result, format!("path={}; mode=open; access=read", filename.display()));
1509     }
1510
1511     #[test]
1512     fn file_test_iounlinking_invalid_path_should_raise_condition() {
1513         let tmpdir = tmpdir();
1514         let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
1515
1516         let result = fs::remove_file(filename);
1517
1518         if cfg!(unix) {
1519             error!(result, "o such file or directory");
1520         }
1521         // error!(result, "couldn't unlink path");
1522         // error!(result, format!("path={}", filename.display()));
1523     }
1524
1525     #[test]
1526     fn file_test_io_non_positional_read() {
1527         let message: &str = "ten-four";
1528         let mut read_mem = [0; 8];
1529         let tmpdir = tmpdir();
1530         let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
1531         {
1532             let mut rw_stream = check!(File::create(filename));
1533             check!(rw_stream.write(message.as_bytes()));
1534         }
1535         {
1536             let mut read_stream = check!(File::open(filename));
1537             {
1538                 let read_buf = &mut read_mem[0..4];
1539                 check!(read_stream.read(read_buf));
1540             }
1541             {
1542                 let read_buf = &mut read_mem[4..8];
1543                 check!(read_stream.read(read_buf));
1544             }
1545         }
1546         check!(fs::remove_file(filename));
1547         let read_str = str::from_utf8(&read_mem).unwrap();
1548         assert_eq!(read_str, message);
1549     }
1550
1551     #[test]
1552     fn file_test_io_seek_and_tell_smoke_test() {
1553         let message = "ten-four";
1554         let mut read_mem = [0; 4];
1555         let set_cursor = 4 as u64;
1556         let tell_pos_pre_read;
1557         let tell_pos_post_read;
1558         let tmpdir = tmpdir();
1559         let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
1560         {
1561             let mut rw_stream = check!(File::create(filename));
1562             check!(rw_stream.write(message.as_bytes()));
1563         }
1564         {
1565             let mut read_stream = check!(File::open(filename));
1566             check!(read_stream.seek(SeekFrom::Start(set_cursor)));
1567             tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0)));
1568             check!(read_stream.read(&mut read_mem));
1569             tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0)));
1570         }
1571         check!(fs::remove_file(filename));
1572         let read_str = str::from_utf8(&read_mem).unwrap();
1573         assert_eq!(read_str, &message[4..8]);
1574         assert_eq!(tell_pos_pre_read, set_cursor);
1575         assert_eq!(tell_pos_post_read, message.len() as u64);
1576     }
1577
1578     #[test]
1579     fn file_test_io_seek_and_write() {
1580         let initial_msg =   "food-is-yummy";
1581         let overwrite_msg =    "-the-bar!!";
1582         let final_msg =     "foo-the-bar!!";
1583         let seek_idx = 3;
1584         let mut read_mem = [0; 13];
1585         let tmpdir = tmpdir();
1586         let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
1587         {
1588             let mut rw_stream = check!(File::create(filename));
1589             check!(rw_stream.write(initial_msg.as_bytes()));
1590             check!(rw_stream.seek(SeekFrom::Start(seek_idx)));
1591             check!(rw_stream.write(overwrite_msg.as_bytes()));
1592         }
1593         {
1594             let mut read_stream = check!(File::open(filename));
1595             check!(read_stream.read(&mut read_mem));
1596         }
1597         check!(fs::remove_file(filename));
1598         let read_str = str::from_utf8(&read_mem).unwrap();
1599         assert!(read_str == final_msg);
1600     }
1601
1602     #[test]
1603     fn file_test_io_seek_shakedown() {
1604         //                   01234567890123
1605         let initial_msg =   "qwer-asdf-zxcv";
1606         let chunk_one: &str = "qwer";
1607         let chunk_two: &str = "asdf";
1608         let chunk_three: &str = "zxcv";
1609         let mut read_mem = [0; 4];
1610         let tmpdir = tmpdir();
1611         let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
1612         {
1613             let mut rw_stream = check!(File::create(filename));
1614             check!(rw_stream.write(initial_msg.as_bytes()));
1615         }
1616         {
1617             let mut read_stream = check!(File::open(filename));
1618
1619             check!(read_stream.seek(SeekFrom::End(-4)));
1620             check!(read_stream.read(&mut read_mem));
1621             assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three);
1622
1623             check!(read_stream.seek(SeekFrom::Current(-9)));
1624             check!(read_stream.read(&mut read_mem));
1625             assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two);
1626
1627             check!(read_stream.seek(SeekFrom::Start(0)));
1628             check!(read_stream.read(&mut read_mem));
1629             assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one);
1630         }
1631         check!(fs::remove_file(filename));
1632     }
1633
1634     #[test]
1635     fn file_test_stat_is_correct_on_is_file() {
1636         let tmpdir = tmpdir();
1637         let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
1638         {
1639             let mut opts = OpenOptions::new();
1640             let mut fs = check!(opts.read(true).write(true)
1641                                     .create(true).open(filename));
1642             let msg = "hw";
1643             fs.write(msg.as_bytes()).unwrap();
1644
1645             let fstat_res = check!(fs.metadata());
1646             assert!(fstat_res.is_file());
1647         }
1648         let stat_res_fn = check!(fs::metadata(filename));
1649         assert!(stat_res_fn.is_file());
1650         let stat_res_meth = check!(filename.metadata());
1651         assert!(stat_res_meth.is_file());
1652         check!(fs::remove_file(filename));
1653     }
1654
1655     #[test]
1656     fn file_test_stat_is_correct_on_is_dir() {
1657         let tmpdir = tmpdir();
1658         let filename = &tmpdir.join("file_stat_correct_on_is_dir");
1659         check!(fs::create_dir(filename));
1660         let stat_res_fn = check!(fs::metadata(filename));
1661         assert!(stat_res_fn.is_dir());
1662         let stat_res_meth = check!(filename.metadata());
1663         assert!(stat_res_meth.is_dir());
1664         check!(fs::remove_dir(filename));
1665     }
1666
1667     #[test]
1668     fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
1669         let tmpdir = tmpdir();
1670         let dir = &tmpdir.join("fileinfo_false_on_dir");
1671         check!(fs::create_dir(dir));
1672         assert!(dir.is_file() == false);
1673         check!(fs::remove_dir(dir));
1674     }
1675
1676     #[test]
1677     fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
1678         let tmpdir = tmpdir();
1679         let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
1680         check!(check!(File::create(file)).write(b"foo"));
1681         assert!(file.exists());
1682         check!(fs::remove_file(file));
1683         assert!(!file.exists());
1684     }
1685
1686     #[test]
1687     fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
1688         let tmpdir = tmpdir();
1689         let dir = &tmpdir.join("before_and_after_dir");
1690         assert!(!dir.exists());
1691         check!(fs::create_dir(dir));
1692         assert!(dir.exists());
1693         assert!(dir.is_dir());
1694         check!(fs::remove_dir(dir));
1695         assert!(!dir.exists());
1696     }
1697
1698     #[test]
1699     fn file_test_directoryinfo_readdir() {
1700         let tmpdir = tmpdir();
1701         let dir = &tmpdir.join("di_readdir");
1702         check!(fs::create_dir(dir));
1703         let prefix = "foo";
1704         for n in 0..3 {
1705             let f = dir.join(&format!("{}.txt", n));
1706             let mut w = check!(File::create(&f));
1707             let msg_str = format!("{}{}", prefix, n.to_string());
1708             let msg = msg_str.as_bytes();
1709             check!(w.write(msg));
1710         }
1711         let files = check!(fs::read_dir(dir));
1712         let mut mem = [0; 4];
1713         for f in files {
1714             let f = f.unwrap().path();
1715             {
1716                 let n = f.file_stem().unwrap();
1717                 check!(check!(File::open(&f)).read(&mut mem));
1718                 let read_str = str::from_utf8(&mem).unwrap();
1719                 let expected = format!("{}{}", prefix, n.to_str().unwrap());
1720                 assert_eq!(expected, read_str);
1721             }
1722             check!(fs::remove_file(&f));
1723         }
1724         check!(fs::remove_dir(dir));
1725     }
1726
1727     #[test]
1728     fn file_test_walk_dir() {
1729         let tmpdir = tmpdir();
1730         let dir = &tmpdir.join("walk_dir");
1731         check!(fs::create_dir(dir));
1732
1733         let dir1 = &dir.join("01/02/03");
1734         check!(fs::create_dir_all(dir1));
1735         check!(File::create(&dir1.join("04")));
1736
1737         let dir2 = &dir.join("11/12/13");
1738         check!(fs::create_dir_all(dir2));
1739         check!(File::create(&dir2.join("14")));
1740
1741         let files = check!(fs::walk_dir(dir));
1742         let mut cur = [0; 2];
1743         for f in files {
1744             let f = f.unwrap().path();
1745             let stem = f.file_stem().unwrap().to_str().unwrap();
1746             let root = stem.as_bytes()[0] - b'0';
1747             let name = stem.as_bytes()[1] - b'0';
1748             assert!(cur[root as usize] < name);
1749             cur[root as usize] = name;
1750         }
1751
1752         check!(fs::remove_dir_all(dir));
1753     }
1754
1755     #[test]
1756     fn mkdir_path_already_exists_error() {
1757         let tmpdir = tmpdir();
1758         let dir = &tmpdir.join("mkdir_error_twice");
1759         check!(fs::create_dir(dir));
1760         let e = fs::create_dir(dir).err().unwrap();
1761         assert_eq!(e.kind(), ErrorKind::AlreadyExists);
1762     }
1763
1764     #[test]
1765     fn recursive_mkdir() {
1766         let tmpdir = tmpdir();
1767         let dir = tmpdir.join("d1/d2");
1768         check!(fs::create_dir_all(&dir));
1769         assert!(dir.is_dir())
1770     }
1771
1772     #[test]
1773     fn recursive_mkdir_failure() {
1774         let tmpdir = tmpdir();
1775         let dir = tmpdir.join("d1");
1776         let file = dir.join("f1");
1777
1778         check!(fs::create_dir_all(&dir));
1779         check!(File::create(&file));
1780
1781         let result = fs::create_dir_all(&file);
1782
1783         assert!(result.is_err());
1784         // error!(result, "couldn't recursively mkdir");
1785         // error!(result, "couldn't create directory");
1786         // error!(result, "mode=0700");
1787         // error!(result, format!("path={}", file.display()));
1788     }
1789
1790     #[test]
1791     fn recursive_mkdir_slash() {
1792         check!(fs::create_dir_all(&Path2::new("/")));
1793     }
1794
1795     // FIXME(#12795) depends on lstat to work on windows
1796     #[cfg(not(windows))]
1797     #[test]
1798     fn recursive_rmdir() {
1799         let tmpdir = tmpdir();
1800         let d1 = tmpdir.join("d1");
1801         let dt = d1.join("t");
1802         let dtt = dt.join("t");
1803         let d2 = tmpdir.join("d2");
1804         let canary = d2.join("do_not_delete");
1805         check!(fs::create_dir_all(&dtt));
1806         check!(fs::create_dir_all(&d2));
1807         check!(check!(File::create(&canary)).write(b"foo"));
1808         check!(fs::soft_link(&d2, &dt.join("d2")));
1809         check!(fs::remove_dir_all(&d1));
1810
1811         assert!(!d1.is_dir());
1812         assert!(canary.exists());
1813     }
1814
1815     #[test]
1816     fn unicode_path_is_dir() {
1817         assert!(Path2::new(".").is_dir());
1818         assert!(!Path2::new("test/stdtest/fs.rs").is_dir());
1819
1820         let tmpdir = tmpdir();
1821
1822         let mut dirpath = tmpdir.path().to_path_buf();
1823         dirpath.push("test-가一ー你好");
1824         check!(fs::create_dir(&dirpath));
1825         assert!(dirpath.is_dir());
1826
1827         let mut filepath = dirpath;
1828         filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
1829         check!(File::create(&filepath)); // ignore return; touch only
1830         assert!(!filepath.is_dir());
1831         assert!(filepath.exists());
1832     }
1833
1834     #[test]
1835     fn unicode_path_exists() {
1836         assert!(Path2::new(".").exists());
1837         assert!(!Path2::new("test/nonexistent-bogus-path").exists());
1838
1839         let tmpdir = tmpdir();
1840         let unicode = tmpdir.path();
1841         let unicode = unicode.join(&format!("test-각丁ー再见"));
1842         check!(fs::create_dir(&unicode));
1843         assert!(unicode.exists());
1844         assert!(!Path2::new("test/unicode-bogus-path-각丁ー再见").exists());
1845     }
1846
1847     #[test]
1848     fn copy_file_does_not_exist() {
1849         let from = Path2::new("test/nonexistent-bogus-path");
1850         let to = Path2::new("test/other-bogus-path");
1851
1852         match fs::copy(&from, &to) {
1853             Ok(..) => panic!(),
1854             Err(..) => {
1855                 assert!(!from.exists());
1856                 assert!(!to.exists());
1857             }
1858         }
1859     }
1860
1861     #[test]
1862     fn copy_src_does_not_exist() {
1863         let tmpdir = tmpdir();
1864         let from = Path2::new("test/nonexistent-bogus-path");
1865         let to = tmpdir.join("out.txt");
1866         check!(check!(File::create(&to)).write(b"hello"));
1867         assert!(fs::copy(&from, &to).is_err());
1868         assert!(!from.exists());
1869         let mut v = Vec::new();
1870         check!(check!(File::open(&to)).read_to_end(&mut v));
1871         assert_eq!(v, b"hello");
1872     }
1873
1874     #[test]
1875     fn copy_file_ok() {
1876         let tmpdir = tmpdir();
1877         let input = tmpdir.join("in.txt");
1878         let out = tmpdir.join("out.txt");
1879
1880         check!(check!(File::create(&input)).write(b"hello"));
1881         check!(fs::copy(&input, &out));
1882         let mut v = Vec::new();
1883         check!(check!(File::open(&out)).read_to_end(&mut v));
1884         assert_eq!(v, b"hello");
1885
1886         assert_eq!(check!(input.metadata()).permissions(),
1887                    check!(out.metadata()).permissions());
1888     }
1889
1890     #[test]
1891     fn copy_file_dst_dir() {
1892         let tmpdir = tmpdir();
1893         let out = tmpdir.join("out");
1894
1895         check!(File::create(&out));
1896         match fs::copy(&*out, tmpdir.path()) {
1897             Ok(..) => panic!(), Err(..) => {}
1898         }
1899     }
1900
1901     #[test]
1902     fn copy_file_dst_exists() {
1903         let tmpdir = tmpdir();
1904         let input = tmpdir.join("in");
1905         let output = tmpdir.join("out");
1906
1907         check!(check!(File::create(&input)).write("foo".as_bytes()));
1908         check!(check!(File::create(&output)).write("bar".as_bytes()));
1909         check!(fs::copy(&input, &output));
1910
1911         let mut v = Vec::new();
1912         check!(check!(File::open(&output)).read_to_end(&mut v));
1913         assert_eq!(v, b"foo".to_vec());
1914     }
1915
1916     #[test]
1917     fn copy_file_src_dir() {
1918         let tmpdir = tmpdir();
1919         let out = tmpdir.join("out");
1920
1921         match fs::copy(tmpdir.path(), &out) {
1922             Ok(..) => panic!(), Err(..) => {}
1923         }
1924         assert!(!out.exists());
1925     }
1926
1927     #[test]
1928     fn copy_file_preserves_perm_bits() {
1929         let tmpdir = tmpdir();
1930         let input = tmpdir.join("in.txt");
1931         let out = tmpdir.join("out.txt");
1932
1933         let attr = check!(check!(File::create(&input)).metadata());
1934         let mut p = attr.permissions();
1935         p.set_readonly(true);
1936         check!(fs::set_permissions(&input, p));
1937         check!(fs::copy(&input, &out));
1938         assert!(check!(out.metadata()).permissions().readonly());
1939         check!(fs::set_permissions(&input, attr.permissions()));
1940         check!(fs::set_permissions(&out, attr.permissions()));
1941     }
1942
1943     #[cfg(windows)]
1944     #[test]
1945     fn copy_file_preserves_streams() {
1946         let tmp = tmpdir();
1947         check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes()));
1948         assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 6);
1949         assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0);
1950         let mut v = Vec::new();
1951         check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v));
1952         assert_eq!(v, b"carrot".to_vec());
1953     }
1954
1955     #[cfg(not(windows))] // FIXME(#10264) operation not permitted?
1956     #[test]
1957     fn symlinks_work() {
1958         let tmpdir = tmpdir();
1959         let input = tmpdir.join("in.txt");
1960         let out = tmpdir.join("out.txt");
1961
1962         check!(check!(File::create(&input)).write("foobar".as_bytes()));
1963         check!(fs::soft_link(&input, &out));
1964         // if cfg!(not(windows)) {
1965         //     assert_eq!(check!(lstat(&out)).kind, FileType::Symlink);
1966         //     assert_eq!(check!(out.lstat()).kind, FileType::Symlink);
1967         // }
1968         assert_eq!(check!(fs::metadata(&out)).len(),
1969                    check!(fs::metadata(&input)).len());
1970         let mut v = Vec::new();
1971         check!(check!(File::open(&out)).read_to_end(&mut v));
1972         assert_eq!(v, b"foobar".to_vec());
1973     }
1974
1975     #[cfg(not(windows))] // apparently windows doesn't like symlinks
1976     #[test]
1977     fn symlink_noexist() {
1978         let tmpdir = tmpdir();
1979         // symlinks can point to things that don't exist
1980         check!(fs::soft_link(&tmpdir.join("foo"), &tmpdir.join("bar")));
1981         assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))),
1982                    tmpdir.join("foo"));
1983     }
1984
1985     #[test]
1986     fn readlink_not_symlink() {
1987         let tmpdir = tmpdir();
1988         match fs::read_link(tmpdir.path()) {
1989             Ok(..) => panic!("wanted a failure"),
1990             Err(..) => {}
1991         }
1992     }
1993
1994     #[test]
1995     fn links_work() {
1996         let tmpdir = tmpdir();
1997         let input = tmpdir.join("in.txt");
1998         let out = tmpdir.join("out.txt");
1999
2000         check!(check!(File::create(&input)).write("foobar".as_bytes()));
2001         check!(fs::hard_link(&input, &out));
2002         assert_eq!(check!(fs::metadata(&out)).len(),
2003                    check!(fs::metadata(&input)).len());
2004         assert_eq!(check!(fs::metadata(&out)).len(),
2005                    check!(input.metadata()).len());
2006         let mut v = Vec::new();
2007         check!(check!(File::open(&out)).read_to_end(&mut v));
2008         assert_eq!(v, b"foobar".to_vec());
2009
2010         // can't link to yourself
2011         match fs::hard_link(&input, &input) {
2012             Ok(..) => panic!("wanted a failure"),
2013             Err(..) => {}
2014         }
2015         // can't link to something that doesn't exist
2016         match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
2017             Ok(..) => panic!("wanted a failure"),
2018             Err(..) => {}
2019         }
2020     }
2021
2022     #[test]
2023     fn chmod_works() {
2024         let tmpdir = tmpdir();
2025         let file = tmpdir.join("in.txt");
2026
2027         check!(File::create(&file));
2028         let attr = check!(fs::metadata(&file));
2029         assert!(!attr.permissions().readonly());
2030         let mut p = attr.permissions();
2031         p.set_readonly(true);
2032         check!(fs::set_permissions(&file, p.clone()));
2033         let attr = check!(fs::metadata(&file));
2034         assert!(attr.permissions().readonly());
2035
2036         match fs::set_permissions(&tmpdir.join("foo"), p.clone()) {
2037             Ok(..) => panic!("wanted an error"),
2038             Err(..) => {}
2039         }
2040
2041         p.set_readonly(false);
2042         check!(fs::set_permissions(&file, p));
2043     }
2044
2045     #[test]
2046     fn sync_doesnt_kill_anything() {
2047         let tmpdir = tmpdir();
2048         let path = tmpdir.join("in.txt");
2049
2050         let mut file = check!(File::create(&path));
2051         check!(file.sync_all());
2052         check!(file.sync_data());
2053         check!(file.write(b"foo"));
2054         check!(file.sync_all());
2055         check!(file.sync_data());
2056     }
2057
2058     #[test]
2059     fn truncate_works() {
2060         let tmpdir = tmpdir();
2061         let path = tmpdir.join("in.txt");
2062
2063         let mut file = check!(File::create(&path));
2064         check!(file.write(b"foo"));
2065         check!(file.sync_all());
2066
2067         // Do some simple things with truncation
2068         assert_eq!(check!(file.metadata()).len(), 3);
2069         check!(file.set_len(10));
2070         assert_eq!(check!(file.metadata()).len(), 10);
2071         check!(file.write(b"bar"));
2072         check!(file.sync_all());
2073         assert_eq!(check!(file.metadata()).len(), 10);
2074
2075         let mut v = Vec::new();
2076         check!(check!(File::open(&path)).read_to_end(&mut v));
2077         assert_eq!(v, b"foobar\0\0\0\0".to_vec());
2078
2079         // Truncate to a smaller length, don't seek, and then write something.
2080         // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
2081         // past the end of the file).
2082         check!(file.set_len(2));
2083         assert_eq!(check!(file.metadata()).len(), 2);
2084         check!(file.write(b"wut"));
2085         check!(file.sync_all());
2086         assert_eq!(check!(file.metadata()).len(), 9);
2087         let mut v = Vec::new();
2088         check!(check!(File::open(&path)).read_to_end(&mut v));
2089         assert_eq!(v, b"fo\0\0\0\0wut".to_vec());
2090     }
2091
2092     #[test]
2093     fn open_flavors() {
2094         use fs::OpenOptions as OO;
2095         fn c<T: Clone>(t: &T) -> T { t.clone() }
2096
2097         let tmpdir = tmpdir();
2098
2099         let mut r = OO::new(); r.read(true);
2100         let mut w = OO::new(); w.write(true);
2101         let mut rw = OO::new(); rw.write(true).read(true);
2102
2103         match r.open(&tmpdir.join("a")) {
2104             Ok(..) => panic!(), Err(..) => {}
2105         }
2106
2107         // Perform each one twice to make sure that it succeeds the second time
2108         // (where the file exists)
2109         check!(c(&w).create(true).open(&tmpdir.join("b")));
2110         assert!(tmpdir.join("b").exists());
2111         check!(c(&w).create(true).open(&tmpdir.join("b")));
2112         check!(w.open(&tmpdir.join("b")));
2113
2114         check!(c(&rw).create(true).open(&tmpdir.join("c")));
2115         assert!(tmpdir.join("c").exists());
2116         check!(c(&rw).create(true).open(&tmpdir.join("c")));
2117         check!(rw.open(&tmpdir.join("c")));
2118
2119         check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
2120         assert!(tmpdir.join("d").exists());
2121         check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
2122         check!(c(&w).append(true).open(&tmpdir.join("d")));
2123
2124         check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
2125         assert!(tmpdir.join("e").exists());
2126         check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
2127         check!(c(&rw).append(true).open(&tmpdir.join("e")));
2128
2129         check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
2130         assert!(tmpdir.join("f").exists());
2131         check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
2132         check!(c(&w).truncate(true).open(&tmpdir.join("f")));
2133
2134         check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
2135         assert!(tmpdir.join("g").exists());
2136         check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
2137         check!(c(&rw).truncate(true).open(&tmpdir.join("g")));
2138
2139         check!(check!(File::create(&tmpdir.join("h"))).write("foo".as_bytes()));
2140         check!(r.open(&tmpdir.join("h")));
2141         {
2142             let mut f = check!(r.open(&tmpdir.join("h")));
2143             assert!(f.write("wut".as_bytes()).is_err());
2144         }
2145         assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
2146         {
2147             let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
2148             check!(f.write("bar".as_bytes()));
2149         }
2150         assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
2151         {
2152             let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
2153             check!(f.write("bar".as_bytes()));
2154         }
2155         assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
2156     }
2157
2158     #[test]
2159     fn binary_file() {
2160         let mut bytes = [0; 1024];
2161         StdRng::new().unwrap().fill_bytes(&mut bytes);
2162
2163         let tmpdir = tmpdir();
2164
2165         check!(check!(File::create(&tmpdir.join("test"))).write(&bytes));
2166         let mut v = Vec::new();
2167         check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v));
2168         assert!(v == &bytes[..]);
2169     }
2170
2171     #[test]
2172     #[cfg(not(windows))]
2173     fn unlink_readonly() {
2174         let tmpdir = tmpdir();
2175         let path = tmpdir.join("file");
2176         check!(File::create(&path));
2177         let mut perm = check!(fs::metadata(&path)).permissions();
2178         perm.set_readonly(true);
2179         check!(fs::set_permissions(&path, perm));
2180         check!(fs::remove_file(&path));
2181     }
2182
2183     #[test]
2184     fn mkdir_trailing_slash() {
2185         let tmpdir = tmpdir();
2186         let path = tmpdir.join("file");
2187         check!(fs::create_dir_all(&path.join("a/")));
2188     }
2189
2190     #[test]
2191     fn canonicalize_works_simple() {
2192         let tmpdir = tmpdir();
2193         let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
2194         let file = tmpdir.join("test");
2195         File::create(&file).unwrap();
2196         assert_eq!(fs::canonicalize(&file).unwrap(), file);
2197     }
2198
2199     #[test]
2200     #[cfg(not(windows))]
2201     fn realpath_works() {
2202         let tmpdir = tmpdir();
2203         let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
2204         let file = tmpdir.join("test");
2205         let dir = tmpdir.join("test2");
2206         let link = dir.join("link");
2207         let linkdir = tmpdir.join("test3");
2208
2209         File::create(&file).unwrap();
2210         fs::create_dir(&dir).unwrap();
2211         fs::soft_link(&file, &link).unwrap();
2212         fs::soft_link(&dir, &linkdir).unwrap();
2213
2214         assert!(link.symlink_metadata().unwrap().file_type().is_symlink());
2215
2216         assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir);
2217         assert_eq!(fs::canonicalize(&file).unwrap(), file);
2218         assert_eq!(fs::canonicalize(&link).unwrap(), file);
2219         assert_eq!(fs::canonicalize(&linkdir).unwrap(), dir);
2220         assert_eq!(fs::canonicalize(&linkdir.join("link")).unwrap(), file);
2221     }
2222
2223     #[test]
2224     #[cfg(not(windows))]
2225     fn realpath_works_tricky() {
2226         let tmpdir = tmpdir();
2227         let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
2228
2229         let a = tmpdir.join("a");
2230         let b = a.join("b");
2231         let c = b.join("c");
2232         let d = a.join("d");
2233         let e = d.join("e");
2234         let f = a.join("f");
2235
2236         fs::create_dir_all(&b).unwrap();
2237         fs::create_dir_all(&d).unwrap();
2238         File::create(&f).unwrap();
2239         fs::soft_link("../d/e", &c).unwrap();
2240         fs::soft_link("../f", &e).unwrap();
2241
2242         assert_eq!(fs::canonicalize(&c).unwrap(), f);
2243         assert_eq!(fs::canonicalize(&e).unwrap(), f);
2244     }
2245
2246     #[test]
2247     fn dir_entry_methods() {
2248         let tmpdir = tmpdir();
2249
2250         fs::create_dir_all(&tmpdir.join("a")).unwrap();
2251         File::create(&tmpdir.join("b")).unwrap();
2252
2253         for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) {
2254             let fname = file.file_name();
2255             match fname.to_str() {
2256                 Some("a") => {
2257                     assert!(file.file_type().unwrap().is_dir());
2258                     assert!(file.metadata().unwrap().is_dir());
2259                 }
2260                 Some("b") => {
2261                     assert!(file.file_type().unwrap().is_file());
2262                     assert!(file.metadata().unwrap().is_file());
2263                 }
2264                 f => panic!("unknown file name: {:?}", f),
2265             }
2266         }
2267     }
2268
2269     #[test]
2270     fn read_dir_not_found() {
2271         let res = fs::read_dir("/path/that/does/not/exist");
2272         assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound);
2273     }
2274 }