diff options
| author | Jeremy Soller <jackpot51@gmail.com> | 2016-11-23 08:21:15 -0700 |
|---|---|---|
| committer | Jeremy Soller <jackpot51@gmail.com> | 2016-11-23 08:21:15 -0700 |
| commit | b3c91dfb6a2e21c82966d0a13f9cd3e51da94654 (patch) | |
| tree | 08bb76f6d05c6295b9ee7c3690b78a9ff52c7693 /src/libstd | |
| parent | ae2029fc62d744e252a5a077ce0dfbf2d1683d25 (diff) | |
| parent | 9fba8df2115141173ad60837f129f18e74424531 (diff) | |
| download | rust-b3c91dfb6a2e21c82966d0a13f9cd3e51da94654.tar.gz rust-b3c91dfb6a2e21c82966d0a13f9cd3e51da94654.zip | |
Merge branch 'master' into redox
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/fs.rs | 55 | ||||
| -rw-r--r-- | src/libstd/net/addr.rs | 79 | ||||
| -rw-r--r-- | src/libstd/process.rs | 15 | ||||
| -rw-r--r-- | src/libstd/sys/unix/fs.rs | 5 | ||||
| -rw-r--r-- | src/libstd/sys/windows/c.rs | 10 | ||||
| -rw-r--r-- | src/libstd/sys/windows/fs.rs | 18 | ||||
| -rw-r--r-- | src/libstd/sys/windows/pipe.rs | 33 |
7 files changed, 205 insertions, 10 deletions
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 3fc1267c06e..0cb9a49ad67 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -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() } @@ -2480,6 +2515,24 @@ mod tests { } #[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(); let path = tmpdir.join("in.txt"); diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 20dc5b3801b..1c016015b79 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -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 { diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 9d21a76e81b..c99fda9febc 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -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::*; diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 0b43fd2ac8c..9ee0458b5da 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -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 { diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index ce563dc7b16..1a563127f7f 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -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; @@ -389,6 +390,15 @@ pub enum FILE_INFO_BY_HANDLE_CLASS { } #[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, } diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 98fd15f863b..7d7d78bbd87 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -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 { diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index ed7e88e72cd..1eb17305476 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -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) } |
