From d4a2c941809f303b97d153e06ba07e95cd245f88 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 30 Mar 2015 11:00:05 -0700 Subject: std: Clean out #[deprecated] APIs This commit cleans out a large amount of deprecated APIs from the standard library and some of the facade crates as well, updating all users in the compiler and in tests as it goes along. --- src/libstd/collections/hash/table.rs | 2 +- src/libstd/dynamic_lib.rs | 2 +- src/libstd/env.rs | 24 +- src/libstd/ffi/c_str.rs | 95 -- src/libstd/ffi/mod.rs | 11 +- src/libstd/ffi/os_str.rs | 25 +- src/libstd/fs.rs | 1641 ++++++++++++++++++++++++++++++ src/libstd/fs/mod.rs | 1646 ------------------------------ src/libstd/fs/tempdir.rs | 127 --- src/libstd/io/cursor.rs | 8 +- src/libstd/io/error.rs | 22 - src/libstd/lib.rs | 2 - src/libstd/net/tcp.rs | 18 +- src/libstd/net/udp.rs | 9 +- src/libstd/old_io/fs.rs | 5 +- src/libstd/old_io/mem.rs | 4 +- src/libstd/old_io/mod.rs | 2 +- src/libstd/old_io/pipe.rs | 6 +- src/libstd/old_io/process.rs | 36 +- src/libstd/old_io/tempfile.rs | 6 +- src/libstd/old_io/test.rs | 2 +- src/libstd/old_path/mod.rs | 5 +- src/libstd/old_path/posix.rs | 13 +- src/libstd/old_path/windows.rs | 2 - src/libstd/os.rs | 1821 +--------------------------------- src/libstd/path.rs | 2 +- src/libstd/prelude/v1.rs | 9 +- src/libstd/process.rs | 52 +- src/libstd/rand/os.rs | 33 +- src/libstd/rt/args.rs | 14 +- src/libstd/sync/mod.rs | 3 - src/libstd/sync/poison.rs | 6 - src/libstd/sync/task_pool.rs | 217 ---- src/libstd/sys/unix/backtrace.rs | 1 - src/libstd/sys/unix/fs.rs | 4 +- src/libstd/sys/unix/fs2.rs | 2 +- src/libstd/sys/unix/helper_signal.rs | 6 +- src/libstd/sys/unix/os.rs | 13 +- src/libstd/sys/unix/process.rs | 6 +- src/libstd/sys/unix/timer.rs | 5 +- src/libstd/sys/windows/os.rs | 13 +- src/libstd/sys/windows/process.rs | 16 +- src/libstd/thread/local.rs | 6 - src/libstd/thread/mod.rs | 104 +- 44 files changed, 1794 insertions(+), 4252 deletions(-) create mode 100644 src/libstd/fs.rs delete mode 100644 src/libstd/fs/mod.rs delete mode 100644 src/libstd/fs/tempdir.rs delete mode 100644 src/libstd/sync/task_pool.rs (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index aa3195cbf01..053ceceb496 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -15,7 +15,7 @@ use self::BucketState::*; use clone::Clone; use cmp; use hash::{Hash, Hasher}; -use iter::{Iterator, ExactSizeIterator, count}; +use iter::{Iterator, ExactSizeIterator}; use marker::{Copy, Send, Sync, Sized, self}; use mem::{min_align_of, size_of}; use mem; diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index d8a95133d94..9a68a60361c 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -18,7 +18,7 @@ use prelude::v1::*; use env; -use ffi::{AsOsStr, CString, OsString}; +use ffi::{CString, OsString}; use mem; use path::{Path, PathBuf}; diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 71f072302fb..ec0e4b6737f 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -20,7 +20,7 @@ use prelude::v1::*; use iter::IntoIterator; use error::Error; -use ffi::{OsString, AsOsStr}; +use ffi::{OsStr, OsString}; use fmt; use io; use path::{Path, PathBuf}; @@ -176,7 +176,7 @@ impl Iterator for VarsOs { /// } /// ``` #[stable(feature = "env", since = "1.0.0")] -pub fn var(key: &K) -> Result where K: AsOsStr { +pub fn var(key: &K) -> Result where K: AsRef { match var_os(key) { Some(s) => s.into_string().map_err(VarError::NotUnicode), None => Err(VarError::NotPresent) @@ -198,9 +198,9 @@ pub fn var(key: &K) -> Result where K: AsOsStr { /// } /// ``` #[stable(feature = "env", since = "1.0.0")] -pub fn var_os(key: &K) -> Option where K: AsOsStr { +pub fn var_os(key: &K) -> Option where K: AsRef { let _g = ENV_LOCK.lock(); - os_imp::getenv(key.as_os_str()) + os_imp::getenv(key.as_ref()) } /// Possible errors from the `env::var` method. @@ -255,17 +255,17 @@ impl Error for VarError { /// ``` #[stable(feature = "env", since = "1.0.0")] pub fn set_var(k: &K, v: &V) - where K: AsOsStr, V: AsOsStr + where K: AsRef, V: AsRef { let _g = ENV_LOCK.lock(); - os_imp::setenv(k.as_os_str(), v.as_os_str()) + os_imp::setenv(k.as_ref(), v.as_ref()) } /// Remove a variable from the environment entirely. #[stable(feature = "env", since = "1.0.0")] -pub fn remove_var(k: &K) where K: AsOsStr { +pub fn remove_var(k: &K) where K: AsRef { let _g = ENV_LOCK.lock(); - os_imp::unsetenv(k.as_os_str()) + os_imp::unsetenv(k.as_ref()) } /// An iterator over `Path` instances for parsing an environment variable @@ -296,8 +296,8 @@ pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> } /// } /// ``` #[stable(feature = "env", since = "1.0.0")] -pub fn split_paths(unparsed: &T) -> SplitPaths { - SplitPaths { inner: os_imp::split_paths(unparsed.as_os_str()) } +pub fn split_paths + ?Sized>(unparsed: &T) -> SplitPaths { + SplitPaths { inner: os_imp::split_paths(unparsed.as_ref()) } } #[stable(feature = "env", since = "1.0.0")] @@ -340,7 +340,7 @@ pub struct JoinPathsError { /// ``` #[stable(feature = "env", since = "1.0.0")] pub fn join_paths(paths: I) -> Result - where I: IntoIterator, T: AsOsStr + where I: IntoIterator, T: AsRef { os_imp::join_paths(paths.into_iter()).map_err(|e| { JoinPathsError { inner: e } @@ -740,7 +740,7 @@ mod tests { let mut rng = rand::thread_rng(); let n = format!("TEST{}", rng.gen_ascii_chars().take(10) .collect::()); - let n = OsString::from_string(n); + let n = OsString::from(n); assert!(var_os(&n).is_none()); n } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index a00f7708025..544d6bcc2c6 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -132,15 +132,6 @@ pub struct CStr { #[stable(feature = "rust1", since = "1.0.0")] pub struct NulError(usize, Vec); -/// A conversion trait used by the constructor of `CString` for types that can -/// be converted to a vector of bytes. -#[deprecated(since = "1.0.0", reason = "use std::convert::Into> instead")] -#[unstable(feature = "std_misc")] -pub trait IntoBytes { - /// Consumes this container, returning a vector of bytes. - fn into_bytes(self) -> Vec; -} - impl CString { /// Create a new C-compatible string from a container of bytes. /// @@ -178,57 +169,6 @@ impl CString { } } - /// Create a new C-compatible string from a byte slice. - /// - /// This method will copy the data of the slice provided into a new - /// allocation, ensuring that there is a trailing 0 byte. - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(libc)] - /// extern crate libc; - /// use std::ffi::CString; - /// - /// extern { fn puts(s: *const libc::c_char); } - /// - /// fn main() { - /// let to_print = CString::new("Hello!").unwrap(); - /// unsafe { - /// puts(to_print.as_ptr()); - /// } - /// } - /// ``` - /// - /// # Panics - /// - /// This function will panic if the provided slice contains any - /// interior nul bytes. - #[unstable(feature = "std_misc")] - #[deprecated(since = "1.0.0", reason = "use CString::new instead")] - #[allow(deprecated)] - pub fn from_slice(v: &[u8]) -> CString { - CString::from_vec(v.to_vec()) - } - - /// Create a C-compatible string from a byte vector. - /// - /// This method will consume ownership of the provided vector, appending a 0 - /// byte to the end after verifying that there are no interior 0 bytes. - /// - /// # Panics - /// - /// This function will panic if the provided slice contains any - /// interior nul bytes. - #[unstable(feature = "std_misc")] - #[deprecated(since = "1.0.0", reason = "use CString::new instead")] - pub fn from_vec(v: Vec) -> CString { - match v.iter().position(|x| *x == 0) { - Some(i) => panic!("null byte found in slice at: {}", i), - None => unsafe { CString::from_vec_unchecked(v) }, - } - } - /// Create a C-compatible string from a byte vector without checking for /// interior 0 bytes. /// @@ -424,41 +364,6 @@ impl Ord for CStr { } } -/// Deprecated in favor of `CStr` -#[unstable(feature = "std_misc")] -#[deprecated(since = "1.0.0", reason = "use CStr::from_ptr(p).to_bytes() instead")] -pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] { - let len = libc::strlen(*raw); - slice::from_raw_parts(*(raw as *const _ as *const *const u8), len as usize) -} - -/// Deprecated in favor of `CStr` -#[unstable(feature = "std_misc")] -#[deprecated(since = "1.0.0", - reason = "use CStr::from_ptr(p).to_bytes_with_nul() instead")] -pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char) - -> &'a [u8] { - let len = libc::strlen(*raw) + 1; - slice::from_raw_parts(*(raw as *const _ as *const *const u8), len as usize) -} - -#[allow(deprecated)] -impl<'a> IntoBytes for &'a str { - fn into_bytes(self) -> Vec { self.as_bytes().to_vec() } -} -#[allow(deprecated)] -impl<'a> IntoBytes for &'a [u8] { - fn into_bytes(self) -> Vec { self.to_vec() } -} -#[allow(deprecated)] -impl IntoBytes for String { - fn into_bytes(self) -> Vec { self.into_bytes() } -} -#[allow(deprecated)] -impl IntoBytes for Vec { - fn into_bytes(self) -> Vec { self } -} - #[cfg(test)] mod tests { use prelude::v1::*; diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index f17dc654249..1b7e913d46c 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -13,17 +13,10 @@ #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -pub use self::c_str::{CString, CStr}; -pub use self::c_str::{NulError, IntoBytes}; -#[allow(deprecated)] -pub use self::c_str::c_str_to_bytes; -#[allow(deprecated)] -pub use self::c_str::c_str_to_bytes_with_nul; +pub use self::c_str::{CString, CStr, NulError}; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::os_str::OsString; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::os_str::OsStr; +pub use self::os_str::{OsString, OsStr}; mod c_str; mod os_str; diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 49dbac4585b..d9a6a1006f4 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -29,7 +29,7 @@ //! for conversion to/from various other string types. Eventually these types //! will offer a full-fledged string API. -#![unstable(feature = "os", +#![unstable(feature = "os_str", reason = "recently added as part of path/io reform")] use core::prelude::*; @@ -61,22 +61,6 @@ pub struct OsStr { } impl OsString { - /// Constructs an `OsString` at no cost by consuming a `String`. - #[stable(feature = "rust1", since = "1.0.0")] - #[deprecated(since = "1.0.0", reason = "use `from` instead")] - pub fn from_string(s: String) -> OsString { - OsString::from(s) - } - - /// Constructs an `OsString` by copying from a `&str` slice. - /// - /// Equivalent to: `OsString::from_string(String::from_str(s))`. - #[stable(feature = "rust1", since = "1.0.0")] - #[deprecated(since = "1.0.0", reason = "use `from` instead")] - pub fn from_str(s: &str) -> OsString { - OsString::from(s) - } - /// Constructs a new empty `OsString`. #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> OsString { @@ -91,13 +75,6 @@ impl OsString { self.inner.into_string().map_err(|buf| OsString { inner: buf} ) } - /// Extend the string with the given `&OsStr` slice. - #[deprecated(since = "1.0.0", reason = "renamed to `push`")] - #[unstable(feature = "os")] - pub fn push_os_str(&mut self, s: &OsStr) { - self.inner.push_slice(&s.inner) - } - /// Extend the string with the given `&OsStr` slice. #[stable(feature = "rust1", since = "1.0.0")] pub fn push>(&mut self, s: T) { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs new file mode 100644 index 00000000000..071e5b5c28c --- /dev/null +++ b/src/libstd/fs.rs @@ -0,0 +1,1641 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Filesystem manipulation operations +//! +//! This module contains basic methods to manipulate the contents of the local +//! filesystem. All methods in this module represent cross-platform filesystem +//! operations. Extra platform-specific functionality can be found in the +//! extension traits of `std::os::$platform`. + +#![stable(feature = "rust1", since = "1.0.0")] + +use core::prelude::*; + +use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write}; +use path::{Path, PathBuf}; +use sys::fs2 as fs_imp; +use sys_common::{AsInnerMut, FromInner, AsInner}; +use vec::Vec; + +/// A reference to an open file on the filesystem. +/// +/// An instance of a `File` can be read and/or written depending on what options +/// it was opened with. Files also implement `Seek` to alter the logical cursor +/// that the file contains internally. +/// +/// # Examples +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::fs::File; +/// +/// # fn foo() -> std::io::Result<()> { +/// let mut f = try!(File::create("foo.txt")); +/// try!(f.write_all(b"Hello, world!")); +/// +/// let mut f = try!(File::open("foo.txt")); +/// let mut s = String::new(); +/// try!(f.read_to_string(&mut s)); +/// assert_eq!(s, "Hello, world!"); +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct File { + inner: fs_imp::File, + path: PathBuf, +} + +/// Metadata information about a file. +/// +/// This structure is returned from the `metadata` function or method and +/// represents known metadata about a file such as its permissions, size, +/// modification times, etc. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Metadata(fs_imp::FileAttr); + +/// Iterator over the entries in a directory. +/// +/// This iterator is returned from the `read_dir` function of this module and +/// will yield instances of `io::Result`. Through a `DirEntry` +/// information like the entry's path and possibly other metadata can be +/// learned. +/// +/// # Failure +/// +/// This `io::Result` will be an `Err` if there's some sort of intermittent +/// IO error during iteration. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ReadDir(fs_imp::ReadDir); + +/// Entries returned by the `ReadDir` iterator. +/// +/// An instance of `DirEntry` represents an entry inside of a directory on the +/// filesystem. Each entry can be inspected via methods to learn about the full +/// path or possibly other metadata through per-platform extension traits. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct DirEntry(fs_imp::DirEntry); + +/// An iterator that recursively walks over the contents of a directory. +#[unstable(feature = "fs_walk", + reason = "the precise semantics and defaults for a recursive walk \ + may change and this may end up accounting for files such \ + as symlinks differently")] +pub struct WalkDir { + cur: Option, + stack: Vec>, +} + +/// Options and flags which can be used to configure how a file is opened. +/// +/// This builder exposes the ability to configure how a `File` is opened and +/// what operations are permitted on the open file. The `File::open` and +/// `File::create` methods are aliases for commonly used options using this +/// builder. +#[derive(Clone)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct OpenOptions(fs_imp::OpenOptions); + +/// Representation of the various permissions on a file. +/// +/// This module only currently provides one bit of information, `readonly`, +/// which is exposed on all currently supported platforms. Unix-specific +/// functionality, such as mode bits, is available through the +/// `os::unix::PermissionsExt` trait. +#[derive(Clone, PartialEq, Eq, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Permissions(fs_imp::FilePermissions); + +impl File { + /// Attempts to open a file in read-only mode. + /// + /// See the `OpenOptions::open` method for more details. + /// + /// # Errors + /// + /// This function will return an error if `path` does not already exist. + /// Other errors may also be returned according to `OpenOptions::open`. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn open>(path: P) -> io::Result { + OpenOptions::new().read(true).open(path) + } + + /// Open a file in write-only mode. + /// + /// This function will create a file if it does not exist, + /// and will truncate it if it does. + /// + /// See the `OpenOptions::open` function for more details. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::create("foo.txt")); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn create>(path: P) -> io::Result { + OpenOptions::new().write(true).create(true).truncate(true).open(path) + } + + /// Returns the original path that was used to open this file. + #[unstable(feature = "file_path", + reason = "this abstraction is imposed by this library instead \ + of the underlying OS and may be removed")] + pub fn path(&self) -> Option<&Path> { + Some(&self.path) + } + + /// Attempt to sync all OS-internal metadata to disk. + /// + /// This function will attempt to ensure that all in-core data reaches the + /// filesystem before returning. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::prelude::*; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::create("foo.txt")); + /// try!(f.write_all(b"Hello, world!")); + /// + /// try!(f.sync_all()); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn sync_all(&self) -> io::Result<()> { + self.inner.fsync() + } + + /// This function is similar to `sync_all`, except that it may not + /// synchronize file metadata to the filesystem. + /// + /// This is intended for use cases that must synchronize content, but don't + /// need the metadata on disk. The goal of this method is to reduce disk + /// operations. + /// + /// Note that some platforms may simply implement this in terms of + /// `sync_all`. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::prelude::*; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::create("foo.txt")); + /// try!(f.write_all(b"Hello, world!")); + /// + /// try!(f.sync_data()); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn sync_data(&self) -> io::Result<()> { + self.inner.datasync() + } + + /// Truncates or extends the underlying file, updating the size of + /// this file to become `size`. + /// + /// If the `size` is less than the current file's size, then the file will + /// be shrunk. If it is greater than the current file's size, then the file + /// will be extended to `size` and have all of the intermediate data filled + /// in with 0s. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// try!(f.set_len(0)); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn set_len(&self, size: u64) -> io::Result<()> { + self.inner.truncate(size) + } + + /// Queries metadata about the underlying file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let metadata = try!(f.metadata()); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn metadata(&self) -> io::Result { + self.inner.file_attr().map(Metadata) + } +} + +impl AsInner for File { + fn as_inner(&self) -> &fs_imp::File { &self.inner } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl Read for File { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for File { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + fn flush(&mut self) -> io::Result<()> { self.inner.flush() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl Seek for File { + fn seek(&mut self, pos: SeekFrom) -> io::Result { + self.inner.seek(pos) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Read for &'a File { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Write for &'a File { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + fn flush(&mut self) -> io::Result<()> { self.inner.flush() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Seek for &'a File { + fn seek(&mut self, pos: SeekFrom) -> io::Result { + self.inner.seek(pos) + } +} + +impl OpenOptions { + /// Creates a blank net set of options ready for configuration. + /// + /// All options are initially set to `false`. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new() -> OpenOptions { + OpenOptions(fs_imp::OpenOptions::new()) + } + + /// Set the option for read access. + /// + /// This option, when true, will indicate that the file should be + /// `read`-able if opened. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn read(&mut self, read: bool) -> &mut OpenOptions { + self.0.read(read); self + } + + /// Set the option for write access. + /// + /// This option, when true, will indicate that the file should be + /// `write`-able if opened. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn write(&mut self, write: bool) -> &mut OpenOptions { + self.0.write(write); self + } + + /// Set the option for the append mode. + /// + /// This option, when true, means that writes will append to a file instead + /// of overwriting previous contents. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn append(&mut self, append: bool) -> &mut OpenOptions { + self.0.append(append); self + } + + /// Set the option for truncating a previous file. + /// + /// If a file is successfully opened with this option set it will truncate + /// the file to 0 length if it already exists. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions { + self.0.truncate(truncate); self + } + + /// Set the option for creating a new file. + /// + /// This option indicates whether a new file will be created if the file + /// does not yet already exist. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn create(&mut self, create: bool) -> &mut OpenOptions { + self.0.create(create); self + } + + /// Open a file at `path` with the options specified by `self`. + /// + /// # Errors + /// + /// This function will return an error under a number of different + /// circumstances, to include but not limited to: + /// + /// * Opening a file that does not exist with read access. + /// * Attempting to open a file with access that the user lacks + /// permissions for + /// * Filesystem-level errors (full disk, etc) + #[stable(feature = "rust1", since = "1.0.0")] + pub fn open>(&self, path: P) -> io::Result { + let path = path.as_ref(); + let inner = try!(fs_imp::File::open(path, &self.0)); + Ok(File { path: path.to_path_buf(), inner: inner }) + } +} + +impl AsInnerMut for OpenOptions { + fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 } +} + +impl Metadata { + /// Returns whether this metadata is for a directory. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_dir(&self) -> bool { self.0.is_dir() } + + /// Returns whether this metadata is for a regular file. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_file(&self) -> bool { self.0.is_file() } + + /// Returns the size of the file, in bytes, this metadata is for. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn len(&self) -> u64 { self.0.size() } + + /// Returns the permissions of the file this metadata is for. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn permissions(&self) -> Permissions { + Permissions(self.0.perm()) + } + + /// Returns the most recent access time for a file. + /// + /// The return value is in milliseconds since the epoch. + #[unstable(feature = "fs_time", + reason = "the return type of u64 is not quite appropriate for \ + this method and may change if the standard library \ + gains a type to represent a moment in time")] + pub fn accessed(&self) -> u64 { self.0.accessed() } + + /// Returns the most recent modification time for a file. + /// + /// The return value is in milliseconds since the epoch. + #[unstable(feature = "fs_time", + reason = "the return type of u64 is not quite appropriate for \ + this method and may change if the standard library \ + gains a type to represent a moment in time")] + pub fn modified(&self) -> u64 { self.0.modified() } +} + +impl Permissions { + /// Returns whether these permissions describe a readonly file. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn readonly(&self) -> bool { self.0.readonly() } + + /// Modify the readonly flag for this set of permissions. + /// + /// This operation does **not** modify the filesystem. To modify the + /// filesystem use the `fs::set_permissions` function. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn set_readonly(&mut self, readonly: bool) { + self.0.set_readonly(readonly) + } +} + +impl FromInner for Permissions { + fn from_inner(f: fs_imp::FilePermissions) -> Permissions { + Permissions(f) + } +} + +impl AsInner for Permissions { + fn as_inner(&self) -> &fs_imp::FilePermissions { &self.0 } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for ReadDir { + type Item = io::Result; + + fn next(&mut self) -> Option> { + self.0.next().map(|entry| entry.map(DirEntry)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DirEntry { + /// Returns the full path to the file that this entry represents. + /// + /// The full path is created by joining the original path to `read_dir` or + /// `walk_dir` with the filename of this entry. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn path(&self) -> PathBuf { self.0.path() } +} + +/// Remove a file from the underlying filesystem. +/// +/// # Examples +/// +/// ```rust,no_run +/// use std::fs; +/// +/// fs::remove_file("/some/file/path.txt"); +/// ``` +/// +/// Note that, just because an unlink call was successful, it is not +/// guaranteed that a file is immediately deleted (e.g. depending on +/// platform, other open file descriptors may prevent immediate removal). +/// +/// # Errors +/// +/// This function will return an error if `path` points to a directory, if the +/// user lacks permissions to remove the file, or if some other filesystem-level +/// error occurs. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn remove_file>(path: P) -> io::Result<()> { + fs_imp::unlink(path.as_ref()) +} + +/// Given a path, query the file system to get information about a file, +/// directory, etc. +/// +/// This function will traverse soft links to query information about the +/// destination file. +/// +/// # Examples +/// +/// ```rust,no_run +/// # fn foo() -> std::io::Result<()> { +/// use std::fs; +/// +/// let attr = try!(fs::metadata("/some/file/path.txt")); +/// // inspect attr ... +/// # Ok(()) +/// # } +/// ``` +/// +/// # Errors +/// +/// This function will return an error if the user lacks the requisite +/// permissions to perform a `metadata` call on the given `path` or if there +/// is no entry in the filesystem at the provided path. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn metadata>(path: P) -> io::Result { + fs_imp::stat(path.as_ref()).map(Metadata) +} + +/// Rename a file or directory to a new name. +/// +/// # Examples +/// +/// ```rust,no_run +/// use std::fs; +/// +/// fs::rename("foo", "bar"); +/// ``` +/// +/// # Errors +/// +/// This function will return an error if the provided `from` doesn't exist, if +/// the process lacks permissions to view the contents, if `from` and `to` +/// reside on separate filesystems, or if some other intermittent I/O error +/// occurs. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> { + fs_imp::rename(from.as_ref(), to.as_ref()) +} + +/// Copies the contents of one file to another. This function will also +/// copy the permission bits of the original file to the destination file. +/// +/// This function will **overwrite** the contents of `to`. +/// +/// Note that if `from` and `to` both point to the same file, then the file +/// will likely get truncated by this operation. +/// +/// # Examples +/// +/// ``` +/// use std::fs; +/// +/// fs::copy("foo.txt", "bar.txt"); +/// ``` +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not +/// limited to just these cases: +/// +/// * The `from` path is not a file +/// * The `from` file does not exist +/// * The current process does not have the permission rights to access +/// `from` or write `to` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { + let from = from.as_ref(); + let to = to.as_ref(); + if !from.is_file() { + return Err(Error::new(ErrorKind::InvalidInput, + "the source path is not an existing file", + None)) + } + + let mut reader = try!(File::open(from)); + let mut writer = try!(File::create(to)); + let perm = try!(reader.metadata()).permissions(); + + let ret = try!(io::copy(&mut reader, &mut writer)); + try!(set_permissions(to, perm)); + Ok(ret) +} + +/// Creates a new hard link on the filesystem. +/// +/// The `dst` path will be a link pointing to the `src` path. Note that systems +/// often require these two paths to both be located on the same filesystem. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn hard_link, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { + fs_imp::link(src.as_ref(), dst.as_ref()) +} + +/// Creates a new soft link on the filesystem. +/// +/// The `dst` path will be a soft link pointing to the `src` path. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { + fs_imp::symlink(src.as_ref(), dst.as_ref()) +} + +/// Reads a soft link, returning the file that the link points to. +/// +/// # Errors +/// +/// This function will return an error on failure. Failure conditions include +/// reading a file that does not exist or reading a file that is not a soft +/// link. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn read_link>(path: P) -> io::Result { + fs_imp::readlink(path.as_ref()) +} + +/// Create a new, empty directory at the provided path +/// +/// # Examples +/// +/// ``` +/// use std::fs; +/// +/// fs::create_dir("/some/dir"); +/// ``` +/// +/// # Errors +/// +/// This function will return an error if the user lacks permissions to make a +/// new directory at the provided `path`, or if the directory already exists. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn create_dir>(path: P) -> io::Result<()> { + fs_imp::mkdir(path.as_ref()) +} + +/// Recursively create a directory and all of its parent components if they +/// are missing. +/// +/// # Errors +/// +/// This function will fail if any directory in the path specified by `path` +/// does not already exist and it could not be created otherwise. The specific +/// error conditions for when a directory is being created (after it is +/// determined to not exist) are outlined by `fs::create_dir`. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn create_dir_all>(path: P) -> io::Result<()> { + let path = path.as_ref(); + if path == Path::new("") || path.is_dir() { return Ok(()) } + if let Some(p) = path.parent() { try!(create_dir_all(p)) } + create_dir(path) +} + +/// Remove an existing, empty directory +/// +/// # Examples +/// +/// ``` +/// use std::fs; +/// +/// fs::remove_dir("/some/dir"); +/// ``` +/// +/// # Errors +/// +/// This function will return an error if the user lacks permissions to remove +/// the directory at the provided `path`, or if the directory isn't empty. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn remove_dir>(path: P) -> io::Result<()> { + fs_imp::rmdir(path.as_ref()) +} + +/// Removes a directory at this path, after removing all its contents. Use +/// carefully! +/// +/// This function does **not** follow soft links and it will simply remove the +/// soft link itself. +/// +/// # Errors +/// +/// See `file::remove_file` and `fs::remove_dir` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn remove_dir_all>(path: P) -> io::Result<()> { + let path = path.as_ref(); + for child in try!(read_dir(path)) { + let child = try!(child).path(); + let stat = try!(lstat(&*child)); + if stat.is_dir() { + try!(remove_dir_all(&*child)); + } else { + try!(remove_file(&*child)); + } + } + return remove_dir(path); + + #[cfg(unix)] + fn lstat(path: &Path) -> io::Result { fs_imp::lstat(path) } + #[cfg(windows)] + fn lstat(path: &Path) -> io::Result { fs_imp::stat(path) } +} + +/// Returns an iterator over the entries within a directory. +/// +/// The iterator will yield instances of `io::Result`. New errors may +/// be encountered after an iterator is initially constructed. +/// +/// # Examples +/// +/// ``` +/// # #![feature(path_ext)] +/// use std::io; +/// use std::fs::{self, PathExt, DirEntry}; +/// use std::path::Path; +/// +/// // one possible implementation of fs::walk_dir only visiting files +/// fn visit_dirs(dir: &Path, cb: &mut FnMut(DirEntry)) -> io::Result<()> { +/// if dir.is_dir() { +/// for entry in try!(fs::read_dir(dir)) { +/// let entry = try!(entry); +/// if entry.path().is_dir() { +/// try!(visit_dirs(&entry.path(), cb)); +/// } else { +/// cb(entry); +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +/// +/// # Errors +/// +/// This function will return an error if the provided `path` doesn't exist, if +/// the process lacks permissions to view the contents or if the `path` points +/// at a non-directory file +#[stable(feature = "rust1", since = "1.0.0")] +pub fn read_dir>(path: P) -> io::Result { + fs_imp::readdir(path.as_ref()).map(ReadDir) +} + +/// Returns an iterator that will recursively walk the directory structure +/// rooted at `path`. +/// +/// The path given will not be iterated over, and this will perform iteration in +/// some top-down order. The contents of unreadable subdirectories are ignored. +/// +/// The iterator will yield instances of `io::Result`. New errors may +/// be encountered after an iterator is initially constructed. +#[unstable(feature = "fs_walk", + reason = "the precise semantics and defaults for a recursive walk \ + may change and this may end up accounting for files such \ + as symlinks differently")] +pub fn walk_dir>(path: P) -> io::Result { + let start = try!(read_dir(path)); + Ok(WalkDir { cur: Some(start), stack: Vec::new() }) +} + +#[unstable(feature = "fs_walk")] +impl Iterator for WalkDir { + type Item = io::Result; + + fn next(&mut self) -> Option> { + loop { + if let Some(ref mut cur) = self.cur { + match cur.next() { + Some(Err(e)) => return Some(Err(e)), + Some(Ok(next)) => { + let path = next.path(); + if path.is_dir() { + self.stack.push(read_dir(&*path)); + } + return Some(Ok(next)) + } + None => {} + } + } + self.cur = None; + match self.stack.pop() { + Some(Err(e)) => return Some(Err(e)), + Some(Ok(next)) => self.cur = Some(next), + None => return None, + } + } + } +} + +/// Utility methods for paths. +#[unstable(feature = "path_ext", + reason = "the precise set of methods exposed on this trait may \ + change and some methods may be removed")] +pub trait PathExt { + /// Get information on the file, directory, etc at this path. + /// + /// Consult the `fs::stat` documentation for more info. + /// + /// This call preserves identical runtime/error semantics with `file::stat`. + fn metadata(&self) -> io::Result; + + /// Boolean value indicator whether the underlying file exists on the local + /// filesystem. Returns false in exactly the cases where `fs::stat` fails. + fn exists(&self) -> bool; + + /// Whether the underlying implementation (be it a file path, or something + /// else) points at a "regular file" on the FS. Will return false for paths + /// to non-existent locations or directories or other non-regular files + /// (named pipes, etc). Follows links when making this determination. + fn is_file(&self) -> bool; + + /// Whether the underlying implementation (be it a file path, or something + /// else) is pointing at a directory in the underlying FS. Will return + /// false for paths to non-existent locations or if the item is not a + /// directory (eg files, named pipes, etc). Follows links when making this + /// determination. + fn is_dir(&self) -> bool; +} + +impl PathExt for Path { + fn metadata(&self) -> io::Result { metadata(self) } + + fn exists(&self) -> bool { metadata(self).is_ok() } + + fn is_file(&self) -> bool { + metadata(self).map(|s| s.is_file()).unwrap_or(false) + } + fn is_dir(&self) -> bool { + metadata(self).map(|s| s.is_dir()).unwrap_or(false) + } +} + +/// Changes the timestamps for a file's last modification and access time. +/// +/// The file at the path specified will have its last access time set to +/// `atime` and its modification time set to `mtime`. The times specified should +/// be in milliseconds. +#[unstable(feature = "fs_time", + reason = "the argument type of u64 is not quite appropriate for \ + this function and may change if the standard library \ + gains a type to represent a moment in time")] +pub fn set_file_times>(path: P, accessed: u64, + modified: u64) -> io::Result<()> { + fs_imp::utimes(path.as_ref(), accessed, modified) +} + +/// Changes the permissions found on a file or a directory. +/// +/// # Examples +/// +/// ``` +/// # #![feature(fs)] +/// # fn foo() -> std::io::Result<()> { +/// use std::fs; +/// +/// let mut perms = try!(fs::metadata("foo.txt")).permissions(); +/// perms.set_readonly(true); +/// try!(fs::set_permissions("foo.txt", perms)); +/// # Ok(()) +/// # } +/// ``` +/// +/// # Errors +/// +/// This function will return an error if the provided `path` doesn't exist, if +/// the process lacks permissions to change the attributes of the file, or if +/// some other I/O error is encountered. +#[unstable(feature = "fs", + reason = "a more granual ability to set specific permissions may \ + be exposed on the Permissions structure itself and this \ + method may not always exist")] +pub fn set_permissions>(path: P, perm: Permissions) -> io::Result<()> { + fs_imp::set_perm(path.as_ref(), perm.0) +} + +#[cfg(test)] +mod tests { + #![allow(deprecated)] //rand + + use prelude::v1::*; + use io::prelude::*; + + use env; + use fs::{self, File, OpenOptions}; + use io::{ErrorKind, SeekFrom}; + use path::PathBuf; + use path::Path as Path2; + use os; + use rand::{self, StdRng, Rng}; + use str; + + macro_rules! check { ($e:expr) => ( + match $e { + Ok(t) => t, + Err(e) => panic!("{} failed with: {}", stringify!($e), e), + } + ) } + + macro_rules! error { ($e:expr, $s:expr) => ( + match $e { + Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), + Err(ref err) => assert!(err.to_string().contains($s), + format!("`{}` did not contain `{}`", err, $s)) + } + ) } + + pub struct TempDir(PathBuf); + + impl TempDir { + fn join(&self, path: &str) -> PathBuf { + let TempDir(ref p) = *self; + p.join(path) + } + + fn path<'a>(&'a self) -> &'a Path2 { + let TempDir(ref p) = *self; + p + } + } + + impl Drop for TempDir { + fn drop(&mut self) { + // Gee, seeing how we're testing the fs module I sure hope that we + // at least implement this correctly! + let TempDir(ref p) = *self; + check!(fs::remove_dir_all(p)); + } + } + + pub fn tmpdir() -> TempDir { + let p = env::temp_dir(); + let ret = p.join(&format!("rust-{}", rand::random::())); + check!(fs::create_dir(&ret)); + TempDir(ret) + } + + #[test] + fn file_test_io_smoke_test() { + let message = "it's alright. have a good time"; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test.txt"); + { + let mut write_stream = check!(File::create(filename)); + check!(write_stream.write(message.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + let mut read_buf = [0; 1028]; + let read_str = match check!(read_stream.read(&mut read_buf)) { + -1|0 => panic!("shouldn't happen"), + n => str::from_utf8(&read_buf[..n]).unwrap().to_string() + }; + assert_eq!(read_str, message); + } + check!(fs::remove_file(filename)); + } + + #[test] + fn invalid_path_raises() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_that_does_not_exist.txt"); + let result = File::open(filename); + + if cfg!(unix) { + error!(result, "o such file or directory"); + } + // error!(result, "couldn't open path as file"); + // error!(result, format!("path={}; mode=open; access=read", filename.display())); + } + + #[test] + fn file_test_iounlinking_invalid_path_should_raise_condition() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt"); + + let result = fs::remove_file(filename); + + if cfg!(unix) { + error!(result, "o such file or directory"); + } + // error!(result, "couldn't unlink path"); + // error!(result, format!("path={}", filename.display())); + } + + #[test] + fn file_test_io_non_positional_read() { + let message: &str = "ten-four"; + let mut read_mem = [0; 8]; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test_positional.txt"); + { + let mut rw_stream = check!(File::create(filename)); + check!(rw_stream.write(message.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + { + let read_buf = &mut read_mem[0..4]; + check!(read_stream.read(read_buf)); + } + { + let read_buf = &mut read_mem[4..8]; + check!(read_stream.read(read_buf)); + } + } + check!(fs::remove_file(filename)); + let read_str = str::from_utf8(&read_mem).unwrap(); + assert_eq!(read_str, message); + } + + #[test] + fn file_test_io_seek_and_tell_smoke_test() { + let message = "ten-four"; + let mut read_mem = [0; 4]; + let set_cursor = 4 as u64; + let mut tell_pos_pre_read; + let mut tell_pos_post_read; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt"); + { + let mut rw_stream = check!(File::create(filename)); + check!(rw_stream.write(message.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + check!(read_stream.seek(SeekFrom::Start(set_cursor))); + tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0))); + check!(read_stream.read(&mut read_mem)); + tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0))); + } + check!(fs::remove_file(filename)); + let read_str = str::from_utf8(&read_mem).unwrap(); + assert_eq!(read_str, &message[4..8]); + assert_eq!(tell_pos_pre_read, set_cursor); + assert_eq!(tell_pos_post_read, message.len() as u64); + } + + #[test] + fn file_test_io_seek_and_write() { + let initial_msg = "food-is-yummy"; + let overwrite_msg = "-the-bar!!"; + let final_msg = "foo-the-bar!!"; + let seek_idx = 3; + let mut read_mem = [0; 13]; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt"); + { + let mut rw_stream = check!(File::create(filename)); + check!(rw_stream.write(initial_msg.as_bytes())); + check!(rw_stream.seek(SeekFrom::Start(seek_idx))); + check!(rw_stream.write(overwrite_msg.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + check!(read_stream.read(&mut read_mem)); + } + check!(fs::remove_file(filename)); + let read_str = str::from_utf8(&read_mem).unwrap(); + assert!(read_str == final_msg); + } + + #[test] + fn file_test_io_seek_shakedown() { + // 01234567890123 + let initial_msg = "qwer-asdf-zxcv"; + let chunk_one: &str = "qwer"; + let chunk_two: &str = "asdf"; + let chunk_three: &str = "zxcv"; + let mut read_mem = [0; 4]; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt"); + { + let mut rw_stream = check!(File::create(filename)); + check!(rw_stream.write(initial_msg.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + + check!(read_stream.seek(SeekFrom::End(-4))); + check!(read_stream.read(&mut read_mem)); + assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three); + + check!(read_stream.seek(SeekFrom::Current(-9))); + check!(read_stream.read(&mut read_mem)); + assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two); + + check!(read_stream.seek(SeekFrom::Start(0))); + check!(read_stream.read(&mut read_mem)); + assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one); + } + check!(fs::remove_file(filename)); + } + + #[test] + fn file_test_stat_is_correct_on_is_file() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_stat_correct_on_is_file.txt"); + { + let mut opts = OpenOptions::new(); + let mut fs = check!(opts.read(true).write(true) + .create(true).open(filename)); + let msg = "hw"; + fs.write(msg.as_bytes()).unwrap(); + + let fstat_res = check!(fs.metadata()); + assert!(fstat_res.is_file()); + } + let stat_res_fn = check!(fs::metadata(filename)); + assert!(stat_res_fn.is_file()); + let stat_res_meth = check!(filename.metadata()); + assert!(stat_res_meth.is_file()); + check!(fs::remove_file(filename)); + } + + #[test] + fn file_test_stat_is_correct_on_is_dir() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_stat_correct_on_is_dir"); + check!(fs::create_dir(filename)); + let stat_res_fn = check!(fs::metadata(filename)); + assert!(stat_res_fn.is_dir()); + let stat_res_meth = check!(filename.metadata()); + assert!(stat_res_meth.is_dir()); + check!(fs::remove_dir(filename)); + } + + #[test] + fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { + let tmpdir = tmpdir(); + let dir = &tmpdir.join("fileinfo_false_on_dir"); + check!(fs::create_dir(dir)); + assert!(dir.is_file() == false); + check!(fs::remove_dir(dir)); + } + + #[test] + fn file_test_fileinfo_check_exists_before_and_after_file_creation() { + let tmpdir = tmpdir(); + let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt"); + check!(check!(File::create(file)).write(b"foo")); + assert!(file.exists()); + check!(fs::remove_file(file)); + assert!(!file.exists()); + } + + #[test] + fn file_test_directoryinfo_check_exists_before_and_after_mkdir() { + let tmpdir = tmpdir(); + let dir = &tmpdir.join("before_and_after_dir"); + assert!(!dir.exists()); + check!(fs::create_dir(dir)); + assert!(dir.exists()); + assert!(dir.is_dir()); + check!(fs::remove_dir(dir)); + assert!(!dir.exists()); + } + + #[test] + fn file_test_directoryinfo_readdir() { + let tmpdir = tmpdir(); + let dir = &tmpdir.join("di_readdir"); + check!(fs::create_dir(dir)); + let prefix = "foo"; + for n in 0..3 { + let f = dir.join(&format!("{}.txt", n)); + let mut w = check!(File::create(&f)); + let msg_str = format!("{}{}", prefix, n.to_string()); + let msg = msg_str.as_bytes(); + check!(w.write(msg)); + } + let files = check!(fs::read_dir(dir)); + let mut mem = [0; 4]; + for f in files { + let f = f.unwrap().path(); + { + let n = f.file_stem().unwrap(); + check!(check!(File::open(&f)).read(&mut mem)); + let read_str = str::from_utf8(&mem).unwrap(); + let expected = format!("{}{}", prefix, n.to_str().unwrap()); + assert_eq!(expected, read_str); + } + check!(fs::remove_file(&f)); + } + check!(fs::remove_dir(dir)); + } + + #[test] + fn file_test_walk_dir() { + let tmpdir = tmpdir(); + let dir = &tmpdir.join("walk_dir"); + check!(fs::create_dir(dir)); + + let dir1 = &dir.join("01/02/03"); + check!(fs::create_dir_all(dir1)); + check!(File::create(&dir1.join("04"))); + + let dir2 = &dir.join("11/12/13"); + check!(fs::create_dir_all(dir2)); + check!(File::create(&dir2.join("14"))); + + let files = check!(fs::walk_dir(dir)); + let mut cur = [0; 2]; + for f in files { + let f = f.unwrap().path(); + let stem = f.file_stem().unwrap().to_str().unwrap(); + let root = stem.as_bytes()[0] - b'0'; + let name = stem.as_bytes()[1] - b'0'; + assert!(cur[root as usize] < name); + cur[root as usize] = name; + } + + check!(fs::remove_dir_all(dir)); + } + + #[test] + fn mkdir_path_already_exists_error() { + let tmpdir = tmpdir(); + let dir = &tmpdir.join("mkdir_error_twice"); + check!(fs::create_dir(dir)); + let e = fs::create_dir(dir).err().unwrap(); + assert_eq!(e.kind(), ErrorKind::AlreadyExists); + } + + #[test] + fn recursive_mkdir() { + let tmpdir = tmpdir(); + let dir = tmpdir.join("d1/d2"); + check!(fs::create_dir_all(&dir)); + assert!(dir.is_dir()) + } + + #[test] + fn recursive_mkdir_failure() { + let tmpdir = tmpdir(); + let dir = tmpdir.join("d1"); + let file = dir.join("f1"); + + check!(fs::create_dir_all(&dir)); + check!(File::create(&file)); + + let result = fs::create_dir_all(&file); + + assert!(result.is_err()); + // error!(result, "couldn't recursively mkdir"); + // error!(result, "couldn't create directory"); + // error!(result, "mode=0700"); + // error!(result, format!("path={}", file.display())); + } + + #[test] + fn recursive_mkdir_slash() { + check!(fs::create_dir_all(&Path2::new("/"))); + } + + // FIXME(#12795) depends on lstat to work on windows + #[cfg(not(windows))] + #[test] + fn recursive_rmdir() { + let tmpdir = tmpdir(); + let d1 = tmpdir.join("d1"); + let dt = d1.join("t"); + let dtt = dt.join("t"); + let d2 = tmpdir.join("d2"); + let canary = d2.join("do_not_delete"); + check!(fs::create_dir_all(&dtt)); + check!(fs::create_dir_all(&d2)); + check!(check!(File::create(&canary)).write(b"foo")); + check!(fs::soft_link(&d2, &dt.join("d2"))); + check!(fs::remove_dir_all(&d1)); + + assert!(!d1.is_dir()); + assert!(canary.exists()); + } + + #[test] + fn unicode_path_is_dir() { + assert!(Path2::new(".").is_dir()); + assert!(!Path2::new("test/stdtest/fs.rs").is_dir()); + + let tmpdir = tmpdir(); + + let mut dirpath = tmpdir.path().to_path_buf(); + dirpath.push(&format!("test-가一ー你好")); + check!(fs::create_dir(&dirpath)); + assert!(dirpath.is_dir()); + + let mut filepath = dirpath; + filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs"); + check!(File::create(&filepath)); // ignore return; touch only + assert!(!filepath.is_dir()); + assert!(filepath.exists()); + } + + #[test] + fn unicode_path_exists() { + assert!(Path2::new(".").exists()); + assert!(!Path2::new("test/nonexistent-bogus-path").exists()); + + let tmpdir = tmpdir(); + let unicode = tmpdir.path(); + let unicode = unicode.join(&format!("test-각丁ー再见")); + check!(fs::create_dir(&unicode)); + assert!(unicode.exists()); + assert!(!Path2::new("test/unicode-bogus-path-각丁ー再见").exists()); + } + + #[test] + fn copy_file_does_not_exist() { + let from = Path2::new("test/nonexistent-bogus-path"); + let to = Path2::new("test/other-bogus-path"); + + match fs::copy(&from, &to) { + Ok(..) => panic!(), + Err(..) => { + assert!(!from.exists()); + assert!(!to.exists()); + } + } + } + + #[test] + fn copy_file_ok() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + check!(check!(File::create(&input)).write(b"hello")); + check!(fs::copy(&input, &out)); + let mut v = Vec::new(); + check!(check!(File::open(&out)).read_to_end(&mut v)); + assert_eq!(v, b"hello"); + + assert_eq!(check!(input.metadata()).permissions(), + check!(out.metadata()).permissions()); + } + + #[test] + fn copy_file_dst_dir() { + let tmpdir = tmpdir(); + let out = tmpdir.join("out"); + + check!(File::create(&out)); + match fs::copy(&*out, tmpdir.path()) { + Ok(..) => panic!(), Err(..) => {} + } + } + + #[test] + fn copy_file_dst_exists() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in"); + let output = tmpdir.join("out"); + + check!(check!(File::create(&input)).write("foo".as_bytes())); + check!(check!(File::create(&output)).write("bar".as_bytes())); + check!(fs::copy(&input, &output)); + + let mut v = Vec::new(); + check!(check!(File::open(&output)).read_to_end(&mut v)); + assert_eq!(v, b"foo".to_vec()); + } + + #[test] + fn copy_file_src_dir() { + let tmpdir = tmpdir(); + let out = tmpdir.join("out"); + + match fs::copy(tmpdir.path(), &out) { + Ok(..) => panic!(), Err(..) => {} + } + assert!(!out.exists()); + } + + #[test] + fn copy_file_preserves_perm_bits() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + let attr = check!(check!(File::create(&input)).metadata()); + let mut p = attr.permissions(); + p.set_readonly(true); + check!(fs::set_permissions(&input, p)); + check!(fs::copy(&input, &out)); + assert!(check!(out.metadata()).permissions().readonly()); + check!(fs::set_permissions(&input, attr.permissions())); + check!(fs::set_permissions(&out, attr.permissions())); + } + + #[cfg(not(windows))] // FIXME(#10264) operation not permitted? + #[test] + fn symlinks_work() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + check!(check!(File::create(&input)).write("foobar".as_bytes())); + check!(fs::soft_link(&input, &out)); + // if cfg!(not(windows)) { + // assert_eq!(check!(lstat(&out)).kind, FileType::Symlink); + // assert_eq!(check!(out.lstat()).kind, FileType::Symlink); + // } + assert_eq!(check!(fs::metadata(&out)).len(), + check!(fs::metadata(&input)).len()); + let mut v = Vec::new(); + check!(check!(File::open(&out)).read_to_end(&mut v)); + assert_eq!(v, b"foobar".to_vec()); + } + + #[cfg(not(windows))] // apparently windows doesn't like symlinks + #[test] + fn symlink_noexist() { + let tmpdir = tmpdir(); + // symlinks can point to things that don't exist + check!(fs::soft_link(&tmpdir.join("foo"), &tmpdir.join("bar"))); + assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))), + tmpdir.join("foo")); + } + + #[test] + fn readlink_not_symlink() { + let tmpdir = tmpdir(); + match fs::read_link(tmpdir.path()) { + Ok(..) => panic!("wanted a failure"), + Err(..) => {} + } + } + + #[test] + fn links_work() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + check!(check!(File::create(&input)).write("foobar".as_bytes())); + check!(fs::hard_link(&input, &out)); + assert_eq!(check!(fs::metadata(&out)).len(), + check!(fs::metadata(&input)).len()); + assert_eq!(check!(fs::metadata(&out)).len(), + check!(input.metadata()).len()); + let mut v = Vec::new(); + check!(check!(File::open(&out)).read_to_end(&mut v)); + assert_eq!(v, b"foobar".to_vec()); + + // can't link to yourself + match fs::hard_link(&input, &input) { + Ok(..) => panic!("wanted a failure"), + Err(..) => {} + } + // can't link to something that doesn't exist + match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) { + Ok(..) => panic!("wanted a failure"), + Err(..) => {} + } + } + + #[test] + fn chmod_works() { + let tmpdir = tmpdir(); + let file = tmpdir.join("in.txt"); + + check!(File::create(&file)); + let attr = check!(fs::metadata(&file)); + assert!(!attr.permissions().readonly()); + let mut p = attr.permissions(); + p.set_readonly(true); + check!(fs::set_permissions(&file, p.clone())); + let attr = check!(fs::metadata(&file)); + assert!(attr.permissions().readonly()); + + match fs::set_permissions(&tmpdir.join("foo"), p.clone()) { + Ok(..) => panic!("wanted an error"), + Err(..) => {} + } + + p.set_readonly(false); + check!(fs::set_permissions(&file, p)); + } + + #[test] + fn sync_doesnt_kill_anything() { + let tmpdir = tmpdir(); + let path = tmpdir.join("in.txt"); + + let mut file = check!(File::create(&path)); + check!(file.sync_all()); + check!(file.sync_data()); + check!(file.write(b"foo")); + check!(file.sync_all()); + check!(file.sync_data()); + } + + #[test] + fn truncate_works() { + let tmpdir = tmpdir(); + let path = tmpdir.join("in.txt"); + + let mut file = check!(File::create(&path)); + check!(file.write(b"foo")); + check!(file.sync_all()); + + // Do some simple things with truncation + assert_eq!(check!(file.metadata()).len(), 3); + check!(file.set_len(10)); + assert_eq!(check!(file.metadata()).len(), 10); + check!(file.write(b"bar")); + check!(file.sync_all()); + assert_eq!(check!(file.metadata()).len(), 10); + + let mut v = Vec::new(); + check!(check!(File::open(&path)).read_to_end(&mut v)); + assert_eq!(v, b"foobar\0\0\0\0".to_vec()); + + // Truncate to a smaller length, don't seek, and then write something. + // Ensure that the intermediate zeroes are all filled in (we have `seek`ed + // past the end of the file). + check!(file.set_len(2)); + assert_eq!(check!(file.metadata()).len(), 2); + check!(file.write(b"wut")); + check!(file.sync_all()); + assert_eq!(check!(file.metadata()).len(), 9); + let mut v = Vec::new(); + check!(check!(File::open(&path)).read_to_end(&mut v)); + assert_eq!(v, b"fo\0\0\0\0wut".to_vec()); + } + + #[test] + fn open_flavors() { + use fs::OpenOptions as OO; + fn c(t: &T) -> T { t.clone() } + + let tmpdir = tmpdir(); + + let mut r = OO::new(); r.read(true); + let mut w = OO::new(); w.write(true); + let mut rw = OO::new(); rw.write(true).read(true); + + match r.open(&tmpdir.join("a")) { + Ok(..) => panic!(), Err(..) => {} + } + + // Perform each one twice to make sure that it succeeds the second time + // (where the file exists) + check!(c(&w).create(true).open(&tmpdir.join("b"))); + assert!(tmpdir.join("b").exists()); + check!(c(&w).create(true).open(&tmpdir.join("b"))); + check!(w.open(&tmpdir.join("b"))); + + check!(c(&rw).create(true).open(&tmpdir.join("c"))); + assert!(tmpdir.join("c").exists()); + check!(c(&rw).create(true).open(&tmpdir.join("c"))); + check!(rw.open(&tmpdir.join("c"))); + + check!(c(&w).append(true).create(true).open(&tmpdir.join("d"))); + assert!(tmpdir.join("d").exists()); + check!(c(&w).append(true).create(true).open(&tmpdir.join("d"))); + check!(c(&w).append(true).open(&tmpdir.join("d"))); + + check!(c(&rw).append(true).create(true).open(&tmpdir.join("e"))); + assert!(tmpdir.join("e").exists()); + check!(c(&rw).append(true).create(true).open(&tmpdir.join("e"))); + check!(c(&rw).append(true).open(&tmpdir.join("e"))); + + check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f"))); + assert!(tmpdir.join("f").exists()); + check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f"))); + check!(c(&w).truncate(true).open(&tmpdir.join("f"))); + + check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g"))); + assert!(tmpdir.join("g").exists()); + check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g"))); + check!(c(&rw).truncate(true).open(&tmpdir.join("g"))); + + check!(check!(File::create(&tmpdir.join("h"))).write("foo".as_bytes())); + check!(r.open(&tmpdir.join("h"))); + { + let mut f = check!(r.open(&tmpdir.join("h"))); + assert!(f.write("wut".as_bytes()).is_err()); + } + assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); + { + let mut f = check!(c(&w).append(true).open(&tmpdir.join("h"))); + check!(f.write("bar".as_bytes())); + } + assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6); + { + let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h"))); + check!(f.write("bar".as_bytes())); + } + assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); + } + + #[test] + fn utime() { + let tmpdir = tmpdir(); + let path = tmpdir.join("a"); + check!(File::create(&path)); + // These numbers have to be bigger than the time in the day to account + // for timezones Windows in particular will fail in certain timezones + // with small enough values + check!(fs::set_file_times(&path, 100000, 200000)); + assert_eq!(check!(path.metadata()).accessed(), 100000); + assert_eq!(check!(path.metadata()).modified(), 200000); + } + + #[test] + fn utime_noexist() { + let tmpdir = tmpdir(); + + match fs::set_file_times(&tmpdir.join("a"), 100, 200) { + Ok(..) => panic!(), + Err(..) => {} + } + } + + #[test] + fn binary_file() { + let mut bytes = [0; 1024]; + StdRng::new().unwrap().fill_bytes(&mut bytes); + + let tmpdir = tmpdir(); + + check!(check!(File::create(&tmpdir.join("test"))).write(&bytes)); + let mut v = Vec::new(); + check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v)); + assert!(v == &bytes[..]); + } + + #[test] + #[cfg(not(windows))] + fn unlink_readonly() { + let tmpdir = tmpdir(); + let path = tmpdir.join("file"); + check!(File::create(&path)); + let mut perm = check!(fs::metadata(&path)).permissions(); + perm.set_readonly(true); + check!(fs::set_permissions(&path, perm)); + check!(fs::remove_file(&path)); + } + + #[test] + fn mkdir_trailing_slash() { + let tmpdir = tmpdir(); + let path = tmpdir.join("file"); + check!(fs::create_dir_all(&path.join("a/"))); + } +} diff --git a/src/libstd/fs/mod.rs b/src/libstd/fs/mod.rs deleted file mode 100644 index a3128ef0f8d..00000000000 --- a/src/libstd/fs/mod.rs +++ /dev/null @@ -1,1646 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Filesystem manipulation operations -//! -//! This module contains basic methods to manipulate the contents of the local -//! filesystem. All methods in this module represent cross-platform filesystem -//! operations. Extra platform-specific functionality can be found in the -//! extension traits of `std::os::$platform`. - -#![stable(feature = "rust1", since = "1.0.0")] - -use core::prelude::*; - -use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write}; -use path::{Path, PathBuf}; -use sys::fs2 as fs_imp; -use sys_common::{AsInnerMut, FromInner, AsInner}; -use vec::Vec; - -#[allow(deprecated)] -pub use self::tempdir::TempDir; - -mod tempdir; - -/// A reference to an open file on the filesystem. -/// -/// An instance of a `File` can be read and/or written depending on what options -/// it was opened with. Files also implement `Seek` to alter the logical cursor -/// that the file contains internally. -/// -/// # Examples -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::fs::File; -/// -/// # fn foo() -> std::io::Result<()> { -/// let mut f = try!(File::create("foo.txt")); -/// try!(f.write_all(b"Hello, world!")); -/// -/// let mut f = try!(File::open("foo.txt")); -/// let mut s = String::new(); -/// try!(f.read_to_string(&mut s)); -/// assert_eq!(s, "Hello, world!"); -/// # Ok(()) -/// # } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct File { - inner: fs_imp::File, - path: PathBuf, -} - -/// Metadata information about a file. -/// -/// This structure is returned from the `metadata` function or method and -/// represents known metadata about a file such as its permissions, size, -/// modification times, etc. -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Metadata(fs_imp::FileAttr); - -/// Iterator over the entries in a directory. -/// -/// This iterator is returned from the `read_dir` function of this module and -/// will yield instances of `io::Result`. Through a `DirEntry` -/// information like the entry's path and possibly other metadata can be -/// learned. -/// -/// # Failure -/// -/// This `io::Result` will be an `Err` if there's some sort of intermittent -/// IO error during iteration. -#[stable(feature = "rust1", since = "1.0.0")] -pub struct ReadDir(fs_imp::ReadDir); - -/// Entries returned by the `ReadDir` iterator. -/// -/// An instance of `DirEntry` represents an entry inside of a directory on the -/// filesystem. Each entry can be inspected via methods to learn about the full -/// path or possibly other metadata through per-platform extension traits. -#[stable(feature = "rust1", since = "1.0.0")] -pub struct DirEntry(fs_imp::DirEntry); - -/// An iterator that recursively walks over the contents of a directory. -#[unstable(feature = "fs_walk", - reason = "the precise semantics and defaults for a recursive walk \ - may change and this may end up accounting for files such \ - as symlinks differently")] -pub struct WalkDir { - cur: Option, - stack: Vec>, -} - -/// Options and flags which can be used to configure how a file is opened. -/// -/// This builder exposes the ability to configure how a `File` is opened and -/// what operations are permitted on the open file. The `File::open` and -/// `File::create` methods are aliases for commonly used options using this -/// builder. -#[derive(Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct OpenOptions(fs_imp::OpenOptions); - -/// Representation of the various permissions on a file. -/// -/// This module only currently provides one bit of information, `readonly`, -/// which is exposed on all currently supported platforms. Unix-specific -/// functionality, such as mode bits, is available through the -/// `os::unix::PermissionsExt` trait. -#[derive(Clone, PartialEq, Eq, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Permissions(fs_imp::FilePermissions); - -impl File { - /// Attempts to open a file in read-only mode. - /// - /// See the `OpenOptions::open` method for more details. - /// - /// # Errors - /// - /// This function will return an error if `path` does not already exist. - /// Other errors may also be returned according to `OpenOptions::open`. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = try!(File::open("foo.txt")); - /// # Ok(()) - /// # } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn open>(path: P) -> io::Result { - OpenOptions::new().read(true).open(path) - } - - /// Open a file in write-only mode. - /// - /// This function will create a file if it does not exist, - /// and will truncate it if it does. - /// - /// See the `OpenOptions::open` function for more details. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = try!(File::create("foo.txt")); - /// # Ok(()) - /// # } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn create>(path: P) -> io::Result { - OpenOptions::new().write(true).create(true).truncate(true).open(path) - } - - /// Returns the original path that was used to open this file. - #[unstable(feature = "file_path", - reason = "this abstraction is imposed by this library instead \ - of the underlying OS and may be removed")] - pub fn path(&self) -> Option<&Path> { - Some(&self.path) - } - - /// Attempt to sync all OS-internal metadata to disk. - /// - /// This function will attempt to ensure that all in-core data reaches the - /// filesystem before returning. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::prelude::*; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = try!(File::create("foo.txt")); - /// try!(f.write_all(b"Hello, world!")); - /// - /// try!(f.sync_all()); - /// # Ok(()) - /// # } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn sync_all(&self) -> io::Result<()> { - self.inner.fsync() - } - - /// This function is similar to `sync_all`, except that it may not - /// synchronize file metadata to the filesystem. - /// - /// This is intended for use cases that must synchronize content, but don't - /// need the metadata on disk. The goal of this method is to reduce disk - /// operations. - /// - /// Note that some platforms may simply implement this in terms of - /// `sync_all`. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::prelude::*; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = try!(File::create("foo.txt")); - /// try!(f.write_all(b"Hello, world!")); - /// - /// try!(f.sync_data()); - /// # Ok(()) - /// # } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn sync_data(&self) -> io::Result<()> { - self.inner.datasync() - } - - /// Truncates or extends the underlying file, updating the size of - /// this file to become `size`. - /// - /// If the `size` is less than the current file's size, then the file will - /// be shrunk. If it is greater than the current file's size, then the file - /// will be extended to `size` and have all of the intermediate data filled - /// in with 0s. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = try!(File::open("foo.txt")); - /// try!(f.set_len(0)); - /// # Ok(()) - /// # } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_len(&self, size: u64) -> io::Result<()> { - self.inner.truncate(size) - } - - /// Queries metadata about the underlying file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = try!(File::open("foo.txt")); - /// let metadata = try!(f.metadata()); - /// # Ok(()) - /// # } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn metadata(&self) -> io::Result { - self.inner.file_attr().map(Metadata) - } -} - -impl AsInner for File { - fn as_inner(&self) -> &fs_imp::File { &self.inner } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for File { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for File { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(buf) - } - fn flush(&mut self) -> io::Result<()> { self.inner.flush() } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Seek for File { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.inner.seek(pos) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Read for &'a File { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Write for &'a File { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(buf) - } - fn flush(&mut self) -> io::Result<()> { self.inner.flush() } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Seek for &'a File { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.inner.seek(pos) - } -} - -impl OpenOptions { - /// Creates a blank net set of options ready for configuration. - /// - /// All options are initially set to `false`. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> OpenOptions { - OpenOptions(fs_imp::OpenOptions::new()) - } - - /// Set the option for read access. - /// - /// This option, when true, will indicate that the file should be - /// `read`-able if opened. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn read(&mut self, read: bool) -> &mut OpenOptions { - self.0.read(read); self - } - - /// Set the option for write access. - /// - /// This option, when true, will indicate that the file should be - /// `write`-able if opened. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn write(&mut self, write: bool) -> &mut OpenOptions { - self.0.write(write); self - } - - /// Set the option for the append mode. - /// - /// This option, when true, means that writes will append to a file instead - /// of overwriting previous contents. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn append(&mut self, append: bool) -> &mut OpenOptions { - self.0.append(append); self - } - - /// Set the option for truncating a previous file. - /// - /// If a file is successfully opened with this option set it will truncate - /// the file to 0 length if it already exists. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions { - self.0.truncate(truncate); self - } - - /// Set the option for creating a new file. - /// - /// This option indicates whether a new file will be created if the file - /// does not yet already exist. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn create(&mut self, create: bool) -> &mut OpenOptions { - self.0.create(create); self - } - - /// Open a file at `path` with the options specified by `self`. - /// - /// # Errors - /// - /// This function will return an error under a number of different - /// circumstances, to include but not limited to: - /// - /// * Opening a file that does not exist with read access. - /// * Attempting to open a file with access that the user lacks - /// permissions for - /// * Filesystem-level errors (full disk, etc) - #[stable(feature = "rust1", since = "1.0.0")] - pub fn open>(&self, path: P) -> io::Result { - let path = path.as_ref(); - let inner = try!(fs_imp::File::open(path, &self.0)); - Ok(File { path: path.to_path_buf(), inner: inner }) - } -} - -impl AsInnerMut for OpenOptions { - fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 } -} - -impl Metadata { - /// Returns whether this metadata is for a directory. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_dir(&self) -> bool { self.0.is_dir() } - - /// Returns whether this metadata is for a regular file. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_file(&self) -> bool { self.0.is_file() } - - /// Returns the size of the file, in bytes, this metadata is for. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn len(&self) -> u64 { self.0.size() } - - /// Returns the permissions of the file this metadata is for. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn permissions(&self) -> Permissions { - Permissions(self.0.perm()) - } - - /// Returns the most recent access time for a file. - /// - /// The return value is in milliseconds since the epoch. - #[unstable(feature = "fs_time", - reason = "the return type of u64 is not quite appropriate for \ - this method and may change if the standard library \ - gains a type to represent a moment in time")] - pub fn accessed(&self) -> u64 { self.0.accessed() } - - /// Returns the most recent modification time for a file. - /// - /// The return value is in milliseconds since the epoch. - #[unstable(feature = "fs_time", - reason = "the return type of u64 is not quite appropriate for \ - this method and may change if the standard library \ - gains a type to represent a moment in time")] - pub fn modified(&self) -> u64 { self.0.modified() } -} - -impl Permissions { - /// Returns whether these permissions describe a readonly file. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn readonly(&self) -> bool { self.0.readonly() } - - /// Modify the readonly flag for this set of permissions. - /// - /// This operation does **not** modify the filesystem. To modify the - /// filesystem use the `fs::set_permissions` function. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_readonly(&mut self, readonly: bool) { - self.0.set_readonly(readonly) - } -} - -impl FromInner for Permissions { - fn from_inner(f: fs_imp::FilePermissions) -> Permissions { - Permissions(f) - } -} - -impl AsInner for Permissions { - fn as_inner(&self) -> &fs_imp::FilePermissions { &self.0 } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for ReadDir { - type Item = io::Result; - - fn next(&mut self) -> Option> { - self.0.next().map(|entry| entry.map(DirEntry)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DirEntry { - /// Returns the full path to the file that this entry represents. - /// - /// The full path is created by joining the original path to `read_dir` or - /// `walk_dir` with the filename of this entry. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn path(&self) -> PathBuf { self.0.path() } -} - -/// Remove a file from the underlying filesystem. -/// -/// # Examples -/// -/// ```rust,no_run -/// use std::fs; -/// -/// fs::remove_file("/some/file/path.txt"); -/// ``` -/// -/// Note that, just because an unlink call was successful, it is not -/// guaranteed that a file is immediately deleted (e.g. depending on -/// platform, other open file descriptors may prevent immediate removal). -/// -/// # Errors -/// -/// This function will return an error if `path` points to a directory, if the -/// user lacks permissions to remove the file, or if some other filesystem-level -/// error occurs. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn remove_file>(path: P) -> io::Result<()> { - fs_imp::unlink(path.as_ref()) -} - -/// Given a path, query the file system to get information about a file, -/// directory, etc. -/// -/// This function will traverse soft links to query information about the -/// destination file. -/// -/// # Examples -/// -/// ```rust,no_run -/// # fn foo() -> std::io::Result<()> { -/// use std::fs; -/// -/// let attr = try!(fs::metadata("/some/file/path.txt")); -/// // inspect attr ... -/// # Ok(()) -/// # } -/// ``` -/// -/// # Errors -/// -/// This function will return an error if the user lacks the requisite -/// permissions to perform a `metadata` call on the given `path` or if there -/// is no entry in the filesystem at the provided path. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn metadata>(path: P) -> io::Result { - fs_imp::stat(path.as_ref()).map(Metadata) -} - -/// Rename a file or directory to a new name. -/// -/// # Examples -/// -/// ```rust,no_run -/// use std::fs; -/// -/// fs::rename("foo", "bar"); -/// ``` -/// -/// # Errors -/// -/// This function will return an error if the provided `from` doesn't exist, if -/// the process lacks permissions to view the contents, if `from` and `to` -/// reside on separate filesystems, or if some other intermittent I/O error -/// occurs. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> { - fs_imp::rename(from.as_ref(), to.as_ref()) -} - -/// Copies the contents of one file to another. This function will also -/// copy the permission bits of the original file to the destination file. -/// -/// This function will **overwrite** the contents of `to`. -/// -/// Note that if `from` and `to` both point to the same file, then the file -/// will likely get truncated by this operation. -/// -/// # Examples -/// -/// ``` -/// use std::fs; -/// -/// fs::copy("foo.txt", "bar.txt"); -/// ``` -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The `from` path is not a file -/// * The `from` file does not exist -/// * The current process does not have the permission rights to access -/// `from` or write `to` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { - let from = from.as_ref(); - let to = to.as_ref(); - if !from.is_file() { - return Err(Error::new(ErrorKind::InvalidInput, - "the source path is not an existing file", - None)) - } - - let mut reader = try!(File::open(from)); - let mut writer = try!(File::create(to)); - let perm = try!(reader.metadata()).permissions(); - - let ret = try!(io::copy(&mut reader, &mut writer)); - try!(set_permissions(to, perm)); - Ok(ret) -} - -/// Creates a new hard link on the filesystem. -/// -/// The `dst` path will be a link pointing to the `src` path. Note that systems -/// often require these two paths to both be located on the same filesystem. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn hard_link, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { - fs_imp::link(src.as_ref(), dst.as_ref()) -} - -/// Creates a new soft link on the filesystem. -/// -/// The `dst` path will be a soft link pointing to the `src` path. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { - fs_imp::symlink(src.as_ref(), dst.as_ref()) -} - -/// Reads a soft link, returning the file that the link points to. -/// -/// # Errors -/// -/// This function will return an error on failure. Failure conditions include -/// reading a file that does not exist or reading a file that is not a soft -/// link. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn read_link>(path: P) -> io::Result { - fs_imp::readlink(path.as_ref()) -} - -/// Create a new, empty directory at the provided path -/// -/// # Examples -/// -/// ``` -/// use std::fs; -/// -/// fs::create_dir("/some/dir"); -/// ``` -/// -/// # Errors -/// -/// This function will return an error if the user lacks permissions to make a -/// new directory at the provided `path`, or if the directory already exists. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn create_dir>(path: P) -> io::Result<()> { - fs_imp::mkdir(path.as_ref()) -} - -/// Recursively create a directory and all of its parent components if they -/// are missing. -/// -/// # Errors -/// -/// This function will fail if any directory in the path specified by `path` -/// does not already exist and it could not be created otherwise. The specific -/// error conditions for when a directory is being created (after it is -/// determined to not exist) are outlined by `fs::create_dir`. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn create_dir_all>(path: P) -> io::Result<()> { - let path = path.as_ref(); - if path == Path::new("") || path.is_dir() { return Ok(()) } - if let Some(p) = path.parent() { try!(create_dir_all(p)) } - create_dir(path) -} - -/// Remove an existing, empty directory -/// -/// # Examples -/// -/// ``` -/// use std::fs; -/// -/// fs::remove_dir("/some/dir"); -/// ``` -/// -/// # Errors -/// -/// This function will return an error if the user lacks permissions to remove -/// the directory at the provided `path`, or if the directory isn't empty. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn remove_dir>(path: P) -> io::Result<()> { - fs_imp::rmdir(path.as_ref()) -} - -/// Removes a directory at this path, after removing all its contents. Use -/// carefully! -/// -/// This function does **not** follow soft links and it will simply remove the -/// soft link itself. -/// -/// # Errors -/// -/// See `file::remove_file` and `fs::remove_dir` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn remove_dir_all>(path: P) -> io::Result<()> { - let path = path.as_ref(); - for child in try!(read_dir(path)) { - let child = try!(child).path(); - let stat = try!(lstat(&*child)); - if stat.is_dir() { - try!(remove_dir_all(&*child)); - } else { - try!(remove_file(&*child)); - } - } - return remove_dir(path); - - #[cfg(unix)] - fn lstat(path: &Path) -> io::Result { fs_imp::lstat(path) } - #[cfg(windows)] - fn lstat(path: &Path) -> io::Result { fs_imp::stat(path) } -} - -/// Returns an iterator over the entries within a directory. -/// -/// The iterator will yield instances of `io::Result`. New errors may -/// be encountered after an iterator is initially constructed. -/// -/// # Examples -/// -/// ``` -/// # #![feature(path_ext)] -/// use std::io; -/// use std::fs::{self, PathExt, DirEntry}; -/// use std::path::Path; -/// -/// // one possible implementation of fs::walk_dir only visiting files -/// fn visit_dirs(dir: &Path, cb: &mut FnMut(DirEntry)) -> io::Result<()> { -/// if dir.is_dir() { -/// for entry in try!(fs::read_dir(dir)) { -/// let entry = try!(entry); -/// if entry.path().is_dir() { -/// try!(visit_dirs(&entry.path(), cb)); -/// } else { -/// cb(entry); -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -/// -/// # Errors -/// -/// This function will return an error if the provided `path` doesn't exist, if -/// the process lacks permissions to view the contents or if the `path` points -/// at a non-directory file -#[stable(feature = "rust1", since = "1.0.0")] -pub fn read_dir>(path: P) -> io::Result { - fs_imp::readdir(path.as_ref()).map(ReadDir) -} - -/// Returns an iterator that will recursively walk the directory structure -/// rooted at `path`. -/// -/// The path given will not be iterated over, and this will perform iteration in -/// some top-down order. The contents of unreadable subdirectories are ignored. -/// -/// The iterator will yield instances of `io::Result`. New errors may -/// be encountered after an iterator is initially constructed. -#[unstable(feature = "fs_walk", - reason = "the precise semantics and defaults for a recursive walk \ - may change and this may end up accounting for files such \ - as symlinks differently")] -pub fn walk_dir>(path: P) -> io::Result { - let start = try!(read_dir(path)); - Ok(WalkDir { cur: Some(start), stack: Vec::new() }) -} - -#[unstable(feature = "fs_walk")] -impl Iterator for WalkDir { - type Item = io::Result; - - fn next(&mut self) -> Option> { - loop { - if let Some(ref mut cur) = self.cur { - match cur.next() { - Some(Err(e)) => return Some(Err(e)), - Some(Ok(next)) => { - let path = next.path(); - if path.is_dir() { - self.stack.push(read_dir(&*path)); - } - return Some(Ok(next)) - } - None => {} - } - } - self.cur = None; - match self.stack.pop() { - Some(Err(e)) => return Some(Err(e)), - Some(Ok(next)) => self.cur = Some(next), - None => return None, - } - } - } -} - -/// Utility methods for paths. -#[unstable(feature = "path_ext", - reason = "the precise set of methods exposed on this trait may \ - change and some methods may be removed")] -pub trait PathExt { - /// Get information on the file, directory, etc at this path. - /// - /// Consult the `fs::stat` documentation for more info. - /// - /// This call preserves identical runtime/error semantics with `file::stat`. - fn metadata(&self) -> io::Result; - - /// Boolean value indicator whether the underlying file exists on the local - /// filesystem. Returns false in exactly the cases where `fs::stat` fails. - fn exists(&self) -> bool; - - /// Whether the underlying implementation (be it a file path, or something - /// else) points at a "regular file" on the FS. Will return false for paths - /// to non-existent locations or directories or other non-regular files - /// (named pipes, etc). Follows links when making this determination. - fn is_file(&self) -> bool; - - /// Whether the underlying implementation (be it a file path, or something - /// else) is pointing at a directory in the underlying FS. Will return - /// false for paths to non-existent locations or if the item is not a - /// directory (eg files, named pipes, etc). Follows links when making this - /// determination. - fn is_dir(&self) -> bool; -} - -impl PathExt for Path { - fn metadata(&self) -> io::Result { metadata(self) } - - fn exists(&self) -> bool { metadata(self).is_ok() } - - fn is_file(&self) -> bool { - metadata(self).map(|s| s.is_file()).unwrap_or(false) - } - fn is_dir(&self) -> bool { - metadata(self).map(|s| s.is_dir()).unwrap_or(false) - } -} - -/// Changes the timestamps for a file's last modification and access time. -/// -/// The file at the path specified will have its last access time set to -/// `atime` and its modification time set to `mtime`. The times specified should -/// be in milliseconds. -#[unstable(feature = "fs_time", - reason = "the argument type of u64 is not quite appropriate for \ - this function and may change if the standard library \ - gains a type to represent a moment in time")] -pub fn set_file_times>(path: P, accessed: u64, - modified: u64) -> io::Result<()> { - fs_imp::utimes(path.as_ref(), accessed, modified) -} - -/// Changes the permissions found on a file or a directory. -/// -/// # Examples -/// -/// ``` -/// # #![feature(fs)] -/// # fn foo() -> std::io::Result<()> { -/// use std::fs; -/// -/// let mut perms = try!(fs::metadata("foo.txt")).permissions(); -/// perms.set_readonly(true); -/// try!(fs::set_permissions("foo.txt", perms)); -/// # Ok(()) -/// # } -/// ``` -/// -/// # Errors -/// -/// This function will return an error if the provided `path` doesn't exist, if -/// the process lacks permissions to change the attributes of the file, or if -/// some other I/O error is encountered. -#[unstable(feature = "fs", - reason = "a more granual ability to set specific permissions may \ - be exposed on the Permissions structure itself and this \ - method may not always exist")] -pub fn set_permissions>(path: P, perm: Permissions) -> io::Result<()> { - fs_imp::set_perm(path.as_ref(), perm.0) -} - -#[cfg(test)] -mod tests { - #![allow(deprecated)] //rand - - use prelude::v1::*; - use io::prelude::*; - - use env; - use fs::{self, File, OpenOptions}; - use io::{ErrorKind, SeekFrom}; - use path::PathBuf; - use path::Path as Path2; - use os; - use rand::{self, StdRng, Rng}; - use str; - - macro_rules! check { ($e:expr) => ( - match $e { - Ok(t) => t, - Err(e) => panic!("{} failed with: {}", stringify!($e), e), - } - ) } - - macro_rules! error { ($e:expr, $s:expr) => ( - match $e { - Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), - Err(ref err) => assert!(err.to_string().contains($s), - format!("`{}` did not contain `{}`", err, $s)) - } - ) } - - pub struct TempDir(PathBuf); - - impl TempDir { - fn join(&self, path: &str) -> PathBuf { - let TempDir(ref p) = *self; - p.join(path) - } - - fn path<'a>(&'a self) -> &'a Path2 { - let TempDir(ref p) = *self; - p - } - } - - impl Drop for TempDir { - fn drop(&mut self) { - // Gee, seeing how we're testing the fs module I sure hope that we - // at least implement this correctly! - let TempDir(ref p) = *self; - check!(fs::remove_dir_all(p)); - } - } - - pub fn tmpdir() -> TempDir { - let p = env::temp_dir(); - let ret = p.join(&format!("rust-{}", rand::random::())); - check!(fs::create_dir(&ret)); - TempDir(ret) - } - - #[test] - fn file_test_io_smoke_test() { - let message = "it's alright. have a good time"; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test.txt"); - { - let mut write_stream = check!(File::create(filename)); - check!(write_stream.write(message.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - let mut read_buf = [0; 1028]; - let read_str = match check!(read_stream.read(&mut read_buf)) { - -1|0 => panic!("shouldn't happen"), - n => str::from_utf8(&read_buf[..n]).unwrap().to_string() - }; - assert_eq!(read_str, message); - } - check!(fs::remove_file(filename)); - } - - #[test] - fn invalid_path_raises() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_that_does_not_exist.txt"); - let result = File::open(filename); - - if cfg!(unix) { - error!(result, "o such file or directory"); - } - // error!(result, "couldn't open path as file"); - // error!(result, format!("path={}; mode=open; access=read", filename.display())); - } - - #[test] - fn file_test_iounlinking_invalid_path_should_raise_condition() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt"); - - let result = fs::remove_file(filename); - - if cfg!(unix) { - error!(result, "o such file or directory"); - } - // error!(result, "couldn't unlink path"); - // error!(result, format!("path={}", filename.display())); - } - - #[test] - fn file_test_io_non_positional_read() { - let message: &str = "ten-four"; - let mut read_mem = [0; 8]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_positional.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(message.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - { - let read_buf = &mut read_mem[0..4]; - check!(read_stream.read(read_buf)); - } - { - let read_buf = &mut read_mem[4..8]; - check!(read_stream.read(read_buf)); - } - } - check!(fs::remove_file(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert_eq!(read_str, message); - } - - #[test] - fn file_test_io_seek_and_tell_smoke_test() { - let message = "ten-four"; - let mut read_mem = [0; 4]; - let set_cursor = 4 as u64; - let mut tell_pos_pre_read; - let mut tell_pos_post_read; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(message.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - check!(read_stream.seek(SeekFrom::Start(set_cursor))); - tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0))); - check!(read_stream.read(&mut read_mem)); - tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0))); - } - check!(fs::remove_file(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert_eq!(read_str, &message[4..8]); - assert_eq!(tell_pos_pre_read, set_cursor); - assert_eq!(tell_pos_post_read, message.len() as u64); - } - - #[test] - fn file_test_io_seek_and_write() { - let initial_msg = "food-is-yummy"; - let overwrite_msg = "-the-bar!!"; - let final_msg = "foo-the-bar!!"; - let seek_idx = 3; - let mut read_mem = [0; 13]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(initial_msg.as_bytes())); - check!(rw_stream.seek(SeekFrom::Start(seek_idx))); - check!(rw_stream.write(overwrite_msg.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - check!(read_stream.read(&mut read_mem)); - } - check!(fs::remove_file(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert!(read_str == final_msg); - } - - #[test] - fn file_test_io_seek_shakedown() { - // 01234567890123 - let initial_msg = "qwer-asdf-zxcv"; - let chunk_one: &str = "qwer"; - let chunk_two: &str = "asdf"; - let chunk_three: &str = "zxcv"; - let mut read_mem = [0; 4]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(initial_msg.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - - check!(read_stream.seek(SeekFrom::End(-4))); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three); - - check!(read_stream.seek(SeekFrom::Current(-9))); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two); - - check!(read_stream.seek(SeekFrom::Start(0))); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one); - } - check!(fs::remove_file(filename)); - } - - #[test] - fn file_test_stat_is_correct_on_is_file() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_stat_correct_on_is_file.txt"); - { - let mut opts = OpenOptions::new(); - let mut fs = check!(opts.read(true).write(true) - .create(true).open(filename)); - let msg = "hw"; - fs.write(msg.as_bytes()).unwrap(); - - let fstat_res = check!(fs.metadata()); - assert!(fstat_res.is_file()); - } - let stat_res_fn = check!(fs::metadata(filename)); - assert!(stat_res_fn.is_file()); - let stat_res_meth = check!(filename.metadata()); - assert!(stat_res_meth.is_file()); - check!(fs::remove_file(filename)); - } - - #[test] - fn file_test_stat_is_correct_on_is_dir() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_stat_correct_on_is_dir"); - check!(fs::create_dir(filename)); - let stat_res_fn = check!(fs::metadata(filename)); - assert!(stat_res_fn.is_dir()); - let stat_res_meth = check!(filename.metadata()); - assert!(stat_res_meth.is_dir()); - check!(fs::remove_dir(filename)); - } - - #[test] - fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("fileinfo_false_on_dir"); - check!(fs::create_dir(dir)); - assert!(dir.is_file() == false); - check!(fs::remove_dir(dir)); - } - - #[test] - fn file_test_fileinfo_check_exists_before_and_after_file_creation() { - let tmpdir = tmpdir(); - let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt"); - check!(check!(File::create(file)).write(b"foo")); - assert!(file.exists()); - check!(fs::remove_file(file)); - assert!(!file.exists()); - } - - #[test] - fn file_test_directoryinfo_check_exists_before_and_after_mkdir() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("before_and_after_dir"); - assert!(!dir.exists()); - check!(fs::create_dir(dir)); - assert!(dir.exists()); - assert!(dir.is_dir()); - check!(fs::remove_dir(dir)); - assert!(!dir.exists()); - } - - #[test] - fn file_test_directoryinfo_readdir() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("di_readdir"); - check!(fs::create_dir(dir)); - let prefix = "foo"; - for n in 0..3 { - let f = dir.join(&format!("{}.txt", n)); - let mut w = check!(File::create(&f)); - let msg_str = format!("{}{}", prefix, n.to_string()); - let msg = msg_str.as_bytes(); - check!(w.write(msg)); - } - let files = check!(fs::read_dir(dir)); - let mut mem = [0; 4]; - for f in files { - let f = f.unwrap().path(); - { - let n = f.file_stem().unwrap(); - check!(check!(File::open(&f)).read(&mut mem)); - let read_str = str::from_utf8(&mem).unwrap(); - let expected = format!("{}{}", prefix, n.to_str().unwrap()); - assert_eq!(expected, read_str); - } - check!(fs::remove_file(&f)); - } - check!(fs::remove_dir(dir)); - } - - #[test] - fn file_test_walk_dir() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("walk_dir"); - check!(fs::create_dir(dir)); - - let dir1 = &dir.join("01/02/03"); - check!(fs::create_dir_all(dir1)); - check!(File::create(&dir1.join("04"))); - - let dir2 = &dir.join("11/12/13"); - check!(fs::create_dir_all(dir2)); - check!(File::create(&dir2.join("14"))); - - let files = check!(fs::walk_dir(dir)); - let mut cur = [0; 2]; - for f in files { - let f = f.unwrap().path(); - let stem = f.file_stem().unwrap().to_str().unwrap(); - let root = stem.as_bytes()[0] - b'0'; - let name = stem.as_bytes()[1] - b'0'; - assert!(cur[root as usize] < name); - cur[root as usize] = name; - } - - check!(fs::remove_dir_all(dir)); - } - - #[test] - fn mkdir_path_already_exists_error() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("mkdir_error_twice"); - check!(fs::create_dir(dir)); - let e = fs::create_dir(dir).err().unwrap(); - assert_eq!(e.kind(), ErrorKind::AlreadyExists); - } - - #[test] - fn recursive_mkdir() { - let tmpdir = tmpdir(); - let dir = tmpdir.join("d1/d2"); - check!(fs::create_dir_all(&dir)); - assert!(dir.is_dir()) - } - - #[test] - fn recursive_mkdir_failure() { - let tmpdir = tmpdir(); - let dir = tmpdir.join("d1"); - let file = dir.join("f1"); - - check!(fs::create_dir_all(&dir)); - check!(File::create(&file)); - - let result = fs::create_dir_all(&file); - - assert!(result.is_err()); - // error!(result, "couldn't recursively mkdir"); - // error!(result, "couldn't create directory"); - // error!(result, "mode=0700"); - // error!(result, format!("path={}", file.display())); - } - - #[test] - fn recursive_mkdir_slash() { - check!(fs::create_dir_all(&Path2::new("/"))); - } - - // FIXME(#12795) depends on lstat to work on windows - #[cfg(not(windows))] - #[test] - fn recursive_rmdir() { - let tmpdir = tmpdir(); - let d1 = tmpdir.join("d1"); - let dt = d1.join("t"); - let dtt = dt.join("t"); - let d2 = tmpdir.join("d2"); - let canary = d2.join("do_not_delete"); - check!(fs::create_dir_all(&dtt)); - check!(fs::create_dir_all(&d2)); - check!(check!(File::create(&canary)).write(b"foo")); - check!(fs::soft_link(&d2, &dt.join("d2"))); - check!(fs::remove_dir_all(&d1)); - - assert!(!d1.is_dir()); - assert!(canary.exists()); - } - - #[test] - fn unicode_path_is_dir() { - assert!(Path2::new(".").is_dir()); - assert!(!Path2::new("test/stdtest/fs.rs").is_dir()); - - let tmpdir = tmpdir(); - - let mut dirpath = tmpdir.path().to_path_buf(); - dirpath.push(&format!("test-가一ー你好")); - check!(fs::create_dir(&dirpath)); - assert!(dirpath.is_dir()); - - let mut filepath = dirpath; - filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs"); - check!(File::create(&filepath)); // ignore return; touch only - assert!(!filepath.is_dir()); - assert!(filepath.exists()); - } - - #[test] - fn unicode_path_exists() { - assert!(Path2::new(".").exists()); - assert!(!Path2::new("test/nonexistent-bogus-path").exists()); - - let tmpdir = tmpdir(); - let unicode = tmpdir.path(); - let unicode = unicode.join(&format!("test-각丁ー再见")); - check!(fs::create_dir(&unicode)); - assert!(unicode.exists()); - assert!(!Path2::new("test/unicode-bogus-path-각丁ー再见").exists()); - } - - #[test] - fn copy_file_does_not_exist() { - let from = Path2::new("test/nonexistent-bogus-path"); - let to = Path2::new("test/other-bogus-path"); - - match fs::copy(&from, &to) { - Ok(..) => panic!(), - Err(..) => { - assert!(!from.exists()); - assert!(!to.exists()); - } - } - } - - #[test] - fn copy_file_ok() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(check!(File::create(&input)).write(b"hello")); - check!(fs::copy(&input, &out)); - let mut v = Vec::new(); - check!(check!(File::open(&out)).read_to_end(&mut v)); - assert_eq!(v.as_slice(), b"hello"); - - assert_eq!(check!(input.metadata()).permissions(), - check!(out.metadata()).permissions()); - } - - #[test] - fn copy_file_dst_dir() { - let tmpdir = tmpdir(); - let out = tmpdir.join("out"); - - check!(File::create(&out)); - match fs::copy(&*out, tmpdir.path()) { - Ok(..) => panic!(), Err(..) => {} - } - } - - #[test] - fn copy_file_dst_exists() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in"); - let output = tmpdir.join("out"); - - check!(check!(File::create(&input)).write("foo".as_bytes())); - check!(check!(File::create(&output)).write("bar".as_bytes())); - check!(fs::copy(&input, &output)); - - let mut v = Vec::new(); - check!(check!(File::open(&output)).read_to_end(&mut v)); - assert_eq!(v, b"foo".to_vec()); - } - - #[test] - fn copy_file_src_dir() { - let tmpdir = tmpdir(); - let out = tmpdir.join("out"); - - match fs::copy(tmpdir.path(), &out) { - Ok(..) => panic!(), Err(..) => {} - } - assert!(!out.exists()); - } - - #[test] - fn copy_file_preserves_perm_bits() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - let attr = check!(check!(File::create(&input)).metadata()); - let mut p = attr.permissions(); - p.set_readonly(true); - check!(fs::set_permissions(&input, p)); - check!(fs::copy(&input, &out)); - assert!(check!(out.metadata()).permissions().readonly()); - check!(fs::set_permissions(&input, attr.permissions())); - check!(fs::set_permissions(&out, attr.permissions())); - } - - #[cfg(not(windows))] // FIXME(#10264) operation not permitted? - #[test] - fn symlinks_work() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(check!(File::create(&input)).write("foobar".as_bytes())); - check!(fs::soft_link(&input, &out)); - // if cfg!(not(windows)) { - // assert_eq!(check!(lstat(&out)).kind, FileType::Symlink); - // assert_eq!(check!(out.lstat()).kind, FileType::Symlink); - // } - assert_eq!(check!(fs::metadata(&out)).len(), - check!(fs::metadata(&input)).len()); - let mut v = Vec::new(); - check!(check!(File::open(&out)).read_to_end(&mut v)); - assert_eq!(v, b"foobar".to_vec()); - } - - #[cfg(not(windows))] // apparently windows doesn't like symlinks - #[test] - fn symlink_noexist() { - let tmpdir = tmpdir(); - // symlinks can point to things that don't exist - check!(fs::soft_link(&tmpdir.join("foo"), &tmpdir.join("bar"))); - assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))), - tmpdir.join("foo")); - } - - #[test] - fn readlink_not_symlink() { - let tmpdir = tmpdir(); - match fs::read_link(tmpdir.path()) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn links_work() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(check!(File::create(&input)).write("foobar".as_bytes())); - check!(fs::hard_link(&input, &out)); - assert_eq!(check!(fs::metadata(&out)).len(), - check!(fs::metadata(&input)).len()); - assert_eq!(check!(fs::metadata(&out)).len(), - check!(input.metadata()).len()); - let mut v = Vec::new(); - check!(check!(File::open(&out)).read_to_end(&mut v)); - assert_eq!(v, b"foobar".to_vec()); - - // can't link to yourself - match fs::hard_link(&input, &input) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - // can't link to something that doesn't exist - match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn chmod_works() { - let tmpdir = tmpdir(); - let file = tmpdir.join("in.txt"); - - check!(File::create(&file)); - let attr = check!(fs::metadata(&file)); - assert!(!attr.permissions().readonly()); - let mut p = attr.permissions(); - p.set_readonly(true); - check!(fs::set_permissions(&file, p.clone())); - let attr = check!(fs::metadata(&file)); - assert!(attr.permissions().readonly()); - - match fs::set_permissions(&tmpdir.join("foo"), p.clone()) { - Ok(..) => panic!("wanted an error"), - Err(..) => {} - } - - p.set_readonly(false); - check!(fs::set_permissions(&file, p)); - } - - #[test] - fn sync_doesnt_kill_anything() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let mut file = check!(File::create(&path)); - check!(file.sync_all()); - check!(file.sync_data()); - check!(file.write(b"foo")); - check!(file.sync_all()); - check!(file.sync_data()); - } - - #[test] - fn truncate_works() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let mut file = check!(File::create(&path)); - check!(file.write(b"foo")); - check!(file.sync_all()); - - // Do some simple things with truncation - assert_eq!(check!(file.metadata()).len(), 3); - check!(file.set_len(10)); - assert_eq!(check!(file.metadata()).len(), 10); - check!(file.write(b"bar")); - check!(file.sync_all()); - assert_eq!(check!(file.metadata()).len(), 10); - - let mut v = Vec::new(); - check!(check!(File::open(&path)).read_to_end(&mut v)); - assert_eq!(v, b"foobar\0\0\0\0".to_vec()); - - // Truncate to a smaller length, don't seek, and then write something. - // Ensure that the intermediate zeroes are all filled in (we have `seek`ed - // past the end of the file). - check!(file.set_len(2)); - assert_eq!(check!(file.metadata()).len(), 2); - check!(file.write(b"wut")); - check!(file.sync_all()); - assert_eq!(check!(file.metadata()).len(), 9); - let mut v = Vec::new(); - check!(check!(File::open(&path)).read_to_end(&mut v)); - assert_eq!(v, b"fo\0\0\0\0wut".to_vec()); - } - - #[test] - fn open_flavors() { - use fs::OpenOptions as OO; - fn c(t: &T) -> T { t.clone() } - - let tmpdir = tmpdir(); - - let mut r = OO::new(); r.read(true); - let mut w = OO::new(); w.write(true); - let mut rw = OO::new(); rw.write(true).read(true); - - match r.open(&tmpdir.join("a")) { - Ok(..) => panic!(), Err(..) => {} - } - - // Perform each one twice to make sure that it succeeds the second time - // (where the file exists) - check!(c(&w).create(true).open(&tmpdir.join("b"))); - assert!(tmpdir.join("b").exists()); - check!(c(&w).create(true).open(&tmpdir.join("b"))); - check!(w.open(&tmpdir.join("b"))); - - check!(c(&rw).create(true).open(&tmpdir.join("c"))); - assert!(tmpdir.join("c").exists()); - check!(c(&rw).create(true).open(&tmpdir.join("c"))); - check!(rw.open(&tmpdir.join("c"))); - - check!(c(&w).append(true).create(true).open(&tmpdir.join("d"))); - assert!(tmpdir.join("d").exists()); - check!(c(&w).append(true).create(true).open(&tmpdir.join("d"))); - check!(c(&w).append(true).open(&tmpdir.join("d"))); - - check!(c(&rw).append(true).create(true).open(&tmpdir.join("e"))); - assert!(tmpdir.join("e").exists()); - check!(c(&rw).append(true).create(true).open(&tmpdir.join("e"))); - check!(c(&rw).append(true).open(&tmpdir.join("e"))); - - check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f"))); - assert!(tmpdir.join("f").exists()); - check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f"))); - check!(c(&w).truncate(true).open(&tmpdir.join("f"))); - - check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g"))); - assert!(tmpdir.join("g").exists()); - check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g"))); - check!(c(&rw).truncate(true).open(&tmpdir.join("g"))); - - check!(check!(File::create(&tmpdir.join("h"))).write("foo".as_bytes())); - check!(r.open(&tmpdir.join("h"))); - { - let mut f = check!(r.open(&tmpdir.join("h"))); - assert!(f.write("wut".as_bytes()).is_err()); - } - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); - { - let mut f = check!(c(&w).append(true).open(&tmpdir.join("h"))); - check!(f.write("bar".as_bytes())); - } - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6); - { - let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h"))); - check!(f.write("bar".as_bytes())); - } - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); - } - - #[test] - fn utime() { - let tmpdir = tmpdir(); - let path = tmpdir.join("a"); - check!(File::create(&path)); - // These numbers have to be bigger than the time in the day to account - // for timezones Windows in particular will fail in certain timezones - // with small enough values - check!(fs::set_file_times(&path, 100000, 200000)); - assert_eq!(check!(path.metadata()).accessed(), 100000); - assert_eq!(check!(path.metadata()).modified(), 200000); - } - - #[test] - fn utime_noexist() { - let tmpdir = tmpdir(); - - match fs::set_file_times(&tmpdir.join("a"), 100, 200) { - Ok(..) => panic!(), - Err(..) => {} - } - } - - #[test] - fn binary_file() { - let mut bytes = [0; 1024]; - StdRng::new().unwrap().fill_bytes(&mut bytes); - - let tmpdir = tmpdir(); - - check!(check!(File::create(&tmpdir.join("test"))).write(&bytes)); - let mut v = Vec::new(); - check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v)); - assert!(v == bytes.as_slice()); - } - - #[test] - #[cfg(not(windows))] - fn unlink_readonly() { - let tmpdir = tmpdir(); - let path = tmpdir.join("file"); - check!(File::create(&path)); - let mut perm = check!(fs::metadata(&path)).permissions(); - perm.set_readonly(true); - check!(fs::set_permissions(&path, perm)); - check!(fs::remove_file(&path)); - } - - #[test] - fn mkdir_trailing_slash() { - let tmpdir = tmpdir(); - let path = tmpdir.join("file"); - check!(fs::create_dir_all(&path.join("a/"))); - } -} diff --git a/src/libstd/fs/tempdir.rs b/src/libstd/fs/tempdir.rs deleted file mode 100644 index 8cc1dde98a0..00000000000 --- a/src/libstd/fs/tempdir.rs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "tempdir", reason = "needs an RFC before stabilization")] -#![deprecated(since = "1.0.0", - reason = "use the `tempdir` crate from crates.io instead")] -#![allow(deprecated)] - -use prelude::v1::*; - -use env; -use io::{self, Error, ErrorKind}; -use fs; -use path::{self, PathBuf}; -use rand::{thread_rng, Rng}; - -/// A wrapper for a path to temporary directory implementing automatic -/// scope-based deletion. -pub struct TempDir { - path: Option, -} - -// How many times should we (re)try finding an unused random name? It should be -// enough that an attacker will run out of luck before we run out of patience. -const NUM_RETRIES: u32 = 1 << 31; -// How many characters should we include in a random file name? It needs to -// be enough to dissuade an attacker from trying to preemptively create names -// of that length, but not so huge that we unnecessarily drain the random number -// generator of entropy. -const NUM_RAND_CHARS: usize = 12; - -impl TempDir { - /// Attempts to make a temporary directory inside of `tmpdir` whose name - /// will have the prefix `prefix`. The directory will be automatically - /// deleted once the returned wrapper is destroyed. - /// - /// If no directory can be created, `Err` is returned. - #[allow(deprecated)] // rand usage - pub fn new_in>(tmpdir: P, prefix: &str) -> io::Result { - let storage; - let mut tmpdir = tmpdir.as_ref(); - if !tmpdir.is_absolute() { - let cur_dir = try!(env::current_dir()); - storage = cur_dir.join(tmpdir); - tmpdir = &storage; - // return TempDir::new_in(&cur_dir.join(tmpdir), prefix); - } - - let mut rng = thread_rng(); - for _ in 0..NUM_RETRIES { - let suffix: String = rng.gen_ascii_chars().take(NUM_RAND_CHARS).collect(); - let leaf = if prefix.len() > 0 { - format!("{}.{}", prefix, suffix) - } else { - // If we're given an empty string for a prefix, then creating a - // directory starting with "." would lead to it being - // semi-invisible on some systems. - suffix - }; - let path = tmpdir.join(&leaf); - match fs::create_dir(&path) { - Ok(_) => return Ok(TempDir { path: Some(path) }), - Err(ref e) if e.kind() == ErrorKind::AlreadyExists => {} - Err(e) => return Err(e) - } - } - - Err(Error::new(ErrorKind::AlreadyExists, - "too many temporary directories already exist", - None)) - } - - /// Attempts to make a temporary directory inside of `env::temp_dir()` whose - /// name will have the prefix `prefix`. The directory will be automatically - /// deleted once the returned wrapper is destroyed. - /// - /// If no directory can be created, `Err` is returned. - #[allow(deprecated)] - pub fn new(prefix: &str) -> io::Result { - TempDir::new_in(&env::temp_dir(), prefix) - } - - /// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper. - /// This discards the wrapper so that the automatic deletion of the - /// temporary directory is prevented. - pub fn into_path(mut self) -> PathBuf { - self.path.take().unwrap() - } - - /// Access the wrapped `std::path::Path` to the temporary directory. - pub fn path(&self) -> &path::Path { - self.path.as_ref().unwrap() - } - - /// Close and remove the temporary directory - /// - /// Although `TempDir` removes the directory on drop, in the destructor - /// any errors are ignored. To detect errors cleaning up the temporary - /// directory, call `close` instead. - pub fn close(mut self) -> io::Result<()> { - self.cleanup_dir() - } - - fn cleanup_dir(&mut self) -> io::Result<()> { - match self.path { - Some(ref p) => fs::remove_dir_all(p), - None => Ok(()) - } - } -} - -impl Drop for TempDir { - fn drop(&mut self) { - let _ = self.cleanup_dir(); - } -} - -// the tests for this module need to change the path using change_dir, -// and this doesn't play nicely with other tests so these unit tests are located -// in src/test/run-pass/tempfile.rs diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index d8e403376bd..ad81143b7b4 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -281,19 +281,19 @@ mod tests { #[test] fn test_slice_reader() { let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let mut reader = &mut in_buf.as_slice(); + let mut reader = &mut &in_buf[..]; let mut buf = []; assert_eq!(reader.read(&mut buf), Ok(0)); let mut buf = [0]; assert_eq!(reader.read(&mut buf), Ok(1)); assert_eq!(reader.len(), 7); let b: &[_] = &[0]; - assert_eq!(buf.as_slice(), b); + assert_eq!(&buf[..], b); let mut buf = [0; 4]; assert_eq!(reader.read(&mut buf), Ok(4)); assert_eq!(reader.len(), 3); let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf.as_slice(), b); + assert_eq!(&buf[..], b); assert_eq!(reader.read(&mut buf), Ok(3)); let b: &[_] = &[5, 6, 7]; assert_eq!(&buf[..3], b); @@ -303,7 +303,7 @@ mod tests { #[test] fn test_buf_reader() { let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let mut reader = Cursor::new(in_buf.as_slice()); + let mut reader = Cursor::new(&in_buf[..]); let mut buf = []; assert_eq!(reader.read(&mut buf), Ok(0)); assert_eq!(reader.position(), 0); diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index f445ace081e..615df771e9b 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -9,7 +9,6 @@ // except according to those terms. use boxed::Box; -use clone::Clone; use error; use fmt; use option::Option::{self, Some, None}; @@ -179,27 +178,6 @@ impl Error { Repr::Custom(ref c) => c.kind, } } - - /// Returns a short description for this error message - #[unstable(feature = "io")] - #[deprecated(since = "1.0.0", reason = "use the Error trait's description \ - method instead")] - pub fn description(&self) -> &str { - match self.repr { - Repr::Os(..) => "os error", - Repr::Custom(ref c) => c.desc, - } - } - - /// Returns a detailed error message for this error (if one is available) - #[unstable(feature = "io")] - #[deprecated(since = "1.0.0", reason = "use the to_string() method instead")] - pub fn detail(&self) -> Option { - match self.repr { - Repr::Os(code) => Some(sys::os::error_string(code)), - Repr::Custom(ref s) => s.detail.clone(), - } - } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b7cb8f9ed50..578e057cbb6 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -173,8 +173,6 @@ pub use core::clone; #[cfg(not(test))] pub use core::cmp; pub use core::convert; pub use core::default; -#[allow(deprecated)] -pub use core::finally; pub use core::hash; pub use core::intrinsics; pub use core::iter; diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 869faa795f9..9611e40e1e9 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -100,13 +100,6 @@ impl TcpStream { self.0.peer_addr() } - /// Returns the socket address of the local half of this TCP connection. - #[unstable(feature = "net")] - #[deprecated(since = "1.0.0", reason = "renamed to local_addr")] - pub fn socket_addr(&self) -> io::Result { - self.0.socket_addr() - } - /// Returns the socket address of the local half of this TCP connection. #[stable(feature = "rust1", since = "1.0.0")] pub fn local_addr(&self) -> io::Result { @@ -195,13 +188,6 @@ impl TcpListener { self.0.socket_addr() } - /// Deprecated, renamed to local_addr - #[unstable(feature = "net")] - #[deprecated(since = "1.0.0", reason = "renamed to local_addr")] - pub fn socket_addr(&self) -> io::Result { - self.0.socket_addr() - } - /// Create a new independently owned handle to the underlying socket. /// /// The returned `TcpListener` is a reference to the same socket that this @@ -349,7 +335,7 @@ mod tests { let _t = thread::spawn(move|| { let mut stream = t!(TcpStream::connect(&addr)); t!(stream.write(&[99])); - tx.send(t!(stream.socket_addr())).unwrap(); + tx.send(t!(stream.local_addr())).unwrap(); }); let (mut stream, addr) = t!(acceptor.accept()); @@ -499,7 +485,7 @@ mod tests { fn socket_and_peer_name_ip4() { each_ip(&mut |addr| { let listener = t!(TcpListener::bind(&addr)); - let so_name = t!(listener.socket_addr()); + let so_name = t!(listener.local_addr()); assert_eq!(addr, so_name); let _t = thread::spawn(move|| { t!(listener.accept()); diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 81151114962..85831c2de34 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -80,13 +80,6 @@ impl UdpSocket { } } - /// Returns the socket address that this socket was created from. - #[unstable(feature = "net")] - #[deprecated(since = "1.0.0", reason = "renamed to local_addr")] - pub fn socket_addr(&self) -> io::Result { - self.0.socket_addr() - } - /// Returns the socket address that this socket was created from. #[stable(feature = "rust1", since = "1.0.0")] pub fn local_addr(&self) -> io::Result { @@ -203,7 +196,7 @@ mod tests { fn socket_name_ip4() { each_ip(&mut |addr, _| { let server = t!(UdpSocket::bind(&addr)); - assert_eq!(addr, t!(server.socket_addr())); + assert_eq!(addr, t!(server.local_addr())); }) } diff --git a/src/libstd/old_io/fs.rs b/src/libstd/old_io/fs.rs index 6aa63c395c6..bef6ea53e50 100644 --- a/src/libstd/old_io/fs.rs +++ b/src/libstd/old_io/fs.rs @@ -951,7 +951,8 @@ mod test { pub fn tmpdir() -> TempDir { use os; use rand; - let ret = os::tmpdir().join(format!("rust-{}", rand::random::())); + let temp = Path::new(::env::temp_dir().to_str().unwrap()); + let ret = temp.join(format!("rust-{}", rand::random::())); check!(old_io::fs::mkdir(&ret, old_io::USER_RWX)); TempDir(ret) } @@ -1639,7 +1640,7 @@ mod test { check!(File::create(&tmpdir.join("test")).write(&bytes)); let actual = check!(File::open(&tmpdir.join("test")).read_to_end()); - assert!(actual == bytes.as_slice()); + assert!(actual == &bytes[..]); } #[test] diff --git a/src/libstd/old_io/mem.rs b/src/libstd/old_io/mem.rs index 64803191d4f..c92e74fbc56 100644 --- a/src/libstd/old_io/mem.rs +++ b/src/libstd/old_io/mem.rs @@ -399,7 +399,7 @@ impl<'a> Buffer for BufReader<'a> { mod test { extern crate test as test_crate; use old_io::{SeekSet, SeekCur, SeekEnd, Reader, Writer, Seek, Buffer}; - use prelude::v1::{Ok, Err, Vec, AsSlice}; + use prelude::v1::{Ok, Err, Vec}; use prelude::v1::Iterator; use old_io; use iter::repeat; @@ -744,7 +744,7 @@ mod test { wr.write(&[5; 10]).unwrap(); } } - assert_eq!(buf.as_slice(), [5; 100].as_slice()); + assert_eq!(&buf[..], &[5; 100][..]); }); } diff --git a/src/libstd/old_io/mod.rs b/src/libstd/old_io/mod.rs index df8ac78f7e5..9d7e1082d33 100644 --- a/src/libstd/old_io/mod.rs +++ b/src/libstd/old_io/mod.rs @@ -274,7 +274,7 @@ use mem::transmute; use ops::FnOnce; use option::Option; use option::Option::{Some, None}; -use os; +use sys::os; use boxed::Box; use result::Result; use result::Result::{Ok, Err}; diff --git a/src/libstd/old_io/pipe.rs b/src/libstd/old_io/pipe.rs index 26f24600479..fd1df49473e 100644 --- a/src/libstd/old_io/pipe.rs +++ b/src/libstd/old_io/pipe.rs @@ -124,9 +124,9 @@ mod test { use os; use old_io::pipe::PipeStream; - let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() }; - let out = PipeStream::open(writer); - let mut input = PipeStream::open(reader); + let (reader, writer) = unsafe { ::sys::os::pipe().unwrap() }; + let out = PipeStream::open(writer.unwrap()); + let mut input = PipeStream::open(reader.unwrap()); let (tx, rx) = channel(); let _t = thread::spawn(move|| { let mut out = out; diff --git a/src/libstd/old_io/process.rs b/src/libstd/old_io/process.rs index 06940bf6860..d0fa7dd6882 100644 --- a/src/libstd/old_io/process.rs +++ b/src/libstd/old_io/process.rs @@ -246,7 +246,7 @@ impl Command { None => { // if the env is currently just inheriting from the parent's, // materialize the parent's env into a hashtable. - self.env = Some(os::env_as_bytes().into_iter().map(|(k, v)| { + self.env = Some(::env::vars().map(|(k, v)| { (EnvKey(CString::new(k).unwrap()), CString::new(v).unwrap()) }).collect()); @@ -764,11 +764,9 @@ impl Drop for Process { #[cfg(test)] mod tests { + use prelude::v1::*; use old_io::{Truncate, Write, TimedOut, timer, process, FileNotFound}; use old_io::{Reader, Writer}; - use prelude::v1::{Ok, Err, drop, Some, None, Vec}; - use prelude::v1::{String, Clone}; - use prelude::v1::{Str, AsSlice, ToString}; use old_path::{GenericPath, Path}; use old_io::fs::PathExtensions; use old_io::timer::*; @@ -1003,7 +1001,7 @@ mod tests { let prog = pwd_cmd().spawn().unwrap(); let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap(); - let parent_dir = os::getcwd().unwrap(); + let parent_dir = Path::new(::env::current_dir().unwrap().to_str().unwrap()); let child_dir = Path::new(output.trim()); let parent_stat = parent_dir.stat().unwrap(); @@ -1018,7 +1016,7 @@ mod tests { use os; // test changing to the parent of os::getcwd() because we know // the path exists (and os::getcwd() is not expected to be root) - let parent_dir = os::getcwd().unwrap().dir_path(); + let parent_dir = Path::new(::env::current_dir().unwrap().to_str().unwrap()); let prog = pwd_cmd().cwd(&parent_dir).spawn().unwrap(); let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap(); @@ -1058,11 +1056,11 @@ mod tests { let prog = env_cmd().spawn().unwrap(); let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap(); - let r = os::env(); - for &(ref k, ref v) in &r { + let r = ::env::vars(); + for (k, v) in r { // don't check windows magical empty-named variables assert!(k.is_empty() || - output.contains(&format!("{}={}", *k, *v)), + output.contains(&format!("{}={}", k, v)), "output doesn't contain `{}={}`\n{}", k, v, output); } @@ -1076,16 +1074,12 @@ mod tests { let mut prog = env_cmd().spawn().unwrap(); let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap(); - let r = os::env(); - for &(ref k, ref v) in &r { + let r = env::vars(); + for (k, v) in r { // don't check android RANDOM variables - if *k != "RANDOM".to_string() { - assert!(output.contains(&format!("{}={}", - *k, - *v)) || - output.contains(&format!("{}=\'{}\'", - *k, - *v))); + if k != "RANDOM".to_string() { + assert!(output.contains(&format!("{}={}", k, v)) || + output.contains(&format!("{}=\'{}\'", k, v))); } } } @@ -1100,9 +1094,9 @@ mod tests { // PATH to our sub-process. let path_val: String; let mut new_env = vec![("RUN_TEST_NEW_ENV", "123")]; - match os::getenv("PATH") { - None => {} - Some(val) => { + match ::env::var("PATH") { + Err(..) => {} + Ok(val) => { path_val = val; new_env.push(("PATH", &path_val)) } diff --git a/src/libstd/old_io/tempfile.rs b/src/libstd/old_io/tempfile.rs index 0a2cc517a06..94faa5540bb 100644 --- a/src/libstd/old_io/tempfile.rs +++ b/src/libstd/old_io/tempfile.rs @@ -100,7 +100,8 @@ impl TempDir { #[allow(deprecated)] pub fn new_in(tmpdir: &Path, prefix: &str) -> IoResult { if !tmpdir.is_absolute() { - let cur_dir = try!(::os::getcwd()); + let cur_dir = ::env::current_dir().unwrap(); + let cur_dir = Path::new(cur_dir.to_str().unwrap()); return TempDir::new_in(&cur_dir.join(tmpdir), prefix); } @@ -136,7 +137,8 @@ impl TempDir { /// If no directory can be created, `Err` is returned. #[allow(deprecated)] pub fn new(prefix: &str) -> IoResult { - TempDir::new_in(&::os::tmpdir(), prefix) + let tmp = Path::new(::env::temp_dir().to_str().unwrap()); + TempDir::new_in(&tmp, prefix) } /// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper. diff --git a/src/libstd/old_io/test.rs b/src/libstd/old_io/test.rs index db409ecde45..8c46e2c06b8 100644 --- a/src/libstd/old_io/test.rs +++ b/src/libstd/old_io/test.rs @@ -43,7 +43,7 @@ fn next_test_unix_socket() -> String { pub fn next_test_unix() -> Path { let string = next_test_unix_socket(); if cfg!(unix) { - ::os::tmpdir().join(string) + Path::new(::env::temp_dir().to_str().unwrap()).join(string) } else { Path::new(format!("{}{}", r"\\.\pipe\", string)) } diff --git a/src/libstd/old_path/mod.rs b/src/libstd/old_path/mod.rs index c405df2824e..9c88533d3ba 100644 --- a/src/libstd/old_path/mod.rs +++ b/src/libstd/old_path/mod.rs @@ -69,12 +69,13 @@ use core::marker::Sized; use ffi::CString; use clone::Clone; +use borrow::Cow; use fmt; use iter::Iterator; use option::Option; use option::Option::{None, Some}; use str; -use string::{String, CowString}; +use string::String; use vec::Vec; /// Typedef for POSIX file paths. @@ -907,7 +908,7 @@ impl<'a, P: GenericPath> Display<'a, P> { /// If the path is not UTF-8, invalid sequences will be replaced with the /// Unicode replacement char. This involves allocation. #[inline] - pub fn as_cow(&self) -> CowString<'a> { + pub fn as_cow(&self) -> Cow<'a, str> { String::from_utf8_lossy(if self.filename { match self.path.filename() { None => { diff --git a/src/libstd/old_path/posix.rs b/src/libstd/old_path/posix.rs index bbc1756bee6..f215e73202c 100644 --- a/src/libstd/old_path/posix.rs +++ b/src/libstd/old_path/posix.rs @@ -20,7 +20,7 @@ use iter::{Iterator, Map}; use marker::Sized; use option::Option::{self, Some, None}; use result::Result::{self, Ok, Err}; -use slice::{AsSlice, Split, SliceConcatExt}; +use slice::{Split, SliceConcatExt}; use str::{self, FromStr}; use vec::Vec; @@ -339,11 +339,11 @@ impl Path { /// Returns a normalized byte vector representation of a path, by removing all empty /// components, and unnecessary . and .. components. - fn normalize>(v: &V) -> Vec { + fn normalize(v: &[u8]) -> Vec { // borrowck is being very picky let val = { - let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == SEP_BYTE; - let v_ = if is_abs { &v.as_slice()[1..] } else { v.as_slice() }; + let is_abs = !v.is_empty() && v[0] == SEP_BYTE; + let v_ = if is_abs { &v[1..] } else { v }; let comps = normalize_helper(v_, is_abs); match comps { None => None, @@ -371,7 +371,7 @@ impl Path { } }; match val { - None => v.as_slice().to_vec(), + None => v.to_vec(), Some(val) => val } } @@ -446,8 +446,7 @@ mod tests { use clone::Clone; use option::Option::{self, Some, None}; use old_path::GenericPath; - use slice::AsSlice; - use str::{self, Str}; + use str; use string::ToString; use vec::Vec; use iter::Iterator; diff --git a/src/libstd/old_path/windows.rs b/src/libstd/old_path/windows.rs index bd67855bf1b..0b88f368b39 100644 --- a/src/libstd/old_path/windows.rs +++ b/src/libstd/old_path/windows.rs @@ -1129,8 +1129,6 @@ mod tests { use iter::Iterator; use option::Option::{self, Some, None}; use old_path::GenericPath; - use slice::AsSlice; - use str::Str; use string::ToString; use vec::Vec; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index e19c734b8a3..ee0f04cb991 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -8,1826 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Higher-level interfaces to libc::* functions and operating system services. -//! -//! In general these take and return rust types, use rust idioms (enums, -//! closures, vectors) rather than C idioms, and do more extensive safety -//! checks. -//! -//! This module is not meant to only contain 1:1 mappings to libc entries; any -//! os-interface code that is reasonably useful and broadly applicable can go -//! here. Including utility routines that merely build on other os code. -//! -//! We assume the general case is that users do not care, and do not want to be -//! made to care, which operating system they are on. While they may want to -//! special case various special cases -- and so we will not _hide_ the facts of -//! which OS the user is on -- they should be given the opportunity to write -//! OS-ignorant code by default. +//! OS-specific functionality -#![unstable(feature = "os")] -#![deprecated(since = "1.0.0", reason = "replaced with std::env APIs")] - -#![allow(missing_docs)] -#![allow(non_snake_case)] -#![allow(unused_imports)] -#![allow(deprecated)] - -use self::MemoryMapKind::*; -use self::MapOption::*; -use self::MapError::*; - -use boxed::Box; -use clone::Clone; -use convert::From; -use env; -use error::{FromError, Error}; -use ffi::{OsString, OsStr}; -use fmt; -use iter::Iterator; -use libc::{c_void, c_int, c_char}; -use libc; -use marker::{Copy, Send}; -use old_io::{IoResult, IoError}; -use ops::{Drop, FnOnce}; -use option::Option::{Some, None}; -use option::Option; -use old_path::{Path, GenericPath, BytesContainer}; -use path::{self, PathBuf}; -use ptr; -use result::Result::{Err, Ok}; -use result::Result; -use slice::AsSlice; -use str::Str; -use str; -use string::{String, ToString}; -use sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering}; -use sys::os as os_imp; -use sys; -use vec::Vec; - -#[cfg(unix)] use ffi::{self, CString}; +#![stable(feature = "os", since = "1.0.0")] #[cfg(unix)] pub use sys::ext as unix; #[cfg(windows)] pub use sys::ext as windows; - -fn err2old(new: ::io::Error) -> IoError { - IoError { - kind: ::old_io::OtherIoError, - desc: "os error", - detail: Some(new.to_string()), - } -} - -#[cfg(windows)] -fn path2new(path: &Path) -> PathBuf { - PathBuf::from(path.as_str().unwrap()) -} -#[cfg(unix)] -fn path2new(path: &Path) -> PathBuf { - use os::unix::prelude::*; - PathBuf::from(::from_bytes(path.as_vec())) -} - -#[cfg(unix)] -fn path2old(path: &path::Path) -> Path { - use os::unix::prelude::*; - use ffi::AsOsStr; - Path::new(path.as_os_str().as_bytes()) -} -#[cfg(windows)] -fn path2old(path: &path::Path) -> Path { - Path::new(path.to_str().unwrap()) -} - -/// Get the number of cores available -pub fn num_cpus() -> usize { - unsafe { - return rust_get_num_cpus() as usize; - } - - extern { - fn rust_get_num_cpus() -> libc::uintptr_t; - } -} - -pub const TMPBUF_SZ : usize = 1000; - -/// Returns the current working directory as a `Path`. -/// -/// # Errors -/// -/// Returns an `Err` if the current working directory value is invalid. -/// Possible cases: -/// -/// * Current directory does not exist. -/// * There are insufficient permissions to access the current directory. -/// * The internal buffer is not large enough to hold the path. -/// -/// # Examples -/// -/// ``` -/// # #![feature(os, old_path)] -/// use std::os; -/// use std::old_path::{Path, GenericPath}; -/// -/// // We assume that we are in a valid directory. -/// let current_working_directory = os::getcwd().unwrap(); -/// println!("The current directory is {:?}", current_working_directory.display()); -/// ``` -#[unstable(feature = "os")] -pub fn getcwd() -> IoResult { - env::current_dir().map_err(err2old).map(|s| path2old(&s)) -} - -/// Returns a vector of (variable, value) pairs, for all the environment -/// variables of the current process. -/// -/// Invalid UTF-8 bytes are replaced with \uFFFD. See `String::from_utf8_lossy()` -/// for details. -/// -/// # Examples -/// -/// ``` -/// # #![feature(os)] -/// use std::os; -/// -/// // We will iterate through the references to the element returned by os::env(); -/// for &(ref key, ref value) in os::env().iter() { -/// println!("'{}': '{}'", key, value ); -/// } -/// ``` -#[deprecated(since = "1.0.0", reason = "use env::vars instead")] -#[unstable(feature = "os")] -pub fn env() -> Vec<(String,String)> { - env::vars_os().map(|(k, v)| { - (k.to_string_lossy().into_owned(), v.to_string_lossy().into_owned()) - }).collect() -} - -/// Returns a vector of (variable, value) byte-vector pairs for all the -/// environment variables of the current process. -#[deprecated(since = "1.0.0", reason = "use env::vars_os instead")] -#[unstable(feature = "os")] -pub fn env_as_bytes() -> Vec<(Vec, Vec)> { - env::vars_os().map(|(k, v)| (byteify(k), byteify(v))).collect() -} - -/// Fetches the environment variable `n` from the current process, returning -/// None if the variable isn't set. -/// -/// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See -/// `String::from_utf8_lossy()` for details. -/// -/// # Panics -/// -/// Panics if `n` has any interior NULs. -/// -/// # Examples -/// -/// ``` -/// # #![feature(os)] -/// use std::os; -/// -/// let key = "HOME"; -/// match os::getenv(key) { -/// Some(val) => println!("{}: {}", key, val), -/// None => println!("{} is not defined in the environment.", key) -/// } -/// ``` -#[deprecated(since = "1.0.0", reason = "use env::var instead")] -#[unstable(feature = "os")] -pub fn getenv(n: &str) -> Option { - env::var(n).ok() -} - -/// Fetches the environment variable `n` byte vector from the current process, -/// returning None if the variable isn't set. -/// -/// # Panics -/// -/// Panics if `n` has any interior NULs. -#[deprecated(since = "1.0.0", reason = "use env::var_os instead")] -#[unstable(feature = "os")] -pub fn getenv_as_bytes(n: &str) -> Option> { - env::var_os(n).map(byteify) -} - -#[cfg(unix)] -fn byteify(s: OsString) -> Vec { - use os::unix::prelude::*; - s.into_vec() -} -#[cfg(windows)] -fn byteify(s: OsString) -> Vec { - s.to_string_lossy().as_bytes().to_vec() -} - -/// Sets the environment variable `n` to the value `v` for the currently running -/// process. -/// -/// # Examples -/// -/// ``` -/// # #![feature(os)] -/// use std::os; -/// -/// let key = "KEY"; -/// os::setenv(key, "VALUE"); -/// match os::getenv(key) { -/// Some(ref val) => println!("{}: {}", key, val), -/// None => println!("{} is not defined in the environment.", key) -/// } -/// ``` -#[deprecated(since = "1.0.0", reason = "renamed to env::set_var")] -#[unstable(feature = "os")] -pub fn setenv(n: &str, v: T) { - #[cfg(unix)] - fn _setenv(n: &str, v: &[u8]) { - use os::unix::prelude::*; - let v: OsString = OsStringExt::from_vec(v.to_vec()); - env::set_var(n, &v) - } - - #[cfg(windows)] - fn _setenv(n: &str, v: &[u8]) { - let v = str::from_utf8(v).unwrap(); - env::set_var(n, v) - } - - _setenv(n, v.container_as_bytes()) -} - -/// Remove a variable from the environment entirely. -#[deprecated(since = "1.0.0", reason = "renamed to env::remove_var")] -#[unstable(feature = "os")] -pub fn unsetenv(n: &str) { - env::remove_var(n) -} - -/// Parses input according to platform conventions for the `PATH` -/// environment variable. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_path, os)] -/// use std::os; -/// use std::old_path::{Path, GenericPath}; -/// -/// let key = "PATH"; -/// match os::getenv_as_bytes(key) { -/// Some(paths) => { -/// for path in os::split_paths(paths).iter() { -/// println!("'{}'", path.display()); -/// } -/// } -/// None => println!("{} is not defined in the environment.", key) -/// } -/// ``` -#[unstable(feature = "os")] -pub fn split_paths(unparsed: T) -> Vec { - let b = unparsed.container_as_bytes(); - let s = str::from_utf8(b).unwrap(); - env::split_paths(s).map(|s| path2old(&s)).collect() -} - -/// Joins a collection of `Path`s appropriately for the `PATH` -/// environment variable. -/// -/// Returns a `Vec` on success, since `Path`s are not utf-8 -/// encoded on all platforms. -/// -/// Returns an `Err` (containing an error message) if one of the input -/// `Path`s contains an invalid character for constructing the `PATH` -/// variable (a double quote on Windows or a colon on Unix). -/// -/// # Examples -/// -/// ``` -/// # #![feature(os, old_path, core)] -/// use std::os; -/// use std::old_path::Path; -/// -/// let key = "PATH"; -/// let mut paths = os::getenv_as_bytes(key).map_or(Vec::new(), os::split_paths); -/// paths.push(Path::new("/home/xyz/bin")); -/// os::setenv(key, os::join_paths(paths.as_slice()).unwrap()); -/// ``` -#[unstable(feature = "os")] -pub fn join_paths(paths: &[T]) -> Result, &'static str> { - env::join_paths(paths.iter().map(|s| { - str::from_utf8(s.container_as_bytes()).unwrap() - })).map(|s| { - s.to_string_lossy().into_owned().into_bytes() - }).map_err(|_| "failed to join paths") -} - -/// A low-level OS in-memory pipe. -#[derive(Copy)] -pub struct Pipe { - /// A file descriptor representing the reading end of the pipe. Data written - /// on the `out` file descriptor can be read from this file descriptor. - pub reader: c_int, - /// A file descriptor representing the write end of the pipe. Data written - /// to this file descriptor can be read from the `input` file descriptor. - pub writer: c_int, -} - -/// Creates a new low-level OS in-memory pipe. -/// -/// This function can fail to succeed if there are no more resources available -/// to allocate a pipe. -/// -/// This function is also unsafe as there is no destructor associated with the -/// `Pipe` structure will return. If it is not arranged for the returned file -/// descriptors to be closed, the file descriptors will leak. For safe handling -/// of this scenario, use `std::old_io::PipeStream` instead. -pub unsafe fn pipe() -> IoResult { - let (reader, writer) = try!(sys::os::pipe()); - Ok(Pipe { - reader: reader.unwrap(), - writer: writer.unwrap(), - }) -} - -/// Returns the proper dll filename for the given basename of a file -/// as a String. -#[cfg(not(target_os="ios"))] -#[deprecated(since = "1.0.0", reason = "this function will be removed, use the constants directly")] -#[unstable(feature = "os")] -#[allow(deprecated)] -pub fn dll_filename(base: &str) -> String { - format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX) -} - -/// Optionally returns the filesystem path to the current executable which is -/// running but with the executable name. -/// -/// # Examples -/// -/// ``` -/// # #![feature(os, old_path)] -/// use std::os; -/// use std::old_path::{Path, GenericPath}; -/// -/// match os::self_exe_name() { -/// Some(exe_path) => println!("Path of this executable is: {}", exe_path.display()), -/// None => println!("Unable to get the path of this executable!") -/// }; -/// ``` -#[unstable(feature = "os")] -pub fn self_exe_name() -> Option { - env::current_exe().ok().map(|p| path2old(&p)) -} - -/// Optionally returns the filesystem path to the current executable which is -/// running. -/// -/// Like self_exe_name() but without the binary's name. -/// -/// # Examples -/// -/// ``` -/// # #![feature(os, old_path)] -/// use std::os; -/// use std::old_path::{Path, GenericPath}; -/// -/// match os::self_exe_path() { -/// Some(exe_path) => println!("Executable's Path is: {}", exe_path.display()), -/// None => println!("Impossible to fetch the path of this executable.") -/// }; -/// ``` -#[unstable(feature = "os")] -pub fn self_exe_path() -> Option { - env::current_exe().ok().map(|p| { let mut p = path2old(&p); p.pop(); p }) -} - -/// Optionally returns the path to the current user's home directory if known. -/// -/// # Unix -/// -/// Returns the value of the 'HOME' environment variable if it is set -/// and not equal to the empty string. -/// -/// # Windows -/// -/// Returns the value of the 'HOME' environment variable if it is -/// set and not equal to the empty string. Otherwise, returns the value of the -/// 'USERPROFILE' environment variable if it is set and not equal to the empty -/// string. -/// -/// # Examples -/// -/// ``` -/// # #![feature(os, old_path)] -/// use std::os; -/// use std::old_path::{Path, GenericPath}; -/// -/// match os::homedir() { -/// Some(ref p) => println!("{}", p.display()), -/// None => println!("Impossible to get your home dir!") -/// } -/// ``` -#[unstable(feature = "os")] -#[allow(deprecated)] -pub fn homedir() -> Option { - #[inline] - #[cfg(unix)] - fn _homedir() -> Option { - aux_homedir("HOME") - } - - #[inline] - #[cfg(windows)] - fn _homedir() -> Option { - aux_homedir("HOME").or(aux_homedir("USERPROFILE")) - } - - #[inline] - fn aux_homedir(home_name: &str) -> Option { - match getenv_as_bytes(home_name) { - Some(p) => { - if p.is_empty() { None } else { Path::new_opt(p) } - }, - _ => None - } - } - _homedir() -} - -/// Returns the path to a temporary directory. -/// -/// On Unix, returns the value of the 'TMPDIR' environment variable if it is -/// set, otherwise for non-Android it returns '/tmp'. If Android, since there -/// is no global temporary folder (it is usually allocated per-app), we return -/// '/data/local/tmp'. -/// -/// On Windows, returns the value of, in order, the 'TMP', 'TEMP', -/// 'USERPROFILE' environment variable if any are set and not the empty -/// string. Otherwise, tmpdir returns the path to the Windows directory. -#[unstable(feature = "os")] -#[allow(deprecated)] -pub fn tmpdir() -> Path { - return lookup(); - - fn getenv_nonempty(v: &str) -> Option { - match getenv(v) { - Some(x) => - if x.is_empty() { - None - } else { - Path::new_opt(x) - }, - _ => None - } - } - - #[cfg(unix)] - fn lookup() -> Path { - let default = if cfg!(target_os = "android") { - Path::new("/data/local/tmp") - } else { - Path::new("/tmp") - }; - - getenv_nonempty("TMPDIR").unwrap_or(default) - } - - #[cfg(windows)] - fn lookup() -> Path { - getenv_nonempty("TMP").or( - getenv_nonempty("TEMP").or( - getenv_nonempty("USERPROFILE").or( - getenv_nonempty("WINDIR")))).unwrap_or(Path::new("C:\\Windows")) - } -} - -/// Convert a relative path to an absolute path -/// -/// If the given path is relative, return it prepended with the current working -/// directory. If the given path is already an absolute path, return it -/// as is. -/// -/// # Examples -/// -/// ``` -/// # #![feature(os, old_path)] -/// use std::os; -/// use std::old_path::{Path, GenericPath}; -/// -/// // Assume we're in a path like /home/someuser -/// let rel_path = Path::new(".."); -/// let abs_path = os::make_absolute(&rel_path).unwrap(); -/// println!("The absolute path is {}", abs_path.display()); -/// // Prints "The absolute path is /home" -/// ``` -// NB: this is here rather than in path because it is a form of environment -// querying; what it does depends on the process working directory, not just -// the input paths. -#[deprecated(since = "1.0.0", reason = "use env::current_dir + .join directly")] -#[unstable(feature = "os")] -pub fn make_absolute(p: &Path) -> IoResult { - if p.is_absolute() { - Ok(p.clone()) - } else { - env::current_dir().map_err(err2old).map(|cwd| { - let mut cwd = path2old(&cwd); - cwd.push(p); - cwd - }) - } -} - -/// Changes the current working directory to the specified path, returning -/// whether the change was completed successfully or not. -/// -/// # Examples -/// -/// ``` -/// # #![feature(os, old_path)] -/// use std::os; -/// use std::old_path::{Path, GenericPath}; -/// -/// let root = Path::new("/"); -/// assert!(os::change_dir(&root).is_ok()); -/// println!("Successfully changed working directory to {}!", root.display()); -/// ``` -#[unstable(feature = "os")] -pub fn change_dir(p: &Path) -> IoResult<()> { - sys::os::chdir(&path2new(p)).map_err(err2old) -} - -/// Returns the platform-specific value of errno -pub fn errno() -> i32 { - sys::os::errno() as i32 -} - -/// Return the string corresponding to an `errno()` value of `errnum`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(os)] -/// use std::os; -/// -/// // Same as println!("{}", last_os_error()); -/// println!("{}", os::error_string(os::errno() as i32)); -/// ``` -pub fn error_string(errnum: i32) -> String { - return sys::os::error_string(errnum); -} - -/// Get a string representing the platform-dependent last error -pub fn last_os_error() -> String { - error_string(errno()) -} - -/// Sets the process exit code -/// -/// Sets the exit code returned by the process if all supervised tasks -/// terminate successfully (without panicking). If the current root task panics -/// and is supervised by the scheduler then any user-specified exit status is -/// ignored and the process exits with the default panic status. -/// -/// Note that this is not synchronized against modifications of other threads. -#[deprecated(since = "1.0.0", reason = "renamed to env::set_exit_status")] -#[unstable(feature = "os")] -pub fn set_exit_status(code: isize) { - env::set_exit_status(code as i32) -} - -/// Fetches the process's current exit code. This defaults to 0 and can change -/// by calling `set_exit_status`. -#[deprecated(since = "1.0.0", reason = "renamed to env::get_exit_status")] -#[unstable(feature = "os")] -pub fn get_exit_status() -> isize { - env::get_exit_status() as isize -} - -#[cfg(target_os = "macos")] -unsafe fn load_argc_and_argv(argc: isize, - argv: *const *const c_char) -> Vec> { - use ffi::CStr; - - (0..argc).map(|i| { - CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec() - }).collect() -} - -/// Returns the command line arguments -/// -/// Returns a list of the command line arguments. -#[cfg(target_os = "macos")] -fn real_args_as_bytes() -> Vec> { - unsafe { - let (argc, argv) = (*_NSGetArgc() as isize, - *_NSGetArgv() as *const *const c_char); - load_argc_and_argv(argc, argv) - } -} - -// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs -// and use underscores in their names - they're most probably -// are considered private and therefore should be avoided -// Here is another way to get arguments using Objective C -// runtime -// -// In general it looks like: -// res = Vec::new() -// let args = [[NSProcessInfo processInfo] arguments] -// for i in 0..[args count] -// res.push([args objectAtIndex:i]) -// res -#[cfg(target_os = "ios")] -fn real_args_as_bytes() -> Vec> { - use ffi::CStr; - use iter::range; - use mem; - - #[link(name = "objc")] - extern { - fn sel_registerName(name: *const libc::c_uchar) -> Sel; - fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; - fn objc_getClass(class_name: *const libc::c_uchar) -> NsId; - } - - #[link(name = "Foundation", kind = "framework")] - extern {} - - type Sel = *const libc::c_void; - type NsId = *const libc::c_void; - - let mut res = Vec::new(); - - unsafe { - let processInfoSel = sel_registerName("processInfo\0".as_ptr()); - let argumentsSel = sel_registerName("arguments\0".as_ptr()); - let utf8Sel = sel_registerName("UTF8String\0".as_ptr()); - let countSel = sel_registerName("count\0".as_ptr()); - let objectAtSel = sel_registerName("objectAtIndex:\0".as_ptr()); - - let klass = objc_getClass("NSProcessInfo\0".as_ptr()); - let info = objc_msgSend(klass, processInfoSel); - let args = objc_msgSend(info, argumentsSel); - - let cnt: isize = mem::transmute(objc_msgSend(args, countSel)); - for i in 0..cnt { - let tmp = objc_msgSend(args, objectAtSel, i); - let utf_c_str: *const libc::c_char = - mem::transmute(objc_msgSend(tmp, utf8Sel)); - res.push(CStr::from_ptr(utf_c_str).to_bytes().to_vec()); - } - } - - res -} - -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd"))] -fn real_args_as_bytes() -> Vec> { - use rt; - rt::args::clone().unwrap_or_else(|| vec![]) -} - -#[cfg(not(windows))] -fn real_args() -> Vec { - real_args_as_bytes().into_iter() - .map(|v| { - String::from_utf8_lossy(&v).into_owned() - }).collect() -} - -#[cfg(windows)] -fn real_args() -> Vec { - use slice; - use iter::range; - - let mut nArgs: c_int = 0; - let lpArgCount: *mut c_int = &mut nArgs; - let lpCmdLine = unsafe { GetCommandLineW() }; - let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) }; - - let args: Vec<_> = (0..nArgs as usize).map(|i| unsafe { - // Determine the length of this argument. - let ptr = *szArgList.offset(i as isize); - let mut len = 0; - while *ptr.offset(len as isize) != 0 { len += 1; } - - // Push it onto the list. - let ptr = ptr as *const u16; - let buf = slice::from_raw_parts(ptr, len); - let opt_s = String::from_utf16(sys::truncate_utf16_at_nul(buf)); - opt_s.ok().expect("CommandLineToArgvW returned invalid UTF-16") - }).collect(); - - unsafe { - LocalFree(szArgList as *mut c_void); - } - - return args -} - -#[cfg(windows)] -fn real_args_as_bytes() -> Vec> { - real_args().into_iter().map(|s| s.into_bytes()).collect() -} - -type LPCWSTR = *const u16; - -#[cfg(windows)] -#[link_name="kernel32"] -extern "system" { - fn GetCommandLineW() -> LPCWSTR; - fn LocalFree(ptr: *mut c_void); -} - -#[cfg(windows)] -#[link_name="shell32"] -extern "system" { - fn CommandLineToArgvW(lpCmdLine: LPCWSTR, - pNumArgs: *mut c_int) -> *mut *mut u16; -} - -/// Returns the arguments which this program was started with (normally passed -/// via the command line). -/// -/// The first element is traditionally the path to the executable, but it can be -/// set to arbitrary text, and it may not even exist, so this property should not -/// be relied upon for security purposes. -/// -/// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD. -/// See `String::from_utf8_lossy` for details. -/// # Examples -/// -/// ``` -/// # #![feature(os)] -/// use std::os; -/// -/// // Prints each argument on a separate line -/// for argument in os::args().iter() { -/// println!("{}", argument); -/// } -/// ``` -#[deprecated(since = "1.0.0", reason = "use std::env::args() instead")] -#[unstable(feature = "os")] -pub fn args() -> Vec { - real_args() -} - -/// Returns the arguments which this program was started with (normally passed -/// via the command line) as byte vectors. -#[deprecated(since = "1.0.0", reason = "use env::args_os instead")] -#[unstable(feature = "os")] -pub fn args_as_bytes() -> Vec> { - real_args_as_bytes() -} - -#[cfg(target_os = "macos")] -extern { - // These functions are in crt_externs.h. - fn _NSGetArgc() -> *mut c_int; - fn _NSGetArgv() -> *mut *mut *mut c_char; -} - -/// Returns the page size of the current architecture in bytes. -#[deprecated(since = "1.0.0", reason = "renamed to env::page_size")] -#[unstable(feature = "os")] -pub fn page_size() -> usize { - sys::os::page_size() -} - -/// A memory mapped file or chunk of memory. This is a very system-specific -/// interface to the OS's memory mapping facilities (`mmap` on POSIX, -/// `VirtualAlloc`/`CreateFileMapping` on Windows). It makes no attempt at -/// abstracting platform differences, besides in error values returned. Consider -/// yourself warned. -/// -/// The memory map is released (unmapped) when the destructor is run, so don't -/// let it leave scope by accident if you want it to stick around. -pub struct MemoryMap { - data: *mut u8, - len: usize, - kind: MemoryMapKind, -} - -/// Type of memory map -#[allow(raw_pointer_derive)] -#[derive(Copy)] -pub enum MemoryMapKind { - /// Virtual memory map. Usually used to change the permissions of a given - /// chunk of memory. Corresponds to `VirtualAlloc` on Windows. - MapFile(*const u8), - /// Virtual memory map. Usually used to change the permissions of a given - /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on - /// Windows. - MapVirtual -} - -/// Options the memory map is created with -#[allow(raw_pointer_derive)] -#[derive(Copy)] -pub enum MapOption { - /// The memory should be readable - MapReadable, - /// The memory should be writable - MapWritable, - /// The memory should be executable - MapExecutable, - /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on - /// POSIX. - MapAddr(*const u8), - /// Create a memory mapping for a file with a given HANDLE. - #[cfg(windows)] - MapFd(libc::HANDLE), - /// Create a memory mapping for a file with a given fd. - #[cfg(not(windows))] - MapFd(c_int), - /// When using `MapFd`, the start of the map is `usize` bytes from the start - /// of the file. - MapOffset(usize), - /// On POSIX, this can be used to specify the default flags passed to - /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`, - /// `MAP_ANON`. This will override both of those. This is platform-specific - /// (the exact values used) and ignored on Windows. - MapNonStandardFlags(c_int), -} - -/// Possible errors when creating a map. -#[derive(Copy, Debug)] -pub enum MapError { - /// # The following are POSIX-specific - /// - /// fd was not open for reading or, if using `MapWritable`, was not open for - /// writing. - ErrFdNotAvail, - /// fd was not valid - ErrInvalidFd, - /// Either the address given by `MapAddr` or offset given by `MapOffset` was - /// not a multiple of `MemoryMap::granularity` (unaligned to page size). - ErrUnaligned, - /// With `MapFd`, the fd does not support mapping. - ErrNoMapSupport, - /// If using `MapAddr`, the address + `min_len` was outside of the process's - /// address space. If using `MapFd`, the target of the fd didn't have enough - /// resources to fulfill the request. - ErrNoMem, - /// A zero-length map was requested. This is invalid according to - /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html). - /// Not all platforms obey this, but this wrapper does. - ErrZeroLength, - /// Unrecognized error. The inner value is the unrecognized errno. - ErrUnknown(isize), - /// # The following are Windows-specific - /// - /// Unsupported combination of protection flags - /// (`MapReadable`/`MapWritable`/`MapExecutable`). - ErrUnsupProt, - /// When using `MapFd`, `MapOffset` was given (Windows does not support this - /// at all) - ErrUnsupOffset, - /// When using `MapFd`, there was already a mapping to the file. - ErrAlreadyExists, - /// Unrecognized error from `VirtualAlloc`. The inner value is the return - /// value of GetLastError. - ErrVirtualAlloc(i32), - /// Unrecognized error from `CreateFileMapping`. The inner value is the - /// return value of `GetLastError`. - ErrCreateFileMappingW(i32), - /// Unrecognized error from `MapViewOfFile`. The inner value is the return - /// value of `GetLastError`. - ErrMapViewOfFile(i32) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for MapError { - fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result { - let str = match *self { - ErrFdNotAvail => "fd not available for reading or writing", - ErrInvalidFd => "Invalid fd", - ErrUnaligned => { - "Unaligned address, invalid flags, negative length or \ - unaligned offset" - } - ErrNoMapSupport=> "File doesn't support mapping", - ErrNoMem => "Invalid address, or not enough available memory", - ErrUnsupProt => "Protection mode unsupported", - ErrUnsupOffset => "Offset in virtual memory mode is unsupported", - ErrAlreadyExists => "File mapping for specified file already exists", - ErrZeroLength => "Zero-length mapping not allowed", - ErrUnknown(code) => { - return write!(out, "Unknown error = {}", code) - }, - ErrVirtualAlloc(code) => { - return write!(out, "VirtualAlloc failure = {}", code) - }, - ErrCreateFileMappingW(code) => { - return write!(out, "CreateFileMappingW failure = {}", code) - }, - ErrMapViewOfFile(code) => { - return write!(out, "MapViewOfFile failure = {}", code) - } - }; - write!(out, "{}", str) - } -} - -impl Error for MapError { - fn description(&self) -> &str { "memory map error" } -} - -// Round up `from` to be divisible by `to` -fn round_up(from: usize, to: usize) -> usize { - let r = if from % to == 0 { - from - } else { - from + to - (from % to) - }; - if r == 0 { - to - } else { - r - } -} - -#[cfg(unix)] -impl MemoryMap { - /// Create a new mapping with the given `options`, at least `min_len` bytes - /// long. `min_len` must be greater than zero; see the note on - /// `ErrZeroLength`. - pub fn new(min_len: usize, options: &[MapOption]) -> Result { - use libc::off_t; - - if min_len == 0 { - return Err(ErrZeroLength) - } - let mut addr: *const u8 = ptr::null(); - let mut prot = 0; - let mut flags = libc::MAP_PRIVATE; - let mut fd = -1; - let mut offset = 0; - let mut custom_flags = false; - let len = round_up(min_len, env::page_size()); - - for &o in options { - match o { - MapReadable => { prot |= libc::PROT_READ; }, - MapWritable => { prot |= libc::PROT_WRITE; }, - MapExecutable => { prot |= libc::PROT_EXEC; }, - MapAddr(addr_) => { - flags |= libc::MAP_FIXED; - addr = addr_; - }, - MapFd(fd_) => { - flags |= libc::MAP_FILE; - fd = fd_; - }, - MapOffset(offset_) => { offset = offset_ as off_t; }, - MapNonStandardFlags(f) => { custom_flags = true; flags = f }, - } - } - if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; } - - let r = unsafe { - libc::mmap(addr as *mut c_void, len as libc::size_t, prot, flags, - fd, offset) - }; - if r == libc::MAP_FAILED { - Err(match errno() as c_int { - libc::EACCES => ErrFdNotAvail, - libc::EBADF => ErrInvalidFd, - libc::EINVAL => ErrUnaligned, - libc::ENODEV => ErrNoMapSupport, - libc::ENOMEM => ErrNoMem, - code => ErrUnknown(code as isize) - }) - } else { - Ok(MemoryMap { - data: r as *mut u8, - len: len, - kind: if fd == -1 { - MapVirtual - } else { - MapFile(ptr::null()) - } - }) - } - } - - /// Granularity that the offset or address must be for `MapOffset` and - /// `MapAddr` respectively. - pub fn granularity() -> usize { - env::page_size() - } -} - -#[cfg(unix)] -impl Drop for MemoryMap { - /// Unmap the mapping. Panics the task if `munmap` panics. - fn drop(&mut self) { - if self.len == 0 { /* workaround for dummy_stack */ return; } - - unsafe { - // `munmap` only panics due to logic errors - libc::munmap(self.data as *mut c_void, self.len as libc::size_t); - } - } -} - -#[cfg(windows)] -impl MemoryMap { - /// Create a new mapping with the given `options`, at least `min_len` bytes long. - pub fn new(min_len: usize, options: &[MapOption]) -> Result { - use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE}; - - let mut lpAddress: LPVOID = ptr::null_mut(); - let mut readable = false; - let mut writable = false; - let mut executable = false; - let mut handle: HANDLE = libc::INVALID_HANDLE_VALUE; - let mut offset: usize = 0; - let len = round_up(min_len, env::page_size()); - - for &o in options { - match o { - MapReadable => { readable = true; }, - MapWritable => { writable = true; }, - MapExecutable => { executable = true; } - MapAddr(addr_) => { lpAddress = addr_ as LPVOID; }, - MapFd(handle_) => { handle = handle_; }, - MapOffset(offset_) => { offset = offset_; }, - MapNonStandardFlags(..) => {} - } - } - - let flProtect = match (executable, readable, writable) { - (false, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_NOACCESS, - (false, true, false) => libc::PAGE_READONLY, - (false, true, true) => libc::PAGE_READWRITE, - (true, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_EXECUTE, - (true, true, false) => libc::PAGE_EXECUTE_READ, - (true, true, true) => libc::PAGE_EXECUTE_READWRITE, - _ => return Err(ErrUnsupProt) - }; - - if handle == libc::INVALID_HANDLE_VALUE { - if offset != 0 { - return Err(ErrUnsupOffset); - } - let r = unsafe { - libc::VirtualAlloc(lpAddress, - len as SIZE_T, - libc::MEM_COMMIT | libc::MEM_RESERVE, - flProtect) - }; - match r as usize { - 0 => Err(ErrVirtualAlloc(errno())), - _ => Ok(MemoryMap { - data: r as *mut u8, - len: len, - kind: MapVirtual - }) - } - } else { - let dwDesiredAccess = match (executable, readable, writable) { - (false, true, false) => libc::FILE_MAP_READ, - (false, true, true) => libc::FILE_MAP_WRITE, - (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE, - (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE, - _ => return Err(ErrUnsupProt) // Actually, because of the check above, - // we should never get here. - }; - unsafe { - let hFile = handle; - let mapping = libc::CreateFileMappingW(hFile, - ptr::null_mut(), - flProtect, - 0, - 0, - ptr::null()); - if mapping == ptr::null_mut() { - return Err(ErrCreateFileMappingW(errno())); - } - if errno() as c_int == libc::ERROR_ALREADY_EXISTS { - return Err(ErrAlreadyExists); - } - let r = libc::MapViewOfFile(mapping, - dwDesiredAccess, - ((len as u64) >> 32) as DWORD, - (offset & 0xffff_ffff) as DWORD, - 0); - match r as usize { - 0 => Err(ErrMapViewOfFile(errno())), - _ => Ok(MemoryMap { - data: r as *mut u8, - len: len, - kind: MapFile(mapping as *const u8) - }) - } - } - } - } - - /// Granularity of MapAddr() and MapOffset() parameter values. - /// This may be greater than the value returned by page_size(). - pub fn granularity() -> usize { - use mem; - unsafe { - let mut info = mem::zeroed(); - libc::GetSystemInfo(&mut info); - - return info.dwAllocationGranularity as usize; - } - } -} - -#[cfg(windows)] -impl Drop for MemoryMap { - /// Unmap the mapping. Panics the task if any of `VirtualFree`, - /// `UnmapViewOfFile`, or `CloseHandle` fail. - fn drop(&mut self) { - use libc::types::os::arch::extra::{LPCVOID, HANDLE}; - use libc::consts::os::extra::FALSE; - if self.len == 0 { return } - - unsafe { - match self.kind { - MapVirtual => { - if libc::VirtualFree(self.data as *mut c_void, 0, - libc::MEM_RELEASE) == 0 { - println!("VirtualFree failed: {}", errno()); - } - }, - MapFile(mapping) => { - if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE { - println!("UnmapViewOfFile failed: {}", errno()); - } - if libc::CloseHandle(mapping as HANDLE) == FALSE { - println!("CloseHandle failed: {}", errno()); - } - } - } - } - } -} - -impl MemoryMap { - /// Returns the pointer to the memory created or modified by this map. - pub fn data(&self) -> *mut u8 { self.data } - /// Returns the number of bytes this map applies to. - pub fn len(&self) -> usize { self.len } - /// Returns the type of mapping this represents. - pub fn kind(&self) -> MemoryMapKind { self.kind } -} - -#[cfg(target_os = "linux")] -#[deprecated(since = "1.0.0", reason = "renamed to env::consts")] -#[unstable(feature = "os")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `linux`. - pub const SYSNAME: &'static str = "linux"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, `lib`. - pub const DLL_PREFIX: &'static str = "lib"; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.so`. - pub const DLL_SUFFIX: &'static str = ".so"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `so`. - pub const DLL_EXTENSION: &'static str = "so"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "macos")] -#[deprecated(since = "1.0.0", reason = "renamed to env::consts")] -#[unstable(feature = "os")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `macos`. - pub const SYSNAME: &'static str = "macos"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, `lib`. - pub const DLL_PREFIX: &'static str = "lib"; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.dylib`. - pub const DLL_SUFFIX: &'static str = ".dylib"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `dylib`. - pub const DLL_EXTENSION: &'static str = "dylib"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "ios")] -#[deprecated(since = "1.0.0", reason = "renamed to env::consts")] -#[unstable(feature = "os")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `ios`. - pub const SYSNAME: &'static str = "ios"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "freebsd")] -#[deprecated(since = "1.0.0", reason = "renamed to env::consts")] -#[unstable(feature = "os")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `freebsd`. - pub const SYSNAME: &'static str = "freebsd"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, `lib`. - pub const DLL_PREFIX: &'static str = "lib"; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.so`. - pub const DLL_SUFFIX: &'static str = ".so"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `so`. - pub const DLL_EXTENSION: &'static str = "so"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "dragonfly")] -#[deprecated(since = "1.0.0", reason = "renamed to env::consts")] -#[unstable(feature = "os")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `dragonfly`. - pub const SYSNAME: &'static str = "dragonfly"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, `lib`. - pub const DLL_PREFIX: &'static str = "lib"; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.so`. - pub const DLL_SUFFIX: &'static str = ".so"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `so`. - pub const DLL_EXTENSION: &'static str = "so"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "bitrig")] -#[deprecated(since = "1.0.0", reason = "renamed to env::consts")] -#[unstable(feature = "os")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `bitrig`. - pub const SYSNAME: &'static str = "bitrig"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, `lib`. - pub const DLL_PREFIX: &'static str = "lib"; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.so`. - pub const DLL_SUFFIX: &'static str = ".so"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `so`. - pub const DLL_EXTENSION: &'static str = "so"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "openbsd")] -#[deprecated(since = "1.0.0", reason = "renamed to env::consts")] -#[unstable(feature = "os")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `openbsd`. - pub const SYSNAME: &'static str = "openbsd"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, `lib`. - pub const DLL_PREFIX: &'static str = "lib"; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.so`. - pub const DLL_SUFFIX: &'static str = ".so"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `so`. - pub const DLL_EXTENSION: &'static str = "so"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "android")] -#[deprecated(since = "1.0.0", reason = "renamed to env::consts")] -#[unstable(feature = "os")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `android`. - pub const SYSNAME: &'static str = "android"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, `lib`. - pub const DLL_PREFIX: &'static str = "lib"; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.so`. - pub const DLL_SUFFIX: &'static str = ".so"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `so`. - pub const DLL_EXTENSION: &'static str = "so"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "windows")] -#[deprecated(since = "1.0.0", reason = "renamed to env::consts")] -#[unstable(feature = "os")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "windows"; - - /// A string describing the specific operating system in use: in this - /// case, `windows`. - pub const SYSNAME: &'static str = "windows"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, the empty string. - pub const DLL_PREFIX: &'static str = ""; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.dll`. - pub const DLL_SUFFIX: &'static str = ".dll"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `dll`. - pub const DLL_EXTENSION: &'static str = "dll"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, `.exe`. - pub const EXE_SUFFIX: &'static str = ".exe"; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, `exe`. - pub const EXE_EXTENSION: &'static str = "exe"; -} - -#[cfg(target_arch = "x86")] -mod arch_consts { - pub const ARCH: &'static str = "x86"; -} - -#[cfg(target_arch = "x86_64")] -mod arch_consts { - pub const ARCH: &'static str = "x86_64"; -} - -#[cfg(target_arch = "arm")] -mod arch_consts { - pub const ARCH: &'static str = "arm"; -} - -#[cfg(target_arch = "aarch64")] -mod arch_consts { - pub const ARCH: &'static str = "aarch64"; -} - -#[cfg(target_arch = "mips")] -mod arch_consts { - pub const ARCH: &'static str = "mips"; -} - -#[cfg(target_arch = "mipsel")] -mod arch_consts { - pub const ARCH: &'static str = "mipsel"; -} - -#[cfg(target_arch = "powerpc")] -mod arch_consts { - pub const ARCH: &'static str = "powerpc"; -} - -#[cfg(test)] -mod tests { - #![allow(deprecated)] // rand - - use prelude::v1::*; - - use iter::repeat; - use os::{env, getcwd, getenv, make_absolute}; - use os::{split_paths, join_paths, setenv, unsetenv}; - use os; - use rand::Rng; - use rand; - use old_path::{Path, GenericPath}; - use old_io::{Reader, Writer, Seek}; - - #[test] - pub fn last_os_error() { - debug!("{}", os::last_os_error()); - } - - fn make_rand_name() -> String { - let mut rng = rand::thread_rng(); - let n = format!("TEST{}", rng.gen_ascii_chars().take(10) - .collect::()); - assert!(getenv(&n).is_none()); - n - } - - #[test] - fn test_num_cpus() { - assert!(os::num_cpus() > 0); - } - - #[test] - fn test_setenv() { - let n = make_rand_name(); - setenv(&n, "VALUE"); - assert_eq!(getenv(&n), Some("VALUE".to_string())); - } - - #[test] - fn test_unsetenv() { - let n = make_rand_name(); - setenv(&n, "VALUE"); - unsetenv(&n); - assert_eq!(getenv(&n), None); - } - - #[test] - #[ignore] - fn test_setenv_overwrite() { - let n = make_rand_name(); - setenv(&n, "1"); - setenv(&n, "2"); - assert_eq!(getenv(&n), Some("2".to_string())); - setenv(&n, ""); - assert_eq!(getenv(&n), Some("".to_string())); - } - - // Windows GetEnvironmentVariable requires some extra work to make sure - // the buffer the variable is copied into is the right size - #[test] - #[ignore] - fn test_getenv_big() { - let mut s = "".to_string(); - let mut i = 0; - while i < 100 { - s.push_str("aaaaaaaaaa"); - i += 1; - } - let n = make_rand_name(); - setenv(&n, &s); - debug!("{}", s.clone()); - assert_eq!(getenv(&n), Some(s)); - } - - #[test] - fn test_self_exe_name() { - let path = os::self_exe_name(); - assert!(path.is_some()); - let path = path.unwrap(); - debug!("{}", path.display()); - - // Hard to test this function - assert!(path.is_absolute()); - } - - #[test] - fn test_self_exe_path() { - let path = os::self_exe_path(); - assert!(path.is_some()); - let path = path.unwrap(); - debug!("{}", path.display()); - - // Hard to test this function - assert!(path.is_absolute()); - } - - #[test] - #[ignore] - fn test_env_getenv() { - let e = env(); - assert!(e.len() > 0); - for p in &e { - let (n, v) = (*p).clone(); - debug!("{}", n); - let v2 = getenv(&n); - // MingW seems to set some funky environment variables like - // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned - // from env() but not visible from getenv(). - assert!(v2.is_none() || v2 == Some(v)); - } - } - - #[test] - fn test_env_set_get_huge() { - let n = make_rand_name(); - let s = repeat("x").take(10000).collect::(); - setenv(&n, &s); - assert_eq!(getenv(&n), Some(s)); - unsetenv(&n); - assert_eq!(getenv(&n), None); - } - - #[test] - fn test_env_setenv() { - let n = make_rand_name(); - - let mut e = env(); - setenv(&n, "VALUE"); - assert!(!e.contains(&(n.clone(), "VALUE".to_string()))); - - e = env(); - assert!(e.contains(&(n, "VALUE".to_string()))); - } - - #[test] - fn test() { - assert!((!Path::new("test-path").is_absolute())); - - let cwd = getcwd().unwrap(); - debug!("Current working directory: {}", cwd.display()); - - debug!("{}", make_absolute(&Path::new("test-path")).unwrap().display()); - debug!("{}", make_absolute(&Path::new("/usr/bin")).unwrap().display()); - } - - #[test] - #[cfg(unix)] - fn homedir() { - let oldhome = getenv("HOME"); - - setenv("HOME", "/home/MountainView"); - assert!(os::homedir() == Some(Path::new("/home/MountainView"))); - - setenv("HOME", ""); - assert!(os::homedir().is_none()); - - if let Some(s) = oldhome { - setenv("HOME", s); - } - } - - #[test] - #[cfg(windows)] - fn homedir() { - - let oldhome = getenv("HOME"); - let olduserprofile = getenv("USERPROFILE"); - - setenv("HOME", ""); - setenv("USERPROFILE", ""); - - assert!(os::homedir().is_none()); - - setenv("HOME", "/home/MountainView"); - assert!(os::homedir() == Some(Path::new("/home/MountainView"))); - - setenv("HOME", ""); - - setenv("USERPROFILE", "/home/MountainView"); - assert!(os::homedir() == Some(Path::new("/home/MountainView"))); - - setenv("HOME", "/home/MountainView"); - setenv("USERPROFILE", "/home/PaloAlto"); - assert!(os::homedir() == Some(Path::new("/home/MountainView"))); - - if let Some(s) = oldhome { - setenv("HOME", &s); - } - if let Some(s) = olduserprofile { - setenv("USERPROFILE", &s); - } - } - - #[test] - fn memory_map_rw() { - use result::Result::{Ok, Err}; - - let chunk = match os::MemoryMap::new(16, &[ - os::MapOption::MapReadable, - os::MapOption::MapWritable - ]) { - Ok(chunk) => chunk, - Err(msg) => panic!("{:?}", msg) - }; - assert!(chunk.len >= 16); - - unsafe { - *chunk.data = 0xBE; - assert!(*chunk.data == 0xBE); - } - } - - #[test] - fn memory_map_file() { - use libc; - use os::*; - use old_io::fs::{File, unlink}; - use old_io::SeekStyle::SeekSet; - use old_io::FileMode::Open; - use old_io::FileAccess::ReadWrite; - - #[cfg(not(windows))] - fn get_fd(file: &File) -> libc::c_int { - use os::unix::prelude::*; - file.as_raw_fd() - } - - #[cfg(windows)] - fn get_fd(file: &File) -> libc::HANDLE { - use os::windows::prelude::*; - file.as_raw_handle() - } - - let mut path = tmpdir(); - path.push("mmap_file.tmp"); - let size = MemoryMap::granularity() * 2; - let mut file = File::open_mode(&path, Open, ReadWrite).unwrap(); - file.seek(size as i64, SeekSet).unwrap(); - file.write_u8(0).unwrap(); - - let chunk = MemoryMap::new(size / 2, &[ - MapOption::MapReadable, - MapOption::MapWritable, - MapOption::MapFd(get_fd(&file)), - MapOption::MapOffset(size / 2) - ]).unwrap(); - assert!(chunk.len > 0); - - unsafe { - *chunk.data = 0xbe; - assert!(*chunk.data == 0xbe); - } - drop(chunk); - - unlink(&path).unwrap(); - } - - #[test] - #[cfg(windows)] - fn split_paths_windows() { - fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { - split_paths(unparsed) == - parsed.iter().map(|s| Path::new(*s)).collect::>() - } - - assert!(check_parse("", &mut [""])); - assert!(check_parse(r#""""#, &mut [""])); - assert!(check_parse(";;", &mut ["", "", ""])); - assert!(check_parse(r"c:\", &mut [r"c:\"])); - assert!(check_parse(r"c:\;", &mut [r"c:\", ""])); - assert!(check_parse(r"c:\;c:\Program Files\", - &mut [r"c:\", r"c:\Program Files\"])); - assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"])); - assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#, - &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"])); - } - - #[test] - #[cfg(unix)] - fn split_paths_unix() { - fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { - split_paths(unparsed) == - parsed.iter().map(|s| Path::new(*s)).collect::>() - } - - assert!(check_parse("", &mut [""])); - assert!(check_parse("::", &mut ["", "", ""])); - assert!(check_parse("/", &mut ["/"])); - assert!(check_parse("/:", &mut ["/", ""])); - assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"])); - } - - #[test] - #[cfg(unix)] - fn join_paths_unix() { - fn test_eq(input: &[&str], output: &str) -> bool { - join_paths(input).unwrap() == output.as_bytes() - } - - assert!(test_eq(&[], "")); - assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], - "/bin:/usr/bin:/usr/local/bin")); - assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], - ":/bin:::/usr/bin:")); - assert!(join_paths(&["/te:st"]).is_err()); - } - - #[test] - #[cfg(windows)] - fn join_paths_windows() { - fn test_eq(input: &[&str], output: &str) -> bool { - join_paths(input).unwrap() == output.as_bytes() - } - - assert!(test_eq(&[], "")); - assert!(test_eq(&[r"c:\windows", r"c:\"], - r"c:\windows;c:\")); - assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], - r";c:\windows;;;c:\;")); - assert!(test_eq(&[r"c:\te;st", r"c:\"], - r#""c:\te;st";c:\"#)); - assert!(join_paths(&[r#"c:\te"st"#]).is_err()); - } - - // More recursive_mkdir tests are in extra::tempfile -} diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 58d3ae9f7cf..44421c40901 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1318,7 +1318,7 @@ impl Path { #[stable(feature = "rust1", since = "1.0.0")] pub fn file_name(&self) -> Option<&OsStr> { self.components().next_back().and_then(|p| match p { - Component::Normal(p) => Some(p.as_os_str()), + Component::Normal(p) => Some(p.as_ref()), _ => None }) } diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index 297eccb9f76..84a45086767 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -42,12 +42,11 @@ #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use result::Result::{self, Ok, Err}; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -#[doc(no_inline)] pub use slice::{SliceConcatExt, AsSlice}; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -#[doc(no_inline)] pub use str::Str; +#[doc(no_inline)] pub use slice::SliceConcatExt; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use string::{String, ToString}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use vec::Vec; + +#[allow(deprecated)] pub use slice::AsSlice; +#[allow(deprecated)] pub use str::Str; diff --git a/src/libstd/process.rs b/src/libstd/process.rs index b4bd513e8f0..ece0aa8f064 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -16,15 +16,15 @@ use prelude::v1::*; use io::prelude::*; -use ffi::AsOsStr; +use ffi::OsStr; use fmt; use io::{self, Error, ErrorKind}; use libc; use path; use sync::mpsc::{channel, Receiver}; use sys::pipe2::{self, AnonPipe}; -use sys::process2::Process as ProcessImp; use sys::process2::Command as CommandImp; +use sys::process2::Process as ProcessImp; use sys::process2::ExitStatus as ExitStatusImp; use sys_common::{AsInner, AsInnerMut}; use thread; @@ -147,9 +147,9 @@ impl Command { /// Builder methods are provided to change these defaults and /// otherwise configure the process. #[stable(feature = "process", since = "1.0.0")] - pub fn new(program: S) -> Command { + pub fn new>(program: S) -> Command { Command { - inner: CommandImp::new(program.as_os_str()), + inner: CommandImp::new(program.as_ref()), stdin: None, stdout: None, stderr: None, @@ -158,15 +158,15 @@ impl Command { /// Add an argument to pass to the program. #[stable(feature = "process", since = "1.0.0")] - pub fn arg(&mut self, arg: S) -> &mut Command { - self.inner.arg(arg.as_os_str()); + pub fn arg>(&mut self, arg: S) -> &mut Command { + self.inner.arg(arg.as_ref()); self } /// Add multiple arguments to pass to the program. #[stable(feature = "process", since = "1.0.0")] - pub fn args(&mut self, args: &[S]) -> &mut Command { - self.inner.args(args.iter().map(AsOsStr::as_os_str)); + pub fn args>(&mut self, args: &[S]) -> &mut Command { + self.inner.args(args.iter().map(AsRef::as_ref)); self } @@ -176,16 +176,16 @@ impl Command { /// and case-sensitive on all other platforms. #[stable(feature = "process", since = "1.0.0")] pub fn env(&mut self, key: K, val: V) -> &mut Command - where K: AsOsStr, V: AsOsStr + where K: AsRef, V: AsRef { - self.inner.env(key.as_os_str(), val.as_os_str()); + self.inner.env(key.as_ref(), val.as_ref()); self } /// Removes an environment variable mapping. #[stable(feature = "process", since = "1.0.0")] - pub fn env_remove(&mut self, key: K) -> &mut Command { - self.inner.env_remove(key.as_os_str()); + pub fn env_remove>(&mut self, key: K) -> &mut Command { + self.inner.env_remove(key.as_ref()); self } @@ -199,7 +199,7 @@ impl Command { /// Set the working directory for the child process. #[stable(feature = "process", since = "1.0.0")] pub fn current_dir>(&mut self, dir: P) -> &mut Command { - self.inner.cwd(dir.as_ref().as_os_str()); + self.inner.cwd(dir.as_ref().as_ref()); self } @@ -378,11 +378,6 @@ enum StdioImp { } impl Stdio { - /// A new pipe should be arranged to connect the parent and child processes. - #[unstable(feature = "process_capture")] - #[deprecated(since = "1.0.0", reason = "renamed to `Stdio::piped`")] - pub fn capture() -> Stdio { Stdio::piped() } - /// A new pipe should be arranged to connect the parent and child processes. #[stable(feature = "process", since = "1.0.0")] pub fn piped() -> Stdio { Stdio(StdioImp::Piped) } @@ -529,11 +524,10 @@ impl Child { #[cfg(test)] mod tests { - use io::ErrorKind; + use prelude::v1::*; use io::prelude::*; - use prelude::v1::{Ok, Err, drop, Some, Vec}; - use prelude::v1::{String, Clone}; - use prelude::v1::{Str, AsSlice, ToString}; + + use io::ErrorKind; use old_path::{self, GenericPath}; use old_io::fs::PathExtensions; use rt::running_on_valgrind; @@ -678,7 +672,7 @@ mod tests { fn test_process_output_output() { let Output {status, stdout, stderr} = Command::new("echo").arg("hello").output().unwrap(); - let output_str = str::from_utf8(stdout.as_slice()).unwrap(); + let output_str = str::from_utf8(&stdout).unwrap(); assert!(status.success()); assert_eq!(output_str.trim().to_string(), "hello"); @@ -720,7 +714,7 @@ mod tests { let prog = Command::new("echo").arg("hello").stdout(Stdio::piped()) .spawn().unwrap(); let Output {status, stdout, stderr} = prog.wait_with_output().unwrap(); - let output_str = str::from_utf8(stdout.as_slice()).unwrap(); + let output_str = str::from_utf8(&stdout).unwrap(); assert!(status.success()); assert_eq!(output_str.trim().to_string(), "hello"); @@ -755,7 +749,8 @@ mod tests { let prog = pwd_cmd().spawn().unwrap(); let output = String::from_utf8(prog.wait_with_output().unwrap().stdout).unwrap(); - let parent_dir = os::getcwd().unwrap(); + let parent_dir = ::env::current_dir().unwrap().to_str().unwrap().to_string(); + let parent_dir = old_path::Path::new(parent_dir); let child_dir = old_path::Path::new(output.trim()); let parent_stat = parent_dir.stat().unwrap(); @@ -770,7 +765,8 @@ mod tests { use os; // test changing to the parent of os::getcwd() because we know // the path exists (and os::getcwd() is not expected to be root) - let parent_dir = os::getcwd().unwrap().dir_path(); + let parent_dir = ::env::current_dir().unwrap().to_str().unwrap().to_string(); + let parent_dir = old_path::Path::new(parent_dir).dir_path(); let result = pwd_cmd().current_dir(parent_dir.as_str().unwrap()).output().unwrap(); let output = String::from_utf8(result.stdout).unwrap(); @@ -855,7 +851,7 @@ mod tests { cmd.env("PATH", &p); } let result = cmd.output().unwrap(); - let output = String::from_utf8_lossy(result.stdout.as_slice()).to_string(); + let output = String::from_utf8_lossy(&result.stdout).to_string(); assert!(output.contains("RUN_TEST_NEW_ENV=123"), "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output); @@ -864,7 +860,7 @@ mod tests { #[test] fn test_add_to_env() { let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap(); - let output = String::from_utf8_lossy(result.stdout.as_slice()).to_string(); + let output = String::from_utf8_lossy(&result.stdout).to_string(); assert!(output.contains("RUN_TEST_NEW_ENV=123"), "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output); diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 51b6045cf16..0a619ff8cd0 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -15,17 +15,16 @@ pub use self::imp::OsRng; #[cfg(all(unix, not(target_os = "ios")))] mod imp { - extern crate libc; - + use prelude::v1::*; use self::OsRngInner::*; + use libc; + use mem; use old_io::{IoResult, File}; use old_path::Path; use rand::Rng; use rand::reader::ReaderRng; - use result::Result::Ok; - use mem; - use os::errno; + use sys::os::errno; #[cfg(all(target_os = "linux", any(target_arch = "x86_64", @@ -184,14 +183,13 @@ mod imp { #[cfg(target_os = "ios")] mod imp { - extern crate libc; + use prelude::v1::*; - use old_io::{IoResult}; + use old_io::IoResult; use mem; use os; use rand::Rng; - use result::Result::{Ok}; - use self::libc::{c_int, size_t}; + use libc::{c_int, size_t}; /// A random number generator that retrieves randomness straight from /// the operating system. Platform sources: @@ -251,16 +249,15 @@ mod imp { #[cfg(windows)] mod imp { - extern crate libc; + use prelude::v1::*; - use old_io::{IoResult, IoError}; + use io; use mem; - use ops::Drop; + use old_io::{IoResult, IoError}; use os; use rand::Rng; - use result::Result::{Ok, Err}; - use self::libc::{DWORD, BYTE, LPCSTR, BOOL}; - use self::libc::types::os::arch::extra::{LONG_PTR}; + use libc::types::os::arch::extra::{LONG_PTR}; + use libc::{DWORD, BYTE, LPCSTR, BOOL}; type HCRYPTPROV = LONG_PTR; @@ -330,7 +327,8 @@ mod imp { v.as_mut_ptr()) }; if ret == 0 { - panic!("couldn't generate random bytes: {}", os::last_os_error()); + panic!("couldn't generate random bytes: {}", + io::Error::last_os_error()); } } } @@ -341,7 +339,8 @@ mod imp { CryptReleaseContext(self.hcryptprov, 0) }; if ret == 0 { - panic!("couldn't release context: {}", os::last_os_error()); + panic!("couldn't release context: {}", + io::Error::last_os_error()); } } } diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs index 428bcaa49f7..2329861f29b 100644 --- a/src/libstd/rt/args.rs +++ b/src/libstd/rt/args.rs @@ -108,7 +108,6 @@ mod imp { #[cfg(test)] mod tests { use prelude::v1::*; - use finally::Finally; use super::*; @@ -127,14 +126,11 @@ mod imp { assert!(take() == Some(expected.clone())); assert!(take() == None); - (|| { - }).finally(|| { - // Restore the actual global state. - match saved_value { - Some(ref args) => put(args.clone()), - None => () - } - }) + // Restore the actual global state. + match saved_value { + Some(ref args) => put(args.clone()), + None => () + } } } } diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 68137601c40..a5259a00390 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -31,8 +31,6 @@ pub use self::barrier::{Barrier, BarrierWaitResult}; pub use self::poison::{PoisonError, TryLockError, TryLockResult, LockResult}; pub use self::future::Future; -#[allow(deprecated)] -pub use self::task_pool::TaskPool; pub mod mpsc; @@ -44,4 +42,3 @@ mod once; mod poison; mod rwlock; mod semaphore; -mod task_pool; diff --git a/src/libstd/sync/poison.rs b/src/libstd/sync/poison.rs index c07c83d37f4..6ae8e043e05 100644 --- a/src/libstd/sync/poison.rs +++ b/src/libstd/sync/poison.rs @@ -122,12 +122,6 @@ impl PoisonError { PoisonError { guard: guard } } - /// Consumes this error indicating that a lock is poisoned, returning the - /// underlying guard to allow access regardless. - #[unstable(feature = "std_misc")] - #[deprecated(since = "1.0.0", reason = "renamed to into_inner")] - pub fn into_guard(self) -> T { self.guard } - /// Consumes this error indicating that a lock is poisoned, returning the /// underlying guard to allow access regardless. #[unstable(feature = "std_misc")] diff --git a/src/libstd/sync/task_pool.rs b/src/libstd/sync/task_pool.rs deleted file mode 100644 index 51cf70e615b..00000000000 --- a/src/libstd/sync/task_pool.rs +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Abstraction of a thread pool for basic parallelism. - -#![deprecated(since = "1.0.0", - reason = "This kind of API needs some time to bake in \ - crates.io. This functionality is available through \ - https://crates.io/crates/threadpool")] -#![unstable(feature = "std_misc")] - -#![allow(deprecated)] - -use core::prelude::*; - -use sync::{Arc, Mutex}; -use sync::mpsc::{channel, Sender, Receiver}; -use thread; -use thunk::Thunk; - -struct Sentinel<'a> { - jobs: &'a Arc>>>, - active: bool -} - -impl<'a> Sentinel<'a> { - fn new(jobs: &'a Arc>>>) -> Sentinel<'a> { - Sentinel { - jobs: jobs, - active: true - } - } - - // Cancel and destroy this sentinel. - fn cancel(mut self) { - self.active = false; - } -} - -#[unsafe_destructor] -impl<'a> Drop for Sentinel<'a> { - fn drop(&mut self) { - if self.active { - spawn_in_pool(self.jobs.clone()) - } - } -} - -/// A thread pool used to execute functions in parallel. -/// -/// Spawns `n` worker threads and replenishes the pool if any worker threads -/// panic. -/// -/// # Examples -/// -/// ``` -/// # #![feature(std_misc, core)] -/// use std::sync::TaskPool; -/// use std::iter::AdditiveIterator; -/// use std::sync::mpsc::channel; -/// -/// let pool = TaskPool::new(4); -/// -/// let (tx, rx) = channel(); -/// for _ in 0..8 { -/// let tx = tx.clone(); -/// pool.execute(move|| { -/// tx.send(1_u32).unwrap(); -/// }); -/// } -/// -/// assert_eq!(rx.iter().take(8).sum(), 8); -/// ``` -pub struct TaskPool { - // How the threadpool communicates with subthreads. - // - // This is the only such Sender, so when it is dropped all subthreads will - // quit. - jobs: Sender> -} - -impl TaskPool { - /// Spawns a new thread pool with `threads` threads. - /// - /// # Panics - /// - /// This function will panic if `threads` is 0. - pub fn new(threads: usize) -> TaskPool { - assert!(threads >= 1); - - let (tx, rx) = channel::(); - let rx = Arc::new(Mutex::new(rx)); - - // Threadpool threads - for _ in 0..threads { - spawn_in_pool(rx.clone()); - } - - TaskPool { jobs: tx } - } - - /// Executes the function `job` on a thread in the pool. - pub fn execute(&self, job: F) - where F : FnOnce(), F : Send + 'static - { - self.jobs.send(Thunk::new(job)).unwrap(); - } -} - -fn spawn_in_pool(jobs: Arc>>>) { - thread::spawn(move || { - // Will spawn a new thread on panic unless it is cancelled. - let sentinel = Sentinel::new(&jobs); - - loop { - let message = { - // Only lock jobs for the time it takes - // to get a job, not run it. - let lock = jobs.lock().unwrap(); - lock.recv() - }; - - match message { - Ok(job) => job.invoke(()), - - // The Taskpool was dropped. - Err(..) => break - } - } - - sentinel.cancel(); - }); -} - -#[cfg(test)] -mod test { - use prelude::v1::*; - use super::*; - use sync::mpsc::channel; - - const TEST_TASKS: usize = 4; - - #[test] - fn test_works() { - use iter::AdditiveIterator; - - let pool = TaskPool::new(TEST_TASKS); - - let (tx, rx) = channel(); - for _ in 0..TEST_TASKS { - let tx = tx.clone(); - pool.execute(move|| { - tx.send(1).unwrap(); - }); - } - - assert_eq!(rx.iter().take(TEST_TASKS).sum(), TEST_TASKS); - } - - #[test] - #[should_panic] - fn test_zero_tasks_panic() { - TaskPool::new(0); - } - - #[test] - fn test_recovery_from_subtask_panic() { - use iter::AdditiveIterator; - - let pool = TaskPool::new(TEST_TASKS); - - // Panic all the existing threads. - for _ in 0..TEST_TASKS { - pool.execute(move|| -> () { panic!() }); - } - - // Ensure new threads were spawned to compensate. - let (tx, rx) = channel(); - for _ in 0..TEST_TASKS { - let tx = tx.clone(); - pool.execute(move|| { - tx.send(1).unwrap(); - }); - } - - assert_eq!(rx.iter().take(TEST_TASKS).sum(), TEST_TASKS); - } - - #[test] - fn test_should_not_panic_on_drop_if_subtasks_panic_after_drop() { - use sync::{Arc, Barrier}; - - let pool = TaskPool::new(TEST_TASKS); - let waiter = Arc::new(Barrier::new(TEST_TASKS + 1)); - - // Panic all the existing threads in a bit. - for _ in 0..TEST_TASKS { - let waiter = waiter.clone(); - pool.execute(move|| { - waiter.wait(); - panic!(); - }); - } - - drop(pool); - - // Kick off the failure. - waiter.wait(); - } -} diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index 99a554a835f..ca805ad0242 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -251,7 +251,6 @@ fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, symaddr: *mut libc::c_void) -> io::Result<()> { use env; - use ffi::AsOsStr; use os::unix::prelude::*; use ptr; diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 2569653811f..6b085c8eb7a 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -388,9 +388,7 @@ mod tests { fn test_file_desc() { // Run this test with some pipes so we don't have to mess around with // opening or closing files. - let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() }; - let mut reader = FileDesc::new(reader, true); - let mut writer = FileDesc::new(writer, true); + let (mut reader, mut writer) = unsafe { ::sys::os::pipe().unwrap() }; writer.write(b"test").unwrap(); let mut buf = [0; 4]; diff --git a/src/libstd/sys/unix/fs2.rs b/src/libstd/sys/unix/fs2.rs index 202e5ddaec4..f425c39667a 100644 --- a/src/libstd/sys/unix/fs2.rs +++ b/src/libstd/sys/unix/fs2.rs @@ -12,7 +12,7 @@ use core::prelude::*; use io::prelude::*; use os::unix::prelude::*; -use ffi::{CString, CStr, OsString, AsOsStr, OsStr}; +use ffi::{CString, CStr, OsString, OsStr}; use io::{self, Error, SeekFrom}; use libc::{self, c_int, size_t, off_t, c_char, mode_t}; use mem; diff --git a/src/libstd/sys/unix/helper_signal.rs b/src/libstd/sys/unix/helper_signal.rs index 17c8b21f8b3..fe0ede80fc6 100644 --- a/src/libstd/sys/unix/helper_signal.rs +++ b/src/libstd/sys/unix/helper_signal.rs @@ -11,15 +11,15 @@ #![allow(deprecated)] use libc; -use os; +use sys::os; use sys::fs::FileDesc; pub type signal = libc::c_int; pub fn new() -> (signal, signal) { - let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() }; - (reader, writer) + let (a, b) = unsafe { os::pipe().unwrap() }; + (a.unwrap(), b.unwrap()) } pub fn signal(fd: libc::c_int) { diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index fab443feebd..af5b40af938 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -16,7 +16,7 @@ use prelude::v1::*; use os::unix::prelude::*; use error::Error as StdError; -use ffi::{CString, CStr, OsString, OsStr, AsOsStr}; +use ffi::{CString, CStr, OsString, OsStr}; use fmt; use io; use iter; @@ -125,7 +125,8 @@ pub fn getcwd() -> io::Result { } pub fn chdir(p: &path::Path) -> io::Result<()> { - let p = try!(CString::new(p.as_os_str().as_bytes())); + let p: &OsStr = p.as_ref(); + let p = try!(CString::new(p.as_bytes())); unsafe { match libc::chdir(p.as_ptr()) == (0 as c_int) { true => Ok(()), @@ -158,13 +159,13 @@ impl<'a> Iterator for SplitPaths<'a> { pub struct JoinPathsError; pub fn join_paths(paths: I) -> Result - where I: Iterator, T: AsOsStr + where I: Iterator, T: AsRef { let mut joined = Vec::new(); let sep = b':'; for (i, path) in paths.enumerate() { - let path = path.as_os_str().as_bytes(); + let path = path.as_ref().as_bytes(); if i > 0 { joined.push(sep) } if path.contains(&sep) { return Err(JoinPathsError) @@ -464,7 +465,7 @@ pub fn page_size() -> usize { } pub fn temp_dir() -> PathBuf { - getenv("TMPDIR".as_os_str()).map(os2path).unwrap_or_else(|| { + getenv("TMPDIR".as_ref()).map(os2path).unwrap_or_else(|| { if cfg!(target_os = "android") { PathBuf::from("/data/local/tmp") } else { @@ -474,7 +475,7 @@ pub fn temp_dir() -> PathBuf { } pub fn home_dir() -> Option { - return getenv("HOME".as_os_str()).or_else(|| unsafe { + return getenv("HOME".as_ref()).or_else(|| unsafe { fallback() }).map(os2path); diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 0d35ace185d..8095325f83d 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -19,8 +19,9 @@ use hash::Hash; use old_io::process::{ProcessExit, ExitStatus, ExitSignal}; use old_io::{IoResult, EndOfFile}; use libc::{self, pid_t, c_void, c_int}; +use io; use mem; -use os; +use sys::os; use old_path::BytesContainer; use ptr; use sync::mpsc::{channel, Sender, Receiver}; @@ -496,7 +497,8 @@ impl Process { n if n > 0 => { ret = true; } 0 => return true, -1 if wouldblock() => return ret, - n => panic!("bad read {:?} ({:?})", os::last_os_error(), n), + n => panic!("bad read {} ({})", + io::Error::last_os_error(), n), } } } diff --git a/src/libstd/sys/unix/timer.rs b/src/libstd/sys/unix/timer.rs index d9a162302fc..9309147b15c 100644 --- a/src/libstd/sys/unix/timer.rs +++ b/src/libstd/sys/unix/timer.rs @@ -54,7 +54,8 @@ use self::Req::*; use old_io::IoResult; use libc; use mem; -use os; +use sys::os; +use io; use ptr; use sync::atomic::{self, Ordering}; use sync::mpsc::{channel, Sender, Receiver, TryRecvError}; @@ -209,7 +210,7 @@ fn helper(input: libc::c_int, messages: Receiver, _: ()) { -1 if os::errno() == libc::EINTR as i32 => {} n => panic!("helper thread failed in select() with error: {} ({})", - n, os::last_os_error()) + n, io::Error::last_os_error()) } } } diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 167db1e8ac2..1ebd4c571ac 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -16,7 +16,7 @@ use prelude::v1::*; use os::windows::prelude::*; use error::Error as StdError; -use ffi::{OsString, OsStr, AsOsStr}; +use ffi::{OsString, OsStr}; use fmt; use io; use libc::types::os::arch::extra::LPWCH; @@ -199,13 +199,13 @@ impl<'a> Iterator for SplitPaths<'a> { pub struct JoinPathsError; pub fn join_paths(paths: I) -> Result - where I: Iterator, T: AsOsStr + where I: Iterator, T: AsRef { let mut joined = Vec::new(); let sep = b';' as u16; for (i, path) in paths.enumerate() { - let path = path.as_os_str(); + let path = path.as_ref(); if i > 0 { joined.push(sep) } let v = path.encode_wide().collect::>(); if v.contains(&(b'"' as u16)) { @@ -245,7 +245,8 @@ pub fn getcwd() -> io::Result { } pub fn chdir(p: &path::Path) -> io::Result<()> { - let mut p = p.as_os_str().encode_wide().collect::>(); + let p: &OsStr = p.as_ref(); + let mut p = p.encode_wide().collect::>(); p.push(0); unsafe { @@ -361,8 +362,8 @@ pub fn temp_dir() -> PathBuf { } pub fn home_dir() -> Option { - getenv("HOME".as_os_str()).or_else(|| { - getenv("USERPROFILE".as_os_str()) + getenv("HOME".as_ref()).or_else(|| { + getenv("USERPROFILE".as_ref()) }).map(PathBuf::from).or_else(|| unsafe { let me = c::GetCurrentProcess(); let mut token = ptr::null_mut(); diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 297f6e173ab..2065df4fbe3 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -23,6 +23,7 @@ use mem; use old_io::process::{ProcessExit, ExitStatus}; use old_io::{IoResult, IoError}; use old_io; +use fs::PathExt; use os; use old_path::{BytesContainer, GenericPath}; use ptr; @@ -142,14 +143,19 @@ impl Process { let program = cfg.env().and_then(|env| { for (key, v) in env { if b"PATH" != key.container_as_bytes() { continue } + let v = match ::str::from_utf8(v.container_as_bytes()) { + Ok(s) => s, + Err(..) => continue, + }; // Split the value and test each path to see if the // program exists. - for path in os::split_paths(v.container_as_bytes()) { - let path = path.join(cfg.program().as_bytes()) + for path in ::env::split_paths(v) { + let program = str::from_utf8(cfg.program().as_bytes()).unwrap(); + let path = path.join(program) .with_extension(env::consts::EXE_EXTENSION); if path.exists() { - return Some(CString::from_slice(path.as_vec())) + return Some(CString::new(path.to_str().unwrap()).unwrap()) } } break @@ -482,9 +488,9 @@ mod tests { #[test] fn test_make_command_line() { fn test_wrapper(prog: &str, args: &[&str]) -> String { - make_command_line(&CString::from_slice(prog.as_bytes()), + make_command_line(&CString::new(prog), &args.iter() - .map(|a| CString::from_slice(a.as_bytes())) + .map(|a| CString::new(a)) .collect::>()) } diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index a2b824bb016..b9cbd01bed1 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -294,12 +294,6 @@ impl LocalKey { } } } - - /// Deprecated - #[unstable(feature = "std_misc")] - #[deprecated(since = "1.0.0", - reason = "function renamed to state() and returns more info")] - pub fn destroyed(&'static self) -> bool { self.state() == LocalKeyState::Destroyed } } #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))] diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 074030bd07b..b9515c9a8a1 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -189,8 +189,6 @@ use sys_common::{stack, thread_info}; use thunk::Thunk; use time::Duration; -#[allow(deprecated)] use old_io::Writer; - //////////////////////////////////////////////////////////////////////////////// // Thread-local storage //////////////////////////////////////////////////////////////////////////////// @@ -243,28 +241,6 @@ impl Builder { self } - /// Redirect thread-local stdout. - #[unstable(feature = "std_misc", - reason = "Will likely go away after proc removal")] - #[deprecated(since = "1.0.0", - reason = "the old I/O module is deprecated and this function \ - will be removed with no replacement")] - #[allow(deprecated)] - pub fn stdout(self, _stdout: Box) -> Builder { - self - } - - /// Redirect thread-local stderr. - #[unstable(feature = "std_misc", - reason = "Will likely go away after proc removal")] - #[deprecated(since = "1.0.0", - reason = "the old I/O module is deprecated and this function \ - will be removed with no replacement")] - #[allow(deprecated)] - pub fn stderr(self, _stderr: Box) -> Builder { - self - } - /// Spawn a new thread, and return a join handle for it. /// /// The child thread may outlive the parent (unless the parent thread @@ -568,71 +544,6 @@ impl Thread { } } - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[unstable(feature = "std_misc", - reason = "may change with specifics of new Send semantics")] - pub fn spawn(f: F) -> Thread where F: FnOnce(), F: Send + 'static { - Builder::new().spawn(f).unwrap().thread().clone() - } - - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[unstable(feature = "std_misc", - reason = "may change with specifics of new Send semantics")] - pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where - T: Send + 'a, F: FnOnce() -> T, F: Send + 'a - { - Builder::new().scoped(f).unwrap() - } - - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn current() -> Thread { - thread_info::current_thread() - } - - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[unstable(feature = "std_misc", reason = "name may change")] - pub fn yield_now() { - unsafe { imp::yield_now() } - } - - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn panicking() -> bool { - unwind::panicking() - } - - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[unstable(feature = "std_misc", reason = "recently introduced")] - pub fn park() { - let thread = current(); - let mut guard = thread.inner.lock.lock().unwrap(); - while !*guard { - guard = thread.inner.cvar.wait(guard).unwrap(); - } - *guard = false; - } - - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[unstable(feature = "std_misc", reason = "recently introduced")] - pub fn park_timeout(duration: Duration) { - let thread = current(); - let mut guard = thread.inner.lock.lock().unwrap(); - if !*guard { - let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap(); - guard = g; - } - *guard = false; - } - /// Atomically makes the handle's token available if it is not already. /// /// See the module doc for more detail. @@ -762,8 +673,8 @@ impl<'a, T: Send + 'a> JoinGuard<'a, T> { &self.inner.thread } - /// Wait for the associated thread to finish, returning the result of the thread's - /// calculation. + /// Wait for the associated thread to finish, returning the result of the + /// thread's calculation. /// /// # Panics /// @@ -777,17 +688,6 @@ impl<'a, T: Send + 'a> JoinGuard<'a, T> { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl JoinGuard<'static, T> { - /// Detaches the child thread, allowing it to outlive its parent. - #[deprecated(since = "1.0.0", reason = "use spawn instead")] - #[unstable(feature = "std_misc")] - pub fn detach(mut self) { - unsafe { imp::detach(self.inner.native) }; - self.inner.joined = true; // avoid joining in the destructor - } -} - #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> { -- cgit 1.4.1-3-g733a5