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