PageRenderTime 91ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/libstd/old_io/fs.rs

http://github.com/eholk/rust
Rust | 1630 lines | 1043 code | 164 blank | 423 comment | 45 complexity | ca2c32c9c3b268318fa9ad80aabf10b3 MD5 | raw file
Possible License(s): AGPL-1.0, BSD-2-Clause, 0BSD, Apache-2.0, MIT, LGPL-2.0
  1. // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
  2. // file at the top-level directory of this distribution and at
  3. // http://rust-lang.org/COPYRIGHT.
  4. //
  5. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  6. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  7. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  8. // option. This file may not be copied, modified, or distributed
  9. // except according to those terms.
  10. //
  11. // ignore-lexer-test FIXME #15679
  12. //! Synchronous File I/O
  13. //!
  14. //! This module provides a set of functions and traits for working
  15. //! with regular files & directories on a filesystem.
  16. //!
  17. //! At the top-level of the module are a set of freestanding functions, associated
  18. //! with various filesystem operations. They all operate on `Path` objects.
  19. //!
  20. //! All operations in this module, including those as part of `File` et al block
  21. //! the task during execution. In the event of failure, all functions/methods
  22. //! will return an `IoResult` type with an `Err` value.
  23. //!
  24. //! Also included in this module is an implementation block on the `Path` object
  25. //! defined in `std::path::Path`. The impl adds useful methods about inspecting
  26. //! the metadata of a file. This includes getting the `stat` information,
  27. //! reading off particular bits of it, etc.
  28. //!
  29. //! # Examples
  30. //!
  31. //! ```rust
  32. //! # #![allow(unused_must_use)]
  33. //! use std::old_io::fs::PathExtensions;
  34. //! use std::old_io::{File, fs};
  35. //!
  36. //! let path = Path::new("foo.txt");
  37. //!
  38. //! // create the file, whether it exists or not
  39. //! let mut file = File::create(&path);
  40. //! file.write(b"foobar");
  41. //! # drop(file);
  42. //!
  43. //! // open the file in read-only mode
  44. //! let mut file = File::open(&path);
  45. //! file.read_to_end();
  46. //!
  47. //! println!("{}", path.stat().unwrap().size);
  48. //! # drop(file);
  49. //! fs::unlink(&path);
  50. //! ```
  51. use clone::Clone;
  52. use old_io::standard_error;
  53. use old_io::{FilePermission, Write, Open, FileAccess, FileMode, FileType};
  54. use old_io::{IoResult, IoError, InvalidInput};
  55. use old_io::{FileStat, SeekStyle, Seek, Writer, Reader};
  56. use old_io::{Read, Truncate, ReadWrite, Append};
  57. use old_io::UpdateIoError;
  58. use old_io;
  59. use iter::{Iterator, Extend};
  60. use option::Option;
  61. use option::Option::{Some, None};
  62. use old_path::{Path, GenericPath};
  63. use old_path;
  64. use result::Result::{Err, Ok};
  65. #[cfg(stage0)]
  66. use slice::SliceExt;
  67. use string::String;
  68. use vec::Vec;
  69. use sys::fs as fs_imp;
  70. use sys_common;
  71. /// Unconstrained file access type that exposes read and write operations
  72. ///
  73. /// Can be constructed via `File::open()`, `File::create()`, and
  74. /// `File::open_mode()`.
  75. ///
  76. /// # Error
  77. ///
  78. /// This type will return errors as an `IoResult<T>` if operations are
  79. /// attempted against it for which its underlying file descriptor was not
  80. /// configured at creation time, via the `FileAccess` parameter to
  81. /// `File::open_mode()`.
  82. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::File")]
  83. #[unstable(feature = "old_io")]
  84. pub struct File {
  85. fd: fs_imp::FileDesc,
  86. path: Path,
  87. last_nread: int,
  88. }
  89. impl sys_common::AsInner<fs_imp::FileDesc> for File {
  90. fn as_inner(&self) -> &fs_imp::FileDesc {
  91. &self.fd
  92. }
  93. }
  94. #[deprecated(since = "1.0.0", reason = "replaced with std::fs")]
  95. #[unstable(feature = "old_io")]
  96. impl File {
  97. /// Open a file at `path` in the mode specified by the `mode` and `access`
  98. /// arguments
  99. ///
  100. /// # Examples
  101. ///
  102. /// ```rust,should_fail
  103. /// use std::old_io::{File, Open, ReadWrite};
  104. ///
  105. /// let p = Path::new("/some/file/path.txt");
  106. ///
  107. /// let file = match File::open_mode(&p, Open, ReadWrite) {
  108. /// Ok(f) => f,
  109. /// Err(e) => panic!("file error: {}", e),
  110. /// };
  111. /// // do some stuff with that file
  112. ///
  113. /// // the file will be closed at the end of this block
  114. /// ```
  115. ///
  116. /// `FileMode` and `FileAccess` provide information about the permissions
  117. /// context in which a given stream is created. More information about them
  118. /// can be found in `std::io`'s docs. If a file is opened with `Write`
  119. /// or `ReadWrite` access, then it will be created if it does not already
  120. /// exist.
  121. ///
  122. /// Note that, with this function, a `File` is returned regardless of the
  123. /// access-limitations indicated by `FileAccess` (e.g. calling `write` on a
  124. /// `File` opened as `Read` will return an error at runtime).
  125. ///
  126. /// # Error
  127. ///
  128. /// This function will return an error under a number of different
  129. /// circumstances, to include but not limited to:
  130. ///
  131. /// * Opening a file that does not exist with `Read` access.
  132. /// * Attempting to open a file with a `FileAccess` that the user lacks
  133. /// permissions for
  134. /// * Filesystem-level errors (full disk, etc)
  135. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::OpenOptions")]
  136. #[unstable(feature = "old_io")]
  137. pub fn open_mode(path: &Path,
  138. mode: FileMode,
  139. access: FileAccess) -> IoResult<File> {
  140. fs_imp::open(path, mode, access).and_then(|fd| {
  141. // On *BSD systems, we can open a directory as a file and read from it:
  142. // fd=open("/tmp", O_RDONLY); read(fd, buf, N);
  143. // due to an old tradition before the introduction of opendir(3).
  144. // We explicitly reject it because there are few use cases.
  145. if cfg!(not(any(windows, target_os = "linux", target_os = "android"))) &&
  146. try!(fd.fstat()).kind == FileType::Directory {
  147. Err(IoError {
  148. kind: InvalidInput,
  149. desc: "is a directory",
  150. detail: None
  151. })
  152. } else {
  153. Ok(File {
  154. path: path.clone(),
  155. fd: fd,
  156. last_nread: -1
  157. })
  158. }
  159. }).update_err("couldn't open path as file", |e| {
  160. format!("{}; path={}; mode={}; access={}", e, path.display(),
  161. mode_string(mode), access_string(access))
  162. })
  163. }
  164. /// Attempts to open a file in read-only mode. This function is equivalent to
  165. /// `File::open_mode(path, Open, Read)`, and will raise all of the same
  166. /// errors that `File::open_mode` does.
  167. ///
  168. /// For more information, see the `File::open_mode` function.
  169. ///
  170. /// # Examples
  171. ///
  172. /// ```
  173. /// use std::old_io::File;
  174. ///
  175. /// let contents = File::open(&Path::new("foo.txt")).read_to_end();
  176. /// ```
  177. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::File::open")]
  178. #[unstable(feature = "old_io")]
  179. pub fn open(path: &Path) -> IoResult<File> {
  180. File::open_mode(path, Open, Read)
  181. }
  182. /// Attempts to create a file in write-only mode. This function is
  183. /// equivalent to `File::open_mode(path, Truncate, Write)`, and will
  184. /// raise all of the same errors that `File::open_mode` does.
  185. ///
  186. /// For more information, see the `File::open_mode` function.
  187. ///
  188. /// # Examples
  189. ///
  190. /// ```
  191. /// # #![allow(unused_must_use)]
  192. /// use std::old_io::File;
  193. ///
  194. /// let mut f = File::create(&Path::new("foo.txt"));
  195. /// f.write(b"This is a sample file");
  196. /// # drop(f);
  197. /// # ::std::old_io::fs::unlink(&Path::new("foo.txt"));
  198. /// ```
  199. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::File::create")]
  200. #[unstable(feature = "old_io")]
  201. pub fn create(path: &Path) -> IoResult<File> {
  202. File::open_mode(path, Truncate, Write)
  203. .update_desc("couldn't create file")
  204. }
  205. /// Returns the original path that was used to open this file.
  206. #[deprecated(since = "1.0.0", reason = "replaced with std::fs")]
  207. #[unstable(feature = "old_io")]
  208. pub fn path<'a>(&'a self) -> &'a Path {
  209. &self.path
  210. }
  211. /// Synchronizes all modifications to this file to its permanent storage
  212. /// device. This will flush any internal buffers necessary to perform this
  213. /// operation.
  214. #[deprecated(since = "1.0.0", reason = "replaced with std::fs")]
  215. #[unstable(feature = "old_io")]
  216. pub fn fsync(&mut self) -> IoResult<()> {
  217. self.fd.fsync()
  218. .update_err("couldn't fsync file",
  219. |e| format!("{}; path={}", e, self.path.display()))
  220. }
  221. /// This function is similar to `fsync`, except that it may not synchronize
  222. /// file metadata to the filesystem. This is intended for use cases that
  223. /// must synchronize content, but don't need the metadata on disk. The goal
  224. /// of this method is to reduce disk operations.
  225. #[deprecated(since = "1.0.0", reason = "replaced with std::fs")]
  226. #[unstable(feature = "old_io")]
  227. pub fn datasync(&mut self) -> IoResult<()> {
  228. self.fd.datasync()
  229. .update_err("couldn't datasync file",
  230. |e| format!("{}; path={}", e, self.path.display()))
  231. }
  232. /// Either truncates or extends the underlying file, updating the size of
  233. /// this file to become `size`. This is equivalent to unix's `truncate`
  234. /// function.
  235. ///
  236. /// If the `size` is less than the current file's size, then the file will
  237. /// be shrunk. If it is greater than the current file's size, then the file
  238. /// will be extended to `size` and have all of the intermediate data filled
  239. /// in with 0s.
  240. #[deprecated(since = "1.0.0", reason = "replaced with std::fs")]
  241. #[unstable(feature = "old_io")]
  242. pub fn truncate(&mut self, size: i64) -> IoResult<()> {
  243. self.fd.truncate(size)
  244. .update_err("couldn't truncate file", |e|
  245. format!("{}; path={}; size={}", e, self.path.display(), size))
  246. }
  247. /// Returns true if the stream has reached the end of the file.
  248. ///
  249. /// If true, then this file will no longer continue to return data via
  250. /// `read`.
  251. ///
  252. /// Note that the operating system will not return an `EOF` indicator
  253. /// until you have attempted to read past the end of the file, so if
  254. /// you've read _exactly_ the number of bytes in the file, this will
  255. /// return `false`, not `true`.
  256. #[deprecated(since = "1.0.0", reason = "replaced with std::fs")]
  257. #[unstable(feature = "old_io")]
  258. pub fn eof(&self) -> bool {
  259. self.last_nread == 0
  260. }
  261. /// Queries information about the underlying file.
  262. #[deprecated(since = "1.0.0", reason = "replaced with std::fs")]
  263. #[unstable(feature = "old_io")]
  264. pub fn stat(&self) -> IoResult<FileStat> {
  265. self.fd.fstat()
  266. .update_err("couldn't fstat file", |e|
  267. format!("{}; path={}", e, self.path.display()))
  268. }
  269. }
  270. /// Unlink a file from the underlying filesystem.
  271. ///
  272. /// # Examples
  273. ///
  274. /// ```
  275. /// # #![allow(unused_must_use)]
  276. /// use std::old_io::fs;
  277. ///
  278. /// let p = Path::new("/some/file/path.txt");
  279. /// fs::unlink(&p);
  280. /// ```
  281. ///
  282. /// Note that, just because an unlink call was successful, it is not
  283. /// guaranteed that a file is immediately deleted (e.g. depending on
  284. /// platform, other open file descriptors may prevent immediate removal)
  285. ///
  286. /// # Error
  287. ///
  288. /// This function will return an error if `path` points to a directory, if the
  289. /// user lacks permissions to remove the file, or if some other filesystem-level
  290. /// error occurs.
  291. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::remove_file")]
  292. #[unstable(feature = "old_io")]
  293. pub fn unlink(path: &Path) -> IoResult<()> {
  294. fs_imp::unlink(path)
  295. .update_err("couldn't unlink path", |e|
  296. format!("{}; path={}", e, path.display()))
  297. }
  298. /// Given a path, query the file system to get information about a file,
  299. /// directory, etc. This function will traverse symlinks to query
  300. /// information about the destination file.
  301. ///
  302. /// # Examples
  303. ///
  304. /// ```
  305. /// use std::old_io::fs;
  306. ///
  307. /// let p = Path::new("/some/file/path.txt");
  308. /// match fs::stat(&p) {
  309. /// Ok(stat) => { /* ... */ }
  310. /// Err(e) => { /* handle error */ }
  311. /// }
  312. /// ```
  313. ///
  314. /// # Error
  315. ///
  316. /// This function will return an error if the user lacks the requisite permissions
  317. /// to perform a `stat` call on the given `path` or if there is no entry in the
  318. /// filesystem at the provided path.
  319. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::metadata")]
  320. #[unstable(feature = "old_io")]
  321. pub fn stat(path: &Path) -> IoResult<FileStat> {
  322. fs_imp::stat(path)
  323. .update_err("couldn't stat path", |e|
  324. format!("{}; path={}", e, path.display()))
  325. }
  326. /// Perform the same operation as the `stat` function, except that this
  327. /// function does not traverse through symlinks. This will return
  328. /// information about the symlink file instead of the file that it points
  329. /// to.
  330. ///
  331. /// # Error
  332. ///
  333. /// See `stat`
  334. #[unstable(feature = "old_fs")]
  335. pub fn lstat(path: &Path) -> IoResult<FileStat> {
  336. fs_imp::lstat(path)
  337. .update_err("couldn't lstat path", |e|
  338. format!("{}; path={}", e, path.display()))
  339. }
  340. /// Rename a file or directory to a new name.
  341. ///
  342. /// # Examples
  343. ///
  344. /// ```
  345. /// # #![allow(unused_must_use)]
  346. /// use std::old_io::fs;
  347. ///
  348. /// fs::rename(&Path::new("foo"), &Path::new("bar"));
  349. /// ```
  350. ///
  351. /// # Error
  352. ///
  353. /// This function will return an error if the provided `from` doesn't exist, if
  354. /// the process lacks permissions to view the contents, or if some other
  355. /// intermittent I/O error occurs.
  356. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::rename")]
  357. #[unstable(feature = "old_io")]
  358. pub fn rename(from: &Path, to: &Path) -> IoResult<()> {
  359. fs_imp::rename(from, to)
  360. .update_err("couldn't rename path", |e|
  361. format!("{}; from={:?}; to={:?}", e, from.display(), to.display()))
  362. }
  363. /// Copies the contents of one file to another. This function will also
  364. /// copy the permission bits of the original file to the destination file.
  365. ///
  366. /// Note that if `from` and `to` both point to the same file, then the file
  367. /// will likely get truncated by this operation.
  368. ///
  369. /// # Examples
  370. ///
  371. /// ```
  372. /// # #![allow(unused_must_use)]
  373. /// use std::old_io::fs;
  374. ///
  375. /// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt"));
  376. /// ```
  377. ///
  378. /// # Error
  379. ///
  380. /// This function will return an error in the following situations, but is not
  381. /// limited to just these cases:
  382. ///
  383. /// * The `from` path is not a file
  384. /// * The `from` file does not exist
  385. /// * The current process does not have the permission rights to access
  386. /// `from` or write `to`
  387. ///
  388. /// Note that this copy is not atomic in that once the destination is
  389. /// ensured to not exist, there is nothing preventing the destination from
  390. /// being created and then destroyed by this operation.
  391. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::copy")]
  392. #[unstable(feature = "old_io")]
  393. pub fn copy(from: &Path, to: &Path) -> IoResult<()> {
  394. fn update_err<T>(result: IoResult<T>, from: &Path, to: &Path) -> IoResult<T> {
  395. result.update_err("couldn't copy path", |e| {
  396. format!("{}; from={:?}; to={:?}", e, from.display(), to.display())
  397. })
  398. }
  399. if !from.is_file() {
  400. return update_err(Err(IoError {
  401. kind: old_io::MismatchedFileTypeForOperation,
  402. desc: "the source path is not an existing file",
  403. detail: None
  404. }), from, to)
  405. }
  406. let mut reader = try!(File::open(from));
  407. let mut writer = try!(File::create(to));
  408. try!(update_err(super::util::copy(&mut reader, &mut writer), from, to));
  409. chmod(to, try!(update_err(from.stat(), from, to)).perm)
  410. }
  411. /// Changes the permission mode bits found on a file or a directory. This
  412. /// function takes a mask from the `io` module
  413. ///
  414. /// # Examples
  415. ///
  416. /// ```
  417. /// # #![allow(unused_must_use)]
  418. /// use std::old_io;
  419. /// use std::old_io::fs;
  420. ///
  421. /// fs::chmod(&Path::new("file.txt"), old_io::USER_FILE);
  422. /// fs::chmod(&Path::new("file.txt"), old_io::USER_READ | old_io::USER_WRITE);
  423. /// fs::chmod(&Path::new("dir"), old_io::USER_DIR);
  424. /// fs::chmod(&Path::new("file.exe"), old_io::USER_EXEC);
  425. /// ```
  426. ///
  427. /// # Error
  428. ///
  429. /// This function will return an error if the provided `path` doesn't exist, if
  430. /// the process lacks permissions to change the attributes of the file, or if
  431. /// some other I/O error is encountered.
  432. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::set_permissions")]
  433. #[unstable(feature = "old_io")]
  434. pub fn chmod(path: &Path, mode: old_io::FilePermission) -> IoResult<()> {
  435. fs_imp::chmod(path, mode.bits() as uint)
  436. .update_err("couldn't chmod path", |e|
  437. format!("{}; path={}; mode={:?}", e, path.display(), mode))
  438. }
  439. /// Change the user and group owners of a file at the specified path.
  440. #[unstable(feature = "old_fs")]
  441. pub fn chown(path: &Path, uid: int, gid: int) -> IoResult<()> {
  442. fs_imp::chown(path, uid, gid)
  443. .update_err("couldn't chown path", |e|
  444. format!("{}; path={}; uid={}; gid={}", e, path.display(), uid, gid))
  445. }
  446. /// Creates a new hard link on the filesystem. The `dst` path will be a
  447. /// link pointing to the `src` path. Note that systems often require these
  448. /// two paths to both be located on the same filesystem.
  449. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::hard_link")]
  450. #[unstable(feature = "old_io")]
  451. pub fn link(src: &Path, dst: &Path) -> IoResult<()> {
  452. fs_imp::link(src, dst)
  453. .update_err("couldn't link path", |e|
  454. format!("{}; src={:?}; dest={:?}", e, src.display(), dst.display()))
  455. }
  456. /// Creates a new symbolic link on the filesystem. The `dst` path will be a
  457. /// symlink pointing to the `src` path.
  458. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::soft_link")]
  459. #[unstable(feature = "old_io")]
  460. pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
  461. fs_imp::symlink(src, dst)
  462. .update_err("couldn't symlink path", |e|
  463. format!("{}; src={:?}; dest={:?}", e, src.display(), dst.display()))
  464. }
  465. /// Reads a symlink, returning the file that the symlink points to.
  466. ///
  467. /// # Error
  468. ///
  469. /// This function will return an error on failure. Failure conditions include
  470. /// reading a file that does not exist or reading a file that is not a symlink.
  471. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::read_link")]
  472. #[unstable(feature = "old_io")]
  473. pub fn readlink(path: &Path) -> IoResult<Path> {
  474. fs_imp::readlink(path)
  475. .update_err("couldn't resolve symlink for path", |e|
  476. format!("{}; path={}", e, path.display()))
  477. }
  478. /// Create a new, empty directory at the provided path
  479. ///
  480. /// # Examples
  481. ///
  482. /// ```
  483. /// # #![allow(unused_must_use)]
  484. /// use std::old_io;
  485. /// use std::old_io::fs;
  486. ///
  487. /// let p = Path::new("/some/dir");
  488. /// fs::mkdir(&p, old_io::USER_RWX);
  489. /// ```
  490. ///
  491. /// # Error
  492. ///
  493. /// This function will return an error if the user lacks permissions to make a
  494. /// new directory at the provided `path`, or if the directory already exists.
  495. #[unstable(feature = "old_fs")]
  496. pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> {
  497. fs_imp::mkdir(path, mode.bits() as uint)
  498. .update_err("couldn't create directory", |e|
  499. format!("{}; path={}; mode={}", e, path.display(), mode))
  500. }
  501. /// Remove an existing, empty directory
  502. ///
  503. /// # Examples
  504. ///
  505. /// ```
  506. /// # #![allow(unused_must_use)]
  507. /// use std::old_io::fs;
  508. ///
  509. /// let p = Path::new("/some/dir");
  510. /// fs::rmdir(&p);
  511. /// ```
  512. ///
  513. /// # Error
  514. ///
  515. /// This function will return an error if the user lacks permissions to remove
  516. /// the directory at the provided `path`, or if the directory isn't empty.
  517. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::remove_dir")]
  518. #[unstable(feature = "old_io")]
  519. pub fn rmdir(path: &Path) -> IoResult<()> {
  520. fs_imp::rmdir(path)
  521. .update_err("couldn't remove directory", |e|
  522. format!("{}; path={}", e, path.display()))
  523. }
  524. /// Retrieve a vector containing all entries within a provided directory
  525. ///
  526. /// # Examples
  527. ///
  528. /// ```
  529. /// use std::old_io::fs::PathExtensions;
  530. /// use std::old_io::fs;
  531. /// use std::old_io;
  532. ///
  533. /// // one possible implementation of fs::walk_dir only visiting files
  534. /// fn visit_dirs<F>(dir: &Path, cb: &mut F) -> old_io::IoResult<()> where
  535. /// F: FnMut(&Path),
  536. /// {
  537. /// if dir.is_dir() {
  538. /// let contents = try!(fs::readdir(dir));
  539. /// for entry in contents.iter() {
  540. /// if entry.is_dir() {
  541. /// try!(visit_dirs(entry, cb));
  542. /// } else {
  543. /// (*cb)(entry);
  544. /// }
  545. /// }
  546. /// Ok(())
  547. /// } else {
  548. /// Err(old_io::standard_error(old_io::InvalidInput))
  549. /// }
  550. /// }
  551. /// ```
  552. ///
  553. /// # Error
  554. ///
  555. /// This function will return an error if the provided `path` doesn't exist, if
  556. /// the process lacks permissions to view the contents or if the `path` points
  557. /// at a non-directory file
  558. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::read_dir")]
  559. #[unstable(feature = "old_io")]
  560. pub fn readdir(path: &Path) -> IoResult<Vec<Path>> {
  561. fs_imp::readdir(path)
  562. .update_err("couldn't read directory",
  563. |e| format!("{}; path={}", e, path.display()))
  564. }
  565. /// Returns an iterator that will recursively walk the directory structure
  566. /// rooted at `path`. The path given will not be iterated over, and this will
  567. /// perform iteration in some top-down order. The contents of unreadable
  568. /// subdirectories are ignored.
  569. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::walk_dir")]
  570. #[unstable(feature = "old_io")]
  571. pub fn walk_dir(path: &Path) -> IoResult<Directories> {
  572. Ok(Directories {
  573. stack: try!(readdir(path).update_err("couldn't walk directory",
  574. |e| format!("{}; path={}", e, path.display())))
  575. })
  576. }
  577. /// An iterator that walks over a directory
  578. #[derive(Clone)]
  579. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::ReadDir")]
  580. #[unstable(feature = "old_io")]
  581. pub struct Directories {
  582. stack: Vec<Path>,
  583. }
  584. impl Iterator for Directories {
  585. type Item = Path;
  586. fn next(&mut self) -> Option<Path> {
  587. match self.stack.pop() {
  588. Some(path) => {
  589. if path.is_dir() {
  590. match readdir(&path) {
  591. Ok(dirs) => { self.stack.extend(dirs.into_iter()); }
  592. Err(..) => {}
  593. }
  594. }
  595. Some(path)
  596. }
  597. None => None
  598. }
  599. }
  600. }
  601. /// Recursively create a directory and all of its parent components if they
  602. /// are missing.
  603. ///
  604. /// # Error
  605. ///
  606. /// See `fs::mkdir`.
  607. #[unstable(feature = "old_fs")]
  608. pub fn mkdir_recursive(path: &Path, mode: FilePermission) -> IoResult<()> {
  609. // tjc: if directory exists but with different permissions,
  610. // should we return false?
  611. if path.is_dir() {
  612. return Ok(())
  613. }
  614. let comps = path.components();
  615. let mut curpath = path.root_path().unwrap_or(Path::new("."));
  616. for c in comps {
  617. curpath.push(c);
  618. let result = mkdir(&curpath, mode)
  619. .update_err("couldn't recursively mkdir",
  620. |e| format!("{}; path={}", e, path.display()));
  621. match result {
  622. Err(mkdir_err) => {
  623. // already exists ?
  624. if try!(stat(&curpath)).kind != FileType::Directory {
  625. return Err(mkdir_err);
  626. }
  627. }
  628. Ok(()) => ()
  629. }
  630. }
  631. Ok(())
  632. }
  633. /// Removes a directory at this path, after removing all its contents. Use
  634. /// carefully!
  635. ///
  636. /// # Error
  637. ///
  638. /// See `file::unlink` and `fs::readdir`
  639. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::remove_dir_all")]
  640. #[unstable(feature = "old_io")]
  641. pub fn rmdir_recursive(path: &Path) -> IoResult<()> {
  642. let mut rm_stack = Vec::new();
  643. rm_stack.push(path.clone());
  644. fn rmdir_failed(err: &IoError, path: &Path) -> String {
  645. format!("rmdir_recursive failed; path={}; cause={}",
  646. path.display(), err)
  647. }
  648. fn update_err<T>(err: IoResult<T>, path: &Path) -> IoResult<T> {
  649. err.update_err("couldn't recursively rmdir",
  650. |e| rmdir_failed(e, path))
  651. }
  652. while !rm_stack.is_empty() {
  653. let children = try!(readdir(rm_stack.last().unwrap())
  654. .update_detail(|e| rmdir_failed(e, path)));
  655. let mut has_child_dir = false;
  656. // delete all regular files in the way and push subdirs
  657. // on the stack
  658. for child in children {
  659. // FIXME(#12795) we should use lstat in all cases
  660. let child_type = match cfg!(windows) {
  661. true => try!(update_err(stat(&child), path)),
  662. false => try!(update_err(lstat(&child), path))
  663. };
  664. if child_type.kind == FileType::Directory {
  665. rm_stack.push(child);
  666. has_child_dir = true;
  667. } else {
  668. // we can carry on safely if the file is already gone
  669. // (eg: deleted by someone else since readdir)
  670. match update_err(unlink(&child), path) {
  671. Ok(()) => (),
  672. Err(ref e) if e.kind == old_io::FileNotFound => (),
  673. Err(e) => return Err(e)
  674. }
  675. }
  676. }
  677. // if no subdir was found, let's pop and delete
  678. if !has_child_dir {
  679. let result = update_err(rmdir(&rm_stack.pop().unwrap()), path);
  680. match result {
  681. Ok(()) => (),
  682. Err(ref e) if e.kind == old_io::FileNotFound => (),
  683. Err(e) => return Err(e)
  684. }
  685. }
  686. }
  687. Ok(())
  688. }
  689. /// Changes the timestamps for a file's last modification and access time.
  690. /// The file at the path specified will have its last access time set to
  691. /// `atime` and its modification time set to `mtime`. The times specified should
  692. /// be in milliseconds.
  693. // FIXME(#10301) these arguments should not be u64
  694. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::set_file_times")]
  695. #[unstable(feature = "old_io")]
  696. pub fn change_file_times(path: &Path, atime: u64, mtime: u64) -> IoResult<()> {
  697. fs_imp::utime(path, atime, mtime)
  698. .update_err("couldn't change_file_times", |e|
  699. format!("{}; path={}", e, path.display()))
  700. }
  701. impl Reader for File {
  702. fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
  703. fn update_err<T>(result: IoResult<T>, file: &File) -> IoResult<T> {
  704. result.update_err("couldn't read file",
  705. |e| format!("{}; path={}",
  706. e, file.path.display()))
  707. }
  708. let result = update_err(self.fd.read(buf), self);
  709. match result {
  710. Ok(read) => {
  711. self.last_nread = read as int;
  712. match read {
  713. 0 => update_err(Err(standard_error(old_io::EndOfFile)), self),
  714. _ => Ok(read as uint)
  715. }
  716. },
  717. Err(e) => Err(e)
  718. }
  719. }
  720. }
  721. impl Writer for File {
  722. fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
  723. self.fd.write(buf)
  724. .update_err("couldn't write to file",
  725. |e| format!("{}; path={}", e, self.path.display()))
  726. }
  727. }
  728. impl Seek for File {
  729. fn tell(&self) -> IoResult<u64> {
  730. self.fd.tell()
  731. .update_err("couldn't retrieve file cursor (`tell`)",
  732. |e| format!("{}; path={}", e, self.path.display()))
  733. }
  734. fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
  735. let err = match self.fd.seek(pos, style) {
  736. Ok(_) => {
  737. // successful seek resets EOF indicator
  738. self.last_nread = -1;
  739. Ok(())
  740. }
  741. Err(e) => Err(e),
  742. };
  743. err.update_err("couldn't seek in file",
  744. |e| format!("{}; path={}", e, self.path.display()))
  745. }
  746. }
  747. /// Utility methods for paths.
  748. #[deprecated(since = "1.0.0", reason = "replaced with std::fs::PathExt")]
  749. #[unstable(feature = "old_io")]
  750. pub trait PathExtensions {
  751. /// Get information on the file, directory, etc at this path.
  752. ///
  753. /// Consult the `fs::stat` documentation for more info.
  754. ///
  755. /// This call preserves identical runtime/error semantics with `file::stat`.
  756. fn stat(&self) -> IoResult<FileStat>;
  757. /// Get information on the file, directory, etc at this path, not following
  758. /// symlinks.
  759. ///
  760. /// Consult the `fs::lstat` documentation for more info.
  761. ///
  762. /// This call preserves identical runtime/error semantics with `file::lstat`.
  763. fn lstat(&self) -> IoResult<FileStat>;
  764. /// Boolean value indicator whether the underlying file exists on the local
  765. /// filesystem. Returns false in exactly the cases where `fs::stat` fails.
  766. fn exists(&self) -> bool;
  767. /// Whether the underlying implementation (be it a file path, or something
  768. /// else) points at a "regular file" on the FS. Will return false for paths
  769. /// to non-existent locations or directories or other non-regular files
  770. /// (named pipes, etc). Follows links when making this determination.
  771. fn is_file(&self) -> bool;
  772. /// Whether the underlying implementation (be it a file path, or something
  773. /// else) is pointing at a directory in the underlying FS. Will return
  774. /// false for paths to non-existent locations or if the item is not a
  775. /// directory (eg files, named pipes, etc). Follows links when making this
  776. /// determination.
  777. fn is_dir(&self) -> bool;
  778. }
  779. impl PathExtensions for old_path::Path {
  780. fn stat(&self) -> IoResult<FileStat> { stat(self) }
  781. fn lstat(&self) -> IoResult<FileStat> { lstat(self) }
  782. fn exists(&self) -> bool {
  783. self.stat().is_ok()
  784. }
  785. fn is_file(&self) -> bool {
  786. match self.stat() {
  787. Ok(s) => s.kind == FileType::RegularFile,
  788. Err(..) => false
  789. }
  790. }
  791. fn is_dir(&self) -> bool {
  792. match self.stat() {
  793. Ok(s) => s.kind == FileType::Directory,
  794. Err(..) => false
  795. }
  796. }
  797. }
  798. fn mode_string(mode: FileMode) -> &'static str {
  799. match mode {
  800. super::Open => "open",
  801. super::Append => "append",
  802. super::Truncate => "truncate"
  803. }
  804. }
  805. fn access_string(access: FileAccess) -> &'static str {
  806. match access {
  807. super::Read => "read",
  808. super::Write => "write",
  809. super::ReadWrite => "readwrite"
  810. }
  811. }
  812. #[cfg(test)]
  813. #[allow(unused_imports)]
  814. #[allow(unused_variables)]
  815. #[allow(unused_mut)]
  816. #[allow(deprecated)] // rand
  817. mod test {
  818. use prelude::v1::*;
  819. use old_io::{SeekSet, SeekCur, SeekEnd, Read, Open, ReadWrite, FileType};
  820. use old_io;
  821. use str;
  822. use old_io::fs::*;
  823. macro_rules! check { ($e:expr) => (
  824. match $e {
  825. Ok(t) => t,
  826. Err(e) => panic!("{} failed with: {:?}", stringify!($e), e),
  827. }
  828. ) }
  829. macro_rules! error { ($e:expr, $s:expr) => (
  830. match $e {
  831. Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
  832. Err(ref err) => assert!(err.to_string().contains($s),
  833. format!("`{}` did not contain `{}`", err, $s))
  834. }
  835. ) }
  836. pub struct TempDir(Path);
  837. impl TempDir {
  838. fn join(&self, path: &str) -> Path {
  839. let TempDir(ref p) = *self;
  840. p.join(path)
  841. }
  842. fn path<'a>(&'a self) -> &'a Path {
  843. let TempDir(ref p) = *self;
  844. p
  845. }
  846. }
  847. impl Drop for TempDir {
  848. fn drop(&mut self) {
  849. // Gee, seeing how we're testing the fs module I sure hope that we
  850. // at least implement this correctly!
  851. let TempDir(ref p) = *self;
  852. check!(old_io::fs::rmdir_recursive(p));
  853. }
  854. }
  855. pub fn tmpdir() -> TempDir {
  856. use os;
  857. use rand;
  858. let ret = os::tmpdir().join(format!("rust-{}", rand::random::<u32>()));
  859. check!(old_io::fs::mkdir(&ret, old_io::USER_RWX));
  860. TempDir(ret)
  861. }
  862. #[test]
  863. fn file_test_io_smoke_test() {
  864. let message = "it's alright. have a good time";
  865. let tmpdir = tmpdir();
  866. let filename = &tmpdir.join("file_rt_io_file_test.txt");
  867. {
  868. let mut write_stream = File::open_mode(filename, Open, ReadWrite);
  869. check!(write_stream.write(message.as_bytes()));
  870. }
  871. {
  872. let mut read_stream = File::open_mode(filename, Open, Read);
  873. let mut read_buf = [0; 1028];
  874. let read_str = match check!(read_stream.read(&mut read_buf)) {
  875. -1|0 => panic!("shouldn't happen"),
  876. n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
  877. };
  878. assert_eq!(read_str, message);
  879. }
  880. check!(unlink(filename));
  881. }
  882. #[test]
  883. fn invalid_path_raises() {
  884. let tmpdir = tmpdir();
  885. let filename = &tmpdir.join("file_that_does_not_exist.txt");
  886. let result = File::open_mode(filename, Open, Read);
  887. error!(result, "couldn't open path as file");
  888. if cfg!(unix) {
  889. error!(result, "no such file or directory");
  890. }
  891. error!(result, &format!("path={}; mode=open; access=read", filename.display()));
  892. }
  893. #[test]
  894. fn file_test_iounlinking_invalid_path_should_raise_condition() {
  895. let tmpdir = tmpdir();
  896. let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
  897. let result = unlink(filename);
  898. error!(result, "couldn't unlink path");
  899. if cfg!(unix) {
  900. error!(result, "no such file or directory");
  901. }
  902. error!(result, &format!("path={}", filename.display()));
  903. }
  904. #[test]
  905. fn file_test_io_non_positional_read() {
  906. let message: &str = "ten-four";
  907. let mut read_mem = [0; 8];
  908. let tmpdir = tmpdir();
  909. let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
  910. {
  911. let mut rw_stream = File::open_mode(filename, Open, ReadWrite);
  912. check!(rw_stream.write(message.as_bytes()));
  913. }
  914. {
  915. let mut read_stream = File::open_mode(filename, Open, Read);
  916. {
  917. let read_buf = &mut read_mem[0..4];
  918. check!(read_stream.read(read_buf));
  919. }
  920. {
  921. let read_buf = &mut read_mem[4..8];
  922. check!(read_stream.read(read_buf));
  923. }
  924. }
  925. check!(unlink(filename));
  926. let read_str = str::from_utf8(&read_mem).unwrap();
  927. assert_eq!(read_str, message);
  928. }
  929. #[test]
  930. fn file_test_io_seek_and_tell_smoke_test() {
  931. let message = "ten-four";
  932. let mut read_mem = [0; 4];
  933. let set_cursor = 4 as u64;
  934. let mut tell_pos_pre_read;
  935. let mut tell_pos_post_read;
  936. let tmpdir = tmpdir();
  937. let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
  938. {
  939. let mut rw_stream = File::open_mode(filename, Open, ReadWrite);
  940. check!(rw_stream.write(message.as_bytes()));
  941. }
  942. {
  943. let mut read_stream = File::open_mode(filename, Open, Read);
  944. check!(read_stream.seek(set_cursor as i64, SeekSet));
  945. tell_pos_pre_read = check!(read_stream.tell());
  946. check!(read_stream.read(&mut read_mem));
  947. tell_pos_post_read = check!(read_stream.tell());
  948. }
  949. check!(unlink(filename));
  950. let read_str = str::from_utf8(&read_mem).unwrap();
  951. assert_eq!(read_str, &message[4..8]);
  952. assert_eq!(tell_pos_pre_read, set_cursor);
  953. assert_eq!(tell_pos_post_read, message.len() as u64);
  954. }
  955. #[test]
  956. fn file_test_io_seek_and_write() {
  957. let initial_msg = "food-is-yummy";
  958. let overwrite_msg = "-the-bar!!";
  959. let final_msg = "foo-the-bar!!";
  960. let seek_idx = 3;
  961. let mut read_mem = [0; 13];
  962. let tmpdir = tmpdir();
  963. let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
  964. {
  965. let mut rw_stream = File::open_mode(filename, Open, ReadWrite);
  966. check!(rw_stream.write(initial_msg.as_bytes()));
  967. check!(rw_stream.seek(seek_idx as i64, SeekSet));
  968. check!(rw_stream.write(overwrite_msg.as_bytes()));
  969. }
  970. {
  971. let mut read_stream = File::open_mode(filename, Open, Read);
  972. check!(read_stream.read(&mut read_mem));
  973. }
  974. check!(unlink(filename));
  975. let read_str = str::from_utf8(&read_mem).unwrap();
  976. assert!(read_str == final_msg);
  977. }
  978. #[test]
  979. fn file_test_io_seek_shakedown() {
  980. use str; // 01234567890123
  981. let initial_msg = "qwer-asdf-zxcv";
  982. let chunk_one: &str = "qwer";
  983. let chunk_two: &str = "asdf";
  984. let chunk_three: &str = "zxcv";
  985. let mut read_mem = [0; 4];
  986. let tmpdir = tmpdir();
  987. let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
  988. {
  989. let mut rw_stream = File::open_mode(filename, Open, ReadWrite);
  990. check!(rw_stream.write(initial_msg.as_bytes()));
  991. }
  992. {
  993. let mut read_stream = File::open_mode(filename, Open, Read);
  994. check!(read_stream.seek(-4, SeekEnd));
  995. check!(read_stream.read(&mut read_mem));
  996. assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three);
  997. check!(read_stream.seek(-9, SeekCur));
  998. check!(read_stream.read(&mut read_mem));
  999. assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two);
  1000. check!(read_stream.seek(0, SeekSet));
  1001. check!(read_stream.read(&mut read_mem));
  1002. assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one);
  1003. }
  1004. check!(unlink(filename));
  1005. }
  1006. #[test]
  1007. fn file_test_stat_is_correct_on_is_file() {
  1008. let tmpdir = tmpdir();
  1009. let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
  1010. {
  1011. let mut fs = check!(File::open_mode(filename, Open, ReadWrite));
  1012. let msg = "hw";
  1013. fs.write(msg.as_bytes()).unwrap();
  1014. let fstat_res = check!(fs.stat());
  1015. assert_eq!(fstat_res.kind, FileType::RegularFile);
  1016. }
  1017. let stat_res_fn = check!(stat(filename));
  1018. assert_eq!(stat_res_fn.kind, FileType::RegularFile);
  1019. let stat_res_meth = check!(filename.stat());
  1020. assert_eq!(stat_res_meth.kind, FileType::RegularFile);
  1021. check!(unlink(filename));
  1022. }
  1023. #[test]
  1024. fn file_test_stat_is_correct_on_is_dir() {
  1025. let tmpdir = tmpdir();
  1026. let filename = &tmpdir.join("file_stat_correct_on_is_dir");
  1027. check!(mkdir(filename, old_io::USER_RWX));
  1028. let stat_res_fn = check!(stat(filename));
  1029. assert!(stat_res_fn.kind == FileType::Directory);
  1030. let stat_res_meth = check!(filename.stat());
  1031. assert!(stat_res_meth.kind == FileType::Directory);
  1032. check!(rmdir(filename));
  1033. }
  1034. #[test]
  1035. fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
  1036. let tmpdir = tmpdir();
  1037. let dir = &tmpdir.join("fileinfo_false_on_dir");
  1038. check!(mkdir(dir, old_io::USER_RWX));
  1039. assert!(dir.is_file() == false);
  1040. check!(rmdir(dir));
  1041. }
  1042. #[test]
  1043. fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
  1044. let tmpdir = tmpdir();
  1045. let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
  1046. check!(File::create(file).write(b"foo"));
  1047. assert!(file.exists());
  1048. check!(unlink(file));
  1049. assert!(!file.exists());
  1050. }
  1051. #[test]
  1052. fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
  1053. let tmpdir = tmpdir();
  1054. let dir = &tmpdir.join("before_and_after_dir");
  1055. assert!(!dir.exists());
  1056. check!(mkdir(dir, old_io::USER_RWX));
  1057. assert!(dir.exists());
  1058. assert!(dir.is_dir());
  1059. check!(rmdir(dir));
  1060. assert!(!dir.exists());
  1061. }
  1062. #[test]
  1063. fn file_test_directoryinfo_readdir() {
  1064. use str;
  1065. let tmpdir = tmpdir();
  1066. let dir = &tmpdir.join("di_readdir");
  1067. check!(mkdir(dir, old_io::USER_RWX));
  1068. let prefix = "foo";
  1069. for n in 0..3 {
  1070. let f = dir.join(format!("{}.txt", n));
  1071. let mut w = check!(File::create(&f));
  1072. let msg_str = format!("{}{}", prefix, n);
  1073. let msg = msg_str.as_bytes();
  1074. check!(w.write(msg));
  1075. }
  1076. let files = check!(readdir(dir));
  1077. let mut mem = [0; 4];
  1078. for f in &files {
  1079. {
  1080. let n = f.filestem_str();
  1081. check!(File::open(f).read(&mut mem));
  1082. let read_str = str::from_utf8(&mem).unwrap();
  1083. let expected = match n {
  1084. None|Some("") => panic!("really shouldn't happen.."),
  1085. Some(n) => format!("{}{}", prefix, n),
  1086. };
  1087. assert_eq!(expected, read_str);
  1088. }
  1089. check!(unlink(f));
  1090. }
  1091. check!(rmdir(dir));
  1092. }
  1093. #[test]
  1094. fn file_test_walk_dir() {
  1095. let tmpdir = tmpdir();
  1096. let dir = &tmpdir.join("walk_dir");
  1097. check!(mkdir(dir, old_io::USER_RWX));
  1098. let dir1 = &dir.join("01/02/03");
  1099. check!(mkdir_recursive(dir1, old_io::USER_RWX));
  1100. check!(File::create(&dir1.join("04")));
  1101. let dir2 = &dir.join("11/12/13");
  1102. check!(mkdir_recursive(dir2, old_io::USER_RWX));
  1103. check!(File::create(&dir2.join("14")));
  1104. let mut files = check!(walk_dir(dir));
  1105. let mut cur = [0; 2];
  1106. for f in files {
  1107. let stem = f.filestem_str().unwrap();
  1108. let root = stem.as_bytes()[0] - b'0';
  1109. let name = stem.as_bytes()[1] - b'0';
  1110. assert!(cur[root as uint] < name);
  1111. cur[root as uint] = name;
  1112. }
  1113. check!(rmdir_recursive(dir));
  1114. }
  1115. #[test]
  1116. fn mkdir_path_already_exists_error() {
  1117. use old_io::{IoError, PathAlreadyExists};
  1118. let tmpdir = tmpdir();
  1119. let dir = &tmpdir.join("mkdir_error_twice");
  1120. check!(mkdir(dir, old_io::USER_RWX));
  1121. match mkdir(dir, old_io::USER_RWX) {
  1122. Err(IoError{kind:PathAlreadyExists,..}) => (),
  1123. _ => assert!(false)
  1124. };
  1125. }
  1126. #[test]
  1127. fn recursive_mkdir() {
  1128. let tmpdir = tmpdir();
  1129. let dir = tmpdir.join("d1/d2");
  1130. check!(mkdir_recursive(&dir, old_io::USER_RWX));
  1131. assert!(dir.is_dir())
  1132. }
  1133. #[test]
  1134. fn recursive_mkdir_failure() {
  1135. let tmpdir = tmpdir();
  1136. let dir = tmpdir.join("d1");
  1137. let file = dir.join("f1");
  1138. check!(mkdir_recursive(&dir, old_io::USER_RWX));
  1139. check!(File::create(&file));
  1140. let result = mkdir_recursive(&file, old_io::USER_RWX);
  1141. error!(result, "couldn't recursively mkdir");
  1142. error!(result, "couldn't create directory");
  1143. error!(result, "mode=0700");
  1144. error!(result, &format!("path={}", file.display()));
  1145. }
  1146. #[test]
  1147. fn recursive_mkdir_slash() {
  1148. check!(mkdir_recursive(&Path::new("/"), old_io::USER_RWX));
  1149. }
  1150. // FIXME(#12795) depends on lstat to work on windows
  1151. #[cfg(not(windows))]
  1152. #[test]
  1153. fn recursive_rmdir() {
  1154. let tmpdir = tmpdir();
  1155. let d1 = tmpdir.join("d1");
  1156. let dt = d1.join("t");
  1157. let dtt = dt.join("t");
  1158. let d2 = tmpdir.join("d2");
  1159. let canary = d2.join("do_not_delete");
  1160. check!(mkdir_recursive(&dtt, old_io::USER_RWX));
  1161. check!(mkdir_recursive(&d2, old_io::USER_RWX));
  1162. check!(File::create(&canary).write(b"foo"));
  1163. check!(symlink(&d2, &dt.join("d2")));
  1164. check!(rmdir_recursive(&d1));
  1165. assert!(!d1.is_dir());
  1166. assert!(canary.exists());
  1167. }
  1168. #[test]
  1169. fn unicode_path_is_dir() {
  1170. assert!(Path::new(".").is_dir());
  1171. assert!(!Path::new("test/stdtest/fs.rs").is_dir());
  1172. let tmpdir = tmpdir();
  1173. let mut dirpath = tmpdir.path().clone();
  1174. dirpath.push(format!("test-가一ー你好"));
  1175. check!(mkdir(&dirpath, old_io::USER_RWX));
  1176. assert!(dirpath.is_dir());
  1177. let mut filepath = dirpath;
  1178. filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
  1179. check!(File::create(&filepath)); // ignore return; touch only
  1180. assert!(!filepath.is_dir());
  1181. assert!(filepath.exists());
  1182. }
  1183. #[test]
  1184. fn unicode_path_exists() {
  1185. assert!(Path::new(".").exists());
  1186. assert!(!Path::new("test/nonexistent-bogus-path").exists());
  1187. let tmpdir = tmpdir();
  1188. let unicode = tmpdir.path();
  1189. let unicode = unicode.join(format!("test-각丁ー再见"));
  1190. check!(mkdir(&unicode, old_io::USER_RWX));
  1191. assert!(unicode.exists());
  1192. assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
  1193. }
  1194. #[test]
  1195. fn copy_file_does_not_exist() {
  1196. let from = Path::new("test/nonexistent-bogus-path");
  1197. let to = Path::new("test/other-bogus-path");
  1198. error!(copy(&from, &to),
  1199. &format!("couldn't copy path (the source path is not an \
  1200. existing file; from={:?}; to={:?})",
  1201. from.display(), to.display()));
  1202. match copy(&from, &to) {
  1203. Ok(..) => panic!(),
  1204. Err(..) => {
  1205. assert!(!from.exists());
  1206. assert!(!to.exists());
  1207. }
  1208. }
  1209. }
  1210. #[test]
  1211. fn copy_file_ok() {
  1212. let tmpdir = tmpdir();
  1213. let input = tmpdir.join("in.txt");
  1214. let out = tmpdir.join("out.txt");
  1215. check!(File::create(&input).write(b"hello"));
  1216. check!(copy(&input, &out));
  1217. let contents = check!(File::open(&out).read_to_end());
  1218. assert_eq!(contents, b"hello");
  1219. assert_eq!(check!(input.stat()).perm, check!(out.stat()).perm);
  1220. }
  1221. #[test]
  1222. fn copy_file_dst_dir() {
  1223. let tmpdir = tmpdir();
  1224. let out = tmpdir.join("out");
  1225. check!(File::create(&out));
  1226. match copy(&out, tmpdir.path()) {
  1227. Ok(..) => panic!(), Err(..) => {}
  1228. }
  1229. }
  1230. #[test]
  1231. fn copy_file_dst_exists() {
  1232. let tmpdir = tmpdir();
  1233. let input = tmpdir.join("in");
  1234. let output = tmpdir.join("out");
  1235. check!(File::create(&input).write("foo".as_bytes()));
  1236. check!(File::create(&output).write("bar".as_bytes()));
  1237. check!(copy(&input, &output));
  1238. assert_eq!(check!(File::open(&output).read_to_end()),
  1239. b"foo".to_vec());
  1240. }
  1241. #[test]
  1242. fn copy_file_src_dir() {
  1243. let tmpdir = tmpdir();
  1244. let out = tmpdir.join("out");
  1245. match copy(tmpdir.path(), &out) {
  1246. Ok(..) => panic!(), Err(..) => {}
  1247. }
  1248. assert!(!out.exists());
  1249. }
  1250. #[test]
  1251. fn copy_file_preserves_perm_bits() {
  1252. let tmpdir = tmpdir();
  1253. let input = tmpdir.join("in.txt");
  1254. let out = tmpdir.join("out.txt");
  1255. check!(File::create(&input));
  1256. check!(chmod(&input, old_io::USER_READ));
  1257. check!(copy(&input, &out));
  1258. assert!(!check!(out.stat()).perm.intersects(old_io::USER_WRITE));
  1259. check!(chmod(&input, old_io::USER_FILE));
  1260. check!(chmod(&out, old_io::USER_FILE));
  1261. }
  1262. #[cfg(not(windows))] // FIXME(#10264) operation not permitted?
  1263. #[test]
  1264. fn symlinks_work() {
  1265. let tmpdir = tmpdir();
  1266. let input = tmpdir.join("in.txt");
  1267. let out = tmpdir.join("out.txt");
  1268. check!(File::create(&input).write("foobar".as_bytes()));
  1269. check!(symlink(&input, &out));
  1270. if cfg!(not(windows)) {
  1271. assert_eq!(check!(lstat(&out)).kind, FileType::Symlink);
  1272. assert_eq!(check!(out.lstat()).kind, FileType::Symlink);
  1273. }
  1274. assert_eq!(check!(stat(&out)).size, check!(stat(&input)).size);
  1275. assert_eq!(check!(File::open(&out).read_to_end()),
  1276. b"foobar".to_vec());
  1277. }
  1278. #[cfg(not(windows))] // apparently windows doesn't like symlinks
  1279. #[test]
  1280. fn symlink_noexist() {
  1281. let tmpdir = tmpdir();
  1282. // symlinks can point to things that don't exist
  1283. check!(symlink(&tmpdir.join("foo"), &tmpdir.join("bar")));
  1284. assert!(check!(readlink(&tmpdir.join("bar"))) == tmpdir.join("foo"));
  1285. }
  1286. #[test]
  1287. fn readlink_not_symlink() {
  1288. let tmpdir = tmpdir();
  1289. match readlink(tmpdir.path()) {
  1290. Ok(..) => panic!("wanted a failure"),
  1291. Err(..) => {}
  1292. }
  1293. }
  1294. #[test]
  1295. fn links_work() {
  1296. let tmpdir = tmpdir();
  1297. let input = tmpdir.join("in.txt");
  1298. let out = tmpdir.join("out.txt");
  1299. check!(File::create(&input).write("foobar".as_bytes()));
  1300. check!(link(&input, &out));
  1301. if cfg!(not(windows)) {
  1302. assert_eq!(check!(lstat(&out)).kind, FileType::RegularFile);
  1303. assert_eq!(check!(out.lstat()).kind, FileType::RegularFile);
  1304. assert_eq!(check!(stat(&out)).unstable.nlink, 2);
  1305. assert_eq!(check!(out.stat()).unstable.nlink, 2);
  1306. }
  1307. assert_eq!(check!(stat(&out)).size, check!(stat(&input)).size);
  1308. assert_eq!(check!(stat(&out)).size, check!(input.stat()).size);
  1309. assert_eq!(check!(File::open(&out).read_to_end()),
  1310. b"foobar".to_vec());
  1311. // can't link to yourself
  1312. match link(&input, &input) {
  1313. Ok(..) => panic!("wanted a failure"),
  1314. Err(..) => {}
  1315. }
  1316. // can't link to something that doesn't exist
  1317. match link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
  1318. Ok(..) => panic!("wanted a failure"),
  1319. Err(..) => {}
  1320. }
  1321. }
  1322. #[test]
  1323. fn chmod_works() {
  1324. let tmpdir = tmpdir();
  1325. let file = tmpdir.join("in.txt");
  1326. check!(File::create(&file));
  1327. assert!(check!(stat(&file)).perm.contains(old_io::USER_WRITE));
  1328. check!(chmod(&file, old_io::USER_READ));
  1329. assert!(!check!(stat(&file)).perm.contains(old_io::USER_WRITE));
  1330. match chmod(&tmpdir.join("foo"), old_io::USER_RWX) {
  1331. Ok(..) => panic!("wanted a panic"),
  1332. Err(..) => {}
  1333. }
  1334. check!(chmod(&file, old_io::USER_FILE));
  1335. }
  1336. #[test]
  1337. fn sync_doesnt_kill_anything() {
  1338. let tmpdir = tmpdir();
  1339. let path = tmpdir.join("in.txt");
  1340. let mut file = check!(File::open_mode(&path, old_io::Open, old_io::ReadWrite));
  1341. check!(file.fsync());
  1342. check!(file.datasync());
  1343. check!(file.write(b"foo"));
  1344. check!(file.fsync());
  1345. check!(file.datasync());
  1346. drop(file);
  1347. }
  1348. #[test]
  1349. fn truncate_works() {
  1350. let tmpdir = tmpdir();
  1351. let path = tmpdir.join("in.txt");
  1352. let mut file = check!(File::open_mode(&path, old_io::Open, old_io::ReadWrite));
  1353. check!(file.write(b"foo"));
  1354. check!(file.fsync());
  1355. // Do some simple things with truncation
  1356. assert_eq!(check!(file.stat()).size, 3);
  1357. check!(file.truncate(10));
  1358. assert_eq!(check!(file.stat()).size, 10);
  1359. check!(file.write(b"bar"));
  1360. check!(file.fsync());
  1361. assert_eq!(check!(file.stat()).size, 10);
  1362. assert_eq!(check!(File::open(&path).read_to_end()),
  1363. b"foobar\0\0\0\0".to_vec());
  1364. // Truncate to a smaller length, don't seek, and then write something.
  1365. // Ensure that the intermediate zeroes are all filled in (we're seeked
  1366. // past the end of the file).
  1367. check!(file.truncate(2));
  1368. assert_eq!(check!(file.stat()).size, 2);
  1369. check!(file.write(b"wut"));
  1370. check!(file.fsync());
  1371. assert_eq!(check!(file.stat()).size, 9);
  1372. assert_eq!(check!(File::open(&path).read_to_end()),
  1373. b"fo\0\0\0\0wut".to_vec());
  1374. drop(file);
  1375. }
  1376. #[test]
  1377. fn open_flavors() {
  1378. let tmpdir = tmpdir();
  1379. match File::open_mode(&tmpdir.join("a"), old_io::Open, old_io::Read) {
  1380. Ok(..) => panic!(), Err(..) => {}
  1381. }
  1382. // Perform each one twice to make sure that it succeeds the second time
  1383. // (where the file exists)
  1384. check!(File::open_mode(&tmpdir.join("b"), old_io::Open, old_io::Write));
  1385. assert!(tmpdir.join("b").exists());
  1386. check!(File::open_mode(&tmpdir.join("b"), old_io::Open, old_io::Write));
  1387. check!(File::open_mode(&tmpdir.join("c"), old_io::Open, old_io::ReadWrite));
  1388. assert!(tmpdir.join("c").exists());
  1389. check!(File::open_mode(&tmpdir.join("c"), old_io::Open, old_io::ReadWrite));
  1390. check!(File::open_mode(&tmpdir.join("d"), old_io::Append, old_io::Write));
  1391. assert!(tmpdir.join("d").exists());
  1392. check!(File::open_mode(&tmpdir.join("d"), old_io::Append, old_io::Write));
  1393. check!(File::open_mode(&tmpdir.join("e"), old_io::Append, old_io::ReadWrite));
  1394. assert!(tmpdir.join("e").exists());
  1395. check!(File::open_mode(&tmpdir.join("e"), old_io::Append, old_io::ReadWrite));
  1396. check!(File::open_mode(&tmpdir.join("f"), old_io::Truncate, old_io::Write));
  1397. assert!(tmpdir.join("f").exists());
  1398. check!(File::open_mode(&tmpdir.join("f"), old_io::Truncate, old_io::Write));
  1399. check!(File::open_mode(&tmpdir.join("g"), old_io::Truncate, old_io::ReadWrite));
  1400. assert!(tmpdir.join("g").exists());
  1401. check!(File::open_mode(&tmpdir.join("g"), old_io::Truncate, old_io::ReadWrite));
  1402. check!(File::create(&tmpdir.join("h")).write("foo".as_bytes()));
  1403. check!(File::open_mode(&tmpdir.join("h"), old_io::Open, old_io::Read));
  1404. {
  1405. let mut f = check!(File::open_mode(&tmpdir.join("h"), old_io::Open,
  1406. old_io::Read));
  1407. match f.write("wut".as_bytes()) {
  1408. Ok(..) => panic!(), Err(..) => {}
  1409. }
  1410. }
  1411. assert!(check!(stat(&tmpdir.join("h"))).size == 3,
  1412. "write/stat failed");
  1413. {
  1414. let mut f = check!(File::open_mode(&tmpdir.join("h"), old_io::Append,
  1415. old_io::Write));
  1416. check!(f.write("bar".as_bytes()));
  1417. }
  1418. assert!(check!(stat(&tmpdir.join("h"))).size == 6,
  1419. "append didn't append");
  1420. {
  1421. let mut f = check!(File::open_mode(&tmpdir.join("h"), old_io::Truncate,
  1422. old_io::Write));
  1423. check!(f.write("bar".as_bytes()));
  1424. }
  1425. assert!(check!(stat(&tmpdir.join("h"))).size == 3,
  1426. "truncate didn't truncate");
  1427. }
  1428. #[test]
  1429. fn utime() {
  1430. let tmpdir = tmpdir();
  1431. let path = tmpdir.join("a");
  1432. check!(File::create(&path));
  1433. // These numbers have to be bigger than the time in the day to account
  1434. // for timezones Windows in particular will fail in certain timezones
  1435. // with small enough values
  1436. check!(change_file_times(&path, 100000, 200000));
  1437. assert_eq!(check!(path.stat()).accessed, 100000);
  1438. assert_eq!(check!(path.stat()).modified, 200000);
  1439. }
  1440. #[test]
  1441. fn utime_noexist() {
  1442. let tmpdir = tmpdir();
  1443. match change_file_times(&tmpdir.join("a"), 100, 200) {
  1444. Ok(..) => panic!(),
  1445. Err(..) => {}
  1446. }
  1447. }
  1448. #[test]
  1449. fn binary_file() {
  1450. use rand::{StdRng, Rng};
  1451. let mut bytes = [0; 1024];
  1452. StdRng::new().ok().unwrap().fill_bytes(&mut bytes);
  1453. let tmpdir = tmpdir();
  1454. check!(File::create(&tmpdir.join("test")).write(&bytes));
  1455. let actual = check!(File::open(&tmpdir.join("test")).read_to_end());
  1456. assert!(actual == bytes.as_slice());
  1457. }
  1458. #[test]
  1459. fn unlink_readonly() {
  1460. let tmpdir = tmpdir();
  1461. let path = tmpdir.join("file");
  1462. check!(File::create(&path));
  1463. check!(chmod(&path, old_io::USER_READ));
  1464. check!(unlink(&path));
  1465. }
  1466. }