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")]
22 use io
::{self, SeekFrom, Seek, Read, Write}
;
23 use path
::{Path, PathBuf}
;
24 use sys
::fs
as fs_imp
;
25 use sys_common
::{AsInnerMut, FromInner, AsInner, IntoInner}
;
29 /// A reference to an open file on the filesystem.
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.
38 /// use std::io::prelude::*;
39 /// use std::fs::File;
41 /// # fn foo() -> std::io::Result<()> {
42 /// let mut f = try!(File::create("foo.txt"));
43 /// try!(f.write_all(b"Hello, world!"));
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!");
52 #[stable(feature = "rust1", since = "1.0.0")]
57 /// Metadata information about a file.
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")]
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 /// Options and flags which can be used to configure how a file is opened.
90 /// This builder exposes the ability to configure how a `File` is opened and
91 /// what operations are permitted on the open file. The `File::open` and
92 /// `File::create` methods are aliases for commonly used options using this
95 /// Generally speaking, when using `OpenOptions`, you'll first call `new()`,
96 /// then chain calls to methods to set each option, then call `open()`, passing
97 /// the path of the file you're trying to open. This will give you a
98 /// [`io::Result`][result] with a [`File`][file] inside that you can further
101 /// [result]: ../io/type.Result.html
102 /// [file]: struct.File.html
106 /// Opening a file to read:
109 /// use std::fs::OpenOptions;
111 /// let file = OpenOptions::new().read(true).open("foo.txt");
114 /// Opening a file for both reading and writing, as well as creating it if it
118 /// use std::fs::OpenOptions;
120 /// let file = OpenOptions::new()
124 /// .open("foo.txt");
127 #[stable(feature = "rust1", since = "1.0.0")]
128 pub struct OpenOptions(fs_imp
::OpenOptions
);
130 /// Representation of the various permissions on a file.
132 /// This module only currently provides one bit of information, `readonly`,
133 /// which is exposed on all currently supported platforms. Unix-specific
134 /// functionality, such as mode bits, is available through the
135 /// `os::unix::PermissionsExt` trait.
136 #[derive(Clone, PartialEq, Eq, Debug)]
137 #[stable(feature = "rust1", since = "1.0.0")]
138 pub struct Permissions(fs_imp
::FilePermissions
);
140 /// An structure representing a type of file with accessors for each file type.
141 #[stable(feature = "file_type", since = "1.1.0")]
142 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
143 pub struct FileType(fs_imp
::FileType
);
145 /// A builder used to create directories in various manners.
147 /// This builder also supports platform-specific options.
148 #[stable(feature = "dir_builder", since = "1.6.0")]
149 pub struct DirBuilder
{
150 inner
: fs_imp
::DirBuilder
,
155 /// Attempts to open a file in read-only mode.
157 /// See the `OpenOptions::open` method for more details.
161 /// This function will return an error if `path` does not already exist.
162 /// Other errors may also be returned according to `OpenOptions::open`.
167 /// use std::fs::File;
169 /// # fn foo() -> std::io::Result<()> {
170 /// let mut f = try!(File::open("foo.txt"));
174 #[stable(feature = "rust1", since = "1.0.0")]
175 pub fn open
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<File
> {
176 OpenOptions
::new().read(true).open(path
.as_ref())
179 /// Opens a file in write-only mode.
181 /// This function will create a file if it does not exist,
182 /// and will truncate it if it does.
184 /// See the `OpenOptions::open` function for more details.
189 /// use std::fs::File;
191 /// # fn foo() -> std::io::Result<()> {
192 /// let mut f = try!(File::create("foo.txt"));
196 #[stable(feature = "rust1", since = "1.0.0")]
197 pub fn create
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<File
> {
198 OpenOptions
::new().write(true).create(true).truncate(true).open(path
.as_ref())
201 /// Attempts to sync all OS-internal metadata to disk.
203 /// This function will attempt to ensure that all in-core data reaches the
204 /// filesystem before returning.
209 /// use std::fs::File;
210 /// use std::io::prelude::*;
212 /// # fn foo() -> std::io::Result<()> {
213 /// let mut f = try!(File::create("foo.txt"));
214 /// try!(f.write_all(b"Hello, world!"));
216 /// try!(f.sync_all());
220 #[stable(feature = "rust1", since = "1.0.0")]
221 pub fn sync_all(&self) -> io
::Result
<()> {
225 /// This function is similar to `sync_all`, except that it may not
226 /// synchronize file metadata to the filesystem.
228 /// This is intended for use cases that must synchronize content, but don't
229 /// need the metadata on disk. The goal of this method is to reduce disk
232 /// Note that some platforms may simply implement this in terms of
238 /// use std::fs::File;
239 /// use std::io::prelude::*;
241 /// # fn foo() -> std::io::Result<()> {
242 /// let mut f = try!(File::create("foo.txt"));
243 /// try!(f.write_all(b"Hello, world!"));
245 /// try!(f.sync_data());
249 #[stable(feature = "rust1", since = "1.0.0")]
250 pub fn sync_data(&self) -> io
::Result
<()> {
251 self.inner
.datasync()
254 /// Truncates or extends the underlying file, updating the size of
255 /// this file to become `size`.
257 /// If the `size` is less than the current file's size, then the file will
258 /// be shrunk. If it is greater than the current file's size, then the file
259 /// will be extended to `size` and have all of the intermediate data filled
264 /// This function will return an error if the file is not opened for writing.
269 /// use std::fs::File;
271 /// # fn foo() -> std::io::Result<()> {
272 /// let mut f = try!(File::create("foo.txt"));
273 /// try!(f.set_len(10));
277 #[stable(feature = "rust1", since = "1.0.0")]
278 pub fn set_len(&self, size
: u64) -> io
::Result
<()> {
279 self.inner
.truncate(size
)
282 /// Queries metadata about the underlying file.
287 /// use std::fs::File;
289 /// # fn foo() -> std::io::Result<()> {
290 /// let mut f = try!(File::open("foo.txt"));
291 /// let metadata = try!(f.metadata());
295 #[stable(feature = "rust1", since = "1.0.0")]
296 pub fn metadata(&self) -> io
::Result
<Metadata
> {
297 self.inner
.file_attr().map(Metadata
)
300 /// Creates a new independently owned handle to the underlying file.
302 /// The returned `File` is a reference to the same state that this object
303 /// references. Both handles will read and write with the same cursor
305 #[stable(feature = "file_try_clone", since = "1.9.0")]
306 pub fn try_clone(&self) -> io
::Result
<File
> {
308 inner
: self.inner
.duplicate()?
313 impl AsInner
<fs_imp
::File
> for File
{
314 fn as_inner(&self) -> &fs_imp
::File { &self.inner }
316 impl FromInner
<fs_imp
::File
> for File
{
317 fn from_inner(f
: fs_imp
::File
) -> File
{
321 impl IntoInner
<fs_imp
::File
> for File
{
322 fn into_inner(self) -> fs_imp
::File
{
327 #[stable(feature = "rust1", since = "1.0.0")]
328 impl fmt
::Debug
for File
{
329 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
334 #[stable(feature = "rust1", since = "1.0.0")]
336 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
339 fn read_to_end(&mut self, buf
: &mut Vec
<u8>) -> io
::Result
<usize> {
340 self.inner
.read_to_end(buf
)
343 #[stable(feature = "rust1", since = "1.0.0")]
344 impl Write
for File
{
345 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
346 self.inner
.write(buf
)
348 fn flush(&mut self) -> io
::Result
<()> { self.inner.flush() }
350 #[stable(feature = "rust1", since = "1.0.0")]
352 fn seek(&mut self, pos
: SeekFrom
) -> io
::Result
<u64> {
356 #[stable(feature = "rust1", since = "1.0.0")]
357 impl<'a
> Read
for &'a File
{
358 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
361 fn read_to_end(&mut self, buf
: &mut Vec
<u8>) -> io
::Result
<usize> {
362 self.inner
.read_to_end(buf
)
365 #[stable(feature = "rust1", since = "1.0.0")]
366 impl<'a
> Write
for &'a File
{
367 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
368 self.inner
.write(buf
)
370 fn flush(&mut self) -> io
::Result
<()> { self.inner.flush() }
372 #[stable(feature = "rust1", since = "1.0.0")]
373 impl<'a
> Seek
for &'a File
{
374 fn seek(&mut self, pos
: SeekFrom
) -> io
::Result
<u64> {
380 /// Creates a blank new set of options ready for configuration.
382 /// All options are initially set to `false`.
387 /// use std::fs::OpenOptions;
389 /// let mut options = OpenOptions::new();
390 /// let file = options.read(true).open("foo.txt");
392 #[stable(feature = "rust1", since = "1.0.0")]
393 pub fn new() -> OpenOptions
{
394 OpenOptions(fs_imp
::OpenOptions
::new())
397 /// Sets the option for read access.
399 /// This option, when true, will indicate that the file should be
400 /// `read`-able if opened.
405 /// use std::fs::OpenOptions;
407 /// let file = OpenOptions::new().read(true).open("foo.txt");
409 #[stable(feature = "rust1", since = "1.0.0")]
410 pub fn read(&mut self, read
: bool
) -> &mut OpenOptions
{
411 self.0.read(read
); self
414 /// Sets the option for write access.
416 /// This option, when true, will indicate that the file should be
417 /// `write`-able if opened.
419 /// If the file already exists, any write calls on it will overwrite its
420 /// contents, without truncating it.
425 /// use std::fs::OpenOptions;
427 /// let file = OpenOptions::new().write(true).open("foo.txt");
429 #[stable(feature = "rust1", since = "1.0.0")]
430 pub fn write(&mut self, write
: bool
) -> &mut OpenOptions
{
431 self.0.write(write
); self
434 /// Sets the option for the append mode.
436 /// This option, when true, means that writes will append to a file instead
437 /// of overwriting previous contents.
438 /// Note that setting `.write(true).append(true)` has the same effect as
439 /// setting only `.append(true)`.
441 /// For most filesystems, the operating system guarantees that all writes are
442 /// atomic: no writes get mangled because another process writes at the same
445 /// One maybe obvious note when using append-mode: make sure that all data
446 /// that belongs together is written to the file in one operation. This
447 /// can be done by concatenating strings before passing them to `write()`,
448 /// or using a buffered writer (with a buffer of adequate size),
449 /// and calling `flush()` when the message is complete.
451 /// If a file is opened with both read and append access, beware that after
452 /// opening, and after every write, the position for reading may be set at the
453 /// end of the file. So, before writing, save the current position (using
454 /// `seek(SeekFrom::Current(0))`, and restore it before the next read.
459 /// use std::fs::OpenOptions;
461 /// let file = OpenOptions::new().append(true).open("foo.txt");
463 #[stable(feature = "rust1", since = "1.0.0")]
464 pub fn append(&mut self, append
: bool
) -> &mut OpenOptions
{
465 self.0.append(append
); self
468 /// Sets the option for truncating a previous file.
470 /// If a file is successfully opened with this option set it will truncate
471 /// the file to 0 length if it already exists.
473 /// The file must be opened with write access for truncate to work.
478 /// use std::fs::OpenOptions;
480 /// let file = OpenOptions::new().write(true).truncate(true).open("foo.txt");
482 #[stable(feature = "rust1", since = "1.0.0")]
483 pub fn truncate(&mut self, truncate
: bool
) -> &mut OpenOptions
{
484 self.0.truncate(truncate
); self
487 /// Sets the option for creating a new file.
489 /// This option indicates whether a new file will be created if the file
490 /// does not yet already exist.
492 /// In order for the file to be created, `write` or `append` access must
498 /// use std::fs::OpenOptions;
500 /// let file = OpenOptions::new().write(true).create(true).open("foo.txt");
502 #[stable(feature = "rust1", since = "1.0.0")]
503 pub fn create(&mut self, create
: bool
) -> &mut OpenOptions
{
504 self.0.create(create
); self
507 /// Sets the option to always create a new file.
509 /// This option indicates whether a new file will be created.
510 /// No file is allowed to exist at the target location, also no (dangling)
513 /// This option is useful because it as atomic. Otherwise between checking
514 /// whether a file exists and creating a new one, the file may have been
515 /// created by another process (a TOCTOU race condition / attack).
517 /// If `.create_new(true)` is set, `.create()` and `.truncate()` are
520 /// The file must be opened with write or append access in order to create
526 /// use std::fs::OpenOptions;
528 /// let file = OpenOptions::new().write(true)
529 /// .create_new(true)
530 /// .open("foo.txt");
532 #[stable(feature = "expand_open_options2", since = "1.9.0")]
533 pub fn create_new(&mut self, create_new
: bool
) -> &mut OpenOptions
{
534 self.0.create_new(create_new
); self
537 /// Opens a file at `path` with the options specified by `self`.
541 /// This function will return an error under a number of different
542 /// circumstances, to include but not limited to:
544 /// * Opening a file that does not exist without setting `create` or
546 /// * Attempting to open a file with access that the user lacks
548 /// * Filesystem-level errors (full disk, etc)
549 /// * Invalid combinations of open options (truncate without write access,
550 /// no access mode set, etc)
555 /// use std::fs::OpenOptions;
557 /// let file = OpenOptions::new().open("foo.txt");
559 #[stable(feature = "rust1", since = "1.0.0")]
560 pub fn open
<P
: AsRef
<Path
>>(&self, path
: P
) -> io
::Result
<File
> {
561 self._open(path
.as_ref())
564 fn _open(&self, path
: &Path
) -> io
::Result
<File
> {
565 let inner
= fs_imp
::File
::open(path
, &self.0)?
;
566 Ok(File { inner: inner }
)
570 impl AsInnerMut
<fs_imp
::OpenOptions
> for OpenOptions
{
571 fn as_inner_mut(&mut self) -> &mut fs_imp
::OpenOptions { &mut self.0 }
575 /// Returns the file type for this metadata.
576 #[stable(feature = "file_type", since = "1.1.0")]
577 pub fn file_type(&self) -> FileType
{
578 FileType(self.0.file_type
())
581 /// Returns whether this metadata is for a directory.
586 /// # fn foo() -> std::io::Result<()> {
589 /// let metadata = try!(fs::metadata("foo.txt"));
591 /// assert!(!metadata.is_dir());
595 #[stable(feature = "rust1", since = "1.0.0")]
596 pub fn is_dir(&self) -> bool { self.file_type().is_dir() }
598 /// Returns whether this metadata is for a regular file.
603 /// # fn foo() -> std::io::Result<()> {
606 /// let metadata = try!(fs::metadata("foo.txt"));
608 /// assert!(metadata.is_file());
612 #[stable(feature = "rust1", since = "1.0.0")]
613 pub fn is_file(&self) -> bool { self.file_type().is_file() }
615 /// Returns the size of the file, in bytes, this metadata is for.
620 /// # fn foo() -> std::io::Result<()> {
623 /// let metadata = try!(fs::metadata("foo.txt"));
625 /// assert_eq!(0, metadata.len());
629 #[stable(feature = "rust1", since = "1.0.0")]
630 pub fn len(&self) -> u64 { self.0.size() }
632 /// Returns the permissions of the file this metadata is for.
637 /// # fn foo() -> std::io::Result<()> {
640 /// let metadata = try!(fs::metadata("foo.txt"));
642 /// assert!(!metadata.permissions().readonly());
646 #[stable(feature = "rust1", since = "1.0.0")]
647 pub fn permissions(&self) -> Permissions
{
648 Permissions(self.0.perm())
651 /// Returns the last modification time listed in this metadata.
653 /// The returned value corresponds to the `mtime` field of `stat` on Unix
654 /// platforms and the `ftLastWriteTime` field on Windows platforms.
658 /// This field may not be available on all platforms, and will return an
659 /// `Err` on platforms where it is not available.
660 #[unstable(feature = "fs_time", issue = "31399")]
661 pub fn modified(&self) -> io
::Result
<SystemTime
> {
662 self.0.modified().map(FromInner
::from_inner
)
665 /// Returns the last access time of this metadata.
667 /// The returned value corresponds to the `atime` field of `stat` on Unix
668 /// platforms and the `ftLastAccessTime` field on Windows platforms.
670 /// Note that not all platforms will keep this field update in a file's
671 /// metadata, for example Windows has an option to disable updating this
672 /// time when files are accessed and Linux similarly has `noatime`.
676 /// This field may not be available on all platforms, and will return an
677 /// `Err` on platforms where it is not available.
678 #[unstable(feature = "fs_time", issue = "31399")]
679 pub fn accessed(&self) -> io
::Result
<SystemTime
> {
680 self.0.accessed().map(FromInner
::from_inner
)
683 /// Returns the creation time listed in the this metadata.
685 /// The returned value corresponds to the `birthtime` field of `stat` on
686 /// Unix platforms and the `ftCreationTime` field on Windows platforms.
690 /// This field may not be available on all platforms, and will return an
691 /// `Err` on platforms where it is not available.
692 #[unstable(feature = "fs_time", issue = "31399")]
693 pub fn created(&self) -> io
::Result
<SystemTime
> {
694 self.0.created().map(FromInner
::from_inner
)
698 impl AsInner
<fs_imp
::FileAttr
> for Metadata
{
699 fn as_inner(&self) -> &fs_imp
::FileAttr { &self.0 }
703 /// Returns whether these permissions describe a readonly file.
708 /// use std::fs::File;
710 /// # fn foo() -> std::io::Result<()> {
711 /// let mut f = try!(File::create("foo.txt"));
712 /// let metadata = try!(f.metadata());
714 /// assert_eq!(false, metadata.permissions().readonly());
718 #[stable(feature = "rust1", since = "1.0.0")]
719 pub fn readonly(&self) -> bool { self.0.readonly() }
721 /// Modifies the readonly flag for this set of permissions.
723 /// This operation does **not** modify the filesystem. To modify the
724 /// filesystem use the `fs::set_permissions` function.
729 /// use std::fs::File;
731 /// # fn foo() -> std::io::Result<()> {
732 /// let f = try!(File::create("foo.txt"));
733 /// let metadata = try!(f.metadata());
734 /// let mut permissions = metadata.permissions();
736 /// permissions.set_readonly(true);
738 /// // filesystem doesn't change
739 /// assert_eq!(false, metadata.permissions().readonly());
741 /// // just this particular `permissions`.
742 /// assert_eq!(true, permissions.readonly());
746 #[stable(feature = "rust1", since = "1.0.0")]
747 pub fn set_readonly(&mut self, readonly
: bool
) {
748 self.0.set_readonly(readonly
)
753 /// Test whether this file type represents a directory.
754 #[stable(feature = "file_type", since = "1.1.0")]
755 pub fn is_dir(&self) -> bool { self.0.is_dir() }
757 /// Test whether this file type represents a regular file.
758 #[stable(feature = "file_type", since = "1.1.0")]
759 pub fn is_file(&self) -> bool { self.0.is_file() }
761 /// Test whether this file type represents a symbolic link.
762 #[stable(feature = "file_type", since = "1.1.0")]
763 pub fn is_symlink(&self) -> bool { self.0.is_symlink() }
766 impl AsInner
<fs_imp
::FileType
> for FileType
{
767 fn as_inner(&self) -> &fs_imp
::FileType { &self.0 }
770 impl FromInner
<fs_imp
::FilePermissions
> for Permissions
{
771 fn from_inner(f
: fs_imp
::FilePermissions
) -> Permissions
{
776 impl AsInner
<fs_imp
::FilePermissions
> for Permissions
{
777 fn as_inner(&self) -> &fs_imp
::FilePermissions { &self.0 }
780 #[stable(feature = "rust1", since = "1.0.0")]
781 impl Iterator
for ReadDir
{
782 type Item
= io
::Result
<DirEntry
>;
784 fn next(&mut self) -> Option
<io
::Result
<DirEntry
>> {
785 self.0.next().map(|entry
| entry
.map(DirEntry
))
790 /// Returns the full path to the file that this entry represents.
792 /// The full path is created by joining the original path to `read_dir` or
793 /// `walk_dir` with the filename of this entry.
799 /// # fn foo() -> std::io::Result<()> {
800 /// for entry in try!(fs::read_dir(".")) {
801 /// let dir = try!(entry);
802 /// println!("{:?}", dir.path());
808 /// This prints output like:
813 /// "./hello_world.rs"
816 /// The exact text, of course, depends on what files you have in `.`.
817 #[stable(feature = "rust1", since = "1.0.0")]
818 pub fn path(&self) -> PathBuf { self.0.path() }
820 /// Return the metadata for the file that this entry points at.
822 /// This function will not traverse symlinks if this entry points at a
825 /// # Platform-specific behavior
827 /// On Windows this function is cheap to call (no extra system calls
828 /// needed), but on Unix platforms this function is the equivalent of
829 /// calling `symlink_metadata` on the path.
830 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
831 pub fn metadata(&self) -> io
::Result
<Metadata
> {
832 self.0.metadata().map(Metadata
)
835 /// Return the file type for the file that this entry points at.
837 /// This function will not traverse symlinks if this entry points at a
840 /// # Platform-specific behavior
842 /// On Windows and most Unix platforms this function is free (no extra
843 /// system calls needed), but some Unix platforms may require the equivalent
844 /// call to `symlink_metadata` to learn about the target file type.
845 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
846 pub fn file_type(&self) -> io
::Result
<FileType
> {
847 self.0.file_type
().map(FileType
)
850 /// Returns the bare file name of this directory entry without any other
851 /// leading path component.
852 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
853 pub fn file_name(&self) -> OsString
{
858 impl AsInner
<fs_imp
::DirEntry
> for DirEntry
{
859 fn as_inner(&self) -> &fs_imp
::DirEntry { &self.0 }
862 /// Removes a file from the filesystem.
864 /// Note that there is no
865 /// guarantee that the file is immediately deleted (e.g. depending on
866 /// platform, other open file descriptors may prevent immediate removal).
868 /// # Platform-specific behavior
870 /// This function currently corresponds to the `unlink` function on Unix
871 /// and the `DeleteFile` function on Windows.
872 /// Note that, this [may change in the future][changes].
873 /// [changes]: ../io/index.html#platform-specific-behavior
877 /// This function will return an error in the following situations, but is not
878 /// limited to just these cases:
880 /// * `path` points to a directory.
881 /// * The user lacks permissions to remove the file.
888 /// # fn foo() -> std::io::Result<()> {
889 /// try!(fs::remove_file("a.txt"));
893 #[stable(feature = "rust1", since = "1.0.0")]
894 pub fn remove_file
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<()> {
895 fs_imp
::unlink(path
.as_ref())
898 /// Given a path, query the file system to get information about a file,
901 /// This function will traverse symbolic links to query information about the
902 /// destination file.
904 /// # Platform-specific behavior
906 /// This function currently corresponds to the `stat` function on Unix
907 /// and the `GetFileAttributesEx` function on Windows.
908 /// Note that, this [may change in the future][changes].
909 /// [changes]: ../io/index.html#platform-specific-behavior
913 /// This function will return an error in the following situations, but is not
914 /// limited to just these cases:
916 /// * The user lacks permissions to perform `metadata` call on `path`.
917 /// * `path` does not exist.
922 /// # fn foo() -> std::io::Result<()> {
925 /// let attr = try!(fs::metadata("/some/file/path.txt"));
926 /// // inspect attr ...
930 #[stable(feature = "rust1", since = "1.0.0")]
931 pub fn metadata
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<Metadata
> {
932 fs_imp
::stat(path
.as_ref()).map(Metadata
)
935 /// Query the metadata about a file without following symlinks.
937 /// # Platform-specific behavior
939 /// This function currently corresponds to the `lstat` function on Unix
940 /// and the `GetFileAttributesEx` function on Windows.
941 /// Note that, this [may change in the future][changes].
942 /// [changes]: ../io/index.html#platform-specific-behavior
946 /// This function will return an error in the following situations, but is not
947 /// limited to just these cases:
949 /// * The user lacks permissions to perform `metadata` call on `path`.
950 /// * `path` does not exist.
955 /// # fn foo() -> std::io::Result<()> {
958 /// let attr = try!(fs::symlink_metadata("/some/file/path.txt"));
959 /// // inspect attr ...
963 #[stable(feature = "symlink_metadata", since = "1.1.0")]
964 pub fn symlink_metadata
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<Metadata
> {
965 fs_imp
::lstat(path
.as_ref()).map(Metadata
)
968 /// Rename a file or directory to a new name.
970 /// This will not work if the new name is on a different mount point.
972 /// # Platform-specific behavior
974 /// This function currently corresponds to the `rename` function on Unix
975 /// and the `MoveFileEx` function with the `MOVEFILE_REPLACE_EXISTING` flag on Windows.
976 /// Note that, this [may change in the future][changes].
977 /// [changes]: ../io/index.html#platform-specific-behavior
981 /// This function will return an error in the following situations, but is not
982 /// limited to just these cases:
984 /// * `from` does not exist.
985 /// * The user lacks permissions to view contents.
986 /// * `from` and `to` are on separate filesystems.
993 /// # fn foo() -> std::io::Result<()> {
994 /// try!(fs::rename("a.txt", "b.txt")); // Rename a.txt to b.txt
998 #[stable(feature = "rust1", since = "1.0.0")]
999 pub fn rename
<P
: AsRef
<Path
>, Q
: AsRef
<Path
>>(from
: P
, to
: Q
) -> io
::Result
<()> {
1000 fs_imp
::rename(from
.as_ref(), to
.as_ref())
1003 /// Copies the contents of one file to another. This function will also
1004 /// copy the permission bits of the original file to the destination file.
1006 /// This function will **overwrite** the contents of `to`.
1008 /// Note that if `from` and `to` both point to the same file, then the file
1009 /// will likely get truncated by this operation.
1011 /// On success, the total number of bytes copied is returned.
1013 /// # Platform-specific behavior
1015 /// This function currently corresponds to the `open` function in Unix
1016 /// with `O_RDONLY` for `from` and `O_WRONLY`, `O_CREAT`, and `O_TRUNC` for `to`.
1017 /// `O_CLOEXEC` is set for returned file descriptors.
1018 /// On Windows, this function currently corresponds to `CopyFileEx`.
1019 /// Note that, this [may change in the future][changes].
1020 /// [changes]: ../io/index.html#platform-specific-behavior
1024 /// This function will return an error in the following situations, but is not
1025 /// limited to just these cases:
1027 /// * The `from` path is not a file.
1028 /// * The `from` file does not exist.
1029 /// * The current process does not have the permission rights to access
1030 /// `from` or write `to`.
1037 /// # fn foo() -> std::io::Result<()> {
1038 /// try!(fs::copy("foo.txt", "bar.txt")); // Copy foo.txt to bar.txt
1041 #[stable(feature = "rust1", since = "1.0.0")]
1042 pub fn copy
<P
: AsRef
<Path
>, Q
: AsRef
<Path
>>(from
: P
, to
: Q
) -> io
::Result
<u64> {
1043 fs_imp
::copy(from
.as_ref(), to
.as_ref())
1046 /// Creates a new hard link on the filesystem.
1048 /// The `dst` path will be a link pointing to the `src` path. Note that systems
1049 /// often require these two paths to both be located on the same filesystem.
1051 /// # Platform-specific behavior
1053 /// This function currently corresponds to the `link` function on Unix
1054 /// and the `CreateHardLink` function on Windows.
1055 /// Note that, this [may change in the future][changes].
1056 /// [changes]: ../io/index.html#platform-specific-behavior
1060 /// This function will return an error in the following situations, but is not
1061 /// limited to just these cases:
1063 /// * The `src` path is not a file or doesn't exist.
1070 /// # fn foo() -> std::io::Result<()> {
1071 /// try!(fs::hard_link("a.txt", "b.txt")); // Hard link a.txt to b.txt
1075 #[stable(feature = "rust1", since = "1.0.0")]
1076 pub fn hard_link
<P
: AsRef
<Path
>, Q
: AsRef
<Path
>>(src
: P
, dst
: Q
) -> io
::Result
<()> {
1077 fs_imp
::link(src
.as_ref(), dst
.as_ref())
1080 /// Creates a new symbolic link on the filesystem.
1082 /// The `dst` path will be a symbolic link pointing to the `src` path.
1083 /// On Windows, this will be a file symlink, not a directory symlink;
1084 /// for this reason, the platform-specific `std::os::unix::fs::symlink`
1085 /// and `std::os::windows::fs::{symlink_file, symlink_dir}` should be
1086 /// used instead to make the intent explicit.
1093 /// # fn foo() -> std::io::Result<()> {
1094 /// try!(fs::soft_link("a.txt", "b.txt"));
1098 #[stable(feature = "rust1", since = "1.0.0")]
1099 #[rustc_deprecated(since = "1.1.0",
1100 reason
= "replaced with std::os::unix::fs::symlink and \
1101 std::os::windows::fs::{symlink_file, symlink_dir}")]
1102 pub fn soft_link
<P
: AsRef
<Path
>, Q
: AsRef
<Path
>>(src
: P
, dst
: Q
) -> io
::Result
<()> {
1103 fs_imp
::symlink(src
.as_ref(), dst
.as_ref())
1106 /// Reads a symbolic link, returning the file that the link points to.
1108 /// # Platform-specific behavior
1110 /// This function currently corresponds to the `readlink` function on Unix
1111 /// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and
1112 /// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows.
1113 /// Note that, this [may change in the future][changes].
1114 /// [changes]: ../io/index.html#platform-specific-behavior
1118 /// This function will return an error in the following situations, but is not
1119 /// limited to just these cases:
1121 /// * `path` is not a symbolic link.
1122 /// * `path` does not exist.
1129 /// # fn foo() -> std::io::Result<()> {
1130 /// let path = try!(fs::read_link("a.txt"));
1134 #[stable(feature = "rust1", since = "1.0.0")]
1135 pub fn read_link
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<PathBuf
> {
1136 fs_imp
::readlink(path
.as_ref())
1139 /// Returns the canonical form of a path with all intermediate components
1140 /// normalized and symbolic links resolved.
1142 /// # Platform-specific behavior
1144 /// This function currently corresponds to the `realpath` function on Unix
1145 /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows.
1146 /// Note that, this [may change in the future][changes].
1147 /// [changes]: ../io/index.html#platform-specific-behavior
1151 /// This function will return an error in the following situations, but is not
1152 /// limited to just these cases:
1154 /// * `path` does not exist.
1155 /// * A component in path is not a directory.
1162 /// # fn foo() -> std::io::Result<()> {
1163 /// let path = try!(fs::canonicalize("../a/../foo.txt"));
1167 #[stable(feature = "fs_canonicalize", since = "1.5.0")]
1168 pub fn canonicalize
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<PathBuf
> {
1169 fs_imp
::canonicalize(path
.as_ref())
1172 /// Creates a new, empty directory at the provided path
1174 /// # Platform-specific behavior
1176 /// This function currently corresponds to the `mkdir` function on Unix
1177 /// and the `CreateDirectory` function on Windows.
1178 /// Note that, this [may change in the future][changes].
1179 /// [changes]: ../io/index.html#platform-specific-behavior
1183 /// This function will return an error in the following situations, but is not
1184 /// limited to just these cases:
1186 /// * User lacks permissions to create directory at `path`.
1187 /// * `path` already exists.
1194 /// # fn foo() -> std::io::Result<()> {
1195 /// try!(fs::create_dir("/some/dir"));
1199 #[stable(feature = "rust1", since = "1.0.0")]
1200 pub fn create_dir
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<()> {
1201 DirBuilder
::new().create(path
.as_ref())
1204 /// Recursively create a directory and all of its parent components if they
1207 /// # Platform-specific behavior
1209 /// This function currently corresponds to the `mkdir` function on Unix
1210 /// and the `CreateDirectory` function on Windows.
1211 /// Note that, this [may change in the future][changes].
1212 /// [changes]: ../io/index.html#platform-specific-behavior
1216 /// This function will return an error in the following situations, but is not
1217 /// limited to just these cases:
1219 /// * If any directory in the path specified by `path`
1220 /// does not already exist and it could not be created otherwise. The specific
1221 /// error conditions for when a directory is being created (after it is
1222 /// determined to not exist) are outlined by `fs::create_dir`.
1229 /// # fn foo() -> std::io::Result<()> {
1230 /// try!(fs::create_dir_all("/some/dir"));
1234 #[stable(feature = "rust1", since = "1.0.0")]
1235 pub fn create_dir_all
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<()> {
1236 DirBuilder
::new().recursive(true).create(path
.as_ref())
1239 /// Removes an existing, empty directory.
1241 /// # Platform-specific behavior
1243 /// This function currently corresponds to the `rmdir` function on Unix
1244 /// and the `RemoveDirectory` function on Windows.
1245 /// Note that, this [may change in the future][changes].
1246 /// [changes]: ../io/index.html#platform-specific-behavior
1250 /// This function will return an error in the following situations, but is not
1251 /// limited to just these cases:
1253 /// * The user lacks permissions to remove the directory at the provided `path`.
1254 /// * The directory isn't empty.
1261 /// # fn foo() -> std::io::Result<()> {
1262 /// try!(fs::remove_dir("/some/dir"));
1266 #[stable(feature = "rust1", since = "1.0.0")]
1267 pub fn remove_dir
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<()> {
1268 fs_imp
::rmdir(path
.as_ref())
1271 /// Removes a directory at this path, after removing all its contents. Use
1274 /// This function does **not** follow symbolic links and it will simply remove the
1275 /// symbolic link itself.
1277 /// # Platform-specific behavior
1279 /// This function currently corresponds to `opendir`, `lstat`, `rm` and `rmdir` functions on Unix
1280 /// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions
1282 /// Note that, this [may change in the future][changes].
1283 /// [changes]: ../io/index.html#platform-specific-behavior
1287 /// See `file::remove_file` and `fs::remove_dir`.
1294 /// # fn foo() -> std::io::Result<()> {
1295 /// try!(fs::remove_dir_all("/some/dir"));
1299 #[stable(feature = "rust1", since = "1.0.0")]
1300 pub fn remove_dir_all
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<()> {
1301 fs_imp
::remove_dir_all(path
.as_ref())
1304 /// Returns an iterator over the entries within a directory.
1306 /// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
1307 /// be encountered after an iterator is initially constructed.
1309 /// # Platform-specific behavior
1311 /// This function currently corresponds to the `opendir` function on Unix
1312 /// and the `FindFirstFile` function on Windows.
1313 /// Note that, this [may change in the future][changes].
1314 /// [changes]: ../io/index.html#platform-specific-behavior
1318 /// This function will return an error in the following situations, but is not
1319 /// limited to just these cases:
1321 /// * The provided `path` doesn't exist.
1322 /// * The process lacks permissions to view the contents.
1323 /// * The `path` points at a non-directory file.
1329 /// use std::fs::{self, DirEntry};
1330 /// use std::path::Path;
1332 /// // one possible implementation of walking a directory only visiting files
1333 /// fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
1334 /// if try!(fs::metadata(dir)).is_dir() {
1335 /// for entry in try!(fs::read_dir(dir)) {
1336 /// let entry = try!(entry);
1337 /// if try!(fs::metadata(entry.path())).is_dir() {
1338 /// try!(visit_dirs(&entry.path(), cb));
1347 #[stable(feature = "rust1", since = "1.0.0")]
1348 pub fn read_dir
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<ReadDir
> {
1349 fs_imp
::readdir(path
.as_ref()).map(ReadDir
)
1352 /// Changes the permissions found on a file or a directory.
1354 /// # Platform-specific behavior
1356 /// This function currently corresponds to the `chmod` function on Unix
1357 /// and the `SetFileAttributes` function on Windows.
1358 /// Note that, this [may change in the future][changes].
1359 /// [changes]: ../io/index.html#platform-specific-behavior
1363 /// This function will return an error in the following situations, but is not
1364 /// limited to just these cases:
1366 /// * `path` does not exist.
1367 /// * The user lacks the permission to change attributes of the file.
1372 /// # fn foo() -> std::io::Result<()> {
1375 /// let mut perms = try!(fs::metadata("foo.txt")).permissions();
1376 /// perms.set_readonly(true);
1377 /// try!(fs::set_permissions("foo.txt", perms));
1381 #[stable(feature = "set_permissions", since = "1.1.0")]
1382 pub fn set_permissions
<P
: AsRef
<Path
>>(path
: P
, perm
: Permissions
)
1384 fs_imp
::set_perm(path
.as_ref(), perm
.0)
1388 /// Creates a new set of options with default mode/security settings for all
1389 /// platforms and also non-recursive.
1390 #[stable(feature = "dir_builder", since = "1.6.0")]
1391 pub fn new() -> DirBuilder
{
1393 inner
: fs_imp
::DirBuilder
::new(),
1398 /// Indicate that directories create should be created recursively, creating
1399 /// all parent directories if they do not exist with the same security and
1400 /// permissions settings.
1402 /// This option defaults to `false`
1403 #[stable(feature = "dir_builder", since = "1.6.0")]
1404 pub fn recursive(&mut self, recursive
: bool
) -> &mut Self {
1405 self.recursive
= recursive
;
1409 /// Create the specified directory with the options configured in this
1415 /// use std::fs::{self, DirBuilder};
1417 /// let path = "/tmp/foo/bar/baz";
1418 /// DirBuilder::new()
1419 /// .recursive(true)
1420 /// .create(path).unwrap();
1422 /// assert!(fs::metadata(path).unwrap().is_dir());
1424 #[stable(feature = "dir_builder", since = "1.6.0")]
1425 pub fn create
<P
: AsRef
<Path
>>(&self, path
: P
) -> io
::Result
<()> {
1426 self._create(path
.as_ref())
1429 fn _create(&self, path
: &Path
) -> io
::Result
<()> {
1431 self.create_dir_all(path
)
1433 self.inner
.mkdir(path
)
1437 fn create_dir_all(&self, path
: &Path
) -> io
::Result
<()> {
1438 if path
== Path
::new("") || path
.is_dir() { return Ok(()) }
1439 if let Some(p
) = path
.parent() {
1440 self.create_dir_all(p
)?
1442 self.inner
.mkdir(path
)
1446 impl AsInnerMut
<fs_imp
::DirBuilder
> for DirBuilder
{
1447 fn as_inner_mut(&mut self) -> &mut fs_imp
::DirBuilder
{
1457 use fs
::{self, File, OpenOptions}
;
1458 use io
::{ErrorKind, SeekFrom}
;
1460 use rand
::{StdRng, Rng}
;
1462 use sys_common
::io
::test
::{TempDir, tmpdir}
;
1465 use os
::windows
::fs
::{symlink_dir, symlink_file}
;
1467 use sys
::fs
::symlink_junction
;
1469 use os
::unix
::fs
::symlink
as symlink_dir
;
1471 use os
::unix
::fs
::symlink
as symlink_file
;
1473 use os
::unix
::fs
::symlink
as symlink_junction
;
1475 macro_rules
! check
{ ($e
:expr
) => (
1478 Err(e
) => panic
!("{} failed with: {}", stringify
!($e
), e
),
1482 macro_rules
! error
{ ($e
:expr
, $s
:expr
) => (
1484 Ok(_
) => panic
!("Unexpected success. Should've been: {:?}", $s
),
1485 Err(ref err
) => assert
!(err
.to_string().contains($s
),
1486 format
!("`{}` did not contain `{}`", err
, $s
))
1490 // Several test fail on windows if the user does not have permission to
1491 // create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
1492 // disabling these test on Windows, use this function to test whether we
1493 // have permission, and return otherwise. This way, we still don't run these
1494 // tests most of the time, but at least we do if the user has the right
1496 pub fn got_symlink_permission(tmpdir
: &TempDir
) -> bool
{
1497 if cfg
!(unix
) { return true }
1498 let link
= tmpdir
.join("some_hopefully_unique_link_name");
1500 match symlink_file(r
"nonexisting_target", link
) {
1503 if err
.to_string().contains("A required privilege is not held by the client.") {
1512 fn file_test_io_smoke_test() {
1513 let message
= "it's alright. have a good time";
1514 let tmpdir
= tmpdir();
1515 let filename
= &tmpdir
.join("file_rt_io_file_test.txt");
1517 let mut write_stream
= check
!(File
::create(filename
));
1518 check
!(write_stream
.write(message
.as_bytes()));
1521 let mut read_stream
= check
!(File
::open(filename
));
1522 let mut read_buf
= [0; 1028];
1523 let read_str
= match check
!(read_stream
.read(&mut read_buf
)) {
1524 0 => panic
!("shouldn't happen"),
1525 n
=> str::from_utf8(&read_buf
[..n
]).unwrap().to_string()
1527 assert_eq
!(read_str
, message
);
1529 check
!(fs
::remove_file(filename
));
1533 fn invalid_path_raises() {
1534 let tmpdir
= tmpdir();
1535 let filename
= &tmpdir
.join("file_that_does_not_exist.txt");
1536 let result
= File
::open(filename
);
1539 error
!(result
, "o such file or directory");
1542 error
!(result
, "The system cannot find the file specified");
1547 fn file_test_iounlinking_invalid_path_should_raise_condition() {
1548 let tmpdir
= tmpdir();
1549 let filename
= &tmpdir
.join("file_another_file_that_does_not_exist.txt");
1551 let result
= fs
::remove_file(filename
);
1554 error
!(result
, "o such file or directory");
1557 error
!(result
, "The system cannot find the file specified");
1562 fn file_test_io_non_positional_read() {
1563 let message
: &str = "ten-four";
1564 let mut read_mem
= [0; 8];
1565 let tmpdir
= tmpdir();
1566 let filename
= &tmpdir
.join("file_rt_io_file_test_positional.txt");
1568 let mut rw_stream
= check
!(File
::create(filename
));
1569 check
!(rw_stream
.write(message
.as_bytes()));
1572 let mut read_stream
= check
!(File
::open(filename
));
1574 let read_buf
= &mut read_mem
[0..4];
1575 check
!(read_stream
.read(read_buf
));
1578 let read_buf
= &mut read_mem
[4..8];
1579 check
!(read_stream
.read(read_buf
));
1582 check
!(fs
::remove_file(filename
));
1583 let read_str
= str::from_utf8(&read_mem
).unwrap();
1584 assert_eq
!(read_str
, message
);
1588 fn file_test_io_seek_and_tell_smoke_test() {
1589 let message
= "ten-four";
1590 let mut read_mem
= [0; 4];
1591 let set_cursor
= 4 as u64;
1592 let tell_pos_pre_read
;
1593 let tell_pos_post_read
;
1594 let tmpdir
= tmpdir();
1595 let filename
= &tmpdir
.join("file_rt_io_file_test_seeking.txt");
1597 let mut rw_stream
= check
!(File
::create(filename
));
1598 check
!(rw_stream
.write(message
.as_bytes()));
1601 let mut read_stream
= check
!(File
::open(filename
));
1602 check
!(read_stream
.seek(SeekFrom
::Start(set_cursor
)));
1603 tell_pos_pre_read
= check
!(read_stream
.seek(SeekFrom
::Current(0)));
1604 check
!(read_stream
.read(&mut read_mem
));
1605 tell_pos_post_read
= check
!(read_stream
.seek(SeekFrom
::Current(0)));
1607 check
!(fs
::remove_file(filename
));
1608 let read_str
= str::from_utf8(&read_mem
).unwrap();
1609 assert_eq
!(read_str
, &message
[4..8]);
1610 assert_eq
!(tell_pos_pre_read
, set_cursor
);
1611 assert_eq
!(tell_pos_post_read
, message
.len() as u64);
1615 fn file_test_io_seek_and_write() {
1616 let initial_msg
= "food-is-yummy";
1617 let overwrite_msg
= "-the-bar!!";
1618 let final_msg
= "foo-the-bar!!";
1620 let mut read_mem
= [0; 13];
1621 let tmpdir
= tmpdir();
1622 let filename
= &tmpdir
.join("file_rt_io_file_test_seek_and_write.txt");
1624 let mut rw_stream
= check
!(File
::create(filename
));
1625 check
!(rw_stream
.write(initial_msg
.as_bytes()));
1626 check
!(rw_stream
.seek(SeekFrom
::Start(seek_idx
)));
1627 check
!(rw_stream
.write(overwrite_msg
.as_bytes()));
1630 let mut read_stream
= check
!(File
::open(filename
));
1631 check
!(read_stream
.read(&mut read_mem
));
1633 check
!(fs
::remove_file(filename
));
1634 let read_str
= str::from_utf8(&read_mem
).unwrap();
1635 assert
!(read_str
== final_msg
);
1639 fn file_test_io_seek_shakedown() {
1641 let initial_msg
= "qwer-asdf-zxcv";
1642 let chunk_one
: &str = "qwer";
1643 let chunk_two
: &str = "asdf";
1644 let chunk_three
: &str = "zxcv";
1645 let mut read_mem
= [0; 4];
1646 let tmpdir
= tmpdir();
1647 let filename
= &tmpdir
.join("file_rt_io_file_test_seek_shakedown.txt");
1649 let mut rw_stream
= check
!(File
::create(filename
));
1650 check
!(rw_stream
.write(initial_msg
.as_bytes()));
1653 let mut read_stream
= check
!(File
::open(filename
));
1655 check
!(read_stream
.seek(SeekFrom
::End(-4)));
1656 check
!(read_stream
.read(&mut read_mem
));
1657 assert_eq
!(str::from_utf8(&read_mem
).unwrap(), chunk_three
);
1659 check
!(read_stream
.seek(SeekFrom
::Current(-9)));
1660 check
!(read_stream
.read(&mut read_mem
));
1661 assert_eq
!(str::from_utf8(&read_mem
).unwrap(), chunk_two
);
1663 check
!(read_stream
.seek(SeekFrom
::Start(0)));
1664 check
!(read_stream
.read(&mut read_mem
));
1665 assert_eq
!(str::from_utf8(&read_mem
).unwrap(), chunk_one
);
1667 check
!(fs
::remove_file(filename
));
1671 fn file_test_stat_is_correct_on_is_file() {
1672 let tmpdir
= tmpdir();
1673 let filename
= &tmpdir
.join("file_stat_correct_on_is_file.txt");
1675 let mut opts
= OpenOptions
::new();
1676 let mut fs
= check
!(opts
.read(true).write(true)
1677 .create(true).open(filename
));
1679 fs
.write(msg
.as_bytes()).unwrap();
1681 let fstat_res
= check
!(fs
.metadata());
1682 assert
!(fstat_res
.is_file());
1684 let stat_res_fn
= check
!(fs
::metadata(filename
));
1685 assert
!(stat_res_fn
.is_file());
1686 let stat_res_meth
= check
!(filename
.metadata());
1687 assert
!(stat_res_meth
.is_file());
1688 check
!(fs
::remove_file(filename
));
1692 fn file_test_stat_is_correct_on_is_dir() {
1693 let tmpdir
= tmpdir();
1694 let filename
= &tmpdir
.join("file_stat_correct_on_is_dir");
1695 check
!(fs
::create_dir(filename
));
1696 let stat_res_fn
= check
!(fs
::metadata(filename
));
1697 assert
!(stat_res_fn
.is_dir());
1698 let stat_res_meth
= check
!(filename
.metadata());
1699 assert
!(stat_res_meth
.is_dir());
1700 check
!(fs
::remove_dir(filename
));
1704 fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
1705 let tmpdir
= tmpdir();
1706 let dir
= &tmpdir
.join("fileinfo_false_on_dir");
1707 check
!(fs
::create_dir(dir
));
1708 assert
!(!dir
.is_file());
1709 check
!(fs
::remove_dir(dir
));
1713 fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
1714 let tmpdir
= tmpdir();
1715 let file
= &tmpdir
.join("fileinfo_check_exists_b_and_a.txt");
1716 check
!(check
!(File
::create(file
)).write(b
"foo"));
1717 assert
!(file
.exists());
1718 check
!(fs
::remove_file(file
));
1719 assert
!(!file
.exists());
1723 fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
1724 let tmpdir
= tmpdir();
1725 let dir
= &tmpdir
.join("before_and_after_dir");
1726 assert
!(!dir
.exists());
1727 check
!(fs
::create_dir(dir
));
1728 assert
!(dir
.exists());
1729 assert
!(dir
.is_dir());
1730 check
!(fs
::remove_dir(dir
));
1731 assert
!(!dir
.exists());
1735 fn file_test_directoryinfo_readdir() {
1736 let tmpdir
= tmpdir();
1737 let dir
= &tmpdir
.join("di_readdir");
1738 check
!(fs
::create_dir(dir
));
1741 let f
= dir
.join(&format
!("{}.txt", n
));
1742 let mut w
= check
!(File
::create(&f
));
1743 let msg_str
= format
!("{}{}", prefix
, n
.to_string());
1744 let msg
= msg_str
.as_bytes();
1745 check
!(w
.write(msg
));
1747 let files
= check
!(fs
::read_dir(dir
));
1748 let mut mem
= [0; 4];
1750 let f
= f
.unwrap().path();
1752 let n
= f
.file_stem().unwrap();
1753 check
!(check
!(File
::open(&f
)).read(&mut mem
));
1754 let read_str
= str::from_utf8(&mem
).unwrap();
1755 let expected
= format
!("{}{}", prefix
, n
.to_str().unwrap());
1756 assert_eq
!(expected
, read_str
);
1758 check
!(fs
::remove_file(&f
));
1760 check
!(fs
::remove_dir(dir
));
1764 fn mkdir_path_already_exists_error() {
1765 let tmpdir
= tmpdir();
1766 let dir
= &tmpdir
.join("mkdir_error_twice");
1767 check
!(fs
::create_dir(dir
));
1768 let e
= fs
::create_dir(dir
).err().unwrap();
1769 assert_eq
!(e
.kind(), ErrorKind
::AlreadyExists
);
1773 fn recursive_mkdir() {
1774 let tmpdir
= tmpdir();
1775 let dir
= tmpdir
.join("d1/d2");
1776 check
!(fs
::create_dir_all(&dir
));
1777 assert
!(dir
.is_dir())
1781 fn recursive_mkdir_failure() {
1782 let tmpdir
= tmpdir();
1783 let dir
= tmpdir
.join("d1");
1784 let file
= dir
.join("f1");
1786 check
!(fs
::create_dir_all(&dir
));
1787 check
!(File
::create(&file
));
1789 let result
= fs
::create_dir_all(&file
);
1791 assert
!(result
.is_err());
1795 fn recursive_mkdir_slash() {
1796 check
!(fs
::create_dir_all(&Path
::new("/")));
1800 fn recursive_rmdir() {
1801 let tmpdir
= tmpdir();
1802 let d1
= tmpdir
.join("d1");
1803 let dt
= d1
.join("t");
1804 let dtt
= dt
.join("t");
1805 let d2
= tmpdir
.join("d2");
1806 let canary
= d2
.join("do_not_delete");
1807 check
!(fs
::create_dir_all(&dtt
));
1808 check
!(fs
::create_dir_all(&d2
));
1809 check
!(check
!(File
::create(&canary
)).write(b
"foo"));
1810 check
!(symlink_junction(&d2
, &dt
.join("d2")));
1811 let _
= symlink_file(&canary
, &d1
.join("canary"));
1812 check
!(fs
::remove_dir_all(&d1
));
1814 assert
!(!d1
.is_dir());
1815 assert
!(canary
.exists());
1819 fn recursive_rmdir_of_symlink() {
1820 // test we do not recursively delete a symlink but only dirs.
1821 let tmpdir
= tmpdir();
1822 let link
= tmpdir
.join("d1");
1823 let dir
= tmpdir
.join("d2");
1824 let canary
= dir
.join("do_not_delete");
1825 check
!(fs
::create_dir_all(&dir
));
1826 check
!(check
!(File
::create(&canary
)).write(b
"foo"));
1827 check
!(symlink_junction(&dir
, &link
));
1828 check
!(fs
::remove_dir_all(&link
));
1830 assert
!(!link
.is_dir());
1831 assert
!(canary
.exists());
1835 // only Windows makes a distinction between file and directory symlinks.
1837 fn recursive_rmdir_of_file_symlink() {
1838 let tmpdir
= tmpdir();
1839 if !got_symlink_permission(&tmpdir
) { return }
;
1841 let f1
= tmpdir
.join("f1");
1842 let f2
= tmpdir
.join("f2");
1843 check
!(check
!(File
::create(&f1
)).write(b
"foo"));
1844 check
!(symlink_file(&f1
, &f2
));
1845 match fs
::remove_dir_all(&f2
) {
1846 Ok(..) => panic
!("wanted a failure"),
1852 fn unicode_path_is_dir() {
1853 assert
!(Path
::new(".").is_dir());
1854 assert
!(!Path
::new("test/stdtest/fs.rs").is_dir());
1856 let tmpdir
= tmpdir();
1858 let mut dirpath
= tmpdir
.path().to_path_buf();
1859 dirpath
.push("test-가一ー你好");
1860 check
!(fs
::create_dir(&dirpath
));
1861 assert
!(dirpath
.is_dir());
1863 let mut filepath
= dirpath
;
1864 filepath
.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
1865 check
!(File
::create(&filepath
)); // ignore return; touch only
1866 assert
!(!filepath
.is_dir());
1867 assert
!(filepath
.exists());
1871 fn unicode_path_exists() {
1872 assert
!(Path
::new(".").exists());
1873 assert
!(!Path
::new("test/nonexistent-bogus-path").exists());
1875 let tmpdir
= tmpdir();
1876 let unicode
= tmpdir
.path();
1877 let unicode
= unicode
.join(&format
!("test-각丁ー再见"));
1878 check
!(fs
::create_dir(&unicode
));
1879 assert
!(unicode
.exists());
1880 assert
!(!Path
::new("test/unicode-bogus-path-각丁ー再见").exists());
1884 fn copy_file_does_not_exist() {
1885 let from
= Path
::new("test/nonexistent-bogus-path");
1886 let to
= Path
::new("test/other-bogus-path");
1888 match fs
::copy(&from
, &to
) {
1891 assert
!(!from
.exists());
1892 assert
!(!to
.exists());
1898 fn copy_src_does_not_exist() {
1899 let tmpdir
= tmpdir();
1900 let from
= Path
::new("test/nonexistent-bogus-path");
1901 let to
= tmpdir
.join("out.txt");
1902 check
!(check
!(File
::create(&to
)).write(b
"hello"));
1903 assert
!(fs
::copy(&from
, &to
).is_err());
1904 assert
!(!from
.exists());
1905 let mut v
= Vec
::new();
1906 check
!(check
!(File
::open(&to
)).read_to_end(&mut v
));
1907 assert_eq
!(v
, b
"hello");
1912 let tmpdir
= tmpdir();
1913 let input
= tmpdir
.join("in.txt");
1914 let out
= tmpdir
.join("out.txt");
1916 check
!(check
!(File
::create(&input
)).write(b
"hello"));
1917 check
!(fs
::copy(&input
, &out
));
1918 let mut v
= Vec
::new();
1919 check
!(check
!(File
::open(&out
)).read_to_end(&mut v
));
1920 assert_eq
!(v
, b
"hello");
1922 assert_eq
!(check
!(input
.metadata()).permissions(),
1923 check
!(out
.metadata()).permissions());
1927 fn copy_file_dst_dir() {
1928 let tmpdir
= tmpdir();
1929 let out
= tmpdir
.join("out");
1931 check
!(File
::create(&out
));
1932 match fs
::copy(&*out
, tmpdir
.path()) {
1933 Ok(..) => panic
!(), Err(..) => {}
1938 fn copy_file_dst_exists() {
1939 let tmpdir
= tmpdir();
1940 let input
= tmpdir
.join("in");
1941 let output
= tmpdir
.join("out");
1943 check
!(check
!(File
::create(&input
)).write("foo".as_bytes()));
1944 check
!(check
!(File
::create(&output
)).write("bar".as_bytes()));
1945 check
!(fs
::copy(&input
, &output
));
1947 let mut v
= Vec
::new();
1948 check
!(check
!(File
::open(&output
)).read_to_end(&mut v
));
1949 assert_eq
!(v
, b
"foo".to_vec());
1953 fn copy_file_src_dir() {
1954 let tmpdir
= tmpdir();
1955 let out
= tmpdir
.join("out");
1957 match fs
::copy(tmpdir
.path(), &out
) {
1958 Ok(..) => panic
!(), Err(..) => {}
1960 assert
!(!out
.exists());
1964 fn copy_file_preserves_perm_bits() {
1965 let tmpdir
= tmpdir();
1966 let input
= tmpdir
.join("in.txt");
1967 let out
= tmpdir
.join("out.txt");
1969 let attr
= check
!(check
!(File
::create(&input
)).metadata());
1970 let mut p
= attr
.permissions();
1971 p
.set_readonly(true);
1972 check
!(fs
::set_permissions(&input
, p
));
1973 check
!(fs
::copy(&input
, &out
));
1974 assert
!(check
!(out
.metadata()).permissions().readonly());
1975 check
!(fs
::set_permissions(&input
, attr
.permissions()));
1976 check
!(fs
::set_permissions(&out
, attr
.permissions()));
1981 fn copy_file_preserves_streams() {
1983 check
!(check
!(File
::create(tmp
.join("in.txt:bunny"))).write("carrot".as_bytes()));
1984 assert_eq
!(check
!(fs
::copy(tmp
.join("in.txt"), tmp
.join("out.txt"))), 6);
1985 assert_eq
!(check
!(tmp
.join("out.txt").metadata()).len(), 0);
1986 let mut v
= Vec
::new();
1987 check
!(check
!(File
::open(tmp
.join("out.txt:bunny"))).read_to_end(&mut v
));
1988 assert_eq
!(v
, b
"carrot".to_vec());
1992 fn symlinks_work() {
1993 let tmpdir
= tmpdir();
1994 if !got_symlink_permission(&tmpdir
) { return }
;
1996 let input
= tmpdir
.join("in.txt");
1997 let out
= tmpdir
.join("out.txt");
1999 check
!(check
!(File
::create(&input
)).write("foobar".as_bytes()));
2000 check
!(symlink_file(&input
, &out
));
2001 assert
!(check
!(out
.symlink_metadata()).file_type().is_symlink());
2002 assert_eq
!(check
!(fs
::metadata(&out
)).len(),
2003 check
!(fs
::metadata(&input
)).len());
2004 let mut v
= Vec
::new();
2005 check
!(check
!(File
::open(&out
)).read_to_end(&mut v
));
2006 assert_eq
!(v
, b
"foobar".to_vec());
2010 fn symlink_noexist() {
2011 // Symlinks can point to things that don't exist
2012 let tmpdir
= tmpdir();
2013 if !got_symlink_permission(&tmpdir
) { return }
;
2015 // Use a relative path for testing. Symlinks get normalized by Windows,
2016 // so we may not get the same path back for absolute paths
2017 check
!(symlink_file(&"foo", &tmpdir
.join("bar")));
2018 assert_eq
!(check
!(fs
::read_link(&tmpdir
.join("bar"))).to_str().unwrap(),
2025 // directory symlink
2026 assert_eq
!(check
!(fs
::read_link(r
"C:\Users\All Users")).to_str().unwrap(),
2029 assert_eq
!(check
!(fs
::read_link(r
"C:\Users\Default User")).to_str().unwrap(),
2030 r
"C:\Users\Default");
2031 // junction with special permissions
2032 assert_eq
!(check
!(fs
::read_link(r
"C:\Documents and Settings\")).to_str().unwrap(),
2035 let tmpdir
= tmpdir();
2036 let link
= tmpdir
.join("link");
2037 if !got_symlink_permission(&tmpdir
) { return }
;
2038 check
!(symlink_file(&"foo", &link
));
2039 assert_eq
!(check
!(fs
::read_link(&link
)).to_str().unwrap(), "foo");
2043 fn readlink_not_symlink() {
2044 let tmpdir
= tmpdir();
2045 match fs
::read_link(tmpdir
.path()) {
2046 Ok(..) => panic
!("wanted a failure"),
2053 let tmpdir
= tmpdir();
2054 let input
= tmpdir
.join("in.txt");
2055 let out
= tmpdir
.join("out.txt");
2057 check
!(check
!(File
::create(&input
)).write("foobar".as_bytes()));
2058 check
!(fs
::hard_link(&input
, &out
));
2059 assert_eq
!(check
!(fs
::metadata(&out
)).len(),
2060 check
!(fs
::metadata(&input
)).len());
2061 assert_eq
!(check
!(fs
::metadata(&out
)).len(),
2062 check
!(input
.metadata()).len());
2063 let mut v
= Vec
::new();
2064 check
!(check
!(File
::open(&out
)).read_to_end(&mut v
));
2065 assert_eq
!(v
, b
"foobar".to_vec());
2067 // can't link to yourself
2068 match fs
::hard_link(&input
, &input
) {
2069 Ok(..) => panic
!("wanted a failure"),
2072 // can't link to something that doesn't exist
2073 match fs
::hard_link(&tmpdir
.join("foo"), &tmpdir
.join("bar")) {
2074 Ok(..) => panic
!("wanted a failure"),
2081 let tmpdir
= tmpdir();
2082 let file
= tmpdir
.join("in.txt");
2084 check
!(File
::create(&file
));
2085 let attr
= check
!(fs
::metadata(&file
));
2086 assert
!(!attr
.permissions().readonly());
2087 let mut p
= attr
.permissions();
2088 p
.set_readonly(true);
2089 check
!(fs
::set_permissions(&file
, p
.clone()));
2090 let attr
= check
!(fs
::metadata(&file
));
2091 assert
!(attr
.permissions().readonly());
2093 match fs
::set_permissions(&tmpdir
.join("foo"), p
.clone()) {
2094 Ok(..) => panic
!("wanted an error"),
2098 p
.set_readonly(false);
2099 check
!(fs
::set_permissions(&file
, p
));
2103 fn sync_doesnt_kill_anything() {
2104 let tmpdir
= tmpdir();
2105 let path
= tmpdir
.join("in.txt");
2107 let mut file
= check
!(File
::create(&path
));
2108 check
!(file
.sync_all());
2109 check
!(file
.sync_data());
2110 check
!(file
.write(b
"foo"));
2111 check
!(file
.sync_all());
2112 check
!(file
.sync_data());
2116 fn truncate_works() {
2117 let tmpdir
= tmpdir();
2118 let path
= tmpdir
.join("in.txt");
2120 let mut file
= check
!(File
::create(&path
));
2121 check
!(file
.write(b
"foo"));
2122 check
!(file
.sync_all());
2124 // Do some simple things with truncation
2125 assert_eq
!(check
!(file
.metadata()).len(), 3);
2126 check
!(file
.set_len(10));
2127 assert_eq
!(check
!(file
.metadata()).len(), 10);
2128 check
!(file
.write(b
"bar"));
2129 check
!(file
.sync_all());
2130 assert_eq
!(check
!(file
.metadata()).len(), 10);
2132 let mut v
= Vec
::new();
2133 check
!(check
!(File
::open(&path
)).read_to_end(&mut v
));
2134 assert_eq
!(v
, b
"foobar\0\0\0\0".to_vec());
2136 // Truncate to a smaller length, don't seek, and then write something.
2137 // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
2138 // past the end of the file).
2139 check
!(file
.set_len(2));
2140 assert_eq
!(check
!(file
.metadata()).len(), 2);
2141 check
!(file
.write(b
"wut"));
2142 check
!(file
.sync_all());
2143 assert_eq
!(check
!(file
.metadata()).len(), 9);
2144 let mut v
= Vec
::new();
2145 check
!(check
!(File
::open(&path
)).read_to_end(&mut v
));
2146 assert_eq
!(v
, b
"fo\0\0\0\0wut".to_vec());
2151 use fs
::OpenOptions
as OO
;
2152 fn c
<T
: Clone
>(t
: &T
) -> T { t.clone() }
2154 let tmpdir
= tmpdir();
2156 let mut r
= OO
::new(); r
.read(true);
2157 let mut w
= OO
::new(); w
.write(true);
2158 let mut rw
= OO
::new(); rw
.read(true).write(true);
2159 let mut a
= OO
::new(); a
.append(true);
2160 let mut ra
= OO
::new(); ra
.read(true).append(true);
2162 let invalid_options
= if cfg
!(windows
) { "The parameter is incorrect" }
2163 else { "Invalid argument" }
;
2165 // Test various combinations of creation modes and access modes.
2168 // creation mode | read | write | read-write | append | read-append |
2169 // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:|
2170 // not set (open existing) | X | X | X | X | X |
2171 // create | | X | X | X | X |
2172 // truncate | | X | X | | |
2173 // create and truncate | | X | X | | |
2174 // create_new | | X | X | X | X |
2176 // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it.
2179 check
!(c(&w
).create_new(true).open(&tmpdir
.join("a")));
2180 check
!(c(&w
).create(true).truncate(true).open(&tmpdir
.join("a")));
2181 check
!(c(&w
).truncate(true).open(&tmpdir
.join("a")));
2182 check
!(c(&w
).create(true).open(&tmpdir
.join("a")));
2183 check
!(c(&w
).open(&tmpdir
.join("a")));
2186 error
!(c(&r
).create_new(true).open(&tmpdir
.join("b")), invalid_options
);
2187 error
!(c(&r
).create(true).truncate(true).open(&tmpdir
.join("b")), invalid_options
);
2188 error
!(c(&r
).truncate(true).open(&tmpdir
.join("b")), invalid_options
);
2189 error
!(c(&r
).create(true).open(&tmpdir
.join("b")), invalid_options
);
2190 check
!(c(&r
).open(&tmpdir
.join("a"))); // try opening the file created with write_only
2193 check
!(c(&rw
).create_new(true).open(&tmpdir
.join("c")));
2194 check
!(c(&rw
).create(true).truncate(true).open(&tmpdir
.join("c")));
2195 check
!(c(&rw
).truncate(true).open(&tmpdir
.join("c")));
2196 check
!(c(&rw
).create(true).open(&tmpdir
.join("c")));
2197 check
!(c(&rw
).open(&tmpdir
.join("c")));
2200 check
!(c(&a
).create_new(true).open(&tmpdir
.join("d")));
2201 error
!(c(&a
).create(true).truncate(true).open(&tmpdir
.join("d")), invalid_options
);
2202 error
!(c(&a
).truncate(true).open(&tmpdir
.join("d")), invalid_options
);
2203 check
!(c(&a
).create(true).open(&tmpdir
.join("d")));
2204 check
!(c(&a
).open(&tmpdir
.join("d")));
2207 check
!(c(&ra
).create_new(true).open(&tmpdir
.join("e")));
2208 error
!(c(&ra
).create(true).truncate(true).open(&tmpdir
.join("e")), invalid_options
);
2209 error
!(c(&ra
).truncate(true).open(&tmpdir
.join("e")), invalid_options
);
2210 check
!(c(&ra
).create(true).open(&tmpdir
.join("e")));
2211 check
!(c(&ra
).open(&tmpdir
.join("e")));
2213 // Test opening a file without setting an access mode
2214 let mut blank
= OO
::new();
2215 error
!(blank
.create(true).open(&tmpdir
.join("f")), invalid_options
);
2218 check
!(check
!(File
::create(&tmpdir
.join("h"))).write("foobar".as_bytes()));
2220 // Test write fails for read-only
2221 check
!(r
.open(&tmpdir
.join("h")));
2223 let mut f
= check
!(r
.open(&tmpdir
.join("h")));
2224 assert
!(f
.write("wut".as_bytes()).is_err());
2227 // Test write overwrites
2229 let mut f
= check
!(c(&w
).open(&tmpdir
.join("h")));
2230 check
!(f
.write("baz".as_bytes()));
2233 let mut f
= check
!(c(&r
).open(&tmpdir
.join("h")));
2234 let mut b
= vec
![0; 6];
2235 check
!(f
.read(&mut b
));
2236 assert_eq
!(b
, "bazbar".as_bytes());
2239 // Test truncate works
2241 let mut f
= check
!(c(&w
).truncate(true).open(&tmpdir
.join("h")));
2242 check
!(f
.write("foo".as_bytes()));
2244 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 3);
2246 // Test append works
2247 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 3);
2249 let mut f
= check
!(c(&a
).open(&tmpdir
.join("h")));
2250 check
!(f
.write("bar".as_bytes()));
2252 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 6);
2254 // Test .append(true) equals .write(true).append(true)
2256 let mut f
= check
!(c(&w
).append(true).open(&tmpdir
.join("h")));
2257 check
!(f
.write("baz".as_bytes()));
2259 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 9);
2263 fn _assert_send_sync() {
2264 fn _assert_send_sync
<T
: Send
+ Sync
>() {}
2265 _assert_send_sync
::<OpenOptions
>();
2270 let mut bytes
= [0; 1024];
2271 StdRng
::new().unwrap().fill_bytes(&mut bytes
);
2273 let tmpdir
= tmpdir();
2275 check
!(check
!(File
::create(&tmpdir
.join("test"))).write(&bytes
));
2276 let mut v
= Vec
::new();
2277 check
!(check
!(File
::open(&tmpdir
.join("test"))).read_to_end(&mut v
));
2278 assert
!(v
== &bytes
[..]);
2282 fn file_try_clone() {
2283 let tmpdir
= tmpdir();
2285 let mut f1
= check
!(OpenOptions
::new()
2289 .open(&tmpdir
.join("test")));
2290 let mut f2
= check
!(f1
.try_clone());
2292 check
!(f1
.write_all(b
"hello world"));
2293 check
!(f1
.seek(SeekFrom
::Start(2)));
2295 let mut buf
= vec
![];
2296 check
!(f2
.read_to_end(&mut buf
));
2297 assert_eq
!(buf
, b
"llo world");
2300 check
!(f1
.write_all(b
"!"));
2304 #[cfg(not(windows))]
2305 fn unlink_readonly() {
2306 let tmpdir
= tmpdir();
2307 let path
= tmpdir
.join("file");
2308 check
!(File
::create(&path
));
2309 let mut perm
= check
!(fs
::metadata(&path
)).permissions();
2310 perm
.set_readonly(true);
2311 check
!(fs
::set_permissions(&path
, perm
));
2312 check
!(fs
::remove_file(&path
));
2316 fn mkdir_trailing_slash() {
2317 let tmpdir
= tmpdir();
2318 let path
= tmpdir
.join("file");
2319 check
!(fs
::create_dir_all(&path
.join("a/")));
2323 fn canonicalize_works_simple() {
2324 let tmpdir
= tmpdir();
2325 let tmpdir
= fs
::canonicalize(tmpdir
.path()).unwrap();
2326 let file
= tmpdir
.join("test");
2327 File
::create(&file
).unwrap();
2328 assert_eq
!(fs
::canonicalize(&file
).unwrap(), file
);
2332 fn realpath_works() {
2333 let tmpdir
= tmpdir();
2334 if !got_symlink_permission(&tmpdir
) { return }
;
2336 let tmpdir
= fs
::canonicalize(tmpdir
.path()).unwrap();
2337 let file
= tmpdir
.join("test");
2338 let dir
= tmpdir
.join("test2");
2339 let link
= dir
.join("link");
2340 let linkdir
= tmpdir
.join("test3");
2342 File
::create(&file
).unwrap();
2343 fs
::create_dir(&dir
).unwrap();
2344 symlink_file(&file
, &link
).unwrap();
2345 symlink_dir(&dir
, &linkdir
).unwrap();
2347 assert
!(link
.symlink_metadata().unwrap().file_type().is_symlink());
2349 assert_eq
!(fs
::canonicalize(&tmpdir
).unwrap(), tmpdir
);
2350 assert_eq
!(fs
::canonicalize(&file
).unwrap(), file
);
2351 assert_eq
!(fs
::canonicalize(&link
).unwrap(), file
);
2352 assert_eq
!(fs
::canonicalize(&linkdir
).unwrap(), dir
);
2353 assert_eq
!(fs
::canonicalize(&linkdir
.join("link")).unwrap(), file
);
2357 fn realpath_works_tricky() {
2358 let tmpdir
= tmpdir();
2359 if !got_symlink_permission(&tmpdir
) { return }
;
2361 let tmpdir
= fs
::canonicalize(tmpdir
.path()).unwrap();
2362 let a
= tmpdir
.join("a");
2363 let b
= a
.join("b");
2364 let c
= b
.join("c");
2365 let d
= a
.join("d");
2366 let e
= d
.join("e");
2367 let f
= a
.join("f");
2369 fs
::create_dir_all(&b
).unwrap();
2370 fs
::create_dir_all(&d
).unwrap();
2371 File
::create(&f
).unwrap();
2372 if cfg
!(not(windows
)) {
2373 symlink_dir("../d/e", &c
).unwrap();
2374 symlink_file("../f", &e
).unwrap();
2377 symlink_dir(r
"..\d\e", &c
).unwrap();
2378 symlink_file(r
"..\f", &e
).unwrap();
2381 assert_eq
!(fs
::canonicalize(&c
).unwrap(), f
);
2382 assert_eq
!(fs
::canonicalize(&e
).unwrap(), f
);
2386 fn dir_entry_methods() {
2387 let tmpdir
= tmpdir();
2389 fs
::create_dir_all(&tmpdir
.join("a")).unwrap();
2390 File
::create(&tmpdir
.join("b")).unwrap();
2392 for file
in tmpdir
.path().read_dir().unwrap().map(|f
| f
.unwrap()) {
2393 let fname
= file
.file_name();
2394 match fname
.to_str() {
2396 assert
!(file
.file_type().unwrap().is_dir());
2397 assert
!(file
.metadata().unwrap().is_dir());
2400 assert
!(file
.file_type().unwrap().is_file());
2401 assert
!(file
.metadata().unwrap().is_file());
2403 f
=> panic
!("unknown file name: {:?}", f
),
2409 fn read_dir_not_found() {
2410 let res
= fs
::read_dir("/path/that/does/not/exist");
2411 assert_eq
!(res
.err().unwrap().kind(), ErrorKind
::NotFound
);
2415 fn create_dir_all_with_junctions() {
2416 let tmpdir
= tmpdir();
2417 let target
= tmpdir
.join("target");
2419 let junction
= tmpdir
.join("junction");
2420 let b
= junction
.join("a/b");
2422 let link
= tmpdir
.join("link");
2423 let d
= link
.join("c/d");
2425 fs
::create_dir(&target
).unwrap();
2427 check
!(symlink_junction(&target
, &junction
));
2428 check
!(fs
::create_dir_all(&b
));
2429 // the junction itself is not a directory, but `is_dir()` on a Path
2431 assert
!(junction
.is_dir());
2432 assert
!(b
.exists());
2434 if !got_symlink_permission(&tmpdir
) { return }
;
2435 check
!(symlink_dir(&target
, &link
));
2436 check
!(fs
::create_dir_all(&d
));
2437 assert
!(link
.is_dir());
2438 assert
!(d
.exists());
2442 fn metadata_access_times() {
2443 let tmpdir
= tmpdir();
2445 let b
= tmpdir
.join("b");
2446 File
::create(&b
).unwrap();
2448 let a
= check
!(fs
::metadata(&tmpdir
.path()));
2449 let b
= check
!(fs
::metadata(&b
));
2451 assert_eq
!(check
!(a
.accessed()), check
!(a
.accessed()));
2452 assert_eq
!(check
!(a
.modified()), check
!(a
.modified()));
2453 assert_eq
!(check
!(b
.accessed()), check
!(b
.modified()));
2455 if cfg
!(target_os
= "macos") || cfg
!(target_os
= "windows") {
2456 check
!(a
.created());
2457 check
!(b
.created());