From 73b0b25e326687aba319df99aee4b0c4124d4498 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 3 Mar 2015 19:18:29 -0800 Subject: [PATCH] std: Stabilize the `fs` module This commit performs a stabilization pass over the `std::fs` module now that it's had some time to bake. The change was largely just adding `#[stable]` tags, but there are a few APIs that remain `#[unstable]`. The following apis are now marked `#[stable]`: * `std::fs` (the name) * `File` * `Metadata` * `ReadDir` * `DirEntry` * `OpenOptions` * `Permissions` * `File::{open, create}` * `File::{sync_all, sync_data}` * `File::set_len` * `File::metadata` * Trait implementations for `File` and `&File` * `OpenOptions::new` * `OpenOptions::{read, write, append, truncate, create}` * `OpenOptions::open` - this function was modified, however, to not attempt to reject cross-platform openings of directories. This means that some platforms will succeed in opening a directory and others will fail. * `Metadata::{is_dir, is_file, len, permissions}` * `Permissions::{readonly, set_readonly}` * `Iterator for ReadDir` * `DirEntry::path` * `remove_file` - like with `OpenOptions::open`, the extra windows code to remove a readonly file has been removed. This means that removing a readonly file will succeed on some platforms but fail on others. * `metadata` * `rename` * `copy` * `hard_link` * `soft_link` * `read_link` * `create_dir` * `create_dir_all` * `remove_dir` * `remove_dir_all` * `read_dir` The following apis remain `#[unstable]`. * `WalkDir` and `walk` - there are many methods by which a directory walk can be constructed, and it's unclear whether the current semantics are the right ones. For example symlinks are not handled super well currently. This is now behind a new `fs_walk` feature. * `File::path` - this is an extra abstraction which the standard library provides on top of what the system offers and it's unclear whether we should be doing so. This is now behind a new `file_path` feature. * `Metadata::{accessed, modified}` - we do not currently have a good abstraction for a moment in time which is what these APIs should likely be returning, so these remain `#[unstable]` for now. These are now behind a new `fs_time` feature * `set_file_times` - like with `Metadata::accessed`, we do not currently have the appropriate abstraction for the arguments here so this API remains unstable behind the `fs_time` feature gate. * `PathExt` - the precise set of methods on this trait may change over time and some methods may be removed. This API remains unstable behind the `path_ext` feature gate. * `set_permissions` - we may wish to expose a more granular ability to set the permissions on a file instead of just a blanket "set all permissions" method. This function remains behind the `fs` feature. The following apis are now `#[deprecated]` * The `TempDir` type is now entirely deprecated and is [located on crates.io][tempdir] as the `tempdir` crate with [its source][github] at rust-lang/tempdir. [tempdir]: https://crates.io/crates/tempdir [github]: https://github.com/rust-lang/tempdir The stability of some of these APIs has been questioned over the past few weeks in using these APIs, and it is intentional that the majority of APIs here are marked `#[stable]`. The `std::fs` module has a lot of room to grow and the material is [being tracked in a RFC issue][rfc-issue]. [rfc-issue]: https://github.com/rust-lang/rfcs/issues/939 [breaking-change] --- src/compiletest/compiletest.rs | 2 +- src/libgetopts/lib.rs | 2 +- src/librustc/lib.rs | 2 +- src/librustc_back/archive.rs | 4 +- src/librustc_back/lib.rs | 5 +- src/librustc_back/tempdir.rs | 121 ++++++++++++++++++++++++++++++++ src/librustc_driver/lib.rs | 1 - src/librustc_trans/back/link.rs | 3 +- src/librustc_trans/lib.rs | 4 +- src/librustdoc/lib.rs | 4 +- src/librustdoc/test.rs | 2 +- src/libstd/fs/mod.rs | 120 +++++++++++++++++++++---------- src/libstd/fs/tempdir.rs | 3 + src/libsyntax/lib.rs | 2 +- src/libterm/lib.rs | 2 +- src/libtest/lib.rs | 1 - src/rustbook/build.rs | 3 +- src/rustbook/main.rs | 4 +- 18 files changed, 229 insertions(+), 56 deletions(-) create mode 100644 src/librustc_back/tempdir.rs diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index b9e6f1842eeab..a7531152a8400 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -24,8 +24,8 @@ #![feature(path)] #![feature(os)] #![feature(io)] -#![feature(fs)] #![feature(net)] +#![feature(path_ext)] #![deny(warnings)] diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 6b9d6cb0000f2..49a062ca3e4ba 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -92,8 +92,8 @@ #![feature(collections)] #![feature(int_uint)] #![feature(staged_api)] -#![feature(str_words)] #![feature(core)] +#![feature(str_words)] #![cfg_attr(test, feature(rustc_private))] #[cfg(test)] #[macro_use] extern crate log; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 2d542eafbe1ae..027360b31ad46 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -40,8 +40,8 @@ #![feature(std_misc)] #![feature(os)] #![feature(path)] -#![feature(fs)] #![feature(io)] +#![feature(path_ext)] #![cfg_attr(test, feature(test))] extern crate arena; diff --git a/src/librustc_back/archive.rs b/src/librustc_back/archive.rs index a6994387f8d6a..ed44bf8952951 100644 --- a/src/librustc_back/archive.rs +++ b/src/librustc_back/archive.rs @@ -11,7 +11,7 @@ //! A helper class for dealing with static archives use std::env; -use std::fs::{self, TempDir}; +use std::fs; use std::io::prelude::*; use std::io; use std::path::{Path, PathBuf}; @@ -19,6 +19,8 @@ use std::process::{Command, Output, Stdio}; use std::str; use syntax::diagnostic::Handler as ErrorHandler; +use tempdir::TempDir; + pub const METADATA_FILENAME: &'static str = "rust.metadata.bin"; pub struct ArchiveConfig<'a> { diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 2b028a5c62623..a7ae9661c3d83 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -34,7 +34,6 @@ #![feature(collections)] #![feature(core)] #![feature(old_fs)] -#![feature(fs)] #![feature(hash)] #![feature(int_uint)] #![feature(io)] @@ -44,7 +43,8 @@ #![feature(path)] #![feature(rustc_private)] #![feature(staged_api)] -#![feature(tempdir)] +#![feature(rand)] +#![feature(path_ext)] extern crate syntax; extern crate serialize; @@ -52,6 +52,7 @@ extern crate serialize; pub mod abi; pub mod archive; +pub mod tempdir; pub mod arm; pub mod fs; pub mod mips; diff --git a/src/librustc_back/tempdir.rs b/src/librustc_back/tempdir.rs new file mode 100644 index 0000000000000..4d8619a81216f --- /dev/null +++ b/src/librustc_back/tempdir.rs @@ -0,0 +1,121 @@ +// 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. + +use std::env; +use std::io::{self, Error, ErrorKind}; +use std::fs; +use std::path::{self, PathBuf, AsPath}; +use std::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: uint = 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_path(); + 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::PathAlreadyExists => {} + Err(e) => return Err(e) + } + } + + Err(Error::new(ErrorKind::PathAlreadyExists, + "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/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index aa8b7c7785d20..b8e84e57a7870 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -39,7 +39,6 @@ #![feature(exit_status)] #![feature(path)] #![feature(io)] -#![feature(fs)] extern crate arena; extern crate flate; diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 1e84bc4b8e0bb..f353c69eca299 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -26,9 +26,10 @@ use middle::ty::{self, Ty}; use util::common::time; use util::ppaux; use util::sha2::{Digest, Sha256}; +use rustc_back::tempdir::TempDir; use std::ffi::{AsOsStr, OsString}; -use std::fs::{self, TempDir, PathExt}; +use std::fs::{self, PathExt}; use std::io::{self, Read, Write}; use std::mem; use std::path::{Path, PathBuf}; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index dcc79e90cc572..7cdd1d0a456cc 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -38,10 +38,10 @@ #![feature(std_misc)] #![feature(unicode)] #![feature(io)] -#![feature(fs)] #![feature(path)] #![feature(os)] -#![feature(tempdir)] +#![feature(path_ext)] +#![feature(fs)] extern crate arena; extern crate flate; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index b4522ad680b77..712168ae70679 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -35,9 +35,8 @@ #![feature(unicode)] #![feature(str_words)] #![feature(io)] -#![feature(fs)] #![feature(path)] -#![feature(tempdir)] +#![feature(path_ext)] extern crate arena; extern crate getopts; @@ -47,6 +46,7 @@ extern crate rustc_trans; extern crate rustc_driver; extern crate rustc_resolve; extern crate rustc_lint; +extern crate rustc_back; extern crate serialize; extern crate syntax; extern crate "test" as testing; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 9fd38ecb13627..80b0177021e74 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -13,7 +13,6 @@ use std::collections::{HashSet, HashMap}; use std::dynamic_lib::DynamicLibrary; use std::env; use std::ffi::OsString; -use std::fs::TempDir; use std::old_io; use std::io; use std::path::PathBuf; @@ -28,6 +27,7 @@ use rustc_lint; use rustc::session::{self, config}; use rustc::session::config::get_unstable_features_setting; use rustc::session::search_paths::{SearchPaths, PathKind}; +use rustc_back::tempdir::TempDir; use rustc_driver::{driver, Compilation}; use syntax::codemap::CodeMap; use syntax::diagnostic; diff --git a/src/libstd/fs/mod.rs b/src/libstd/fs/mod.rs index 64ec025a5c423..706a51c6c9a08 100644 --- a/src/libstd/fs/mod.rs +++ b/src/libstd/fs/mod.rs @@ -15,7 +15,7 @@ //! operations. Extra platform-specific functionality can be found in the //! extension traits of `std::os::$platform`. -#![unstable(feature = "fs")] +#![stable(feature = "rust1", since = "1.0.0")] use core::prelude::*; @@ -25,6 +25,7 @@ use sys::fs2 as fs_imp; use sys_common::{AsInnerMut, FromInner, AsInner}; use vec::Vec; +#[allow(deprecated)] pub use self::tempdir::TempDir; mod tempdir; @@ -52,6 +53,7 @@ mod tempdir; /// # Ok(()) /// # } /// ``` +#[stable(feature = "rust1", since = "1.0.0")] pub struct File { inner: fs_imp::File, path: PathBuf, @@ -62,6 +64,7 @@ pub struct 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. @@ -70,6 +73,7 @@ pub struct Metadata(fs_imp::FileAttr); /// will yield instances of `io::Result`. Through a `DirEntry` /// information like the entry's path and possibly other metadata can be /// learned. +#[stable(feature = "rust1", since = "1.0.0")] pub struct ReadDir(fs_imp::ReadDir); /// Entries returned by the `ReadDir` iterator. @@ -77,9 +81,14 @@ pub struct ReadDir(fs_imp::ReadDir); /// 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>, @@ -92,6 +101,7 @@ pub struct WalkDir { /// `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. @@ -101,6 +111,7 @@ pub struct OpenOptions(fs_imp::OpenOptions); /// 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 { @@ -112,6 +123,7 @@ impl File { /// /// This function will return an error if `path` does not already exist. /// Other errors may also be returned according to `OpenOptions::open`. + #[stable(feature = "rust1", since = "1.0.0")] pub fn open(path: &P) -> io::Result { OpenOptions::new().read(true).open(path) } @@ -122,11 +134,15 @@ impl File { /// and will truncate it if it does. /// /// See the `OpenOptions::open` function for more details. + #[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) } @@ -135,6 +151,7 @@ impl File { /// /// This function will attempt to ensure that all in-core data reaches the /// filesystem before returning. + #[stable(feature = "rust1", since = "1.0.0")] pub fn sync_all(&self) -> io::Result<()> { self.inner.fsync() } @@ -148,6 +165,7 @@ impl File { /// /// Note that some platforms may simply implement this in terms of /// `sync_all`. + #[stable(feature = "rust1", since = "1.0.0")] pub fn sync_data(&self) -> io::Result<()> { self.inner.datasync() } @@ -159,11 +177,13 @@ impl File { /// 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. + #[stable(feature = "rust1", since = "1.0.0")] pub fn set_len(&self, size: u64) -> io::Result<()> { self.inner.truncate(size) } - /// Queries information about the underlying file. + /// Queries metadata about the underlying file. + #[stable(feature = "rust1", since = "1.0.0")] pub fn metadata(&self) -> io::Result { self.inner.file_attr().map(Metadata) } @@ -172,33 +192,39 @@ impl File { 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) @@ -209,6 +235,7 @@ 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()) } @@ -217,6 +244,7 @@ impl OpenOptions { /// /// 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 } @@ -225,6 +253,7 @@ impl OpenOptions { /// /// 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 } @@ -233,6 +262,7 @@ impl OpenOptions { /// /// 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 } @@ -241,6 +271,7 @@ impl OpenOptions { /// /// 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 } @@ -249,6 +280,7 @@ impl OpenOptions { /// /// 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 } @@ -264,37 +296,33 @@ impl OpenOptions { /// * 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_path(); let inner = try!(fs_imp::File::open(path, &self.0)); - - // On *BSD systems, we can open a directory as a file and read from - // it: fd=open("/tmp", O_RDONLY); read(fd, buf, N); due to an old - // tradition before the introduction of opendir(3). We explicitly - // reject it because there are few use cases. - if cfg!(not(any(target_os = "linux", target_os = "android"))) && - try!(inner.file_attr()).is_dir() { - Err(Error::new(ErrorKind::InvalidInput, "is a directory", None)) - } else { - Ok(File { path: path.to_path_buf(), inner: inner }) - } + 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()) } @@ -302,22 +330,32 @@ impl Metadata { /// 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) } @@ -333,6 +371,7 @@ 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; @@ -341,11 +380,13 @@ impl Iterator for ReadDir { } } +#[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() } } @@ -368,31 +409,9 @@ impl DirEntry { /// 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<()> { - let path = path.as_path(); - let e = match fs_imp::unlink(path) { - Ok(()) => return Ok(()), - Err(e) => e, - }; - if !cfg!(windows) { return Err(e) } - - // On unix, a readonly file can be successfully removed. On windows, - // however, it cannot. To keep the two platforms in line with - // respect to their behavior, catch this case on windows, attempt to - // change it to read-write, and then remove the file. - if e.kind() != ErrorKind::PermissionDenied { return Err(e) } - - let attr = match metadata(path) { Ok(a) => a, Err(..) => return Err(e) }; - let mut perms = attr.permissions(); - if !perms.readonly() { return Err(e) } - perms.set_readonly(false); - - if set_permissions(path, perms).is_err() { return Err(e) } - if fs_imp::unlink(path).is_ok() { return Ok(()) } - - // Oops, try to put things back the way we found it - let _ = set_permissions(path, attr.permissions()); - Err(e) + fs_imp::unlink(path.as_path()) } /// Given a path, query the file system to get information about a file, @@ -418,6 +437,7 @@ pub fn remove_file(path: &P) -> io::Result<()> { /// 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_path()).map(Metadata) } @@ -438,6 +458,7 @@ pub fn metadata(path: &P) -> io::Result { /// 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(from: &P, to: &Q) -> io::Result<()> { fs_imp::rename(from.as_path(), to.as_path()) @@ -468,6 +489,7 @@ pub fn rename(from: &P, to: &Q) /// * 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(from: &P, to: &Q) -> io::Result { let from = from.as_path(); @@ -490,6 +512,7 @@ pub fn copy(from: &P, to: &Q) /// /// 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(src: &P, dst: &Q) -> io::Result<()> { fs_imp::link(src.as_path(), dst.as_path()) @@ -498,6 +521,7 @@ pub fn hard_link(src: &P, dst: &Q) /// 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(src: &P, dst: &Q) -> io::Result<()> { fs_imp::symlink(src.as_path(), dst.as_path()) @@ -510,6 +534,7 @@ pub fn soft_link(src: &P, dst: &Q) /// 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_path()) } @@ -528,6 +553,7 @@ pub fn read_link(path: &P) -> io::Result { /// /// 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_path()) } @@ -541,6 +567,7 @@ pub fn create_dir(path: &P) -> io::Result<()> { /// 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_path(); if path.is_dir() { return Ok(()) } @@ -572,6 +599,7 @@ pub fn create_dir_all(path: &P) -> io::Result<()> { /// /// 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_path()) } @@ -585,6 +613,7 @@ pub fn remove_dir(path: &P) -> io::Result<()> { /// # 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_path(); for child in try!(read_dir(path)) { @@ -637,6 +666,7 @@ pub fn remove_dir_all(path: &P) -> io::Result<()> { /// 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_path()).map(ReadDir) } @@ -649,11 +679,16 @@ pub fn read_dir(path: &P) -> io::Result { /// /// 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; @@ -683,6 +718,9 @@ impl Iterator for WalkDir { } /// 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. /// @@ -727,6 +765,10 @@ impl PathExt for Path { /// 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_path(), accessed, modified) @@ -752,6 +794,10 @@ pub fn set_file_times(path: &P, accessed: u64, /// 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_path(), perm.0) diff --git a/src/libstd/fs/tempdir.rs b/src/libstd/fs/tempdir.rs index 79bdb35dd48cd..c1da77a6668f5 100644 --- a/src/libstd/fs/tempdir.rs +++ b/src/libstd/fs/tempdir.rs @@ -9,6 +9,9 @@ // 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::*; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 7bd9cc3b85515..c0977508112c5 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -37,8 +37,8 @@ #![feature(std_misc)] #![feature(unicode)] #![feature(path)] -#![feature(fs)] #![feature(io)] +#![feature(path_ext)] extern crate arena; extern crate fmt_macros; diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index ba9860ee31f60..d4e22c72e1636 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -52,7 +52,6 @@ #![feature(box_syntax)] #![feature(collections)] -#![feature(fs)] #![feature(int_uint)] #![feature(io)] #![feature(old_io)] @@ -61,6 +60,7 @@ #![feature(staged_api)] #![feature(std_misc)] #![feature(unicode)] +#![feature(path_ext)] #![cfg_attr(windows, feature(libc))] #[macro_use] extern crate log; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index e309e7a6c221d..60dd91f8c715e 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -39,7 +39,6 @@ #![feature(int_uint)] #![feature(old_io)] #![feature(path)] -#![feature(fs)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(std_misc)] diff --git a/src/rustbook/build.rs b/src/rustbook/build.rs index 1fb30e15400ef..731773917e091 100644 --- a/src/rustbook/build.rs +++ b/src/rustbook/build.rs @@ -11,10 +11,11 @@ //! Implementation of the `build` subcommand, used to compile a book. use std::env; -use std::fs::{self, File, TempDir}; +use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufWriter}; use std::path::{Path, PathBuf}; +use rustc_back::tempdir::TempDir; use subcommand::Subcommand; use term::Term; diff --git a/src/rustbook/main.rs b/src/rustbook/main.rs index 848f960839e6e..8df622b0b5d0c 100644 --- a/src/rustbook/main.rs +++ b/src/rustbook/main.rs @@ -12,14 +12,14 @@ #![feature(core)] #![feature(exit_status)] -#![feature(fs)] #![feature(io)] #![feature(old_io)] #![feature(path)] #![feature(rustdoc)] -#![feature(tempdir)] +#![feature(rustc_private)] extern crate rustdoc; +extern crate rustc_back; use std::env; use std::error::Error;