Merge branch 'master' into redox

This commit is contained in:
Jeremy Soller 2016-11-23 08:21:15 -07:00
commit b3c91dfb6a
268 changed files with 5042 additions and 3096 deletions

View file

@ -349,12 +349,47 @@ impl File {
})
}
/// Changes the permissions on the underlying file.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `fchmod` function on Unix and
/// the `SetFileInformationByHandle` function on Windows. Note that, this
/// [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
///
/// This function will return an error if the user lacks permission change
/// attributes on the underlying file. It may also return an error in other
/// os-specific unspecified cases.
///
/// # Examples
///
/// ```
/// #![feature(set_permissions_atomic)]
/// # fn foo() -> std::io::Result<()> {
/// use std::fs::File;
///
/// let file = File::open("foo.txt")?;
/// let mut perms = file.metadata()?.permissions();
/// perms.set_readonly(true);
/// file.set_permissions(perms)?;
/// # Ok(())
/// # }
/// ```
#[unstable(feature = "set_permissions_atomic", issue="37916")]
pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
self.inner.set_permissions(perm.0)
}
/// Get the path that this file points to.
///
/// This function is only implemented on Redox, but could be
/// implemented on other operating systems using readlink
#[cfg(target_os = "redox")]
#[stable(feature = "rust1", since = "1.14.0")]
#[unstable(feature = "file_path", issue="0")]
pub fn path(&self) -> io::Result<PathBuf> {
self.inner.path()
}
@ -2479,6 +2514,24 @@ mod tests {
check!(fs::set_permissions(&file, p));
}
#[test]
fn fchmod_works() {
let tmpdir = tmpdir();
let path = tmpdir.join("in.txt");
let file = check!(File::create(&path));
let attr = check!(fs::metadata(&path));
assert!(!attr.permissions().readonly());
let mut p = attr.permissions();
p.set_readonly(true);
check!(file.set_permissions(p.clone()));
let attr = check!(fs::metadata(&path));
assert!(attr.permissions().readonly());
p.set_readonly(false);
check!(file.set_permissions(p));
}
#[test]
fn sync_doesnt_kill_anything() {
let tmpdir = tmpdir();

View file

@ -31,7 +31,7 @@ pub enum SocketAddr {
/// An IPv4 socket address which is a (ip, port) combination.
#[stable(feature = "rust1", since = "1.0.0")]
V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4),
/// An IPv6 socket address
/// An IPv6 socket address.
#[stable(feature = "rust1", since = "1.0.0")]
V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6),
}
@ -48,6 +48,16 @@ pub struct SocketAddrV6 { inner: c::sockaddr_in6 }
impl SocketAddr {
/// Creates a new socket address from the (ip, port) pair.
///
/// # Examples
///
/// ```
/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
///
/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
/// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
/// assert_eq!(socket.port(), 8080);
/// ```
#[stable(feature = "ip_addr", since = "1.7.0")]
pub fn new(ip: IpAddr, port: u16) -> SocketAddr {
match ip {
@ -57,6 +67,15 @@ impl SocketAddr {
}
/// Returns the IP address associated with this socket address.
///
/// # Examples
///
/// ```
/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
///
/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
/// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
/// ```
#[stable(feature = "ip_addr", since = "1.7.0")]
pub fn ip(&self) -> IpAddr {
match *self {
@ -66,6 +85,16 @@ impl SocketAddr {
}
/// Change the IP address associated with this socket address.
///
/// # Examples
///
/// ```
/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
///
/// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
/// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
/// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
/// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")]
pub fn set_ip(&mut self, new_ip: IpAddr) {
// `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
@ -77,6 +106,15 @@ impl SocketAddr {
}
/// Returns the port number associated with this socket address.
///
/// # Examples
///
/// ```
/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
///
/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
/// assert_eq!(socket.port(), 8080);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn port(&self) -> u16 {
match *self {
@ -86,6 +124,16 @@ impl SocketAddr {
}
/// Change the port number associated with this socket address.
///
/// # Examples
///
/// ```
/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
///
/// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
/// socket.set_port(1025);
/// assert_eq!(socket.port(), 1025);
/// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")]
pub fn set_port(&mut self, new_port: u16) {
match *self {
@ -96,6 +144,20 @@ impl SocketAddr {
/// Returns true if the IP in this `SocketAddr` is a valid IPv4 address,
/// false if it's a valid IPv6 address.
///
/// # Examples
///
/// ```
/// #![feature(sockaddr_checker)]
///
/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
///
/// fn main() {
/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
/// assert_eq!(socket.is_ipv4(), true);
/// assert_eq!(socket.is_ipv6(), false);
/// }
/// ```
#[unstable(feature = "sockaddr_checker", issue = "36949")]
pub fn is_ipv4(&self) -> bool {
match *self {
@ -106,6 +168,21 @@ impl SocketAddr {
/// Returns true if the IP in this `SocketAddr` is a valid IPv6 address,
/// false if it's a valid IPv4 address.
///
/// # Examples
///
/// ```
/// #![feature(sockaddr_checker)]
///
/// use std::net::{IpAddr, Ipv6Addr, SocketAddr};
///
/// fn main() {
/// let socket = SocketAddr::new(
/// IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080);
/// assert_eq!(socket.is_ipv4(), false);
/// assert_eq!(socket.is_ipv6(), true);
/// }
/// ```
#[unstable(feature = "sockaddr_checker", issue = "36949")]
pub fn is_ipv6(&self) -> bool {
match *self {

View file

@ -825,6 +825,21 @@ pub fn exit(code: i32) -> ! {
::sys::os::exit(code)
}
/// Terminates the process in an abnormal fashion.
///
/// The function will never return and will immediately terminate the current
/// process in a platform specific "abnormal" manner.
///
/// Note that because this function never returns, and that it terminates the
/// process, no destructors on the current stack or any other thread's stack
/// will be run. If a clean shutdown is needed it is recommended to only call
/// this function at a known point where there are no more destructors left
/// to run.
#[unstable(feature = "process_abort", issue = "37838")]
pub fn abort() -> ! {
unsafe { ::sys::abort_internal() };
}
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use io::prelude::*;

View file

@ -526,6 +526,11 @@ impl File {
pub fn fd(&self) -> &FileDesc { &self.0 }
pub fn into_fd(self) -> FileDesc { self.0 }
pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?;
Ok(())
}
}
impl DirBuilder {

View file

@ -182,6 +182,7 @@ pub const ERROR_INVALID_HANDLE: DWORD = 6;
pub const ERROR_NO_MORE_FILES: DWORD = 18;
pub const ERROR_HANDLE_EOF: DWORD = 38;
pub const ERROR_FILE_EXISTS: DWORD = 80;
pub const ERROR_INVALID_PARAMETER: DWORD = 87;
pub const ERROR_BROKEN_PIPE: DWORD = 109;
pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120;
pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122;
@ -388,6 +389,15 @@ pub enum FILE_INFO_BY_HANDLE_CLASS {
MaximumFileInfoByHandlesClass
}
#[repr(C)]
pub struct FILE_BASIC_INFO {
pub CreationTime: LARGE_INTEGER,
pub LastAccessTime: LARGE_INTEGER,
pub LastWriteTime: LARGE_INTEGER,
pub ChangeTime: LARGE_INTEGER,
pub FileAttributes: DWORD,
}
#[repr(C)]
pub struct FILE_END_OF_FILE_INFO {
pub EndOfFile: LARGE_INTEGER,

View file

@ -417,6 +417,24 @@ impl File {
Ok(PathBuf::from(OsString::from_wide(subst)))
}
}
pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
let mut info = c::FILE_BASIC_INFO {
CreationTime: 0,
LastAccessTime: 0,
LastWriteTime: 0,
ChangeTime: 0,
FileAttributes: perm.attrs,
};
let size = mem::size_of_val(&info);
cvt(unsafe {
c::SetFileInformationByHandle(self.handle.raw(),
c::FileBasicInfo,
&mut info as *mut _ as *mut _,
size as c::DWORD)
})?;
Ok(())
}
}
impl FromInner<c::HANDLE> for File {

View file

@ -43,6 +43,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
let reader;
let mut name;
let mut tries = 0;
let mut reject_remote_clients_flag = c::PIPE_REJECT_REMOTE_CLIENTS;
loop {
tries += 1;
let key: u64 = rand::thread_rng().gen();
@ -56,12 +57,12 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
let handle = c::CreateNamedPipeW(wide_name.as_ptr(),
c::PIPE_ACCESS_INBOUND |
c::FILE_FLAG_FIRST_PIPE_INSTANCE |
c::FILE_FLAG_OVERLAPPED,
c::FILE_FLAG_FIRST_PIPE_INSTANCE |
c::FILE_FLAG_OVERLAPPED,
c::PIPE_TYPE_BYTE |
c::PIPE_READMODE_BYTE |
c::PIPE_WAIT |
c::PIPE_REJECT_REMOTE_CLIENTS,
c::PIPE_READMODE_BYTE |
c::PIPE_WAIT |
reject_remote_clients_flag,
1,
4096,
4096,
@ -76,11 +77,27 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
//
// Don't try again too much though as this could also perhaps be a
// legit error.
// If ERROR_INVALID_PARAMETER is returned, this probably means we're
// running on pre-Vista version where PIPE_REJECT_REMOTE_CLIENTS is
// not supported, so we continue retrying without it. This implies
// reduced security on Windows versions older than Vista by allowing
// connections to this pipe from remote machines.
// Proper fix would increase the number of FFI imports and introduce
// significant amount of Windows XP specific code with no clean
// testing strategy
// for more info see https://github.com/rust-lang/rust/pull/37677
if handle == c::INVALID_HANDLE_VALUE {
let err = io::Error::last_os_error();
if tries < 10 &&
err.raw_os_error() == Some(c::ERROR_ACCESS_DENIED as i32) {
continue
let raw_os_err = err.raw_os_error();
if tries < 10 {
if raw_os_err == Some(c::ERROR_ACCESS_DENIED as i32) {
continue
} else if reject_remote_clients_flag != 0 &&
raw_os_err == Some(c::ERROR_INVALID_PARAMETER as i32) {
reject_remote_clients_flag = 0;
tries -= 1;
continue
}
}
return Err(err)
}