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.
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.
11 //! Filesystem manipulation operations
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`.
18 #![stable(feature = "rust1", since = "1.0.0")]
24 use io
::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write}
;
25 use path
::{Path, PathBuf}
;
26 use sys
::fs
as fs_imp
;
27 use sys_common
::{AsInnerMut, FromInner, AsInner}
;
30 /// A reference to an open file on the filesystem.
32 /// An instance of a `File` can be read and/or written depending on what options
33 /// it was opened with. Files also implement `Seek` to alter the logical cursor
34 /// that the file contains internally.
39 /// use std::io::prelude::*;
40 /// use std::fs::File;
42 /// # fn foo() -> std::io::Result<()> {
43 /// let mut f = try!(File::create("foo.txt"));
44 /// try!(f.write_all(b"Hello, world!"));
46 /// let mut f = try!(File::open("foo.txt"));
47 /// let mut s = String::new();
48 /// try!(f.read_to_string(&mut s));
49 /// assert_eq!(s, "Hello, world!");
53 #[stable(feature = "rust1", since = "1.0.0")]
58 /// Metadata information about a file.
60 /// This structure is returned from the `metadata` function or method and
61 /// represents known metadata about a file such as its permissions, size,
62 /// modification times, etc.
63 #[stable(feature = "rust1", since = "1.0.0")]
64 pub struct Metadata(fs_imp
::FileAttr
);
66 /// Iterator over the entries in a directory.
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
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
);
80 /// Entries returned by the `ReadDir` iterator.
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
);
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")]
95 stack
: Vec
<io
::Result
<ReadDir
>>,
98 /// Options and flags which can be used to configure how a file is opened.
100 /// This builder exposes the ability to configure how a `File` is opened and
101 /// what operations are permitted on the open file. The `File::open` and
102 /// `File::create` methods are aliases for commonly used options using this
105 /// Generally speaking, when using `OpenOptions`, you'll first call `new()`,
106 /// then chain calls to methods to set each option, then call `open()`, passing
107 /// the path of the file you're trying to open. This will give you a
108 /// [`io::Result`][result] with a [`File`][file] inside that you can further
111 /// [result]: ../io/type.Result.html
112 /// [file]: struct.File.html
116 /// Opening a file to read:
119 /// use std::fs::OpenOptions;
121 /// let file = OpenOptions::new().read(true).open("foo.txt");
124 /// Opening a file for both reading and writing, as well as creating it if it
128 /// use std::fs::OpenOptions;
130 /// let file = OpenOptions::new()
134 /// .open("foo.txt");
137 #[stable(feature = "rust1", since = "1.0.0")]
138 pub struct OpenOptions(fs_imp
::OpenOptions
);
140 /// Representation of the various permissions on a file.
142 /// This module only currently provides one bit of information, `readonly`,
143 /// which is exposed on all currently supported platforms. Unix-specific
144 /// functionality, such as mode bits, is available through the
145 /// `os::unix::PermissionsExt` trait.
146 #[derive(Clone, PartialEq, Eq, Debug)]
147 #[stable(feature = "rust1", since = "1.0.0")]
148 pub struct Permissions(fs_imp
::FilePermissions
);
150 /// An structure representing a type of file with accessors for each file type.
151 #[stable(feature = "file_type", since = "1.1.0")]
152 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
153 pub struct FileType(fs_imp
::FileType
);
155 /// A builder used to create directories in various manners.
157 /// This builder also supports platform-specific options.
158 #[unstable(feature = "dir_builder", reason = "recently added API")]
159 pub struct DirBuilder
{
160 inner
: fs_imp
::DirBuilder
,
165 /// Attempts to open a file in read-only mode.
167 /// See the `OpenOptions::open` method for more details.
171 /// This function will return an error if `path` does not already exist.
172 /// Other errors may also be returned according to `OpenOptions::open`.
177 /// use std::fs::File;
179 /// # fn foo() -> std::io::Result<()> {
180 /// let mut f = try!(File::open("foo.txt"));
184 #[stable(feature = "rust1", since = "1.0.0")]
185 pub fn open
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<File
> {
186 OpenOptions
::new().read(true).open(path
)
189 /// Opens a file in write-only mode.
191 /// This function will create a file if it does not exist,
192 /// and will truncate it if it does.
194 /// See the `OpenOptions::open` function for more details.
199 /// use std::fs::File;
201 /// # fn foo() -> std::io::Result<()> {
202 /// let mut f = try!(File::create("foo.txt"));
206 #[stable(feature = "rust1", since = "1.0.0")]
207 pub fn create
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<File
> {
208 OpenOptions
::new().write(true).create(true).truncate(true).open(path
)
211 /// Attempts to sync all OS-internal metadata to disk.
213 /// This function will attempt to ensure that all in-core data reaches the
214 /// filesystem before returning.
219 /// use std::fs::File;
220 /// use std::io::prelude::*;
222 /// # fn foo() -> std::io::Result<()> {
223 /// let mut f = try!(File::create("foo.txt"));
224 /// try!(f.write_all(b"Hello, world!"));
226 /// try!(f.sync_all());
230 #[stable(feature = "rust1", since = "1.0.0")]
231 pub fn sync_all(&self) -> io
::Result
<()> {
235 /// This function is similar to `sync_all`, except that it may not
236 /// synchronize file metadata to the filesystem.
238 /// This is intended for use cases that must synchronize content, but don't
239 /// need the metadata on disk. The goal of this method is to reduce disk
242 /// Note that some platforms may simply implement this in terms of
248 /// use std::fs::File;
249 /// use std::io::prelude::*;
251 /// # fn foo() -> std::io::Result<()> {
252 /// let mut f = try!(File::create("foo.txt"));
253 /// try!(f.write_all(b"Hello, world!"));
255 /// try!(f.sync_data());
259 #[stable(feature = "rust1", since = "1.0.0")]
260 pub fn sync_data(&self) -> io
::Result
<()> {
261 self.inner
.datasync()
264 /// Truncates or extends the underlying file, updating the size of
265 /// this file to become `size`.
267 /// If the `size` is less than the current file's size, then the file will
268 /// be shrunk. If it is greater than the current file's size, then the file
269 /// will be extended to `size` and have all of the intermediate data filled
275 /// use std::fs::File;
277 /// # fn foo() -> std::io::Result<()> {
278 /// let mut f = try!(File::open("foo.txt"));
279 /// try!(f.set_len(0));
283 #[stable(feature = "rust1", since = "1.0.0")]
284 pub fn set_len(&self, size
: u64) -> io
::Result
<()> {
285 self.inner
.truncate(size
)
288 /// Queries metadata about the underlying file.
293 /// use std::fs::File;
295 /// # fn foo() -> std::io::Result<()> {
296 /// let mut f = try!(File::open("foo.txt"));
297 /// let metadata = try!(f.metadata());
301 #[stable(feature = "rust1", since = "1.0.0")]
302 pub fn metadata(&self) -> io
::Result
<Metadata
> {
303 self.inner
.file_attr().map(Metadata
)
307 impl AsInner
<fs_imp
::File
> for File
{
308 fn as_inner(&self) -> &fs_imp
::File { &self.inner }
310 impl FromInner
<fs_imp
::File
> for File
{
311 fn from_inner(f
: fs_imp
::File
) -> File
{
316 impl fmt
::Debug
for File
{
317 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
322 #[stable(feature = "rust1", since = "1.0.0")]
324 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
328 #[stable(feature = "rust1", since = "1.0.0")]
329 impl Write
for File
{
330 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
331 self.inner
.write(buf
)
333 fn flush(&mut self) -> io
::Result
<()> { self.inner.flush() }
335 #[stable(feature = "rust1", since = "1.0.0")]
337 fn seek(&mut self, pos
: SeekFrom
) -> io
::Result
<u64> {
341 #[stable(feature = "rust1", since = "1.0.0")]
342 impl<'a
> Read
for &'a File
{
343 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
347 #[stable(feature = "rust1", since = "1.0.0")]
348 impl<'a
> Write
for &'a File
{
349 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
350 self.inner
.write(buf
)
352 fn flush(&mut self) -> io
::Result
<()> { self.inner.flush() }
354 #[stable(feature = "rust1", since = "1.0.0")]
355 impl<'a
> Seek
for &'a File
{
356 fn seek(&mut self, pos
: SeekFrom
) -> io
::Result
<u64> {
362 /// Creates a blank net set of options ready for configuration.
364 /// All options are initially set to `false`.
369 /// use std::fs::OpenOptions;
371 /// let file = OpenOptions::new().open("foo.txt");
373 #[stable(feature = "rust1", since = "1.0.0")]
374 pub fn new() -> OpenOptions
{
375 OpenOptions(fs_imp
::OpenOptions
::new())
378 /// Sets the option for read access.
380 /// This option, when true, will indicate that the file should be
381 /// `read`-able if opened.
386 /// use std::fs::OpenOptions;
388 /// let file = OpenOptions::new().read(true).open("foo.txt");
390 #[stable(feature = "rust1", since = "1.0.0")]
391 pub fn read(&mut self, read
: bool
) -> &mut OpenOptions
{
392 self.0.read(read
); self
395 /// Sets the option for write access.
397 /// This option, when true, will indicate that the file should be
398 /// `write`-able if opened.
403 /// use std::fs::OpenOptions;
405 /// let file = OpenOptions::new().write(true).open("foo.txt");
407 #[stable(feature = "rust1", since = "1.0.0")]
408 pub fn write(&mut self, write
: bool
) -> &mut OpenOptions
{
409 self.0.write(write
); self
412 /// Sets the option for the append mode.
414 /// This option, when true, means that writes will append to a file instead
415 /// of overwriting previous contents.
420 /// use std::fs::OpenOptions;
422 /// let file = OpenOptions::new().append(true).open("foo.txt");
424 #[stable(feature = "rust1", since = "1.0.0")]
425 pub fn append(&mut self, append
: bool
) -> &mut OpenOptions
{
426 self.0.append(append
); self
429 /// Sets the option for truncating a previous file.
431 /// If a file is successfully opened with this option set it will truncate
432 /// the file to 0 length if it already exists.
437 /// use std::fs::OpenOptions;
439 /// let file = OpenOptions::new().truncate(true).open("foo.txt");
441 #[stable(feature = "rust1", since = "1.0.0")]
442 pub fn truncate(&mut self, truncate
: bool
) -> &mut OpenOptions
{
443 self.0.truncate(truncate
); self
446 /// Sets the option for creating a new file.
448 /// This option indicates whether a new file will be created if the file
449 /// does not yet already exist.
454 /// use std::fs::OpenOptions;
456 /// let file = OpenOptions::new().create(true).open("foo.txt");
458 #[stable(feature = "rust1", since = "1.0.0")]
459 pub fn create(&mut self, create
: bool
) -> &mut OpenOptions
{
460 self.0.create(create
); self
463 /// Opens a file at `path` with the options specified by `self`.
467 /// This function will return an error under a number of different
468 /// circumstances, to include but not limited to:
470 /// * Opening a file that does not exist with read access.
471 /// * Attempting to open a file with access that the user lacks
473 /// * Filesystem-level errors (full disk, etc)
478 /// use std::fs::OpenOptions;
480 /// let file = OpenOptions::new().open("foo.txt");
482 #[stable(feature = "rust1", since = "1.0.0")]
483 pub fn open
<P
: AsRef
<Path
>>(&self, path
: P
) -> io
::Result
<File
> {
484 let path
= path
.as_ref();
485 let inner
= try
!(fs_imp
::File
::open(path
, &self.0));
486 Ok(File { inner: inner }
)
490 impl AsInnerMut
<fs_imp
::OpenOptions
> for OpenOptions
{
491 fn as_inner_mut(&mut self) -> &mut fs_imp
::OpenOptions { &mut self.0 }
495 /// Returns the file type for this metadata.
496 #[stable(feature = "file_type", since = "1.1.0")]
497 pub fn file_type(&self) -> FileType
{
498 FileType(self.0.file_type
())
501 /// Returns whether this metadata is for a directory.
506 /// # fn foo() -> std::io::Result<()> {
509 /// let metadata = try!(fs::metadata("foo.txt"));
511 /// assert!(!metadata.is_dir());
515 #[stable(feature = "rust1", since = "1.0.0")]
516 pub fn is_dir(&self) -> bool { self.file_type().is_dir() }
518 /// Returns whether this metadata is for a regular file.
523 /// # fn foo() -> std::io::Result<()> {
526 /// let metadata = try!(fs::metadata("foo.txt"));
528 /// assert!(metadata.is_file());
532 #[stable(feature = "rust1", since = "1.0.0")]
533 pub fn is_file(&self) -> bool { self.file_type().is_file() }
535 /// Returns the size of the file, in bytes, this metadata is for.
540 /// # fn foo() -> std::io::Result<()> {
543 /// let metadata = try!(fs::metadata("foo.txt"));
545 /// assert_eq!(0, metadata.len());
549 #[stable(feature = "rust1", since = "1.0.0")]
550 pub fn len(&self) -> u64 { self.0.size() }
552 /// Returns the permissions of the file this metadata is for.
557 /// # fn foo() -> std::io::Result<()> {
560 /// let metadata = try!(fs::metadata("foo.txt"));
562 /// assert!(!metadata.permissions().readonly());
566 #[stable(feature = "rust1", since = "1.0.0")]
567 pub fn permissions(&self) -> Permissions
{
568 Permissions(self.0.perm())
572 impl AsInner
<fs_imp
::FileAttr
> for Metadata
{
573 fn as_inner(&self) -> &fs_imp
::FileAttr { &self.0 }
577 /// Returns whether these permissions describe a readonly file.
582 /// use std::fs::File;
584 /// # fn foo() -> std::io::Result<()> {
585 /// let mut f = try!(File::create("foo.txt"));
586 /// let metadata = try!(f.metadata());
588 /// assert_eq!(false, metadata.permissions().readonly());
592 #[stable(feature = "rust1", since = "1.0.0")]
593 pub fn readonly(&self) -> bool { self.0.readonly() }
595 /// Modifies the readonly flag for this set of permissions.
597 /// This operation does **not** modify the filesystem. To modify the
598 /// filesystem use the `fs::set_permissions` function.
603 /// use std::fs::File;
605 /// # fn foo() -> std::io::Result<()> {
606 /// let f = try!(File::create("foo.txt"));
607 /// let metadata = try!(f.metadata());
608 /// let mut permissions = metadata.permissions();
610 /// permissions.set_readonly(true);
612 /// // filesystem doesn't change
613 /// assert_eq!(false, metadata.permissions().readonly());
615 /// // just this particular `permissions`.
616 /// assert_eq!(true, permissions.readonly());
620 #[stable(feature = "rust1", since = "1.0.0")]
621 pub fn set_readonly(&mut self, readonly
: bool
) {
622 self.0.set_readonly(readonly
)
627 /// Test whether this file type represents a directory.
628 #[stable(feature = "file_type", since = "1.1.0")]
629 pub fn is_dir(&self) -> bool { self.0.is_dir() }
631 /// Test whether this file type represents a regular file.
632 #[stable(feature = "file_type", since = "1.1.0")]
633 pub fn is_file(&self) -> bool { self.0.is_file() }
635 /// Test whether this file type represents a symbolic link.
636 #[stable(feature = "file_type", since = "1.1.0")]
637 pub fn is_symlink(&self) -> bool { self.0.is_symlink() }
640 impl FromInner
<fs_imp
::FilePermissions
> for Permissions
{
641 fn from_inner(f
: fs_imp
::FilePermissions
) -> Permissions
{
646 impl AsInner
<fs_imp
::FilePermissions
> for Permissions
{
647 fn as_inner(&self) -> &fs_imp
::FilePermissions { &self.0 }
650 #[stable(feature = "rust1", since = "1.0.0")]
651 impl Iterator
for ReadDir
{
652 type Item
= io
::Result
<DirEntry
>;
654 fn next(&mut self) -> Option
<io
::Result
<DirEntry
>> {
655 self.0.next().map(|entry
| entry
.map(DirEntry
))
659 #[stable(feature = "rust1", since = "1.0.0")]
661 /// Returns the full path to the file that this entry represents.
663 /// The full path is created by joining the original path to `read_dir` or
664 /// `walk_dir` with the filename of this entry.
670 /// # fn foo() -> std::io::Result<()> {
671 /// for entry in try!(fs::read_dir(".")) {
672 /// let dir = try!(entry);
673 /// println!("{:?}", dir.path());
679 /// This prints output like:
684 /// "./hello_world.rs"
687 /// The exact text, of course, depends on what files you have in `.`.
688 #[stable(feature = "rust1", since = "1.0.0")]
689 pub fn path(&self) -> PathBuf { self.0.path() }
691 /// Return the metadata for the file that this entry points at.
693 /// This function will not traverse symlinks if this entry points at a
696 /// # Platform behavior
698 /// On Windows this function is cheap to call (no extra system calls
699 /// needed), but on Unix platforms this function is the equivalent of
700 /// calling `symlink_metadata` on the path.
701 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
702 pub fn metadata(&self) -> io
::Result
<Metadata
> {
703 self.0.metadata().map(Metadata
)
706 /// Return the file type for the file that this entry points at.
708 /// This function will not traverse symlinks if this entry points at a
711 /// # Platform behavior
713 /// On Windows and most Unix platforms this function is free (no extra
714 /// system calls needed), but some Unix platforms may require the equivalent
715 /// call to `symlink_metadata` to learn about the target file type.
716 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
717 pub fn file_type(&self) -> io
::Result
<FileType
> {
718 self.0.file_type
().map(FileType
)
721 /// Returns the bare file name of this directory entry without any other
722 /// leading path component.
723 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
724 pub fn file_name(&self) -> OsString
{
729 impl AsInner
<fs_imp
::DirEntry
> for DirEntry
{
730 fn as_inner(&self) -> &fs_imp
::DirEntry { &self.0 }
733 /// Removes a file from the underlying filesystem.
735 /// Note that, just because an unlink call was successful, it is not
736 /// guaranteed that a file is immediately deleted (e.g. depending on
737 /// platform, other open file descriptors may prevent immediate removal).
741 /// This function will return an error if `path` points to a directory, if the
742 /// user lacks permissions to remove the file, or if some other filesystem-level
750 /// # fn foo() -> std::io::Result<()> {
751 /// try!(fs::remove_file("a.txt"));
755 #[stable(feature = "rust1", since = "1.0.0")]
756 pub fn remove_file
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<()> {
757 fs_imp
::unlink(path
.as_ref())
760 /// Given a path, query the file system to get information about a file,
763 /// This function will traverse symbolic links to query information about the
764 /// destination file.
769 /// # fn foo() -> std::io::Result<()> {
772 /// let attr = try!(fs::metadata("/some/file/path.txt"));
773 /// // inspect attr ...
780 /// This function will return an error if the user lacks the requisite
781 /// permissions to perform a `metadata` call on the given `path` or if there
782 /// is no entry in the filesystem at the provided path.
783 #[stable(feature = "rust1", since = "1.0.0")]
784 pub fn metadata
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<Metadata
> {
785 fs_imp
::stat(path
.as_ref()).map(Metadata
)
788 /// Query the metadata about a file without following symlinks.
793 /// # fn foo() -> std::io::Result<()> {
796 /// let attr = try!(fs::symlink_metadata("/some/file/path.txt"));
797 /// // inspect attr ...
801 #[stable(feature = "symlink_metadata", since = "1.1.0")]
802 pub fn symlink_metadata
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<Metadata
> {
803 fs_imp
::lstat(path
.as_ref()).map(Metadata
)
806 /// Rename a file or directory to a new name.
808 /// This will not work if the new name is on a different mount point.
812 /// This function will return an error if the provided `from` doesn't exist, if
813 /// the process lacks permissions to view the contents, if `from` and `to`
814 /// reside on separate filesystems, or if some other intermittent I/O error
822 /// # fn foo() -> std::io::Result<()> {
823 /// try!(fs::rename("a.txt", "b.txt"));
827 #[stable(feature = "rust1", since = "1.0.0")]
828 pub fn rename
<P
: AsRef
<Path
>, Q
: AsRef
<Path
>>(from
: P
, to
: Q
) -> io
::Result
<()> {
829 fs_imp
::rename(from
.as_ref(), to
.as_ref())
832 /// Copies the contents of one file to another. This function will also
833 /// copy the permission bits of the original file to the destination file.
835 /// This function will **overwrite** the contents of `to`.
837 /// Note that if `from` and `to` both point to the same file, then the file
838 /// will likely get truncated by this operation.
842 /// This function will return an error in the following situations, but is not
843 /// limited to just these cases:
845 /// * The `from` path is not a file
846 /// * The `from` file does not exist
847 /// * The current process does not have the permission rights to access
848 /// `from` or write `to`
855 /// # fn foo() -> std::io::Result<()> {
856 /// try!(fs::copy("foo.txt", "bar.txt"));
859 #[stable(feature = "rust1", since = "1.0.0")]
860 pub fn copy
<P
: AsRef
<Path
>, Q
: AsRef
<Path
>>(from
: P
, to
: Q
) -> io
::Result
<u64> {
861 let from
= from
.as_ref();
862 let to
= to
.as_ref();
864 return Err(Error
::new(ErrorKind
::InvalidInput
,
865 "the source path is not an existing file"))
868 let mut reader
= try
!(File
::open(from
));
869 let mut writer
= try
!(File
::create(to
));
870 let perm
= try
!(reader
.metadata()).permissions();
872 let ret
= try
!(io
::copy(&mut reader
, &mut writer
));
873 try
!(set_permissions(to
, perm
));
877 /// Creates a new hard link on the filesystem.
879 /// The `dst` path will be a link pointing to the `src` path. Note that systems
880 /// often require these two paths to both be located on the same filesystem.
887 /// # fn foo() -> std::io::Result<()> {
888 /// try!(fs::hard_link("a.txt", "b.txt"));
892 #[stable(feature = "rust1", since = "1.0.0")]
893 pub fn hard_link
<P
: AsRef
<Path
>, Q
: AsRef
<Path
>>(src
: P
, dst
: Q
) -> io
::Result
<()> {
894 fs_imp
::link(src
.as_ref(), dst
.as_ref())
897 /// Creates a new symbolic link on the filesystem.
899 /// The `dst` path will be a symbolic link pointing to the `src` path.
900 /// On Windows, this will be a file symlink, not a directory symlink;
901 /// for this reason, the platform-specific `std::os::unix::fs::symlink`
902 /// and `std::os::windows::fs::{symlink_file, symlink_dir}` should be
903 /// used instead to make the intent explicit.
910 /// # fn foo() -> std::io::Result<()> {
911 /// try!(fs::soft_link("a.txt", "b.txt"));
915 #[deprecated(since = "1.1.0",
916 reason
= "replaced with std::os::unix::fs::symlink and \
917 std::os::windows::fs::{symlink_file, symlink_dir}")]
918 #[stable(feature = "rust1", since = "1.0.0")]
919 pub fn soft_link
<P
: AsRef
<Path
>, Q
: AsRef
<Path
>>(src
: P
, dst
: Q
) -> io
::Result
<()> {
920 fs_imp
::symlink(src
.as_ref(), dst
.as_ref())
923 /// Reads a symbolic link, returning the file that the link points to.
927 /// This function will return an error on failure. Failure conditions include
928 /// reading a file that does not exist or reading a file that is not a symbolic
936 /// # fn foo() -> std::io::Result<()> {
937 /// let path = try!(fs::read_link("a.txt"));
941 #[stable(feature = "rust1", since = "1.0.0")]
942 pub fn read_link
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<PathBuf
> {
943 fs_imp
::readlink(path
.as_ref())
946 /// Returns the canonical form of a path with all intermediate components
947 /// normalized and symbolic links resolved.
948 #[unstable(feature = "fs_canonicalize", reason = "recently added API")]
949 pub fn canonicalize
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<PathBuf
> {
950 fs_imp
::canonicalize(path
.as_ref())
953 /// Creates a new, empty directory at the provided path
957 /// This function will return an error if the user lacks permissions to make a
958 /// new directory at the provided `path`, or if the directory already exists.
965 /// # fn foo() -> std::io::Result<()> {
966 /// try!(fs::create_dir("/some/dir"));
970 #[stable(feature = "rust1", since = "1.0.0")]
971 pub fn create_dir
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<()> {
972 DirBuilder
::new().create(path
.as_ref())
975 /// Recursively create a directory and all of its parent components if they
980 /// This function will fail if any directory in the path specified by `path`
981 /// does not already exist and it could not be created otherwise. The specific
982 /// error conditions for when a directory is being created (after it is
983 /// determined to not exist) are outlined by `fs::create_dir`.
990 /// # fn foo() -> std::io::Result<()> {
991 /// try!(fs::create_dir_all("/some/dir"));
995 #[stable(feature = "rust1", since = "1.0.0")]
996 pub fn create_dir_all
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<()> {
997 DirBuilder
::new().recursive(true).create(path
.as_ref())
1000 /// Removes an existing, empty directory.
1004 /// This function will return an error if the user lacks permissions to remove
1005 /// the directory at the provided `path`, or if the directory isn't empty.
1012 /// # fn foo() -> std::io::Result<()> {
1013 /// try!(fs::remove_dir("/some/dir"));
1017 #[stable(feature = "rust1", since = "1.0.0")]
1018 pub fn remove_dir
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<()> {
1019 fs_imp
::rmdir(path
.as_ref())
1022 /// Removes a directory at this path, after removing all its contents. Use
1025 /// This function does **not** follow symbolic links and it will simply remove the
1026 /// symbolic link itself.
1030 /// See `file::remove_file` and `fs::remove_dir`.
1037 /// # fn foo() -> std::io::Result<()> {
1038 /// try!(fs::remove_dir_all("/some/dir"));
1042 #[stable(feature = "rust1", since = "1.0.0")]
1043 pub fn remove_dir_all
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<()> {
1044 let path
= path
.as_ref();
1045 for child
in try
!(read_dir(path
)) {
1046 let child
= try
!(child
).path();
1047 let stat
= try
!(symlink_metadata(&*child
));
1049 try
!(remove_dir_all(&*child
));
1051 try
!(remove_file(&*child
));
1057 /// Returns an iterator over the entries within a directory.
1059 /// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
1060 /// be encountered after an iterator is initially constructed.
1066 /// use std::fs::{self, DirEntry};
1067 /// use std::path::Path;
1069 /// // one possible implementation of fs::walk_dir only visiting files
1070 /// fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
1071 /// if try!(fs::metadata(dir)).is_dir() {
1072 /// for entry in try!(fs::read_dir(dir)) {
1073 /// let entry = try!(entry);
1074 /// if try!(fs::metadata(entry.path())).is_dir() {
1075 /// try!(visit_dirs(&entry.path(), cb));
1087 /// This function will return an error if the provided `path` doesn't exist, if
1088 /// the process lacks permissions to view the contents or if the `path` points
1089 /// at a non-directory file
1090 #[stable(feature = "rust1", since = "1.0.0")]
1091 pub fn read_dir
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<ReadDir
> {
1092 fs_imp
::readdir(path
.as_ref()).map(ReadDir
)
1095 /// Returns an iterator that will recursively walk the directory structure
1096 /// rooted at `path`.
1098 /// The path given will not be iterated over, and this will perform iteration in
1099 /// some top-down order. The contents of unreadable subdirectories are ignored.
1101 /// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
1102 /// be encountered after an iterator is initially constructed.
1103 #[unstable(feature = "fs_walk",
1104 reason
= "the precise semantics and defaults for a recursive walk \
1105 may change and this may end up accounting for files such \
1106 as symlinks differently")]
1107 pub fn walk_dir
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<WalkDir
> {
1108 let start
= try
!(read_dir(path
));
1109 Ok(WalkDir { cur: Some(start), stack: Vec::new() }
)
1112 #[unstable(feature = "fs_walk")]
1113 impl Iterator
for WalkDir
{
1114 type Item
= io
::Result
<DirEntry
>;
1116 fn next(&mut self) -> Option
<io
::Result
<DirEntry
>> {
1118 if let Some(ref mut cur
) = self.cur
{
1120 Some(Err(e
)) => return Some(Err(e
)),
1122 let path
= next
.path();
1124 self.stack
.push(read_dir(&*path
));
1126 return Some(Ok(next
))
1132 match self.stack
.pop() {
1133 Some(Err(e
)) => return Some(Err(e
)),
1134 Some(Ok(next
)) => self.cur
= Some(next
),
1135 None
=> return None
,
1141 /// Utility methods for paths.
1142 #[unstable(feature = "path_ext",
1143 reason
= "The precise set of methods exposed on this trait may \
1144 change and some methods may be removed. For stable code, \
1145 see the std::fs::metadata function.")]
1147 /// Gets information on the file, directory, etc at this path.
1149 /// Consult the `fs::metadata` documentation for more info.
1151 /// This call preserves identical runtime/error semantics with
1153 fn metadata(&self) -> io
::Result
<Metadata
>;
1155 /// Gets information on the file, directory, etc at this path.
1157 /// Consult the `fs::symlink_metadata` documentation for more info.
1159 /// This call preserves identical runtime/error semantics with
1160 /// `fs::symlink_metadata`.
1161 fn symlink_metadata(&self) -> io
::Result
<Metadata
>;
1163 /// Returns the canonical form of a path, normalizing all components and
1164 /// eliminate all symlinks.
1166 /// This call preserves identical runtime/error semantics with
1167 /// `fs::canonicalize`.
1168 fn canonicalize(&self) -> io
::Result
<PathBuf
>;
1170 /// Reads the symlink at this path.
1172 /// For more information see `fs::read_link`.
1173 fn read_link(&self) -> io
::Result
<PathBuf
>;
1175 /// Reads the directory at this path.
1177 /// For more information see `fs::read_dir`.
1178 fn read_dir(&self) -> io
::Result
<ReadDir
>;
1180 /// Boolean value indicator whether the underlying file exists on the local
1181 /// filesystem. Returns false in exactly the cases where `fs::stat` fails.
1182 fn exists(&self) -> bool
;
1184 /// Whether the underlying implementation (be it a file path, or something
1185 /// else) points at a "regular file" on the FS. Will return false for paths
1186 /// to non-existent locations or directories or other non-regular files
1187 /// (named pipes, etc). Follows links when making this determination.
1188 fn is_file(&self) -> bool
;
1190 /// Whether the underlying implementation (be it a file path, or something
1191 /// else) is pointing at a directory in the underlying FS. Will return
1192 /// false for paths to non-existent locations or if the item is not a
1193 /// directory (eg files, named pipes, etc). Follows links when making this
1195 fn is_dir(&self) -> bool
;
1198 impl PathExt
for Path
{
1199 fn metadata(&self) -> io
::Result
<Metadata
> { metadata(self) }
1200 fn symlink_metadata(&self) -> io
::Result
<Metadata
> { symlink_metadata(self) }
1201 fn canonicalize(&self) -> io
::Result
<PathBuf
> { canonicalize(self) }
1202 fn read_link(&self) -> io
::Result
<PathBuf
> { read_link(self) }
1203 fn read_dir(&self) -> io
::Result
<ReadDir
> { read_dir(self) }
1204 fn exists(&self) -> bool { metadata(self).is_ok() }
1206 fn is_file(&self) -> bool
{
1207 metadata(self).map(|s
| s
.is_file()).unwrap_or(false)
1210 fn is_dir(&self) -> bool
{
1211 metadata(self).map(|s
| s
.is_dir()).unwrap_or(false)
1215 /// Changes the timestamps for a file's last modification and access time.
1217 /// The file at the path specified will have its last access time set to
1218 /// `accessed` and its modification time set to `modified`. The times specified
1219 /// should be in milliseconds.
1220 #[unstable(feature = "fs_time",
1221 reason
= "the argument type of u64 is not quite appropriate for \
1222 this function and may change if the standard library \
1223 gains a type to represent a moment in time")]
1224 pub fn set_file_times
<P
: AsRef
<Path
>>(path
: P
, accessed
: u64,
1225 modified
: u64) -> io
::Result
<()> {
1226 fs_imp
::utimes(path
.as_ref(), accessed
, modified
)
1229 /// Changes the permissions found on a file or a directory.
1234 /// # fn foo() -> std::io::Result<()> {
1237 /// let mut perms = try!(fs::metadata("foo.txt")).permissions();
1238 /// perms.set_readonly(true);
1239 /// try!(fs::set_permissions("foo.txt", perms));
1246 /// This function will return an error if the provided `path` doesn't exist, if
1247 /// the process lacks permissions to change the attributes of the file, or if
1248 /// some other I/O error is encountered.
1249 #[stable(feature = "set_permissions", since = "1.1.0")]
1250 pub fn set_permissions
<P
: AsRef
<Path
>>(path
: P
, perm
: Permissions
)
1252 fs_imp
::set_perm(path
.as_ref(), perm
.0)
1255 #[unstable(feature = "dir_builder", reason = "recently added API")]
1257 /// Creates a new set of options with default mode/security settings for all
1258 /// platforms and also non-recursive.
1259 pub fn new() -> DirBuilder
{
1261 inner
: fs_imp
::DirBuilder
::new(),
1266 /// Indicate that directories create should be created recursively, creating
1267 /// all parent directories if they do not exist with the same security and
1268 /// permissions settings.
1270 /// This option defaults to `false`
1271 pub fn recursive(&mut self, recursive
: bool
) -> &mut Self {
1272 self.recursive
= recursive
;
1276 /// Create the specified directory with the options configured in this
1278 pub fn create
<P
: AsRef
<Path
>>(&self, path
: P
) -> io
::Result
<()> {
1279 let path
= path
.as_ref();
1281 self.create_dir_all(path
)
1283 self.inner
.mkdir(path
)
1287 fn create_dir_all(&self, path
: &Path
) -> io
::Result
<()> {
1288 if path
== Path
::new("") || path
.is_dir() { return Ok(()) }
1289 if let Some(p
) = path
.parent() {
1290 try
!(self.create_dir_all(p
))
1292 self.inner
.mkdir(path
)
1296 impl AsInnerMut
<fs_imp
::DirBuilder
> for DirBuilder
{
1297 fn as_inner_mut(&mut self) -> &mut fs_imp
::DirBuilder
{
1304 #![allow(deprecated)] //rand
1310 use fs
::{self, File, OpenOptions}
;
1311 use io
::{ErrorKind, SeekFrom}
;
1313 use path
::Path
as Path2
;
1315 use rand
::{self, StdRng, Rng}
;
1318 macro_rules
! check
{ ($e
:expr
) => (
1321 Err(e
) => panic
!("{} failed with: {}", stringify
!($e
), e
),
1325 macro_rules
! error
{ ($e
:expr
, $s
:expr
) => (
1327 Ok(_
) => panic
!("Unexpected success. Should've been: {:?}", $s
),
1328 Err(ref err
) => assert
!(err
.to_string().contains($s
),
1329 format
!("`{}` did not contain `{}`", err
, $s
))
1333 pub struct TempDir(PathBuf
);
1336 fn join(&self, path
: &str) -> PathBuf
{
1337 let TempDir(ref p
) = *self;
1341 fn path
<'a
>(&'a
self) -> &'a Path2
{
1342 let TempDir(ref p
) = *self;
1347 impl Drop
for TempDir
{
1348 fn drop(&mut self) {
1349 // Gee, seeing how we're testing the fs module I sure hope that we
1350 // at least implement this correctly!
1351 let TempDir(ref p
) = *self;
1352 check
!(fs
::remove_dir_all(p
));
1356 pub fn tmpdir() -> TempDir
{
1357 let p
= env
::temp_dir();
1358 let mut r
= rand
::thread_rng();
1359 let ret
= p
.join(&format
!("rust-{}", r
.next_u32()));
1360 check
!(fs
::create_dir(&ret
));
1365 fn file_test_io_smoke_test() {
1366 let message
= "it's alright. have a good time";
1367 let tmpdir
= tmpdir();
1368 let filename
= &tmpdir
.join("file_rt_io_file_test.txt");
1370 let mut write_stream
= check
!(File
::create(filename
));
1371 check
!(write_stream
.write(message
.as_bytes()));
1374 let mut read_stream
= check
!(File
::open(filename
));
1375 let mut read_buf
= [0; 1028];
1376 let read_str
= match check
!(read_stream
.read(&mut read_buf
)) {
1377 0 => panic
!("shouldn't happen"),
1378 n
=> str::from_utf8(&read_buf
[..n
]).unwrap().to_string()
1380 assert_eq
!(read_str
, message
);
1382 check
!(fs
::remove_file(filename
));
1386 fn invalid_path_raises() {
1387 let tmpdir
= tmpdir();
1388 let filename
= &tmpdir
.join("file_that_does_not_exist.txt");
1389 let result
= File
::open(filename
);
1392 error
!(result
, "o such file or directory");
1394 // error!(result, "couldn't open path as file");
1395 // error!(result, format!("path={}; mode=open; access=read", filename.display()));
1399 fn file_test_iounlinking_invalid_path_should_raise_condition() {
1400 let tmpdir
= tmpdir();
1401 let filename
= &tmpdir
.join("file_another_file_that_does_not_exist.txt");
1403 let result
= fs
::remove_file(filename
);
1406 error
!(result
, "o such file or directory");
1408 // error!(result, "couldn't unlink path");
1409 // error!(result, format!("path={}", filename.display()));
1413 fn file_test_io_non_positional_read() {
1414 let message
: &str = "ten-four";
1415 let mut read_mem
= [0; 8];
1416 let tmpdir
= tmpdir();
1417 let filename
= &tmpdir
.join("file_rt_io_file_test_positional.txt");
1419 let mut rw_stream
= check
!(File
::create(filename
));
1420 check
!(rw_stream
.write(message
.as_bytes()));
1423 let mut read_stream
= check
!(File
::open(filename
));
1425 let read_buf
= &mut read_mem
[0..4];
1426 check
!(read_stream
.read(read_buf
));
1429 let read_buf
= &mut read_mem
[4..8];
1430 check
!(read_stream
.read(read_buf
));
1433 check
!(fs
::remove_file(filename
));
1434 let read_str
= str::from_utf8(&read_mem
).unwrap();
1435 assert_eq
!(read_str
, message
);
1439 fn file_test_io_seek_and_tell_smoke_test() {
1440 let message
= "ten-four";
1441 let mut read_mem
= [0; 4];
1442 let set_cursor
= 4 as u64;
1443 let mut tell_pos_pre_read
;
1444 let mut tell_pos_post_read
;
1445 let tmpdir
= tmpdir();
1446 let filename
= &tmpdir
.join("file_rt_io_file_test_seeking.txt");
1448 let mut rw_stream
= check
!(File
::create(filename
));
1449 check
!(rw_stream
.write(message
.as_bytes()));
1452 let mut read_stream
= check
!(File
::open(filename
));
1453 check
!(read_stream
.seek(SeekFrom
::Start(set_cursor
)));
1454 tell_pos_pre_read
= check
!(read_stream
.seek(SeekFrom
::Current(0)));
1455 check
!(read_stream
.read(&mut read_mem
));
1456 tell_pos_post_read
= check
!(read_stream
.seek(SeekFrom
::Current(0)));
1458 check
!(fs
::remove_file(filename
));
1459 let read_str
= str::from_utf8(&read_mem
).unwrap();
1460 assert_eq
!(read_str
, &message
[4..8]);
1461 assert_eq
!(tell_pos_pre_read
, set_cursor
);
1462 assert_eq
!(tell_pos_post_read
, message
.len() as u64);
1466 fn file_test_io_seek_and_write() {
1467 let initial_msg
= "food-is-yummy";
1468 let overwrite_msg
= "-the-bar!!";
1469 let final_msg
= "foo-the-bar!!";
1471 let mut read_mem
= [0; 13];
1472 let tmpdir
= tmpdir();
1473 let filename
= &tmpdir
.join("file_rt_io_file_test_seek_and_write.txt");
1475 let mut rw_stream
= check
!(File
::create(filename
));
1476 check
!(rw_stream
.write(initial_msg
.as_bytes()));
1477 check
!(rw_stream
.seek(SeekFrom
::Start(seek_idx
)));
1478 check
!(rw_stream
.write(overwrite_msg
.as_bytes()));
1481 let mut read_stream
= check
!(File
::open(filename
));
1482 check
!(read_stream
.read(&mut read_mem
));
1484 check
!(fs
::remove_file(filename
));
1485 let read_str
= str::from_utf8(&read_mem
).unwrap();
1486 assert
!(read_str
== final_msg
);
1490 fn file_test_io_seek_shakedown() {
1492 let initial_msg
= "qwer-asdf-zxcv";
1493 let chunk_one
: &str = "qwer";
1494 let chunk_two
: &str = "asdf";
1495 let chunk_three
: &str = "zxcv";
1496 let mut read_mem
= [0; 4];
1497 let tmpdir
= tmpdir();
1498 let filename
= &tmpdir
.join("file_rt_io_file_test_seek_shakedown.txt");
1500 let mut rw_stream
= check
!(File
::create(filename
));
1501 check
!(rw_stream
.write(initial_msg
.as_bytes()));
1504 let mut read_stream
= check
!(File
::open(filename
));
1506 check
!(read_stream
.seek(SeekFrom
::End(-4)));
1507 check
!(read_stream
.read(&mut read_mem
));
1508 assert_eq
!(str::from_utf8(&read_mem
).unwrap(), chunk_three
);
1510 check
!(read_stream
.seek(SeekFrom
::Current(-9)));
1511 check
!(read_stream
.read(&mut read_mem
));
1512 assert_eq
!(str::from_utf8(&read_mem
).unwrap(), chunk_two
);
1514 check
!(read_stream
.seek(SeekFrom
::Start(0)));
1515 check
!(read_stream
.read(&mut read_mem
));
1516 assert_eq
!(str::from_utf8(&read_mem
).unwrap(), chunk_one
);
1518 check
!(fs
::remove_file(filename
));
1522 fn file_test_stat_is_correct_on_is_file() {
1523 let tmpdir
= tmpdir();
1524 let filename
= &tmpdir
.join("file_stat_correct_on_is_file.txt");
1526 let mut opts
= OpenOptions
::new();
1527 let mut fs
= check
!(opts
.read(true).write(true)
1528 .create(true).open(filename
));
1530 fs
.write(msg
.as_bytes()).unwrap();
1532 let fstat_res
= check
!(fs
.metadata());
1533 assert
!(fstat_res
.is_file());
1535 let stat_res_fn
= check
!(fs
::metadata(filename
));
1536 assert
!(stat_res_fn
.is_file());
1537 let stat_res_meth
= check
!(filename
.metadata());
1538 assert
!(stat_res_meth
.is_file());
1539 check
!(fs
::remove_file(filename
));
1543 fn file_test_stat_is_correct_on_is_dir() {
1544 let tmpdir
= tmpdir();
1545 let filename
= &tmpdir
.join("file_stat_correct_on_is_dir");
1546 check
!(fs
::create_dir(filename
));
1547 let stat_res_fn
= check
!(fs
::metadata(filename
));
1548 assert
!(stat_res_fn
.is_dir());
1549 let stat_res_meth
= check
!(filename
.metadata());
1550 assert
!(stat_res_meth
.is_dir());
1551 check
!(fs
::remove_dir(filename
));
1555 fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
1556 let tmpdir
= tmpdir();
1557 let dir
= &tmpdir
.join("fileinfo_false_on_dir");
1558 check
!(fs
::create_dir(dir
));
1559 assert
!(dir
.is_file() == false);
1560 check
!(fs
::remove_dir(dir
));
1564 fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
1565 let tmpdir
= tmpdir();
1566 let file
= &tmpdir
.join("fileinfo_check_exists_b_and_a.txt");
1567 check
!(check
!(File
::create(file
)).write(b
"foo"));
1568 assert
!(file
.exists());
1569 check
!(fs
::remove_file(file
));
1570 assert
!(!file
.exists());
1574 fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
1575 let tmpdir
= tmpdir();
1576 let dir
= &tmpdir
.join("before_and_after_dir");
1577 assert
!(!dir
.exists());
1578 check
!(fs
::create_dir(dir
));
1579 assert
!(dir
.exists());
1580 assert
!(dir
.is_dir());
1581 check
!(fs
::remove_dir(dir
));
1582 assert
!(!dir
.exists());
1586 fn file_test_directoryinfo_readdir() {
1587 let tmpdir
= tmpdir();
1588 let dir
= &tmpdir
.join("di_readdir");
1589 check
!(fs
::create_dir(dir
));
1592 let f
= dir
.join(&format
!("{}.txt", n
));
1593 let mut w
= check
!(File
::create(&f
));
1594 let msg_str
= format
!("{}{}", prefix
, n
.to_string());
1595 let msg
= msg_str
.as_bytes();
1596 check
!(w
.write(msg
));
1598 let files
= check
!(fs
::read_dir(dir
));
1599 let mut mem
= [0; 4];
1601 let f
= f
.unwrap().path();
1603 let n
= f
.file_stem().unwrap();
1604 check
!(check
!(File
::open(&f
)).read(&mut mem
));
1605 let read_str
= str::from_utf8(&mem
).unwrap();
1606 let expected
= format
!("{}{}", prefix
, n
.to_str().unwrap());
1607 assert_eq
!(expected
, read_str
);
1609 check
!(fs
::remove_file(&f
));
1611 check
!(fs
::remove_dir(dir
));
1615 fn file_test_walk_dir() {
1616 let tmpdir
= tmpdir();
1617 let dir
= &tmpdir
.join("walk_dir");
1618 check
!(fs
::create_dir(dir
));
1620 let dir1
= &dir
.join("01/02/03");
1621 check
!(fs
::create_dir_all(dir1
));
1622 check
!(File
::create(&dir1
.join("04")));
1624 let dir2
= &dir
.join("11/12/13");
1625 check
!(fs
::create_dir_all(dir2
));
1626 check
!(File
::create(&dir2
.join("14")));
1628 let files
= check
!(fs
::walk_dir(dir
));
1629 let mut cur
= [0; 2];
1631 let f
= f
.unwrap().path();
1632 let stem
= f
.file_stem().unwrap().to_str().unwrap();
1633 let root
= stem
.as_bytes()[0] - b'
0'
;
1634 let name
= stem
.as_bytes()[1] - b'
0'
;
1635 assert
!(cur
[root
as usize] < name
);
1636 cur
[root
as usize] = name
;
1639 check
!(fs
::remove_dir_all(dir
));
1643 fn mkdir_path_already_exists_error() {
1644 let tmpdir
= tmpdir();
1645 let dir
= &tmpdir
.join("mkdir_error_twice");
1646 check
!(fs
::create_dir(dir
));
1647 let e
= fs
::create_dir(dir
).err().unwrap();
1648 assert_eq
!(e
.kind(), ErrorKind
::AlreadyExists
);
1652 fn recursive_mkdir() {
1653 let tmpdir
= tmpdir();
1654 let dir
= tmpdir
.join("d1/d2");
1655 check
!(fs
::create_dir_all(&dir
));
1656 assert
!(dir
.is_dir())
1660 fn recursive_mkdir_failure() {
1661 let tmpdir
= tmpdir();
1662 let dir
= tmpdir
.join("d1");
1663 let file
= dir
.join("f1");
1665 check
!(fs
::create_dir_all(&dir
));
1666 check
!(File
::create(&file
));
1668 let result
= fs
::create_dir_all(&file
);
1670 assert
!(result
.is_err());
1671 // error!(result, "couldn't recursively mkdir");
1672 // error!(result, "couldn't create directory");
1673 // error!(result, "mode=0700");
1674 // error!(result, format!("path={}", file.display()));
1678 fn recursive_mkdir_slash() {
1679 check
!(fs
::create_dir_all(&Path2
::new("/")));
1682 // FIXME(#12795) depends on lstat to work on windows
1683 #[cfg(not(windows))]
1685 fn recursive_rmdir() {
1686 let tmpdir
= tmpdir();
1687 let d1
= tmpdir
.join("d1");
1688 let dt
= d1
.join("t");
1689 let dtt
= dt
.join("t");
1690 let d2
= tmpdir
.join("d2");
1691 let canary
= d2
.join("do_not_delete");
1692 check
!(fs
::create_dir_all(&dtt
));
1693 check
!(fs
::create_dir_all(&d2
));
1694 check
!(check
!(File
::create(&canary
)).write(b
"foo"));
1695 check
!(fs
::soft_link(&d2
, &dt
.join("d2")));
1696 check
!(fs
::remove_dir_all(&d1
));
1698 assert
!(!d1
.is_dir());
1699 assert
!(canary
.exists());
1703 fn unicode_path_is_dir() {
1704 assert
!(Path2
::new(".").is_dir());
1705 assert
!(!Path2
::new("test/stdtest/fs.rs").is_dir());
1707 let tmpdir
= tmpdir();
1709 let mut dirpath
= tmpdir
.path().to_path_buf();
1710 dirpath
.push(&format
!("test-가一ー你好"));
1711 check
!(fs
::create_dir(&dirpath
));
1712 assert
!(dirpath
.is_dir());
1714 let mut filepath
= dirpath
;
1715 filepath
.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
1716 check
!(File
::create(&filepath
)); // ignore return; touch only
1717 assert
!(!filepath
.is_dir());
1718 assert
!(filepath
.exists());
1722 fn unicode_path_exists() {
1723 assert
!(Path2
::new(".").exists());
1724 assert
!(!Path2
::new("test/nonexistent-bogus-path").exists());
1726 let tmpdir
= tmpdir();
1727 let unicode
= tmpdir
.path();
1728 let unicode
= unicode
.join(&format
!("test-각丁ー再见"));
1729 check
!(fs
::create_dir(&unicode
));
1730 assert
!(unicode
.exists());
1731 assert
!(!Path2
::new("test/unicode-bogus-path-각丁ー再见").exists());
1735 fn copy_file_does_not_exist() {
1736 let from
= Path2
::new("test/nonexistent-bogus-path");
1737 let to
= Path2
::new("test/other-bogus-path");
1739 match fs
::copy(&from
, &to
) {
1742 assert
!(!from
.exists());
1743 assert
!(!to
.exists());
1750 let tmpdir
= tmpdir();
1751 let input
= tmpdir
.join("in.txt");
1752 let out
= tmpdir
.join("out.txt");
1754 check
!(check
!(File
::create(&input
)).write(b
"hello"));
1755 check
!(fs
::copy(&input
, &out
));
1756 let mut v
= Vec
::new();
1757 check
!(check
!(File
::open(&out
)).read_to_end(&mut v
));
1758 assert_eq
!(v
, b
"hello");
1760 assert_eq
!(check
!(input
.metadata()).permissions(),
1761 check
!(out
.metadata()).permissions());
1765 fn copy_file_dst_dir() {
1766 let tmpdir
= tmpdir();
1767 let out
= tmpdir
.join("out");
1769 check
!(File
::create(&out
));
1770 match fs
::copy(&*out
, tmpdir
.path()) {
1771 Ok(..) => panic
!(), Err(..) => {}
1776 fn copy_file_dst_exists() {
1777 let tmpdir
= tmpdir();
1778 let input
= tmpdir
.join("in");
1779 let output
= tmpdir
.join("out");
1781 check
!(check
!(File
::create(&input
)).write("foo".as_bytes()));
1782 check
!(check
!(File
::create(&output
)).write("bar".as_bytes()));
1783 check
!(fs
::copy(&input
, &output
));
1785 let mut v
= Vec
::new();
1786 check
!(check
!(File
::open(&output
)).read_to_end(&mut v
));
1787 assert_eq
!(v
, b
"foo".to_vec());
1791 fn copy_file_src_dir() {
1792 let tmpdir
= tmpdir();
1793 let out
= tmpdir
.join("out");
1795 match fs
::copy(tmpdir
.path(), &out
) {
1796 Ok(..) => panic
!(), Err(..) => {}
1798 assert
!(!out
.exists());
1802 fn copy_file_preserves_perm_bits() {
1803 let tmpdir
= tmpdir();
1804 let input
= tmpdir
.join("in.txt");
1805 let out
= tmpdir
.join("out.txt");
1807 let attr
= check
!(check
!(File
::create(&input
)).metadata());
1808 let mut p
= attr
.permissions();
1809 p
.set_readonly(true);
1810 check
!(fs
::set_permissions(&input
, p
));
1811 check
!(fs
::copy(&input
, &out
));
1812 assert
!(check
!(out
.metadata()).permissions().readonly());
1813 check
!(fs
::set_permissions(&input
, attr
.permissions()));
1814 check
!(fs
::set_permissions(&out
, attr
.permissions()));
1817 #[cfg(not(windows))] // FIXME(#10264) operation not permitted?
1819 fn symlinks_work() {
1820 let tmpdir
= tmpdir();
1821 let input
= tmpdir
.join("in.txt");
1822 let out
= tmpdir
.join("out.txt");
1824 check
!(check
!(File
::create(&input
)).write("foobar".as_bytes()));
1825 check
!(fs
::soft_link(&input
, &out
));
1826 // if cfg!(not(windows)) {
1827 // assert_eq!(check!(lstat(&out)).kind, FileType::Symlink);
1828 // assert_eq!(check!(out.lstat()).kind, FileType::Symlink);
1830 assert_eq
!(check
!(fs
::metadata(&out
)).len(),
1831 check
!(fs
::metadata(&input
)).len());
1832 let mut v
= Vec
::new();
1833 check
!(check
!(File
::open(&out
)).read_to_end(&mut v
));
1834 assert_eq
!(v
, b
"foobar".to_vec());
1837 #[cfg(not(windows))] // apparently windows doesn't like symlinks
1839 fn symlink_noexist() {
1840 let tmpdir
= tmpdir();
1841 // symlinks can point to things that don't exist
1842 check
!(fs
::soft_link(&tmpdir
.join("foo"), &tmpdir
.join("bar")));
1843 assert_eq
!(check
!(fs
::read_link(&tmpdir
.join("bar"))),
1844 tmpdir
.join("foo"));
1848 fn readlink_not_symlink() {
1849 let tmpdir
= tmpdir();
1850 match fs
::read_link(tmpdir
.path()) {
1851 Ok(..) => panic
!("wanted a failure"),
1858 let tmpdir
= tmpdir();
1859 let input
= tmpdir
.join("in.txt");
1860 let out
= tmpdir
.join("out.txt");
1862 check
!(check
!(File
::create(&input
)).write("foobar".as_bytes()));
1863 check
!(fs
::hard_link(&input
, &out
));
1864 assert_eq
!(check
!(fs
::metadata(&out
)).len(),
1865 check
!(fs
::metadata(&input
)).len());
1866 assert_eq
!(check
!(fs
::metadata(&out
)).len(),
1867 check
!(input
.metadata()).len());
1868 let mut v
= Vec
::new();
1869 check
!(check
!(File
::open(&out
)).read_to_end(&mut v
));
1870 assert_eq
!(v
, b
"foobar".to_vec());
1872 // can't link to yourself
1873 match fs
::hard_link(&input
, &input
) {
1874 Ok(..) => panic
!("wanted a failure"),
1877 // can't link to something that doesn't exist
1878 match fs
::hard_link(&tmpdir
.join("foo"), &tmpdir
.join("bar")) {
1879 Ok(..) => panic
!("wanted a failure"),
1886 let tmpdir
= tmpdir();
1887 let file
= tmpdir
.join("in.txt");
1889 check
!(File
::create(&file
));
1890 let attr
= check
!(fs
::metadata(&file
));
1891 assert
!(!attr
.permissions().readonly());
1892 let mut p
= attr
.permissions();
1893 p
.set_readonly(true);
1894 check
!(fs
::set_permissions(&file
, p
.clone()));
1895 let attr
= check
!(fs
::metadata(&file
));
1896 assert
!(attr
.permissions().readonly());
1898 match fs
::set_permissions(&tmpdir
.join("foo"), p
.clone()) {
1899 Ok(..) => panic
!("wanted an error"),
1903 p
.set_readonly(false);
1904 check
!(fs
::set_permissions(&file
, p
));
1908 fn sync_doesnt_kill_anything() {
1909 let tmpdir
= tmpdir();
1910 let path
= tmpdir
.join("in.txt");
1912 let mut file
= check
!(File
::create(&path
));
1913 check
!(file
.sync_all());
1914 check
!(file
.sync_data());
1915 check
!(file
.write(b
"foo"));
1916 check
!(file
.sync_all());
1917 check
!(file
.sync_data());
1921 fn truncate_works() {
1922 let tmpdir
= tmpdir();
1923 let path
= tmpdir
.join("in.txt");
1925 let mut file
= check
!(File
::create(&path
));
1926 check
!(file
.write(b
"foo"));
1927 check
!(file
.sync_all());
1929 // Do some simple things with truncation
1930 assert_eq
!(check
!(file
.metadata()).len(), 3);
1931 check
!(file
.set_len(10));
1932 assert_eq
!(check
!(file
.metadata()).len(), 10);
1933 check
!(file
.write(b
"bar"));
1934 check
!(file
.sync_all());
1935 assert_eq
!(check
!(file
.metadata()).len(), 10);
1937 let mut v
= Vec
::new();
1938 check
!(check
!(File
::open(&path
)).read_to_end(&mut v
));
1939 assert_eq
!(v
, b
"foobar\0\0\0\0".to_vec());
1941 // Truncate to a smaller length, don't seek, and then write something.
1942 // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
1943 // past the end of the file).
1944 check
!(file
.set_len(2));
1945 assert_eq
!(check
!(file
.metadata()).len(), 2);
1946 check
!(file
.write(b
"wut"));
1947 check
!(file
.sync_all());
1948 assert_eq
!(check
!(file
.metadata()).len(), 9);
1949 let mut v
= Vec
::new();
1950 check
!(check
!(File
::open(&path
)).read_to_end(&mut v
));
1951 assert_eq
!(v
, b
"fo\0\0\0\0wut".to_vec());
1956 use fs
::OpenOptions
as OO
;
1957 fn c
<T
: Clone
>(t
: &T
) -> T { t.clone() }
1959 let tmpdir
= tmpdir();
1961 let mut r
= OO
::new(); r
.read(true);
1962 let mut w
= OO
::new(); w
.write(true);
1963 let mut rw
= OO
::new(); rw
.write(true).read(true);
1965 match r
.open(&tmpdir
.join("a")) {
1966 Ok(..) => panic
!(), Err(..) => {}
1969 // Perform each one twice to make sure that it succeeds the second time
1970 // (where the file exists)
1971 check
!(c(&w
).create(true).open(&tmpdir
.join("b")));
1972 assert
!(tmpdir
.join("b").exists());
1973 check
!(c(&w
).create(true).open(&tmpdir
.join("b")));
1974 check
!(w
.open(&tmpdir
.join("b")));
1976 check
!(c(&rw
).create(true).open(&tmpdir
.join("c")));
1977 assert
!(tmpdir
.join("c").exists());
1978 check
!(c(&rw
).create(true).open(&tmpdir
.join("c")));
1979 check
!(rw
.open(&tmpdir
.join("c")));
1981 check
!(c(&w
).append(true).create(true).open(&tmpdir
.join("d")));
1982 assert
!(tmpdir
.join("d").exists());
1983 check
!(c(&w
).append(true).create(true).open(&tmpdir
.join("d")));
1984 check
!(c(&w
).append(true).open(&tmpdir
.join("d")));
1986 check
!(c(&rw
).append(true).create(true).open(&tmpdir
.join("e")));
1987 assert
!(tmpdir
.join("e").exists());
1988 check
!(c(&rw
).append(true).create(true).open(&tmpdir
.join("e")));
1989 check
!(c(&rw
).append(true).open(&tmpdir
.join("e")));
1991 check
!(c(&w
).truncate(true).create(true).open(&tmpdir
.join("f")));
1992 assert
!(tmpdir
.join("f").exists());
1993 check
!(c(&w
).truncate(true).create(true).open(&tmpdir
.join("f")));
1994 check
!(c(&w
).truncate(true).open(&tmpdir
.join("f")));
1996 check
!(c(&rw
).truncate(true).create(true).open(&tmpdir
.join("g")));
1997 assert
!(tmpdir
.join("g").exists());
1998 check
!(c(&rw
).truncate(true).create(true).open(&tmpdir
.join("g")));
1999 check
!(c(&rw
).truncate(true).open(&tmpdir
.join("g")));
2001 check
!(check
!(File
::create(&tmpdir
.join("h"))).write("foo".as_bytes()));
2002 check
!(r
.open(&tmpdir
.join("h")));
2004 let mut f
= check
!(r
.open(&tmpdir
.join("h")));
2005 assert
!(f
.write("wut".as_bytes()).is_err());
2007 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 3);
2009 let mut f
= check
!(c(&w
).append(true).open(&tmpdir
.join("h")));
2010 check
!(f
.write("bar".as_bytes()));
2012 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 6);
2014 let mut f
= check
!(c(&w
).truncate(true).open(&tmpdir
.join("h")));
2015 check
!(f
.write("bar".as_bytes()));
2017 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 3);
2022 let tmpdir
= tmpdir();
2023 let path
= tmpdir
.join("a");
2024 check
!(File
::create(&path
));
2025 // These numbers have to be bigger than the time in the day to account
2026 // for timezones Windows in particular will fail in certain timezones
2027 // with small enough values
2028 check
!(fs
::set_file_times(&path
, 100_000, 200_000));
2030 check(&check
!(path
.metadata()));
2033 fn check(metadata
: &fs
::Metadata
) {
2034 use os
::unix
::prelude
::*;
2035 assert_eq
!(metadata
.atime(), 100);
2036 assert_eq
!(metadata
.atime_nsec(), 0);
2037 assert_eq
!(metadata
.mtime(), 200);
2038 assert_eq
!(metadata
.mtime_nsec(), 0);
2041 fn check(metadata
: &fs
::Metadata
) {
2042 use os
::windows
::prelude
::*;
2043 assert_eq
!(metadata
.last_access_time(), 100_000 * 10_000);
2044 assert_eq
!(metadata
.last_write_time(), 200_000 * 10_000);
2049 fn utime_noexist() {
2050 let tmpdir
= tmpdir();
2052 match fs
::set_file_times(&tmpdir
.join("a"), 100, 200) {
2060 let mut bytes
= [0; 1024];
2061 StdRng
::new().unwrap().fill_bytes(&mut bytes
);
2063 let tmpdir
= tmpdir();
2065 check
!(check
!(File
::create(&tmpdir
.join("test"))).write(&bytes
));
2066 let mut v
= Vec
::new();
2067 check
!(check
!(File
::open(&tmpdir
.join("test"))).read_to_end(&mut v
));
2068 assert
!(v
== &bytes
[..]);
2072 #[cfg(not(windows))]
2073 fn unlink_readonly() {
2074 let tmpdir
= tmpdir();
2075 let path
= tmpdir
.join("file");
2076 check
!(File
::create(&path
));
2077 let mut perm
= check
!(fs
::metadata(&path
)).permissions();
2078 perm
.set_readonly(true);
2079 check
!(fs
::set_permissions(&path
, perm
));
2080 check
!(fs
::remove_file(&path
));
2084 fn mkdir_trailing_slash() {
2085 let tmpdir
= tmpdir();
2086 let path
= tmpdir
.join("file");
2087 check
!(fs
::create_dir_all(&path
.join("a/")));
2091 #[cfg(not(windows))]
2092 fn realpath_works() {
2093 let tmpdir
= tmpdir();
2094 let tmpdir
= fs
::canonicalize(tmpdir
.path()).unwrap();
2095 let file
= tmpdir
.join("test");
2096 let dir
= tmpdir
.join("test2");
2097 let link
= dir
.join("link");
2098 let linkdir
= tmpdir
.join("test3");
2100 File
::create(&file
).unwrap();
2101 fs
::create_dir(&dir
).unwrap();
2102 fs
::soft_link(&file
, &link
).unwrap();
2103 fs
::soft_link(&dir
, &linkdir
).unwrap();
2105 assert
!(link
.symlink_metadata().unwrap().file_type().is_symlink());
2107 assert_eq
!(fs
::canonicalize(&tmpdir
).unwrap(), tmpdir
);
2108 assert_eq
!(fs
::canonicalize(&file
).unwrap(), file
);
2109 assert_eq
!(fs
::canonicalize(&link
).unwrap(), file
);
2110 assert_eq
!(fs
::canonicalize(&linkdir
).unwrap(), dir
);
2111 assert_eq
!(fs
::canonicalize(&linkdir
.join("link")).unwrap(), file
);
2115 #[cfg(not(windows))]
2116 fn realpath_works_tricky() {
2117 let tmpdir
= tmpdir();
2118 let tmpdir
= fs
::canonicalize(tmpdir
.path()).unwrap();
2120 let a
= tmpdir
.join("a");
2121 let b
= a
.join("b");
2122 let c
= b
.join("c");
2123 let d
= a
.join("d");
2124 let e
= d
.join("e");
2125 let f
= a
.join("f");
2127 fs
::create_dir_all(&b
).unwrap();
2128 fs
::create_dir_all(&d
).unwrap();
2129 File
::create(&f
).unwrap();
2130 fs
::soft_link("../d/e", &c
).unwrap();
2131 fs
::soft_link("../f", &e
).unwrap();
2133 assert_eq
!(fs
::canonicalize(&c
).unwrap(), f
);
2134 assert_eq
!(fs
::canonicalize(&e
).unwrap(), f
);
2138 fn dir_entry_methods() {
2139 let tmpdir
= tmpdir();
2141 fs
::create_dir_all(&tmpdir
.join("a")).unwrap();
2142 File
::create(&tmpdir
.join("b")).unwrap();
2144 for file
in tmpdir
.path().read_dir().unwrap().map(|f
| f
.unwrap()) {
2145 let fname
= file
.file_name();
2146 match fname
.to_str() {
2148 assert
!(file
.file_type().unwrap().is_dir());
2149 assert
!(file
.metadata().unwrap().is_dir());
2152 assert
!(file
.file_type().unwrap().is_file());
2153 assert
!(file
.metadata().unwrap().is_file());
2155 f
=> panic
!("unknown file name: {:?}", f
),