(index<- )        ./libstd/io/fs.rs

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


libstd/io/fs.rs:80:25-80:25 -struct- definition:
/// `File::open_mode()`.
pub struct File {
    fd: Box<RtioFileStream:Send>,
references:- 8
130:             io.fs_open(&path.to_c_str(), mode, access).map(|fd| {
131:                 File {
132:                     path: path.clone(),
--
152:     /// ```
153:     pub fn open(path: &Path) -> IoResult<File> {
154:         File::open_mode(path, Open, Read)
--
632: impl Seek for File {
633:     fn tell(&self) -> IoResult<u64> {


libstd/io/fs.rs:482:9-482:9 -fn- definition:
/// file
pub fn readdir(path: &Path) -> IoResult<Vec<Path>> {
    LocalIo::maybe_raise(|io| {
references:- 3
493: pub fn walk_dir(path: &Path) -> IoResult<Directories> {
494:     Ok(Directories { stack: try!(readdir(path)) })
495: }
--
506:                 if path.is_dir() {
507:                     match readdir(&path) {
508:                         Ok(dirs) => { self.stack.push_all_move(dirs); }
--
564:     while !rm_stack.is_empty() {
565:         let children = try!(readdir(rm_stack.last().unwrap()));
566:         let mut has_child_dir = false;


libstd/io/fs.rs:427:72-427:72 -fn- definition:
/// directory at the provided path, or if the directory already exists.
pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> {
    LocalIo::maybe_raise(|io| io.fs_mkdir(&path.to_c_str(), mode))
references:- 2
libstd/io/tempfile.rs:
48:             let p = tmpdir.join(filename);
49:             match fs::mkdir(&p, io::UserRWX) {
50:                 Err(..) => {}
libstd/io/fs.rs:
539:         match mkdir(&curpath, mode) {
540:             Err(mkdir_err) => {


libstd/io/fs.rs:278:15-278:15 -fn- definition:
/// See `stat`
pub fn lstat(path: &Path) -> IoResult<FileStat> {
    LocalIo::maybe_raise(|io| {
references:- 2
662:     /// This call preserves identical runtime/error semantics with `file::lstat`.
663:     pub fn lstat(&self) -> IoResult<FileStat> { lstat(self) }


libstd/io/fs.rs:497:45-497:45 -struct- definition:
/// An iterator which walks over a directory
pub struct Directories {
    stack: Vec<Path>,
references:- 3
493: pub fn walk_dir(path: &Path) -> IoResult<Directories> {
494:     Ok(Directories { stack: try!(readdir(path)) })
495: }
--
502: impl Iterator<Path> for Directories {
503:     fn next(&mut self) -> Option<Path> {


libstd/io/fs.rs:264:37-264:37 -fn- definition:
/// filesystem at the provided path.
pub fn stat(path: &Path) -> IoResult<FileStat> {
    LocalIo::maybe_raise(|io| {
references:- 3
572:             let child_type = match cfg!(windows) {
573:                 true => try!(stat(&child)).kind,
574:                 false => try!(lstat(&child)).kind
--
654:     /// This call preserves identical runtime/error semantics with `file::stat`.
655:     pub fn stat(&self) -> IoResult<FileStat> { stat(self) }