PageRenderTime 54ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/libstd/fs/mod.rs

http://github.com/eholk/rust
Rust | 1563 lines | 983 code | 170 blank | 410 comment | 30 complexity | 1ba7921bf3552a51752b0639901de52b MD5 | raw file
Possible License(s): AGPL-1.0, BSD-2-Clause, 0BSD, Apache-2.0, MIT, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
  2. // file at the top-level directory of this distribution and at
  3. // http://rust-lang.org/COPYRIGHT.
  4. //
  5. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  6. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  7. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  8. // option. This file may not be copied, modified, or distributed
  9. // except according to those terms.
  10. //! Filesystem manipulation operations
  11. //!
  12. //! This module contains basic methods to manipulate the contents of the local
  13. //! filesystem. All methods in this module represent cross-platform filesystem
  14. //! operations. Extra platform-specific functionality can be found in the
  15. //! extension traits of `std::os::$platform`.
  16. #![stable(feature = "rust1", since = "1.0.0")]
  17. use core::prelude::*;
  18. use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write};
  19. use path::{AsPath, Path, PathBuf};
  20. use sys::fs2 as fs_imp;
  21. use sys_common::{AsInnerMut, FromInner, AsInner};
  22. use vec::Vec;
  23. #[allow(deprecated)]
  24. pub use self::tempdir::TempDir;
  25. mod tempdir;
  26. /// A reference to an open file on the filesystem.
  27. ///
  28. /// An instance of a `File` can be read and/or written depending on what options
  29. /// it was opened with. Files also implement `Seek` to alter the logical cursor
  30. /// that the file contains internally.
  31. ///
  32. /// # Examples
  33. ///
  34. /// ```no_run
  35. /// use std::io::prelude::*;
  36. /// use std::fs::File;
  37. ///
  38. /// # fn foo() -> std::io::Result<()> {
  39. /// let mut f = try!(File::create("foo.txt"));
  40. /// try!(f.write_all(b"Hello, world!"));
  41. ///
  42. /// let mut f = try!(File::open("foo.txt"));
  43. /// let mut s = String::new();
  44. /// try!(f.read_to_string(&mut s));
  45. /// assert_eq!(s, "Hello, world!");
  46. /// # Ok(())
  47. /// # }
  48. /// ```
  49. #[stable(feature = "rust1", since = "1.0.0")]
  50. pub struct File {
  51. inner: fs_imp::File,
  52. path: PathBuf,
  53. }
  54. /// Metadata information about a file.
  55. ///
  56. /// This structure is returned from the `metadata` function or method and
  57. /// represents known metadata about a file such as its permissions, size,
  58. /// modification times, etc.
  59. #[stable(feature = "rust1", since = "1.0.0")]
  60. pub struct Metadata(fs_imp::FileAttr);
  61. /// Iterator over the entries in a directory.
  62. ///
  63. /// This iterator is returned from the `read_dir` function of this module and
  64. /// will yield instances of `io::Result<DirEntry>`. Through a `DirEntry`
  65. /// information like the entry's path and possibly other metadata can be
  66. /// learned.
  67. #[stable(feature = "rust1", since = "1.0.0")]
  68. pub struct ReadDir(fs_imp::ReadDir);
  69. /// Entries returned by the `ReadDir` iterator.
  70. ///
  71. /// An instance of `DirEntry` represents an entry inside of a directory on the
  72. /// filesystem. Each entry can be inspected via methods to learn about the full
  73. /// path or possibly other metadata through per-platform extension traits.
  74. #[stable(feature = "rust1", since = "1.0.0")]
  75. pub struct DirEntry(fs_imp::DirEntry);
  76. /// An iterator that recursively walks over the contents of a directory.
  77. #[unstable(feature = "fs_walk",
  78. reason = "the precise semantics and defaults for a recursive walk \
  79. may change and this may end up accounting for files such \
  80. as symlinks differently")]
  81. pub struct WalkDir {
  82. cur: Option<ReadDir>,
  83. stack: Vec<io::Result<ReadDir>>,
  84. }
  85. /// Options and flags which can be used to configure how a file is opened.
  86. ///
  87. /// This builder exposes the ability to configure how a `File` is opened and
  88. /// what operations are permitted on the open file. The `File::open` and
  89. /// `File::create` methods are aliases for commonly used options using this
  90. /// builder.
  91. #[derive(Clone)]
  92. #[stable(feature = "rust1", since = "1.0.0")]
  93. pub struct OpenOptions(fs_imp::OpenOptions);
  94. /// Representation of the various permissions on a file.
  95. ///
  96. /// This module only currently provides one bit of information, `readonly`,
  97. /// which is exposed on all currently supported platforms. Unix-specific
  98. /// functionality, such as mode bits, is available through the
  99. /// `os::unix::PermissionsExt` trait.
  100. #[derive(Clone, PartialEq, Eq, Debug)]
  101. #[stable(feature = "rust1", since = "1.0.0")]
  102. pub struct Permissions(fs_imp::FilePermissions);
  103. impl File {
  104. /// Attempts to open a file in read-only mode.
  105. ///
  106. /// See the `OpenOptions::open` method for more details.
  107. ///
  108. /// # Errors
  109. ///
  110. /// This function will return an error if `path` does not already exist.
  111. /// Other errors may also be returned according to `OpenOptions::open`.
  112. #[stable(feature = "rust1", since = "1.0.0")]
  113. pub fn open<P: AsPath>(path: P) -> io::Result<File> {
  114. OpenOptions::new().read(true).open(path)
  115. }
  116. /// Open a file in write-only mode.
  117. ///
  118. /// This function will create a file if it does not exist,
  119. /// and will truncate it if it does.
  120. ///
  121. /// See the `OpenOptions::open` function for more details.
  122. #[stable(feature = "rust1", since = "1.0.0")]
  123. pub fn create<P: AsPath>(path: P) -> io::Result<File> {
  124. OpenOptions::new().write(true).create(true).truncate(true).open(path)
  125. }
  126. /// Returns the original path that was used to open this file.
  127. #[unstable(feature = "file_path",
  128. reason = "this abstraction is imposed by this library instead \
  129. of the underlying OS and may be removed")]
  130. pub fn path(&self) -> Option<&Path> {
  131. Some(&self.path)
  132. }
  133. /// Attempt to sync all OS-internal metadata to disk.
  134. ///
  135. /// This function will attempt to ensure that all in-core data reaches the
  136. /// filesystem before returning.
  137. #[stable(feature = "rust1", since = "1.0.0")]
  138. pub fn sync_all(&self) -> io::Result<()> {
  139. self.inner.fsync()
  140. }
  141. /// This function is similar to `sync_all`, except that it may not
  142. /// synchronize file metadata to the filesystem.
  143. ///
  144. /// This is intended for use cases that must synchronize content, but don't
  145. /// need the metadata on disk. The goal of this method is to reduce disk
  146. /// operations.
  147. ///
  148. /// Note that some platforms may simply implement this in terms of
  149. /// `sync_all`.
  150. #[stable(feature = "rust1", since = "1.0.0")]
  151. pub fn sync_data(&self) -> io::Result<()> {
  152. self.inner.datasync()
  153. }
  154. /// Truncates or extends the underlying file, updating the size of
  155. /// this file to become `size`.
  156. ///
  157. /// If the `size` is less than the current file's size, then the file will
  158. /// be shrunk. If it is greater than the current file's size, then the file
  159. /// will be extended to `size` and have all of the intermediate data filled
  160. /// in with 0s.
  161. #[stable(feature = "rust1", since = "1.0.0")]
  162. pub fn set_len(&self, size: u64) -> io::Result<()> {
  163. self.inner.truncate(size)
  164. }
  165. /// Queries metadata about the underlying file.
  166. #[stable(feature = "rust1", since = "1.0.0")]
  167. pub fn metadata(&self) -> io::Result<Metadata> {
  168. self.inner.file_attr().map(Metadata)
  169. }
  170. }
  171. impl AsInner<fs_imp::File> for File {
  172. fn as_inner(&self) -> &fs_imp::File { &self.inner }
  173. }
  174. #[stable(feature = "rust1", since = "1.0.0")]
  175. impl Read for File {
  176. fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
  177. self.inner.read(buf)
  178. }
  179. }
  180. #[stable(feature = "rust1", since = "1.0.0")]
  181. impl Write for File {
  182. fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
  183. self.inner.write(buf)
  184. }
  185. fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
  186. }
  187. #[stable(feature = "rust1", since = "1.0.0")]
  188. impl Seek for File {
  189. fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
  190. self.inner.seek(pos)
  191. }
  192. }
  193. #[stable(feature = "rust1", since = "1.0.0")]
  194. impl<'a> Read for &'a File {
  195. fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
  196. self.inner.read(buf)
  197. }
  198. }
  199. #[stable(feature = "rust1", since = "1.0.0")]
  200. impl<'a> Write for &'a File {
  201. fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
  202. self.inner.write(buf)
  203. }
  204. fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
  205. }
  206. #[stable(feature = "rust1", since = "1.0.0")]
  207. impl<'a> Seek for &'a File {
  208. fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
  209. self.inner.seek(pos)
  210. }
  211. }
  212. impl OpenOptions {
  213. /// Creates a blank net set of options ready for configuration.
  214. ///
  215. /// All options are initially set to `false`.
  216. #[stable(feature = "rust1", since = "1.0.0")]
  217. pub fn new() -> OpenOptions {
  218. OpenOptions(fs_imp::OpenOptions::new())
  219. }
  220. /// Set the option for read access.
  221. ///
  222. /// This option, when true, will indicate that the file should be
  223. /// `read`-able if opened.
  224. #[stable(feature = "rust1", since = "1.0.0")]
  225. pub fn read(&mut self, read: bool) -> &mut OpenOptions {
  226. self.0.read(read); self
  227. }
  228. /// Set the option for write access.
  229. ///
  230. /// This option, when true, will indicate that the file should be
  231. /// `write`-able if opened.
  232. #[stable(feature = "rust1", since = "1.0.0")]
  233. pub fn write(&mut self, write: bool) -> &mut OpenOptions {
  234. self.0.write(write); self
  235. }
  236. /// Set the option for the append mode.
  237. ///
  238. /// This option, when true, means that writes will append to a file instead
  239. /// of overwriting previous contents.
  240. #[stable(feature = "rust1", since = "1.0.0")]
  241. pub fn append(&mut self, append: bool) -> &mut OpenOptions {
  242. self.0.append(append); self
  243. }
  244. /// Set the option for truncating a previous file.
  245. ///
  246. /// If a file is successfully opened with this option set it will truncate
  247. /// the file to 0 length if it already exists.
  248. #[stable(feature = "rust1", since = "1.0.0")]
  249. pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
  250. self.0.truncate(truncate); self
  251. }
  252. /// Set the option for creating a new file.
  253. ///
  254. /// This option indicates whether a new file will be created if the file
  255. /// does not yet already exist.
  256. #[stable(feature = "rust1", since = "1.0.0")]
  257. pub fn create(&mut self, create: bool) -> &mut OpenOptions {
  258. self.0.create(create); self
  259. }
  260. /// Open a file at `path` with the options specified by `self`.
  261. ///
  262. /// # Errors
  263. ///
  264. /// This function will return an error under a number of different
  265. /// circumstances, to include but not limited to:
  266. ///
  267. /// * Opening a file that does not exist with read access.
  268. /// * Attempting to open a file with access that the user lacks
  269. /// permissions for
  270. /// * Filesystem-level errors (full disk, etc)
  271. #[stable(feature = "rust1", since = "1.0.0")]
  272. pub fn open<P: AsPath>(&self, path: P) -> io::Result<File> {
  273. let path = path.as_path();
  274. let inner = try!(fs_imp::File::open(path, &self.0));
  275. Ok(File { path: path.to_path_buf(), inner: inner })
  276. }
  277. }
  278. impl AsInnerMut<fs_imp::OpenOptions> for OpenOptions {
  279. fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 }
  280. }
  281. impl Metadata {
  282. /// Returns whether this metadata is for a directory.
  283. #[stable(feature = "rust1", since = "1.0.0")]
  284. pub fn is_dir(&self) -> bool { self.0.is_dir() }
  285. /// Returns whether this metadata is for a regular file.
  286. #[stable(feature = "rust1", since = "1.0.0")]
  287. pub fn is_file(&self) -> bool { self.0.is_file() }
  288. /// Returns the size of the file, in bytes, this metadata is for.
  289. #[stable(feature = "rust1", since = "1.0.0")]
  290. pub fn len(&self) -> u64 { self.0.size() }
  291. /// Returns the permissions of the file this metadata is for.
  292. #[stable(feature = "rust1", since = "1.0.0")]
  293. pub fn permissions(&self) -> Permissions {
  294. Permissions(self.0.perm())
  295. }
  296. /// Returns the most recent access time for a file.
  297. ///
  298. /// The return value is in milliseconds since the epoch.
  299. #[unstable(feature = "fs_time",
  300. reason = "the return type of u64 is not quite appropriate for \
  301. this method and may change if the standard library \
  302. gains a type to represent a moment in time")]
  303. pub fn accessed(&self) -> u64 { self.0.accessed() }
  304. /// Returns the most recent modification time for a file.
  305. ///
  306. /// The return value is in milliseconds since the epoch.
  307. #[unstable(feature = "fs_time",
  308. reason = "the return type of u64 is not quite appropriate for \
  309. this method and may change if the standard library \
  310. gains a type to represent a moment in time")]
  311. pub fn modified(&self) -> u64 { self.0.modified() }
  312. }
  313. impl Permissions {
  314. /// Returns whether these permissions describe a readonly file.
  315. #[stable(feature = "rust1", since = "1.0.0")]
  316. pub fn readonly(&self) -> bool { self.0.readonly() }
  317. /// Modify the readonly flag for this set of permissions.
  318. ///
  319. /// This operation does **not** modify the filesystem. To modify the
  320. /// filesystem use the `fs::set_permissions` function.
  321. #[stable(feature = "rust1", since = "1.0.0")]
  322. pub fn set_readonly(&mut self, readonly: bool) {
  323. self.0.set_readonly(readonly)
  324. }
  325. }
  326. impl FromInner<fs_imp::FilePermissions> for Permissions {
  327. fn from_inner(f: fs_imp::FilePermissions) -> Permissions {
  328. Permissions(f)
  329. }
  330. }
  331. impl AsInner<fs_imp::FilePermissions> for Permissions {
  332. fn as_inner(&self) -> &fs_imp::FilePermissions { &self.0 }
  333. }
  334. #[stable(feature = "rust1", since = "1.0.0")]
  335. impl Iterator for ReadDir {
  336. type Item = io::Result<DirEntry>;
  337. fn next(&mut self) -> Option<io::Result<DirEntry>> {
  338. self.0.next().map(|entry| entry.map(DirEntry))
  339. }
  340. }
  341. #[stable(feature = "rust1", since = "1.0.0")]
  342. impl DirEntry {
  343. /// Returns the full path to the file that this entry represents.
  344. ///
  345. /// The full path is created by joining the original path to `read_dir` or
  346. /// `walk_dir` with the filename of this entry.
  347. #[stable(feature = "rust1", since = "1.0.0")]
  348. pub fn path(&self) -> PathBuf { self.0.path() }
  349. }
  350. /// Remove a file from the underlying filesystem.
  351. ///
  352. /// # Examples
  353. ///
  354. /// ```rust,no_run
  355. /// use std::fs;
  356. ///
  357. /// fs::remove_file("/some/file/path.txt");
  358. /// ```
  359. ///
  360. /// Note that, just because an unlink call was successful, it is not
  361. /// guaranteed that a file is immediately deleted (e.g. depending on
  362. /// platform, other open file descriptors may prevent immediate removal).
  363. ///
  364. /// # Errors
  365. ///
  366. /// This function will return an error if `path` points to a directory, if the
  367. /// user lacks permissions to remove the file, or if some other filesystem-level
  368. /// error occurs.
  369. #[stable(feature = "rust1", since = "1.0.0")]
  370. pub fn remove_file<P: AsPath>(path: P) -> io::Result<()> {
  371. fs_imp::unlink(path.as_path())
  372. }
  373. /// Given a path, query the file system to get information about a file,
  374. /// directory, etc.
  375. ///
  376. /// This function will traverse soft links to query information about the
  377. /// destination file.
  378. ///
  379. /// # Examples
  380. ///
  381. /// ```rust,no_run
  382. /// # fn foo() -> std::io::Result<()> {
  383. /// use std::fs;
  384. ///
  385. /// let attr = try!(fs::metadata("/some/file/path.txt"));
  386. /// // inspect attr ...
  387. /// # Ok(())
  388. /// # }
  389. /// ```
  390. ///
  391. /// # Errors
  392. ///
  393. /// This function will return an error if the user lacks the requisite
  394. /// permissions to perform a `metadata` call on the given `path` or if there
  395. /// is no entry in the filesystem at the provided path.
  396. #[stable(feature = "rust1", since = "1.0.0")]
  397. pub fn metadata<P: AsPath>(path: P) -> io::Result<Metadata> {
  398. fs_imp::stat(path.as_path()).map(Metadata)
  399. }
  400. /// Rename a file or directory to a new name.
  401. ///
  402. /// # Examples
  403. ///
  404. /// ```rust,no_run
  405. /// use std::fs;
  406. ///
  407. /// fs::rename("foo", "bar");
  408. /// ```
  409. ///
  410. /// # Errors
  411. ///
  412. /// This function will return an error if the provided `from` doesn't exist, if
  413. /// the process lacks permissions to view the contents, if `from` and `to`
  414. /// reside on separate filesystems, or if some other intermittent I/O error
  415. /// occurs.
  416. #[stable(feature = "rust1", since = "1.0.0")]
  417. pub fn rename<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<()> {
  418. fs_imp::rename(from.as_path(), to.as_path())
  419. }
  420. /// Copies the contents of one file to another. This function will also
  421. /// copy the permission bits of the original file to the destination file.
  422. ///
  423. /// This function will **overwrite** the contents of `to`.
  424. ///
  425. /// Note that if `from` and `to` both point to the same file, then the file
  426. /// will likely get truncated by this operation.
  427. ///
  428. /// # Examples
  429. ///
  430. /// ```
  431. /// use std::fs;
  432. ///
  433. /// fs::copy("foo.txt", "bar.txt");
  434. /// ```
  435. ///
  436. /// # Errors
  437. ///
  438. /// This function will return an error in the following situations, but is not
  439. /// limited to just these cases:
  440. ///
  441. /// * The `from` path is not a file
  442. /// * The `from` file does not exist
  443. /// * The current process does not have the permission rights to access
  444. /// `from` or write `to`
  445. #[stable(feature = "rust1", since = "1.0.0")]
  446. pub fn copy<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<u64> {
  447. let from = from.as_path();
  448. let to = to.as_path();
  449. if !from.is_file() {
  450. return Err(Error::new(ErrorKind::MismatchedFileTypeForOperation,
  451. "the source path is not an existing file",
  452. None))
  453. }
  454. let mut reader = try!(File::open(from));
  455. let mut writer = try!(File::create(to));
  456. let perm = try!(reader.metadata()).permissions();
  457. let ret = try!(io::copy(&mut reader, &mut writer));
  458. try!(set_permissions(to, perm));
  459. Ok(ret)
  460. }
  461. /// Creates a new hard link on the filesystem.
  462. ///
  463. /// The `dst` path will be a link pointing to the `src` path. Note that systems
  464. /// often require these two paths to both be located on the same filesystem.
  465. #[stable(feature = "rust1", since = "1.0.0")]
  466. pub fn hard_link<P: AsPath, Q: AsPath>(src: P, dst: Q) -> io::Result<()> {
  467. fs_imp::link(src.as_path(), dst.as_path())
  468. }
  469. /// Creates a new soft link on the filesystem.
  470. ///
  471. /// The `dst` path will be a soft link pointing to the `src` path.
  472. #[stable(feature = "rust1", since = "1.0.0")]
  473. pub fn soft_link<P: AsPath, Q: AsPath>(src: P, dst: Q) -> io::Result<()> {
  474. fs_imp::symlink(src.as_path(), dst.as_path())
  475. }
  476. /// Reads a soft link, returning the file that the link points to.
  477. ///
  478. /// # Errors
  479. ///
  480. /// This function will return an error on failure. Failure conditions include
  481. /// reading a file that does not exist or reading a file that is not a soft
  482. /// link.
  483. #[stable(feature = "rust1", since = "1.0.0")]
  484. pub fn read_link<P: AsPath>(path: P) -> io::Result<PathBuf> {
  485. fs_imp::readlink(path.as_path())
  486. }
  487. /// Create a new, empty directory at the provided path
  488. ///
  489. /// # Examples
  490. ///
  491. /// ```
  492. /// use std::fs;
  493. ///
  494. /// fs::create_dir("/some/dir");
  495. /// ```
  496. ///
  497. /// # Errors
  498. ///
  499. /// This function will return an error if the user lacks permissions to make a
  500. /// new directory at the provided `path`, or if the directory already exists.
  501. #[stable(feature = "rust1", since = "1.0.0")]
  502. pub fn create_dir<P: AsPath>(path: P) -> io::Result<()> {
  503. fs_imp::mkdir(path.as_path())
  504. }
  505. /// Recursively create a directory and all of its parent components if they
  506. /// are missing.
  507. ///
  508. /// # Errors
  509. ///
  510. /// This function will fail if any directory in the path specified by `path`
  511. /// does not already exist and it could not be created otherwise. The specific
  512. /// error conditions for when a directory is being created (after it is
  513. /// determined to not exist) are outlined by `fs::create_dir`.
  514. #[stable(feature = "rust1", since = "1.0.0")]
  515. pub fn create_dir_all<P: AsPath>(path: P) -> io::Result<()> {
  516. let path = path.as_path();
  517. if path.is_dir() { return Ok(()) }
  518. if let Some(p) = path.parent() { try!(create_dir_all(p)) }
  519. create_dir(path)
  520. }
  521. /// Remove an existing, empty directory
  522. ///
  523. /// # Examples
  524. ///
  525. /// ```
  526. /// use std::fs;
  527. ///
  528. /// fs::remove_dir("/some/dir");
  529. /// ```
  530. ///
  531. /// # Errors
  532. ///
  533. /// This function will return an error if the user lacks permissions to remove
  534. /// the directory at the provided `path`, or if the directory isn't empty.
  535. #[stable(feature = "rust1", since = "1.0.0")]
  536. pub fn remove_dir<P: AsPath>(path: P) -> io::Result<()> {
  537. fs_imp::rmdir(path.as_path())
  538. }
  539. /// Removes a directory at this path, after removing all its contents. Use
  540. /// carefully!
  541. ///
  542. /// This function does **not** follow soft links and it will simply remove the
  543. /// soft link itself.
  544. ///
  545. /// # Errors
  546. ///
  547. /// See `file::remove_file` and `fs::remove_dir`
  548. #[stable(feature = "rust1", since = "1.0.0")]
  549. pub fn remove_dir_all<P: AsPath>(path: P) -> io::Result<()> {
  550. let path = path.as_path();
  551. for child in try!(read_dir(path)) {
  552. let child = try!(child).path();
  553. let stat = try!(lstat(&*child));
  554. if stat.is_dir() {
  555. try!(remove_dir_all(&*child));
  556. } else {
  557. try!(remove_file(&*child));
  558. }
  559. }
  560. return remove_dir(path);
  561. #[cfg(unix)]
  562. fn lstat(path: &Path) -> io::Result<fs_imp::FileAttr> { fs_imp::lstat(path) }
  563. #[cfg(windows)]
  564. fn lstat(path: &Path) -> io::Result<fs_imp::FileAttr> { fs_imp::stat(path) }
  565. }
  566. /// Returns an iterator over the entries within a directory.
  567. ///
  568. /// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
  569. /// be encountered after an iterator is initially constructed.
  570. ///
  571. /// # Examples
  572. ///
  573. /// ```
  574. /// use std::io;
  575. /// use std::fs::{self, PathExt, DirEntry};
  576. /// use std::path::Path;
  577. ///
  578. /// // one possible implementation of fs::walk_dir only visiting files
  579. /// fn visit_dirs(dir: &Path, cb: &mut FnMut(DirEntry)) -> io::Result<()> {
  580. /// if dir.is_dir() {
  581. /// for entry in try!(fs::read_dir(dir)) {
  582. /// let entry = try!(entry);
  583. /// if entry.path().is_dir() {
  584. /// try!(visit_dirs(&entry.path(), cb));
  585. /// } else {
  586. /// cb(entry);
  587. /// }
  588. /// }
  589. /// }
  590. /// Ok(())
  591. /// }
  592. /// ```
  593. ///
  594. /// # Errors
  595. ///
  596. /// This function will return an error if the provided `path` doesn't exist, if
  597. /// the process lacks permissions to view the contents or if the `path` points
  598. /// at a non-directory file
  599. #[stable(feature = "rust1", since = "1.0.0")]
  600. pub fn read_dir<P: AsPath>(path: P) -> io::Result<ReadDir> {
  601. fs_imp::readdir(path.as_path()).map(ReadDir)
  602. }
  603. /// Returns an iterator that will recursively walk the directory structure
  604. /// rooted at `path`.
  605. ///
  606. /// The path given will not be iterated over, and this will perform iteration in
  607. /// some top-down order. The contents of unreadable subdirectories are ignored.
  608. ///
  609. /// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
  610. /// be encountered after an iterator is initially constructed.
  611. #[unstable(feature = "fs_walk",
  612. reason = "the precise semantics and defaults for a recursive walk \
  613. may change and this may end up accounting for files such \
  614. as symlinks differently")]
  615. pub fn walk_dir<P: AsPath>(path: P) -> io::Result<WalkDir> {
  616. let start = try!(read_dir(path));
  617. Ok(WalkDir { cur: Some(start), stack: Vec::new() })
  618. }
  619. #[unstable(feature = "fs_walk")]
  620. impl Iterator for WalkDir {
  621. type Item = io::Result<DirEntry>;
  622. fn next(&mut self) -> Option<io::Result<DirEntry>> {
  623. loop {
  624. if let Some(ref mut cur) = self.cur {
  625. match cur.next() {
  626. Some(Err(e)) => return Some(Err(e)),
  627. Some(Ok(next)) => {
  628. let path = next.path();
  629. if path.is_dir() {
  630. self.stack.push(read_dir(&*path));
  631. }
  632. return Some(Ok(next))
  633. }
  634. None => {}
  635. }
  636. }
  637. self.cur = None;
  638. match self.stack.pop() {
  639. Some(Err(e)) => return Some(Err(e)),
  640. Some(Ok(next)) => self.cur = Some(next),
  641. None => return None,
  642. }
  643. }
  644. }
  645. }
  646. /// Utility methods for paths.
  647. #[unstable(feature = "path_ext",
  648. reason = "the precise set of methods exposed on this trait may \
  649. change and some methods may be removed")]
  650. pub trait PathExt {
  651. /// Get information on the file, directory, etc at this path.
  652. ///
  653. /// Consult the `fs::stat` documentation for more info.
  654. ///
  655. /// This call preserves identical runtime/error semantics with `file::stat`.
  656. fn metadata(&self) -> io::Result<Metadata>;
  657. /// Boolean value indicator whether the underlying file exists on the local
  658. /// filesystem. Returns false in exactly the cases where `fs::stat` fails.
  659. fn exists(&self) -> bool;
  660. /// Whether the underlying implementation (be it a file path, or something
  661. /// else) points at a "regular file" on the FS. Will return false for paths
  662. /// to non-existent locations or directories or other non-regular files
  663. /// (named pipes, etc). Follows links when making this determination.
  664. fn is_file(&self) -> bool;
  665. /// Whether the underlying implementation (be it a file path, or something
  666. /// else) is pointing at a directory in the underlying FS. Will return
  667. /// false for paths to non-existent locations or if the item is not a
  668. /// directory (eg files, named pipes, etc). Follows links when making this
  669. /// determination.
  670. fn is_dir(&self) -> bool;
  671. }
  672. impl PathExt for Path {
  673. fn metadata(&self) -> io::Result<Metadata> { metadata(self) }
  674. fn exists(&self) -> bool { metadata(self).is_ok() }
  675. fn is_file(&self) -> bool {
  676. metadata(self).map(|s| s.is_file()).unwrap_or(false)
  677. }
  678. fn is_dir(&self) -> bool {
  679. metadata(self).map(|s| s.is_dir()).unwrap_or(false)
  680. }
  681. }
  682. /// Changes the timestamps for a file's last modification and access time.
  683. ///
  684. /// The file at the path specified will have its last access time set to
  685. /// `atime` and its modification time set to `mtime`. The times specified should
  686. /// be in milliseconds.
  687. #[unstable(feature = "fs_time",
  688. reason = "the argument type of u64 is not quite appropriate for \
  689. this function and may change if the standard library \
  690. gains a type to represent a moment in time")]
  691. pub fn set_file_times<P: AsPath>(path: P, accessed: u64,
  692. modified: u64) -> io::Result<()> {
  693. fs_imp::utimes(path.as_path(), accessed, modified)
  694. }
  695. /// Changes the permissions found on a file or a directory.
  696. ///
  697. /// # Examples
  698. ///
  699. /// ```
  700. /// # fn foo() -> std::io::Result<()> {
  701. /// use std::fs;
  702. ///
  703. /// let mut perms = try!(fs::metadata("foo.txt")).permissions();
  704. /// perms.set_readonly(true);
  705. /// try!(fs::set_permissions("foo.txt", perms));
  706. /// # Ok(())
  707. /// # }
  708. /// ```
  709. ///
  710. /// # Errors
  711. ///
  712. /// This function will return an error if the provided `path` doesn't exist, if
  713. /// the process lacks permissions to change the attributes of the file, or if
  714. /// some other I/O error is encountered.
  715. #[unstable(feature = "fs",
  716. reason = "a more granual ability to set specific permissions may \
  717. be exposed on the Permissions structure itself and this \
  718. method may not always exist")]
  719. pub fn set_permissions<P: AsPath>(path: P, perm: Permissions) -> io::Result<()> {
  720. fs_imp::set_perm(path.as_path(), perm.0)
  721. }
  722. #[cfg(test)]
  723. mod tests {
  724. #![allow(deprecated)] //rand
  725. use prelude::v1::*;
  726. use io::prelude::*;
  727. use fs::{self, File, OpenOptions};
  728. use io::{ErrorKind, SeekFrom};
  729. use path::PathBuf;
  730. use path::Path as Path2;
  731. use os;
  732. use rand::{self, StdRng, Rng};
  733. use str;
  734. macro_rules! check { ($e:expr) => (
  735. match $e {
  736. Ok(t) => t,
  737. Err(e) => panic!("{} failed with: {}", stringify!($e), e),
  738. }
  739. ) }
  740. macro_rules! error { ($e:expr, $s:expr) => (
  741. match $e {
  742. Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
  743. Err(ref err) => assert!(err.to_string().contains($s),
  744. format!("`{}` did not contain `{}`", err, $s))
  745. }
  746. ) }
  747. pub struct TempDir(PathBuf);
  748. impl TempDir {
  749. fn join(&self, path: &str) -> PathBuf {
  750. let TempDir(ref p) = *self;
  751. p.join(path)
  752. }
  753. fn path<'a>(&'a self) -> &'a Path2 {
  754. let TempDir(ref p) = *self;
  755. p
  756. }
  757. }
  758. impl Drop for TempDir {
  759. fn drop(&mut self) {
  760. // Gee, seeing how we're testing the fs module I sure hope that we
  761. // at least implement this correctly!
  762. let TempDir(ref p) = *self;
  763. check!(fs::remove_dir_all(p));
  764. }
  765. }
  766. pub fn tmpdir() -> TempDir {
  767. let s = os::tmpdir();
  768. let p = Path2::new(s.as_str().unwrap());
  769. let ret = p.join(&format!("rust-{}", rand::random::<u32>()));
  770. check!(fs::create_dir(&ret));
  771. TempDir(ret)
  772. }
  773. #[test]
  774. fn file_test_io_smoke_test() {
  775. let message = "it's alright. have a good time";
  776. let tmpdir = tmpdir();
  777. let filename = &tmpdir.join("file_rt_io_file_test.txt");
  778. {
  779. let mut write_stream = check!(File::create(filename));
  780. check!(write_stream.write(message.as_bytes()));
  781. }
  782. {
  783. let mut read_stream = check!(File::open(filename));
  784. let mut read_buf = [0; 1028];
  785. let read_str = match check!(read_stream.read(&mut read_buf)) {
  786. -1|0 => panic!("shouldn't happen"),
  787. n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
  788. };
  789. assert_eq!(read_str, message);
  790. }
  791. check!(fs::remove_file(filename));
  792. }
  793. #[test]
  794. fn invalid_path_raises() {
  795. let tmpdir = tmpdir();
  796. let filename = &tmpdir.join("file_that_does_not_exist.txt");
  797. let result = File::open(filename);
  798. if cfg!(unix) {
  799. error!(result, "o such file or directory");
  800. }
  801. // error!(result, "couldn't open path as file");
  802. // error!(result, format!("path={}; mode=open; access=read", filename.display()));
  803. }
  804. #[test]
  805. fn file_test_iounlinking_invalid_path_should_raise_condition() {
  806. let tmpdir = tmpdir();
  807. let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
  808. let result = fs::remove_file(filename);
  809. if cfg!(unix) {
  810. error!(result, "o such file or directory");
  811. }
  812. // error!(result, "couldn't unlink path");
  813. // error!(result, format!("path={}", filename.display()));
  814. }
  815. #[test]
  816. fn file_test_io_non_positional_read() {
  817. let message: &str = "ten-four";
  818. let mut read_mem = [0; 8];
  819. let tmpdir = tmpdir();
  820. let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
  821. {
  822. let mut rw_stream = check!(File::create(filename));
  823. check!(rw_stream.write(message.as_bytes()));
  824. }
  825. {
  826. let mut read_stream = check!(File::open(filename));
  827. {
  828. let read_buf = &mut read_mem[0..4];
  829. check!(read_stream.read(read_buf));
  830. }
  831. {
  832. let read_buf = &mut read_mem[4..8];
  833. check!(read_stream.read(read_buf));
  834. }
  835. }
  836. check!(fs::remove_file(filename));
  837. let read_str = str::from_utf8(&read_mem).unwrap();
  838. assert_eq!(read_str, message);
  839. }
  840. #[test]
  841. fn file_test_io_seek_and_tell_smoke_test() {
  842. let message = "ten-four";
  843. let mut read_mem = [0; 4];
  844. let set_cursor = 4 as u64;
  845. let mut tell_pos_pre_read;
  846. let mut tell_pos_post_read;
  847. let tmpdir = tmpdir();
  848. let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
  849. {
  850. let mut rw_stream = check!(File::create(filename));
  851. check!(rw_stream.write(message.as_bytes()));
  852. }
  853. {
  854. let mut read_stream = check!(File::open(filename));
  855. check!(read_stream.seek(SeekFrom::Start(set_cursor)));
  856. tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0)));
  857. check!(read_stream.read(&mut read_mem));
  858. tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0)));
  859. }
  860. check!(fs::remove_file(filename));
  861. let read_str = str::from_utf8(&read_mem).unwrap();
  862. assert_eq!(read_str, &message[4..8]);
  863. assert_eq!(tell_pos_pre_read, set_cursor);
  864. assert_eq!(tell_pos_post_read, message.len() as u64);
  865. }
  866. #[test]
  867. fn file_test_io_seek_and_write() {
  868. let initial_msg = "food-is-yummy";
  869. let overwrite_msg = "-the-bar!!";
  870. let final_msg = "foo-the-bar!!";
  871. let seek_idx = 3;
  872. let mut read_mem = [0; 13];
  873. let tmpdir = tmpdir();
  874. let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
  875. {
  876. let mut rw_stream = check!(File::create(filename));
  877. check!(rw_stream.write(initial_msg.as_bytes()));
  878. check!(rw_stream.seek(SeekFrom::Start(seek_idx)));
  879. check!(rw_stream.write(overwrite_msg.as_bytes()));
  880. }
  881. {
  882. let mut read_stream = check!(File::open(filename));
  883. check!(read_stream.read(&mut read_mem));
  884. }
  885. check!(fs::remove_file(filename));
  886. let read_str = str::from_utf8(&read_mem).unwrap();
  887. assert!(read_str == final_msg);
  888. }
  889. #[test]
  890. fn file_test_io_seek_shakedown() {
  891. // 01234567890123
  892. let initial_msg = "qwer-asdf-zxcv";
  893. let chunk_one: &str = "qwer";
  894. let chunk_two: &str = "asdf";
  895. let chunk_three: &str = "zxcv";
  896. let mut read_mem = [0; 4];
  897. let tmpdir = tmpdir();
  898. let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
  899. {
  900. let mut rw_stream = check!(File::create(filename));
  901. check!(rw_stream.write(initial_msg.as_bytes()));
  902. }
  903. {
  904. let mut read_stream = check!(File::open(filename));
  905. check!(read_stream.seek(SeekFrom::End(-4)));
  906. check!(read_stream.read(&mut read_mem));
  907. assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three);
  908. check!(read_stream.seek(SeekFrom::Current(-9)));
  909. check!(read_stream.read(&mut read_mem));
  910. assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two);
  911. check!(read_stream.seek(SeekFrom::Start(0)));
  912. check!(read_stream.read(&mut read_mem));
  913. assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one);
  914. }
  915. check!(fs::remove_file(filename));
  916. }
  917. #[test]
  918. fn file_test_stat_is_correct_on_is_file() {
  919. let tmpdir = tmpdir();
  920. let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
  921. {
  922. let mut opts = OpenOptions::new();
  923. let mut fs = check!(opts.read(true).write(true)
  924. .create(true).open(filename));
  925. let msg = "hw";
  926. fs.write(msg.as_bytes()).unwrap();
  927. let fstat_res = check!(fs.metadata());
  928. assert!(fstat_res.is_file());
  929. }
  930. let stat_res_fn = check!(fs::metadata(filename));
  931. assert!(stat_res_fn.is_file());
  932. let stat_res_meth = check!(filename.metadata());
  933. assert!(stat_res_meth.is_file());
  934. check!(fs::remove_file(filename));
  935. }
  936. #[test]
  937. fn file_test_stat_is_correct_on_is_dir() {
  938. let tmpdir = tmpdir();
  939. let filename = &tmpdir.join("file_stat_correct_on_is_dir");
  940. check!(fs::create_dir(filename));
  941. let stat_res_fn = check!(fs::metadata(filename));
  942. assert!(stat_res_fn.is_dir());
  943. let stat_res_meth = check!(filename.metadata());
  944. assert!(stat_res_meth.is_dir());
  945. check!(fs::remove_dir(filename));
  946. }
  947. #[test]
  948. fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
  949. let tmpdir = tmpdir();
  950. let dir = &tmpdir.join("fileinfo_false_on_dir");
  951. check!(fs::create_dir(dir));
  952. assert!(dir.is_file() == false);
  953. check!(fs::remove_dir(dir));
  954. }
  955. #[test]
  956. fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
  957. let tmpdir = tmpdir();
  958. let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
  959. check!(check!(File::create(file)).write(b"foo"));
  960. assert!(file.exists());
  961. check!(fs::remove_file(file));
  962. assert!(!file.exists());
  963. }
  964. #[test]
  965. fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
  966. let tmpdir = tmpdir();
  967. let dir = &tmpdir.join("before_and_after_dir");
  968. assert!(!dir.exists());
  969. check!(fs::create_dir(dir));
  970. assert!(dir.exists());
  971. assert!(dir.is_dir());
  972. check!(fs::remove_dir(dir));
  973. assert!(!dir.exists());
  974. }
  975. #[test]
  976. fn file_test_directoryinfo_readdir() {
  977. let tmpdir = tmpdir();
  978. let dir = &tmpdir.join("di_readdir");
  979. check!(fs::create_dir(dir));
  980. let prefix = "foo";
  981. for n in range(0, 3) {
  982. let f = dir.join(&format!("{}.txt", n));
  983. let mut w = check!(File::create(&f));
  984. let msg_str = format!("{}{}", prefix, n.to_string());
  985. let msg = msg_str.as_bytes();
  986. check!(w.write(msg));
  987. }
  988. let files = check!(fs::read_dir(dir));
  989. let mut mem = [0; 4];
  990. for f in files {
  991. let f = f.unwrap().path();
  992. {
  993. let n = f.file_stem().unwrap();
  994. check!(check!(File::open(&f)).read(&mut mem));
  995. let read_str = str::from_utf8(&mem).unwrap();
  996. let expected = format!("{}{}", prefix, n.to_str().unwrap());
  997. assert_eq!(expected, read_str);
  998. }
  999. check!(fs::remove_file(&f));
  1000. }
  1001. check!(fs::remove_dir(dir));
  1002. }
  1003. #[test]
  1004. fn file_test_walk_dir() {
  1005. let tmpdir = tmpdir();
  1006. let dir = &tmpdir.join("walk_dir");
  1007. check!(fs::create_dir(dir));
  1008. let dir1 = &dir.join("01/02/03");
  1009. check!(fs::create_dir_all(dir1));
  1010. check!(File::create(&dir1.join("04")));
  1011. let dir2 = &dir.join("11/12/13");
  1012. check!(fs::create_dir_all(dir2));
  1013. check!(File::create(&dir2.join("14")));
  1014. let files = check!(fs::walk_dir(dir));
  1015. let mut cur = [0; 2];
  1016. for f in files {
  1017. let f = f.unwrap().path();
  1018. let stem = f.file_stem().unwrap().to_str().unwrap();
  1019. let root = stem.as_bytes()[0] - b'0';
  1020. let name = stem.as_bytes()[1] - b'0';
  1021. assert!(cur[root as usize] < name);
  1022. cur[root as usize] = name;
  1023. }
  1024. check!(fs::remove_dir_all(dir));
  1025. }
  1026. #[test]
  1027. fn mkdir_path_already_exists_error() {
  1028. let tmpdir = tmpdir();
  1029. let dir = &tmpdir.join("mkdir_error_twice");
  1030. check!(fs::create_dir(dir));
  1031. let e = fs::create_dir(dir).err().unwrap();
  1032. assert_eq!(e.kind(), ErrorKind::PathAlreadyExists);
  1033. }
  1034. #[test]
  1035. fn recursive_mkdir() {
  1036. let tmpdir = tmpdir();
  1037. let dir = tmpdir.join("d1/d2");
  1038. check!(fs::create_dir_all(&dir));
  1039. assert!(dir.is_dir())
  1040. }
  1041. #[test]
  1042. fn recursive_mkdir_failure() {
  1043. let tmpdir = tmpdir();
  1044. let dir = tmpdir.join("d1");
  1045. let file = dir.join("f1");
  1046. check!(fs::create_dir_all(&dir));
  1047. check!(File::create(&file));
  1048. let result = fs::create_dir_all(&file);
  1049. assert!(result.is_err());
  1050. // error!(result, "couldn't recursively mkdir");
  1051. // error!(result, "couldn't create directory");
  1052. // error!(result, "mode=0700");
  1053. // error!(result, format!("path={}", file.display()));
  1054. }
  1055. #[test]
  1056. fn recursive_mkdir_slash() {
  1057. check!(fs::create_dir_all(&Path2::new("/")));
  1058. }
  1059. // FIXME(#12795) depends on lstat to work on windows
  1060. #[cfg(not(windows))]
  1061. #[test]
  1062. fn recursive_rmdir() {
  1063. let tmpdir = tmpdir();
  1064. let d1 = tmpdir.join("d1");
  1065. let dt = d1.join("t");
  1066. let dtt = dt.join("t");
  1067. let d2 = tmpdir.join("d2");
  1068. let canary = d2.join("do_not_delete");
  1069. check!(fs::create_dir_all(&dtt));
  1070. check!(fs::create_dir_all(&d2));
  1071. check!(check!(File::create(&canary)).write(b"foo"));
  1072. check!(fs::soft_link(&d2, &dt.join("d2")));
  1073. check!(fs::remove_dir_all(&d1));
  1074. assert!(!d1.is_dir());
  1075. assert!(canary.exists());
  1076. }
  1077. #[test]
  1078. fn unicode_path_is_dir() {
  1079. assert!(Path2::new(".").is_dir());
  1080. assert!(!Path2::new("test/stdtest/fs.rs").is_dir());
  1081. let tmpdir = tmpdir();
  1082. let mut dirpath = tmpdir.path().to_path_buf();
  1083. dirpath.push(&format!("test-가一ー你好"));
  1084. check!(fs::create_dir(&dirpath));
  1085. assert!(dirpath.is_dir());
  1086. let mut filepath = dirpath;
  1087. filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
  1088. check!(File::create(&filepath)); // ignore return; touch only
  1089. assert!(!filepath.is_dir());
  1090. assert!(filepath.exists());
  1091. }
  1092. #[test]
  1093. fn unicode_path_exists() {
  1094. assert!(Path2::new(".").exists());
  1095. assert!(!Path2::new("test/nonexistent-bogus-path").exists());
  1096. let tmpdir = tmpdir();
  1097. let unicode = tmpdir.path();
  1098. let unicode = unicode.join(&format!("test-각丁ー再见"));
  1099. check!(fs::create_dir(&unicode));
  1100. assert!(unicode.exists());
  1101. assert!(!Path2::new("test/unicode-bogus-path-각丁ー再见").exists());
  1102. }
  1103. #[test]
  1104. fn copy_file_does_not_exist() {
  1105. let from = Path2::new("test/nonexistent-bogus-path");
  1106. let to = Path2::new("test/other-bogus-path");
  1107. match fs::copy(&from, &to) {
  1108. Ok(..) => panic!(),
  1109. Err(..) => {
  1110. assert!(!from.exists());
  1111. assert!(!to.exists());
  1112. }
  1113. }
  1114. }
  1115. #[test]
  1116. fn copy_file_ok() {
  1117. let tmpdir = tmpdir();
  1118. let input = tmpdir.join("in.txt");
  1119. let out = tmpdir.join("out.txt");
  1120. check!(check!(File::create(&input)).write(b"hello"));
  1121. check!(fs::copy(&input, &out));
  1122. let mut v = Vec::new();
  1123. check!(check!(File::open(&out)).read_to_end(&mut v));
  1124. assert_eq!(v.as_slice(), b"hello");
  1125. assert_eq!(check!(input.metadata()).permissions(),
  1126. check!(out.metadata()).permissions());
  1127. }
  1128. #[test]
  1129. fn copy_file_dst_dir() {
  1130. let tmpdir = tmpdir();
  1131. let out = tmpdir.join("out");
  1132. check!(File::create(&out));
  1133. match fs::copy(&*out, tmpdir.path()) {
  1134. Ok(..) => panic!(), Err(..) => {}
  1135. }
  1136. }
  1137. #[test]
  1138. fn copy_file_dst_exists() {
  1139. let tmpdir = tmpdir();
  1140. let input = tmpdir.join("in");
  1141. let output = tmpdir.join("out");
  1142. check!(check!(File::create(&input)).write("foo".as_bytes()));
  1143. check!(check!(File::create(&output)).write("bar".as_bytes()));
  1144. check!(fs::copy(&input, &output));
  1145. let mut v = Vec::new();
  1146. check!(check!(File::open(&output)).read_to_end(&mut v));
  1147. assert_eq!(v, b"foo".to_vec());
  1148. }
  1149. #[test]
  1150. fn copy_file_src_dir() {
  1151. let tmpdir = tmpdir();
  1152. let out = tmpdir.join("out");
  1153. match fs::copy(tmpdir.path(), &out) {
  1154. Ok(..) => panic!(), Err(..) => {}
  1155. }
  1156. assert!(!out.exists());
  1157. }
  1158. #[test]
  1159. fn copy_file_preserves_perm_bits() {
  1160. let tmpdir = tmpdir();
  1161. let input = tmpdir.join("in.txt");
  1162. let out = tmpdir.join("out.txt");
  1163. let attr = check!(check!(File::create(&input)).metadata());
  1164. let mut p = attr.permissions();
  1165. p.set_readonly(true);
  1166. check!(fs::set_permissions(&input, p));
  1167. check!(fs::copy(&input, &out));
  1168. assert!(check!(out.metadata()).permissions().readonly());
  1169. check!(fs::set_permissions(&input, attr.permissions()));
  1170. check!(fs::set_permissions(&out, attr.permissions()));
  1171. }
  1172. #[cfg(not(windows))] // FIXME(#10264) operation not permitted?
  1173. #[test]
  1174. fn symlinks_work() {
  1175. let tmpdir = tmpdir();
  1176. let input = tmpdir.join("in.txt");
  1177. let out = tmpdir.join("out.txt");
  1178. check!(check!(File::create(&input)).write("foobar".as_bytes()));
  1179. check!(fs::soft_link(&input, &out));
  1180. // if cfg!(not(windows)) {
  1181. // assert_eq!(check!(lstat(&out)).kind, FileType::Symlink);
  1182. // assert_eq!(check!(out.lstat()).kind, FileType::Symlink);
  1183. // }
  1184. assert_eq!(check!(fs::metadata(&out)).len(),
  1185. check!(fs::metadata(&input)).len());
  1186. let mut v = Vec::new();
  1187. check!(check!(File::open(&out)).read_to_end(&mut v));
  1188. assert_eq!(v, b"foobar".to_vec());
  1189. }
  1190. #[cfg(not(windows))] // apparently windows doesn't like symlinks
  1191. #[test]
  1192. fn symlink_noexist() {
  1193. let tmpdir = tmpdir();
  1194. // symlinks can point to things that don't exist
  1195. check!(fs::soft_link(&tmpdir.join("foo"), &tmpdir.join("bar")));
  1196. assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))),
  1197. tmpdir.join("foo"));
  1198. }
  1199. #[test]
  1200. fn readlink_not_symlink() {
  1201. let tmpdir = tmpdir();
  1202. match fs::read_link(tmpdir.path()) {
  1203. Ok(..) => panic!("wanted a failure"),
  1204. Err(..) => {}
  1205. }
  1206. }
  1207. #[test]
  1208. fn links_work() {
  1209. let tmpdir = tmpdir();
  1210. let input = tmpdir.join("in.txt");
  1211. let out = tmpdir.join("out.txt");
  1212. check!(check!(File::create(&input)).write("foobar".as_bytes()));
  1213. check!(fs::hard_link(&input, &out));
  1214. assert_eq!(check!(fs::metadata(&out)).len(),
  1215. check!(fs::metadata(&input)).len());
  1216. assert_eq!(check!(fs::metadata(&out)).len(),
  1217. check!(input.metadata()).len());
  1218. let mut v = Vec::new();
  1219. check!(check!(File::open(&out)).read_to_end(&mut v));
  1220. assert_eq!(v, b"foobar".to_vec());
  1221. // can't link to yourself
  1222. match fs::hard_link(&input, &input) {
  1223. Ok(..) => panic!("wanted a failure"),
  1224. Err(..) => {}
  1225. }
  1226. // can't link to something that doesn't exist
  1227. match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
  1228. Ok(..) => panic!("wanted a failure"),
  1229. Err(..) => {}
  1230. }
  1231. }
  1232. #[test]
  1233. fn chmod_works() {
  1234. let tmpdir = tmpdir();
  1235. let file = tmpdir.join("in.txt");
  1236. check!(File::create(&file));
  1237. let attr = check!(fs::metadata(&file));
  1238. assert!(!attr.permissions().readonly());
  1239. let mut p = attr.permissions();
  1240. p.set_readonly(true);
  1241. check!(fs::set_permissions(&file, p.clone()));
  1242. let attr = check!(fs::metadata(&file));
  1243. assert!(attr.permissions().readonly());
  1244. match fs::set_permissions(&tmpdir.join("foo"), p.clone()) {
  1245. Ok(..) => panic!("wanted an error"),
  1246. Err(..) => {}
  1247. }
  1248. p.set_readonly(false);
  1249. check!(fs::set_permissions(&file, p));
  1250. }
  1251. #[test]
  1252. fn sync_doesnt_kill_anything() {
  1253. let tmpdir = tmpdir();
  1254. let path = tmpdir.join("in.txt");
  1255. let mut file = check!(File::create(&path));
  1256. check!(file.sync_all());
  1257. check!(file.sync_data());
  1258. check!(file.write(b"foo"));
  1259. check!(file.sync_all());
  1260. check!(file.sync_data());
  1261. }
  1262. #[test]
  1263. fn truncate_works() {
  1264. let tmpdir = tmpdir();
  1265. let path = tmpdir.join("in.txt");
  1266. let mut file = check!(File::create(&path));
  1267. check!(file.write(b"foo"));
  1268. check!(file.sync_all());
  1269. // Do some simple things with truncation
  1270. assert_eq!(check!(file.metadata()).len(), 3);
  1271. check!(file.set_len(10));
  1272. assert_eq!(check!(file.metadata()).len(), 10);
  1273. check!(file.write(b"bar"));
  1274. check!(file.sync_all());
  1275. assert_eq!(check!(file.metadata()).len(), 10);
  1276. let mut v = Vec::new();
  1277. check!(check!(File::open(&path)).read_to_end(&mut v));
  1278. assert_eq!(v, b"foobar\0\0\0\0".to_vec());
  1279. // Truncate to a smaller length, don't seek, and then write something.
  1280. // Ensure that the intermediate zeroes are all filled in (we're seeked
  1281. // past the end of the file).
  1282. check!(file.set_len(2));
  1283. assert_eq!(check!(file.metadata()).len(), 2);
  1284. check!(file.write(b"wut"));
  1285. check!(file.sync_all());
  1286. assert_eq!(check!(file.metadata()).len(), 9);
  1287. let mut v = Vec::new();
  1288. check!(check!(File::open(&path)).read_to_end(&mut v));
  1289. assert_eq!(v, b"fo\0\0\0\0wut".to_vec());
  1290. }
  1291. #[test]
  1292. fn open_flavors() {
  1293. use fs::OpenOptions as OO;
  1294. fn c<T: Clone>(t: &T) -> T { t.clone() }
  1295. let tmpdir = tmpdir();
  1296. let mut r = OO::new(); r.read(true);
  1297. let mut w = OO::new(); w.write(true);
  1298. let mut rw = OO::new(); rw.write(true).read(true);
  1299. match r.open(&tmpdir.join("a")) {
  1300. Ok(..) => panic!(), Err(..) => {}
  1301. }
  1302. // Perform each one twice to make sure that it succeeds the second time
  1303. // (where the file exists)
  1304. check!(c(&w).create(true).open(&tmpdir.join("b")));
  1305. assert!(tmpdir.join("b").exists());
  1306. check!(c(&w).create(true).open(&tmpdir.join("b")));
  1307. check!(w.open(&tmpdir.join("b")));
  1308. check!(c(&rw).create(true).open(&tmpdir.join("c")));
  1309. assert!(tmpdir.join("c").exists());
  1310. check!(c(&rw).create(true).open(&tmpdir.join("c")));
  1311. check!(rw.open(&tmpdir.join("c")));
  1312. check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
  1313. asser

Large files files are truncated, but you can click here to view the full file