Importing rustc-1.60.0
Test: ./build.py --lto=thin
Bug: 218368713
Change-Id: Id769ad47aab28ec7b551d06785fb811cdf441aec
diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs
index 9665d1f..e06eaf6 100644
--- a/library/std/src/sys/common/alloc.rs
+++ b/library/std/src/sys/common/alloc.rs
@@ -14,8 +14,8 @@
target_arch = "asmjs",
target_arch = "wasm32",
target_arch = "hexagon",
- target_arch = "riscv32",
- target_arch = "xtensa"
+ all(target_arch = "riscv32", not(target_os = "espidf")),
+ all(target_arch = "xtensa", not(target_os = "espidf")),
)))]
pub const MIN_ALIGN: usize = 8;
#[cfg(all(any(
@@ -28,6 +28,12 @@
target_arch = "wasm64",
)))]
pub const MIN_ALIGN: usize = 16;
+// The allocator on the esp-idf platform guarentees 4 byte alignment.
+#[cfg(all(any(
+ all(target_arch = "riscv32", target_os = "espidf"),
+ all(target_arch = "xtensa", target_os = "espidf"),
+)))]
+pub const MIN_ALIGN: usize = 4;
pub unsafe fn realloc_fallback(
alloc: &System,
diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs
index 974c44e..fa9a7fb 100644
--- a/library/std/src/sys/hermit/fs.rs
+++ b/library/std/src/sys/hermit/fs.rs
@@ -226,7 +226,7 @@
(false, _, true) => Ok(O_WRONLY | O_APPEND),
(true, _, true) => Ok(O_RDWR | O_APPEND),
(false, false, false) => {
- Err(io::Error::new_const(ErrorKind::InvalidInput, &"invalid access mode"))
+ Err(io::const_io_error!(ErrorKind::InvalidInput, "invalid access mode"))
}
}
}
@@ -236,17 +236,17 @@
(true, false) => {}
(false, false) => {
if self.truncate || self.create || self.create_new {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid creation mode",
+ "invalid creation mode",
));
}
}
(_, true) => {
if self.truncate && !self.create_new {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid creation mode",
+ "invalid creation mode",
));
}
}
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index 185b68c..b798c97 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -58,9 +58,9 @@
}
pub fn unsupported_err() -> crate::io::Error {
- crate::io::Error::new_const(
+ crate::io::const_io_error!(
crate::io::ErrorKind::Unsupported,
- &"operation not supported on HermitCore yet",
+ "operation not supported on HermitCore yet",
)
}
diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs
index 1a6b3bc..f65fd8e 100644
--- a/library/std/src/sys/hermit/net.rs
+++ b/library/std/src/sys/hermit/net.rs
@@ -14,9 +14,9 @@
/// if not, starts it.
pub fn init() -> io::Result<()> {
if abi::network_init() < 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::Uncategorized,
- &"Unable to initialize network interface",
+ "Unable to initialize network interface",
));
}
@@ -50,9 +50,9 @@
match abi::tcpstream::connect(addr.ip().to_string().as_bytes(), addr.port(), None) {
Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
- _ => Err(io::Error::new_const(
+ _ => Err(io::const_io_error!(
ErrorKind::Uncategorized,
- &"Unable to initiate a connection on a socket",
+ "Unable to initiate a connection on a socket",
)),
}
}
@@ -64,9 +64,9 @@
Some(duration.as_millis() as u64),
) {
Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
- _ => Err(io::Error::new_const(
+ _ => Err(io::const_io_error!(
ErrorKind::Uncategorized,
- &"Unable to initiate a connection on a socket",
+ "Unable to initiate a connection on a socket",
)),
}
}
@@ -74,7 +74,7 @@
pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
abi::tcpstream::set_read_timeout(*self.0.as_inner(), duration.map(|d| d.as_millis() as u64))
.map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to set timeout value")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value")
})
}
@@ -83,12 +83,12 @@
*self.0.as_inner(),
duration.map(|d| d.as_millis() as u64),
)
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"Unable to set timeout value"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value"))
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
let duration = abi::tcpstream::get_read_timeout(*self.0.as_inner()).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to determine timeout value")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
})?;
Ok(duration.map(|d| Duration::from_millis(d)))
@@ -96,7 +96,7 @@
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
let duration = abi::tcpstream::get_write_timeout(*self.0.as_inner()).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to determine timeout value")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
})?;
Ok(duration.map(|d| Duration::from_millis(d)))
@@ -104,7 +104,7 @@
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
abi::tcpstream::peek(*self.0.as_inner(), buf)
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"peek failed"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peek failed"))
}
pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
@@ -116,7 +116,7 @@
for i in ioslice.iter_mut() {
let ret = abi::tcpstream::read(*self.0.as_inner(), &mut i[0..]).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to read on socket")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to read on socket")
})?;
if ret != 0 {
@@ -141,7 +141,7 @@
for i in ioslice.iter() {
size += abi::tcpstream::write(*self.0.as_inner(), i).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to write on socket")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to write on socket")
})?;
}
@@ -155,13 +155,13 @@
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
let (ipaddr, port) = abi::tcpstream::peer_addr(*self.0.as_inner())
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"peer_addr failed"))?;
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"))?;
let saddr = match ipaddr {
Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
_ => {
- return Err(io::Error::new_const(ErrorKind::Uncategorized, &"peer_addr failed"));
+ return Err(io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"));
}
};
@@ -173,9 +173,8 @@
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
- abi::tcpstream::shutdown(*self.0.as_inner(), how as i32).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"unable to shutdown socket")
- })
+ abi::tcpstream::shutdown(*self.0.as_inner(), how as i32)
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to shutdown socket"))
}
pub fn duplicate(&self) -> io::Result<TcpStream> {
@@ -192,22 +191,22 @@
pub fn set_nodelay(&self, mode: bool) -> io::Result<()> {
abi::tcpstream::set_nodelay(*self.0.as_inner(), mode)
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"set_nodelay failed"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "set_nodelay failed"))
}
pub fn nodelay(&self) -> io::Result<bool> {
abi::tcpstream::nodelay(*self.0.as_inner())
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"nodelay failed"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "nodelay failed"))
}
pub fn set_ttl(&self, tll: u32) -> io::Result<()> {
abi::tcpstream::set_tll(*self.0.as_inner(), tll)
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"unable to set TTL"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to set TTL"))
}
pub fn ttl(&self) -> io::Result<u32> {
abi::tcpstream::get_tll(*self.0.as_inner())
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"unable to get TTL"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to get TTL"))
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
@@ -216,7 +215,7 @@
pub fn set_nonblocking(&self, mode: bool) -> io::Result<()> {
abi::tcpstream::set_nonblocking(*self.0.as_inner(), mode).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"unable to set blocking mode")
+ io::const_io_error!(ErrorKind::Uncategorized, "unable to set blocking mode")
})
}
}
@@ -243,12 +242,12 @@
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let (handle, ipaddr, port) = abi::tcplistener::accept(self.0.port())
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"accept failed"))?;
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "accept failed"))?;
let saddr = match ipaddr {
Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
_ => {
- return Err(io::Error::new_const(ErrorKind::Uncategorized, &"accept failed"));
+ return Err(io::const_io_error!(ErrorKind::Uncategorized, "accept failed"));
}
};
diff --git a/library/std/src/sys/hermit/stdio.rs b/library/std/src/sys/hermit/stdio.rs
index 33b8390..514de1d 100644
--- a/library/std/src/sys/hermit/stdio.rs
+++ b/library/std/src/sys/hermit/stdio.rs
@@ -40,7 +40,7 @@
unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stdout is not able to print"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
} else {
Ok(len as usize)
}
@@ -52,7 +52,7 @@
unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stdout is not able to print"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
} else {
Ok(len as usize)
}
@@ -81,7 +81,7 @@
unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stderr is not able to print"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
} else {
Ok(len as usize)
}
@@ -93,7 +93,7 @@
unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stderr is not able to print"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
} else {
Ok(len as usize)
}
diff --git a/library/std/src/sys/hermit/thread.rs b/library/std/src/sys/hermit/thread.rs
index 81b21fb..e53a1fe 100644
--- a/library/std/src/sys/hermit/thread.rs
+++ b/library/std/src/sys/hermit/thread.rs
@@ -39,7 +39,7 @@
// The thread failed to start and as a result p was not consumed. Therefore, it is
// safe to reconstruct the box so that it gets deallocated.
drop(Box::from_raw(p));
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Unable to create thread!"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Unable to create thread!"))
} else {
Ok(Thread { tid: tid })
};
diff --git a/library/std/src/sys/hermit/time.rs b/library/std/src/sys/hermit/time.rs
index c02de17..27173de 100644
--- a/library/std/src/sys/hermit/time.rs
+++ b/library/std/src/sys/hermit/time.rs
@@ -115,14 +115,6 @@
Instant { t: time }
}
- pub const fn zero() -> Instant {
- Instant { t: Timespec::zero() }
- }
-
- pub fn actually_monotonic() -> bool {
- true
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.t.sub_timespec(&other.t).ok()
}
diff --git a/library/std/src/sys/itron/condvar.rs b/library/std/src/sys/itron/condvar.rs
index dac4b8a..2992a6a 100644
--- a/library/std/src/sys/itron/condvar.rs
+++ b/library/std/src/sys/itron/condvar.rs
@@ -15,10 +15,12 @@
pub type MovableCondvar = Condvar;
impl Condvar {
+ #[inline]
pub const fn new() -> Condvar {
Condvar { waiters: SpinMutex::new(waiter_queue::WaiterQueue::new()) }
}
+ #[inline]
pub unsafe fn init(&mut self) {}
pub unsafe fn notify_one(&self) {
@@ -190,7 +192,7 @@
let insert_after = {
let mut cursor = head.last;
loop {
- if waiter.priority <= cursor.as_ref().priority {
+ if waiter.priority >= cursor.as_ref().priority {
// `cursor` and all previous waiters have the same or higher
// priority than `current_task_priority`. Insert the new
// waiter right after `cursor`.
@@ -206,7 +208,7 @@
if let Some(mut insert_after) = insert_after {
// Insert `waiter` after `insert_after`
- let insert_before = insert_after.as_ref().prev;
+ let insert_before = insert_after.as_ref().next;
waiter.prev = Some(insert_after);
insert_after.as_mut().next = Some(waiter_ptr);
@@ -214,6 +216,8 @@
waiter.next = insert_before;
if let Some(mut insert_before) = insert_before {
insert_before.as_mut().prev = Some(waiter_ptr);
+ } else {
+ head.last = waiter_ptr;
}
} else {
// Insert `waiter` to the front
@@ -240,11 +244,11 @@
match (waiter.prev, waiter.next) {
(Some(mut prev), Some(mut next)) => {
prev.as_mut().next = Some(next);
- next.as_mut().next = Some(prev);
+ next.as_mut().prev = Some(prev);
}
(None, Some(mut next)) => {
head.first = next;
- next.as_mut().next = None;
+ next.as_mut().prev = None;
}
(Some(mut prev), None) => {
prev.as_mut().next = None;
@@ -271,6 +275,7 @@
unsafe { waiter.as_ref().task != 0 }
}
+ #[inline]
pub fn pop_front(&mut self) -> Option<abi::ID> {
unsafe {
let head = self.head.as_mut()?;
diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs
index ebcc9ab..5b718a4 100644
--- a/library/std/src/sys/itron/thread.rs
+++ b/library/std/src/sys/itron/thread.rs
@@ -77,17 +77,14 @@
const LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE: usize = usize::MAX;
// there's no single value for `JOINING`
-pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * crate::mem::size_of::<usize>();
+// 64KiB for 32-bit ISAs, 128KiB for 64-bit ISAs.
+pub const DEFAULT_MIN_STACK_SIZE: usize = 0x4000 * crate::mem::size_of::<usize>();
impl Thread {
/// # Safety
///
/// See `thread::Builder::spawn_unchecked` for safety requirements.
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
- // Inherit the current task's priority
- let current_task = task::try_current_task_id().map_err(|e| e.as_io_error())?;
- let priority = task::try_task_priority(current_task).map_err(|e| e.as_io_error())?;
-
let inner = Box::new(ThreadInner {
start: UnsafeCell::new(ManuallyDrop::new(p)),
lifecycle: AtomicUsize::new(LIFECYCLE_INIT),
@@ -175,7 +172,8 @@
exinf: inner_ptr as abi::EXINF,
// The entry point
task: Some(trampoline),
- itskpri: priority,
+ // Inherit the calling task's base priority
+ itskpri: abi::TPRI_SELF,
stksz: stack,
// Let the kernel allocate the stack,
stk: crate::ptr::null_mut(),
diff --git a/library/std/src/sys/itron/time.rs b/library/std/src/sys/itron/time.rs
index 6a992ad..25f13ee 100644
--- a/library/std/src/sys/itron/time.rs
+++ b/library/std/src/sys/itron/time.rs
@@ -14,15 +14,6 @@
}
}
- pub const fn zero() -> Instant {
- Instant(0)
- }
-
- pub fn actually_monotonic() -> bool {
- // There are ways to change the system time
- false
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.0.checked_sub(other.0).map(|ticks| {
// `SYSTIM` is measured in microseconds
diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs
index a2a763c..158c92e 100644
--- a/library/std/src/sys/sgx/mod.rs
+++ b/library/std/src/sys/sgx/mod.rs
@@ -58,7 +58,7 @@
}
pub fn unsupported_err() -> crate::io::Error {
- crate::io::Error::new_const(ErrorKind::Unsupported, &"operation not supported on SGX yet")
+ crate::io::const_io_error!(ErrorKind::Unsupported, "operation not supported on SGX yet")
}
/// This function is used to implement various functions that doesn't exist,
@@ -69,9 +69,9 @@
pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> {
static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false);
if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) {
- Err(crate::io::Error::new_const(
+ Err(crate::io::const_io_error!(
ErrorKind::Uncategorized,
- &"operation can't be trusted to have any effect on SGX",
+ "operation can't be trusted to have any effect on SGX",
))
} else {
Ok(v)
diff --git a/library/std/src/sys/sgx/net.rs b/library/std/src/sys/sgx/net.rs
index 89c5af6..d14990c 100644
--- a/library/std/src/sys/sgx/net.rs
+++ b/library/std/src/sys/sgx/net.rs
@@ -97,9 +97,9 @@
pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result<TcpStream> {
if dur == Duration::default() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
Self::connect(Ok(addr)) // FIXME: ignoring timeout
@@ -108,9 +108,9 @@
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
match dur {
Some(dur) if dur == Duration::default() => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
_ => sgx_ineffective(()),
@@ -120,9 +120,9 @@
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
match dur {
Some(dur) if dur == Duration::default() => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
_ => sgx_ineffective(()),
diff --git a/library/std/src/sys/sgx/path.rs b/library/std/src/sys/sgx/path.rs
index 840a7ae..c805c15 100644
--- a/library/std/src/sys/sgx/path.rs
+++ b/library/std/src/sys/sgx/path.rs
@@ -1,5 +1,7 @@
use crate::ffi::OsStr;
-use crate::path::Prefix;
+use crate::io;
+use crate::path::{Path, PathBuf, Prefix};
+use crate::sys::unsupported;
#[inline]
pub fn is_sep_byte(b: u8) -> bool {
@@ -17,3 +19,7 @@
pub const MAIN_SEP_STR: &str = "/";
pub const MAIN_SEP: char = '/';
+
+pub(crate) fn absolute(_path: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
diff --git a/library/std/src/sys/sgx/time.rs b/library/std/src/sys/sgx/time.rs
index e2f6e6d..db4cf28 100644
--- a/library/std/src/sys/sgx/time.rs
+++ b/library/std/src/sys/sgx/time.rs
@@ -25,14 +25,6 @@
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant(self.0.checked_sub(*other)?))
}
-
- pub fn actually_monotonic() -> bool {
- false
- }
-
- pub const fn zero() -> Instant {
- Instant(Duration::from_secs(0))
- }
}
impl SystemTime {
diff --git a/library/std/src/sys/solid/abi/sockets.rs b/library/std/src/sys/solid/abi/sockets.rs
index 7c21d0d..eb06a6d 100644
--- a/library/std/src/sys/solid/abi/sockets.rs
+++ b/library/std/src/sys/solid/abi/sockets.rs
@@ -175,6 +175,9 @@
#[link_name = "SOLID_NET_Close"]
pub fn close(s: c_int) -> c_int;
+ #[link_name = "SOLID_NET_Dup"]
+ pub fn dup(s: c_int) -> c_int;
+
#[link_name = "SOLID_NET_GetPeerName"]
pub fn getpeername(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int;
diff --git a/library/std/src/sys/solid/fs.rs b/library/std/src/sys/solid/fs.rs
index 8a0eeff..a2cbee4 100644
--- a/library/std/src/sys/solid/fs.rs
+++ b/library/std/src/sys/solid/fs.rs
@@ -289,7 +289,26 @@
}
fn cstr(path: &Path) -> io::Result<CString> {
- Ok(CString::new(path.as_os_str().as_bytes())?)
+ let path = path.as_os_str().as_bytes();
+
+ if !path.starts_with(br"\") {
+ // Relative paths aren't supported
+ return Err(crate::io::const_io_error!(
+ crate::io::ErrorKind::Unsupported,
+ "relative path is not supported on this platform",
+ ));
+ }
+
+ // Apply the thread-safety wrapper
+ const SAFE_PREFIX: &[u8] = br"\TS";
+ let wrapped_path = [SAFE_PREFIX, &path, &[0]].concat();
+
+ CString::from_vec_with_nul(wrapped_path).map_err(|_| {
+ crate::io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "path provided contains a nul byte",
+ )
+ })
}
impl File {
@@ -461,7 +480,7 @@
pub fn unlink(p: &Path) -> io::Result<()> {
if stat(p)?.file_type().is_dir() {
- Err(io::Error::new_const(io::ErrorKind::IsADirectory, &"is a directory"))
+ Err(io::const_io_error!(io::ErrorKind::IsADirectory, "is a directory"))
} else {
error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) })
.map_err(|e| e.as_io_error())?;
@@ -491,7 +510,7 @@
.map_err(|e| e.as_io_error())?;
Ok(())
} else {
- Err(io::Error::new_const(io::ErrorKind::NotADirectory, &"not a directory"))
+ Err(io::const_io_error!(io::ErrorKind::NotADirectory, "not a directory"))
}
}
@@ -511,7 +530,7 @@
pub fn readlink(p: &Path) -> io::Result<PathBuf> {
// This target doesn't support symlinks
stat(p)?;
- Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"not a symbolic link"))
+ Err(io::const_io_error!(io::ErrorKind::InvalidInput, "not a symbolic link"))
}
pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs
index 211b8d7..2082c94 100644
--- a/library/std/src/sys/solid/mod.rs
+++ b/library/std/src/sys/solid/mod.rs
@@ -57,9 +57,9 @@
}
pub fn unsupported_err() -> crate::io::Error {
- crate::io::Error::new_const(
+ crate::io::const_io_error!(
crate::io::ErrorKind::Unsupported,
- &"operation not supported on this platform",
+ "operation not supported on this platform",
)
}
diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs
index 63ba634..a43407b 100644
--- a/library/std/src/sys/solid/net.rs
+++ b/library/std/src/sys/solid/net.rs
@@ -107,7 +107,7 @@
}
fn duplicate(&self) -> io::Result<FileDesc> {
- super::unsupported()
+ cvt(unsafe { netc::dup(self.fd) }).map(Self::new)
}
}
@@ -243,9 +243,9 @@
}
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
@@ -271,7 +271,7 @@
};
match n {
- 0 => Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")),
+ 0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")),
_ => {
let can_write = writefds.num_fds != 0;
if !can_write {
@@ -364,9 +364,9 @@
let timeout = match dur {
Some(dur) => {
if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
diff --git a/library/std/src/sys/solid/os.rs b/library/std/src/sys/solid/os.rs
index 82542d8..22239e1 100644
--- a/library/std/src/sys/solid/os.rs
+++ b/library/std/src/sys/solid/os.rs
@@ -173,11 +173,7 @@
/// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this
/// function just returns a generic error.
fn cvt_env(t: c_int) -> io::Result<c_int> {
- if t == -1 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"failure"))
- } else {
- Ok(t)
- }
+ if t == -1 { Err(io::const_io_error!(io::ErrorKind::Uncategorized, "failure")) } else { Ok(t) }
}
pub fn temp_dir() -> PathBuf {
diff --git a/library/std/src/sys/solid/path.rs b/library/std/src/sys/solid/path.rs
index 4a14332..7045c9b 100644
--- a/library/std/src/sys/solid/path.rs
+++ b/library/std/src/sys/solid/path.rs
@@ -1,5 +1,7 @@
use crate::ffi::OsStr;
-use crate::path::Prefix;
+use crate::io;
+use crate::path::{Path, PathBuf, Prefix};
+use crate::sys::unsupported;
#[inline]
pub fn is_sep_byte(b: u8) -> bool {
@@ -17,3 +19,7 @@
pub const MAIN_SEP_STR: &str = "\\";
pub const MAIN_SEP: char = '\\';
+
+pub(crate) fn absolute(_path: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
diff --git a/library/std/src/sys/solid/time.rs b/library/std/src/sys/solid/time.rs
index c67a736..ab988be 100644
--- a/library/std/src/sys/solid/time.rs
+++ b/library/std/src/sys/solid/time.rs
@@ -21,7 +21,7 @@
tm_min: rtc.tm_min,
tm_hour: rtc.tm_hour,
tm_mday: rtc.tm_mday,
- tm_mon: rtc.tm_mon,
+ tm_mon: rtc.tm_mon - 1,
tm_year: rtc.tm_year,
tm_wday: rtc.tm_wday,
tm_yday: 0,
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 2362bff..3de7c68 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -259,22 +259,9 @@
}
}
+ #[inline]
pub fn duplicate(&self) -> io::Result<FileDesc> {
- // We want to atomically duplicate this file descriptor and set the
- // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
- // is a POSIX flag that was added to Linux in 2.6.24.
- #[cfg(not(target_os = "espidf"))]
- let cmd = libc::F_DUPFD_CLOEXEC;
-
- // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
- // will never be supported, as this is a bare metal framework with
- // no capabilities for multi-process execution. While F_DUPFD is also
- // not supported yet, it might be (currently it returns ENOSYS).
- #[cfg(target_os = "espidf")]
- let cmd = libc::F_DUPFD;
-
- let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
- Ok(unsafe { FileDesc::from_raw_fd(fd) })
+ Ok(Self(self.0.try_clone()?))
}
}
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index f8deda9..8bd0b9b 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -34,7 +34,20 @@
use libc::dirfd;
#[cfg(any(target_os = "linux", target_os = "emscripten"))]
use libc::fstatat64;
+#[cfg(any(
+ target_os = "android",
+ target_os = "solaris",
+ target_os = "fuchsia",
+ target_os = "redox",
+ target_os = "illumos"
+))]
+use libc::readdir as readdir64;
+#[cfg(target_os = "linux")]
+use libc::readdir64;
+#[cfg(any(target_os = "emscripten", target_os = "l4re"))]
+use libc::readdir64_r;
#[cfg(not(any(
+ target_os = "android",
target_os = "linux",
target_os = "emscripten",
target_os = "solaris",
@@ -60,9 +73,7 @@
lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
};
#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))]
-use libc::{
- dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, readdir64_r, stat64,
-};
+use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64};
pub use crate::sys_common::fs::try_exists;
@@ -202,6 +213,8 @@
pub struct ReadDir {
inner: Arc<InnerReadDir>,
#[cfg(not(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
@@ -218,11 +231,12 @@
pub struct DirEntry {
entry: dirent64,
dir: Arc<InnerReadDir>,
- // We need to store an owned copy of the entry name
- // on Solaris and Fuchsia because a) it uses a zero-length
- // array to store the name, b) its lifetime between readdir
- // calls is not guaranteed.
+ // We need to store an owned copy of the entry name on platforms that use
+ // readdir() (not readdir_r()), because a) struct dirent may use a flexible
+ // array to store the name, b) it lives only until the next readdir() call.
#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
@@ -373,17 +387,17 @@
tv_nsec: ext.stx_btime.tv_nsec as _,
}))
} else {
- Err(io::Error::new_const(
+ Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"creation time is not available for the filesystem",
+ "creation time is not available for the filesystem",
))
};
}
}
- Err(io::Error::new_const(
+ Err(io::const_io_error!(
io::ErrorKind::Unsupported,
- &"creation time is not available on this platform \
+ "creation time is not available on this platform \
currently",
))
}
@@ -449,6 +463,8 @@
type Item = io::Result<DirEntry>;
#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "fuchsia",
target_os = "redox",
@@ -457,12 +473,13 @@
fn next(&mut self) -> Option<io::Result<DirEntry>> {
unsafe {
loop {
- // Although readdir_r(3) would be a correct function to use here because
- // of the thread safety, on Illumos and Fuchsia the readdir(3C) function
- // is safe to use in threaded applications and it is generally preferred
- // over the readdir_r(3C) function.
+ // As of POSIX.1-2017, readdir() is not required to be thread safe; only
+ // readdir_r() is. However, readdir_r() cannot correctly handle platforms
+ // with unlimited or variable NAME_MAX. Many modern platforms guarantee
+ // thread safety for readdir() as long an individual DIR* is not accessed
+ // concurrently, which is sufficient for Rust.
super::os::set_errno(0);
- let entry_ptr = libc::readdir(self.inner.dirp.0);
+ let entry_ptr = readdir64(self.inner.dirp.0);
if entry_ptr.is_null() {
// null can mean either the end is reached or an error occurred.
// So we had to clear errno beforehand to check for an error now.
@@ -472,10 +489,18 @@
};
}
+ // Only d_reclen bytes of *entry_ptr are valid, so we can't just copy the
+ // whole thing (#93384). Instead, copy everything except the name.
+ let entry_bytes = entry_ptr as *const u8;
+ let entry_name = ptr::addr_of!((*entry_ptr).d_name) as *const u8;
+ let name_offset = entry_name.offset_from(entry_bytes) as usize;
+ let mut entry: dirent64 = mem::zeroed();
+ ptr::copy_nonoverlapping(entry_bytes, &mut entry as *mut _ as *mut u8, name_offset);
+
let ret = DirEntry {
- entry: *entry_ptr,
+ entry,
// d_name is guaranteed to be null-terminated.
- name: CStr::from_ptr((*entry_ptr).d_name.as_ptr()).to_owned(),
+ name: CStr::from_ptr(entry_name as *const _).to_owned(),
dir: Arc::clone(&self.inner),
};
if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
@@ -486,6 +511,8 @@
}
#[cfg(not(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "fuchsia",
target_os = "redox",
@@ -531,17 +558,17 @@
impl DirEntry {
pub fn path(&self) -> PathBuf {
- self.dir.root.join(OsStr::from_bytes(self.name_bytes()))
+ self.dir.root.join(self.file_name_os_str())
}
pub fn file_name(&self) -> OsString {
- OsStr::from_bytes(self.name_bytes()).to_os_string()
+ self.file_name_os_str().to_os_string()
}
#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
pub fn metadata(&self) -> io::Result<FileAttr> {
let fd = cvt(unsafe { dirfd(self.dir.dirp.0) })?;
- let name = self.entry.d_name.as_ptr();
+ let name = self.name_cstr().as_ptr();
cfg_has_statx! {
if let Some(ret) = unsafe { try_statx(
@@ -571,7 +598,7 @@
target_os = "vxworks"
))]
pub fn file_type(&self) -> io::Result<FileType> {
- lstat(&self.path()).map(|m| m.file_type())
+ self.metadata().map(|m| m.file_type())
}
#[cfg(not(any(
@@ -589,7 +616,7 @@
libc::DT_SOCK => Ok(FileType { mode: libc::S_IFSOCK }),
libc::DT_DIR => Ok(FileType { mode: libc::S_IFDIR }),
libc::DT_BLK => Ok(FileType { mode: libc::S_IFBLK }),
- _ => lstat(&self.path()).map(|m| m.file_type()),
+ _ => self.metadata().map(|m| m.file_type()),
}
}
@@ -639,29 +666,21 @@
)
}
}
- #[cfg(any(
- target_os = "android",
- target_os = "linux",
- target_os = "emscripten",
- target_os = "l4re",
- target_os = "haiku",
- target_os = "vxworks",
- target_os = "espidf"
- ))]
+ #[cfg(not(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "freebsd",
+ target_os = "dragonfly"
+ )))]
fn name_bytes(&self) -> &[u8] {
- unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() }
- }
- #[cfg(any(
- target_os = "solaris",
- target_os = "illumos",
- target_os = "fuchsia",
- target_os = "redox"
- ))]
- fn name_bytes(&self) -> &[u8] {
- self.name.as_bytes()
+ self.name_cstr().to_bytes()
}
#[cfg(not(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
@@ -670,7 +689,14 @@
fn name_cstr(&self) -> &CStr {
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
}
- #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "fuchsia"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "solaris",
+ target_os = "illumos",
+ target_os = "fuchsia",
+ target_os = "redox"
+ ))]
fn name_cstr(&self) -> &CStr {
&self.name
}
@@ -1076,6 +1102,8 @@
Ok(ReadDir {
inner: Arc::new(inner),
#[cfg(not(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
@@ -1448,8 +1476,8 @@
pub use remove_dir_impl::remove_dir_all;
-// Fallback for REDOX
-#[cfg(target_os = "redox")]
+// Fallback for REDOX and ESP-IDF
+#[cfg(any(target_os = "redox", target_os = "espidf"))]
mod remove_dir_impl {
pub use crate::sys_common::fs::remove_dir_all;
}
@@ -1573,7 +1601,11 @@
}
// Modern implementation using openat(), unlinkat() and fdopendir()
-#[cfg(not(any(all(target_os = "macos", target_arch = "x86_64"), target_os = "redox")))]
+#[cfg(not(any(
+ all(target_os = "macos", target_arch = "x86_64"),
+ target_os = "redox",
+ target_os = "espidf"
+)))]
mod remove_dir_impl {
use super::{cstr, lstat, Dir, DirEntry, InnerReadDir, ReadDir};
use crate::ffi::CStr;
@@ -1611,6 +1643,8 @@
ReadDir {
inner: Arc::new(InnerReadDir { dirp, root: dummy_root }),
#[cfg(not(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
@@ -1627,7 +1661,6 @@
target_os = "illumos",
target_os = "haiku",
target_os = "vxworks",
- target_os = "fuchsia"
))]
fn is_dir(_ent: &DirEntry) -> Option<bool> {
None
@@ -1638,7 +1671,6 @@
target_os = "illumos",
target_os = "haiku",
target_os = "vxworks",
- target_os = "fuchsia"
)))]
fn is_dir(ent: &DirEntry) -> Option<bool> {
match ent.entry.d_type {
diff --git a/library/std/src/sys/unix/l4re.rs b/library/std/src/sys/unix/l4re.rs
index ba63b41..d13e1ec 100644
--- a/library/std/src/sys/unix/l4re.rs
+++ b/library/std/src/sys/unix/l4re.rs
@@ -1,8 +1,8 @@
macro_rules! unimpl {
() => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Unsupported,
- &"No networking available on L4Re.",
+ "No networking available on L4Re.",
));
};
}
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 2ba6c8d..605cc49 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -159,7 +159,7 @@
libc::ENOSPC => StorageFull,
libc::ENOSYS => Unsupported,
libc::EMLINK => TooManyLinks,
- libc::ENAMETOOLONG => FilenameTooLong,
+ libc::ENAMETOOLONG => InvalidFilename,
libc::ENETDOWN => NetworkDown,
libc::ENETUNREACH => NetworkUnreachable,
libc::ENOTCONN => NotConnected,
@@ -322,9 +322,6 @@
}
pub fn unsupported_err() -> io::Error {
- io::Error::new_const(
- io::ErrorKind::Unsupported,
- &"operation not supported on this platform",
- )
+ io::const_io_error!(io::ErrorKind::Unsupported, "operation not supported on this platform",)
}
}
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index a82a017..61c15ec 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -154,9 +154,9 @@
let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 };
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
@@ -165,7 +165,7 @@
loop {
let elapsed = start.elapsed();
if elapsed >= timeout {
- return Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out"));
+ return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
}
let timeout = timeout - elapsed;
@@ -192,9 +192,9 @@
// for POLLHUP rather than read readiness
if pollfd.revents & libc::POLLHUP != 0 {
let e = self.take_error()?.unwrap_or_else(|| {
- io::Error::new_const(
+ io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"no error set after POLLHUP",
+ "no error set after POLLHUP",
)
});
return Err(e);
@@ -338,9 +338,9 @@
let timeout = match dur {
Some(dur) => {
if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 8a028d9..b268ef5 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -75,7 +75,7 @@
}
/// Sets the platform-specific value of errno
-#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall!
+#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall!
#[allow(dead_code)] // but not all target cfgs actually end up using it
pub fn set_errno(e: i32) {
unsafe { *errno_location() = e as c_int }
@@ -294,9 +294,9 @@
0,
))?;
if path_len <= 1 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"KERN_PROC_PATHNAME sysctl returned zero-length string",
+ "KERN_PROC_PATHNAME sysctl returned zero-length string",
));
}
let mut path: Vec<u8> = Vec::with_capacity(path_len);
@@ -317,9 +317,9 @@
if curproc_exe.is_file() {
return crate::fs::read_link(curproc_exe);
}
- Err(io::Error::new_const(
+ Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"/proc/curproc/exe doesn't point to regular file.",
+ "/proc/curproc/exe doesn't point to regular file.",
))
}
sysctl().or_else(|_| procfs())
@@ -336,9 +336,9 @@
cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, &mut argv_len, ptr::null_mut(), 0))?;
argv.set_len(argv_len as usize);
if argv[0].is_null() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"no current exe available",
+ "no current exe available",
));
}
let argv0 = CStr::from_ptr(argv[0]).to_bytes();
@@ -353,9 +353,9 @@
#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
pub fn current_exe() -> io::Result<PathBuf> {
match crate::fs::read_link("/proc/self/exe") {
- Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::Error::new_const(
+ Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"no /proc/self/exe available. Is /proc mounted?",
+ "no /proc/self/exe available. Is /proc mounted?",
)),
other => other,
}
@@ -417,7 +417,7 @@
);
if result != 0 {
use crate::io::ErrorKind;
- Err(io::Error::new_const(ErrorKind::Uncategorized, &"Error getting executable path"))
+ Err(io::const_io_error!(ErrorKind::Uncategorized, "Error getting executable path"))
} else {
let name = CStr::from_ptr((*info.as_ptr()).name.as_ptr()).to_bytes();
Ok(PathBuf::from(OsStr::from_bytes(name)))
@@ -433,7 +433,7 @@
#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
pub fn current_exe() -> io::Result<PathBuf> {
use crate::io::ErrorKind;
- Err(io::Error::new_const(ErrorKind::Unsupported, &"Not yet implemented!"))
+ Err(io::const_io_error!(ErrorKind::Unsupported, "Not yet implemented!"))
}
#[cfg(target_os = "vxworks")]
diff --git a/library/std/src/sys/unix/path.rs b/library/std/src/sys/unix/path.rs
index 717add9..6d6f4c8 100644
--- a/library/std/src/sys/unix/path.rs
+++ b/library/std/src/sys/unix/path.rs
@@ -1,5 +1,7 @@
+use crate::env;
use crate::ffi::OsStr;
-use crate::path::Prefix;
+use crate::io;
+use crate::path::{Path, PathBuf, Prefix};
#[inline]
pub fn is_sep_byte(b: u8) -> bool {
@@ -18,3 +20,43 @@
pub const MAIN_SEP_STR: &str = "/";
pub const MAIN_SEP: char = '/';
+
+/// Make a POSIX path absolute without changing its semantics.
+pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
+ // This is mostly a wrapper around collecting `Path::components`, with
+ // exceptions made where this conflicts with the POSIX specification.
+ // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
+ // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+
+ let mut components = path.components();
+ let path_os = path.as_os_str().bytes();
+
+ let mut normalized = if path.is_absolute() {
+ // "If a pathname begins with two successive <slash> characters, the
+ // first component following the leading <slash> characters may be
+ // interpreted in an implementation-defined manner, although more than
+ // two leading <slash> characters shall be treated as a single <slash>
+ // character."
+ if path_os.starts_with(b"//") && !path_os.starts_with(b"///") {
+ components.next();
+ PathBuf::from("//")
+ } else {
+ PathBuf::new()
+ }
+ } else {
+ env::current_dir()?
+ };
+ normalized.extend(components);
+
+ // "Interfaces using pathname resolution may specify additional constraints
+ // when a pathname that does not name an existing directory contains at
+ // least one non- <slash> character and contains one or more trailing
+ // <slash> characters".
+ // A trailing <slash> is also meaningful if "a symbolic link is
+ // encountered during pathname resolution".
+ if path_os.ends_with(b"/") {
+ normalized.push("");
+ }
+
+ Ok(normalized)
+}
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index 7ac2f9d..97985dd 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -476,6 +476,12 @@
}
}
+impl From<u8> for ExitCode {
+ fn from(code: u8) -> Self {
+ Self(code)
+ }
+}
+
pub struct CommandArgs<'a> {
iter: crate::slice::Iter<'a, CString>,
}
diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs
index ce77c21..09bfd96 100644
--- a/library/std/src/sys/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/unix/process/process_fuchsia.rs
@@ -23,9 +23,9 @@
let envp = self.capture_env();
if self.saw_nul() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"nul byte found in provided data",
+ "nul byte found in provided data",
));
}
@@ -38,9 +38,9 @@
pub fn exec(&mut self, default: Stdio) -> io::Error {
if self.saw_nul() {
- return io::Error::new_const(
+ return io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"nul byte found in provided data",
+ "nul byte found in provided data",
);
}
@@ -186,9 +186,9 @@
))?;
}
if actual != 1 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Failed to get exit status of process",
+ "Failed to get exit status of process",
));
}
Ok(ExitStatus(proc_info.return_code))
@@ -224,9 +224,9 @@
))?;
}
if actual != 1 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Failed to get exit status of process",
+ "Failed to get exit status of process",
));
}
Ok(Some(ExitStatus(proc_info.return_code)))
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index bce35b3..9fc2d9f 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -44,9 +44,9 @@
let envp = self.capture_env();
if self.saw_nul() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"nul byte found in provided data",
+ "nul byte found in provided data",
));
}
@@ -222,10 +222,7 @@
let envp = self.capture_env();
if self.saw_nul() {
- return io::Error::new_const(
- ErrorKind::InvalidInput,
- &"nul byte found in provided data",
- );
+ return io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data",);
}
match self.setup_io(default, true) {
@@ -581,9 +578,9 @@
// and used for another process, and we probably shouldn't be killing
// random processes, so just return an error.
if self.status.is_some() {
- Err(Error::new_const(
+ Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid argument: can't kill an exited process",
+ "invalid argument: can't kill an exited process",
))
} else {
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
diff --git a/library/std/src/sys/unix/process/process_unix/tests.rs b/library/std/src/sys/unix/process/process_unix/tests.rs
index 157debf..560c621 100644
--- a/library/std/src/sys/unix/process/process_unix/tests.rs
+++ b/library/std/src/sys/unix/process/process_unix/tests.rs
@@ -53,5 +53,10 @@
let status = got.expect("panic unexpectedly propagated");
dbg!(status);
let signal = status.signal().expect("expected child process to die of signal");
- assert!(signal == libc::SIGABRT || signal == libc::SIGILL || signal == libc::SIGTRAP);
+ assert!(
+ signal == libc::SIGABRT
+ || signal == libc::SIGILL
+ || signal == libc::SIGTRAP
+ || signal == libc::SIGSEGV
+ );
}
diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs
index c17822f..c6714d3 100644
--- a/library/std/src/sys/unix/process/process_vxworks.rs
+++ b/library/std/src/sys/unix/process/process_vxworks.rs
@@ -24,9 +24,9 @@
let envp = self.capture_env();
if self.saw_nul() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"nul byte found in provided data",
+ "nul byte found in provided data",
));
}
let (ours, theirs) = self.setup_io(default, needs_stdin)?;
@@ -142,9 +142,9 @@
// and used for another process, and we probably shouldn't be killing
// random processes, so just return an error.
if self.status.is_some() {
- Err(Error::new_const(
+ Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid argument: can't kill an exited process",
+ "invalid argument: can't kill an exited process",
))
} else {
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 9e02966..cf8cf5a 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -287,7 +287,7 @@
}
match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
-1 => Err(io::Error::last_os_error()),
- 0 => Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")),
+ 0 => Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")),
cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }),
}
} else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
@@ -318,7 +318,7 @@
if res == -1 {
return Err(io::Error::last_os_error());
} else if cpus == 0 {
- return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+ return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
}
}
Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
@@ -344,7 +344,7 @@
if res == -1 {
return Err(io::Error::last_os_error());
} else if cpus == 0 {
- return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+ return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
}
Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
@@ -356,14 +356,14 @@
let res = libc::get_system_info(&mut sinfo);
if res != libc::B_OK {
- return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+ return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
}
Ok(NonZeroUsize::new_unchecked(sinfo.cpu_count as usize))
}
} else {
// FIXME: implement on vxWorks, Redox, l4re
- Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Getting the number of hardware threads is not supported on the target platform"))
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform"))
}
}
}
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index 824283e..59ddd1a 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -154,14 +154,6 @@
Instant { t: unsafe { mach_absolute_time() } }
}
- pub const fn zero() -> Instant {
- Instant { t: 0 }
- }
-
- pub fn actually_monotonic() -> bool {
- true
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
let diff = self.t.checked_sub(other.t)?;
let info = info();
@@ -296,17 +288,6 @@
Instant { t: now(libc::CLOCK_MONOTONIC) }
}
- pub const fn zero() -> Instant {
- Instant { t: Timespec::zero() }
- }
-
- pub fn actually_monotonic() -> bool {
- (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
- || (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
- || (cfg!(target_os = "linux") && cfg!(target_arch = "aarch64"))
- || cfg!(target_os = "fuchsia")
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.t.sub_timespec(&other.t).ok()
}
diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs
index a06b44e..5274f53 100644
--- a/library/std/src/sys/unsupported/common.rs
+++ b/library/std/src/sys/unsupported/common.rs
@@ -21,9 +21,9 @@
}
pub fn unsupported_err() -> std_io::Error {
- std_io::Error::new_const(
+ std_io::const_io_error!(
std_io::ErrorKind::Unsupported,
- &"operation not supported on this platform",
+ "operation not supported on this platform",
)
}
diff --git a/library/std/src/sys/unsupported/os.rs b/library/std/src/sys/unsupported/os.rs
index 2886ec1..e150ae1 100644
--- a/library/std/src/sys/unsupported/os.rs
+++ b/library/std/src/sys/unsupported/os.rs
@@ -81,11 +81,11 @@
}
pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
- Err(io::Error::new_const(io::ErrorKind::Unsupported, &"cannot set env vars on this platform"))
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
}
pub fn unsetenv(_: &OsStr) -> io::Result<()> {
- Err(io::Error::new_const(io::ErrorKind::Unsupported, &"cannot unset env vars on this platform"))
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
}
pub fn temp_dir() -> PathBuf {
diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs
index 7846e43..42a1ff7 100644
--- a/library/std/src/sys/unsupported/process.rs
+++ b/library/std/src/sys/unsupported/process.rs
@@ -162,6 +162,15 @@
}
}
+impl From<u8> for ExitCode {
+ fn from(code: u8) -> Self {
+ match code {
+ 0 => Self::SUCCESS,
+ 1..=255 => Self::FAILURE,
+ }
+ }
+}
+
pub struct Process(!);
impl Process {
diff --git a/library/std/src/sys/unsupported/time.rs b/library/std/src/sys/unsupported/time.rs
index 8aaf177..6d67b53 100644
--- a/library/std/src/sys/unsupported/time.rs
+++ b/library/std/src/sys/unsupported/time.rs
@@ -13,14 +13,6 @@
panic!("time not implemented on this platform")
}
- pub const fn zero() -> Instant {
- Instant(Duration::from_secs(0))
- }
-
- pub fn actually_monotonic() -> bool {
- false
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.0.checked_sub(other.0)
}
diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs
index e4f4456..0b9c8e6 100644
--- a/library/std/src/sys/wasi/fd.rs
+++ b/library/std/src/sys/wasi/fd.rs
@@ -228,6 +228,10 @@
unsafe { wasi::path_remove_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) }
}
+ pub fn sock_accept(&self, flags: wasi::Fdflags) -> io::Result<wasi::Fd> {
+ unsafe { wasi::sock_accept(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) }
+ }
+
pub fn sock_recv(
&self,
ri_data: &mut [IoSliceMut<'_>],
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index 5924789..cd6815b 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -711,7 +711,7 @@
pub fn osstr2str(f: &OsStr) -> io::Result<&str> {
f.to_str()
- .ok_or_else(|| io::Error::new_const(io::ErrorKind::Uncategorized, &"input must be utf-8"))
+ .ok_or_else(|| io::const_io_error!(io::ErrorKind::Uncategorized, "input must be utf-8"))
}
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
@@ -757,7 +757,7 @@
for entry in ReadDir::new(fd, dummy_root) {
let entry = entry?;
let path = crate::str::from_utf8(&entry.name).map_err(|_| {
- io::Error::new_const(io::ErrorKind::Uncategorized, &"invalid utf-8 file name found")
+ io::const_io_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found")
})?;
if entry.file_type()?.is_dir() {
diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs
index 8d62335..f878941 100644
--- a/library/std/src/sys/wasi/mod.rs
+++ b/library/std/src/sys/wasi/mod.rs
@@ -61,23 +61,26 @@
if errno > u16::MAX as i32 || errno < 0 {
return Uncategorized;
}
- match errno as u16 {
- wasi::ERRNO_CONNREFUSED => ConnectionRefused,
- wasi::ERRNO_CONNRESET => ConnectionReset,
- wasi::ERRNO_PERM | wasi::ERRNO_ACCES => PermissionDenied,
- wasi::ERRNO_PIPE => BrokenPipe,
- wasi::ERRNO_NOTCONN => NotConnected,
- wasi::ERRNO_CONNABORTED => ConnectionAborted,
- wasi::ERRNO_ADDRNOTAVAIL => AddrNotAvailable,
- wasi::ERRNO_ADDRINUSE => AddrInUse,
- wasi::ERRNO_NOENT => NotFound,
- wasi::ERRNO_INTR => Interrupted,
- wasi::ERRNO_INVAL => InvalidInput,
- wasi::ERRNO_TIMEDOUT => TimedOut,
- wasi::ERRNO_EXIST => AlreadyExists,
- wasi::ERRNO_AGAIN => WouldBlock,
- wasi::ERRNO_NOSYS => Unsupported,
- wasi::ERRNO_NOMEM => OutOfMemory,
+
+ match errno {
+ e if e == wasi::ERRNO_CONNREFUSED.raw().into() => ConnectionRefused,
+ e if e == wasi::ERRNO_CONNRESET.raw().into() => ConnectionReset,
+ e if e == wasi::ERRNO_PERM.raw().into() || e == wasi::ERRNO_ACCES.raw().into() => {
+ PermissionDenied
+ }
+ e if e == wasi::ERRNO_PIPE.raw().into() => BrokenPipe,
+ e if e == wasi::ERRNO_NOTCONN.raw().into() => NotConnected,
+ e if e == wasi::ERRNO_CONNABORTED.raw().into() => ConnectionAborted,
+ e if e == wasi::ERRNO_ADDRNOTAVAIL.raw().into() => AddrNotAvailable,
+ e if e == wasi::ERRNO_ADDRINUSE.raw().into() => AddrInUse,
+ e if e == wasi::ERRNO_NOENT.raw().into() => NotFound,
+ e if e == wasi::ERRNO_INTR.raw().into() => Interrupted,
+ e if e == wasi::ERRNO_INVAL.raw().into() => InvalidInput,
+ e if e == wasi::ERRNO_TIMEDOUT.raw().into() => TimedOut,
+ e if e == wasi::ERRNO_EXIST.raw().into() => AlreadyExists,
+ e if e == wasi::ERRNO_AGAIN.raw().into() => WouldBlock,
+ e if e == wasi::ERRNO_NOSYS.raw().into() => Unsupported,
+ e if e == wasi::ERRNO_NOMEM.raw().into() => OutOfMemory,
_ => Uncategorized,
}
}
@@ -96,6 +99,6 @@
return ret;
}
-fn err2io(err: wasi::Error) -> std_io::Error {
- std_io::Error::from_raw_os_error(err.raw_error().into())
+fn err2io(err: wasi::Errno) -> std_io::Error {
+ std_io::Error::from_raw_os_error(err.raw().into())
}
diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs
index a4dbb22..c66e0e4 100644
--- a/library/std/src/sys/wasi/net.rs
+++ b/library/std/src/sys/wasi/net.rs
@@ -1,5 +1,6 @@
#![deny(unsafe_op_in_unsafe_fn)]
+use super::err2io;
use super::fd::WasiFd;
use crate::convert::TryFrom;
use crate::fmt;
@@ -87,24 +88,24 @@
unsupported()
}
- pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
- unsupported()
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.read_vectored(&mut [IoSliceMut::new(buf)])
}
- pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- unsupported()
+ pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ self.socket().as_inner().read(bufs)
}
pub fn is_read_vectored(&self) -> bool {
true
}
- pub fn write(&self, _: &[u8]) -> io::Result<usize> {
- unsupported()
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.write_vectored(&[IoSlice::new(buf)])
}
- pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
- unsupported()
+ pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ self.socket().as_inner().write(bufs)
}
pub fn is_write_vectored(&self) -> bool {
@@ -155,8 +156,23 @@
unsupported()
}
- pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
- unsupported()
+ pub fn set_nonblocking(&self, state: bool) -> io::Result<()> {
+ let fdstat = unsafe {
+ wasi::fd_fdstat_get(self.socket().as_inner().as_raw_fd() as wasi::Fd).map_err(err2io)?
+ };
+
+ let mut flags = fdstat.fs_flags;
+
+ if state {
+ flags |= wasi::FDFLAGS_NONBLOCK;
+ } else {
+ flags &= !wasi::FDFLAGS_NONBLOCK;
+ }
+
+ unsafe {
+ wasi::fd_fdstat_set_flags(self.socket().as_inner().as_raw_fd() as wasi::Fd, flags)
+ .map_err(err2io)
+ }
}
pub fn socket(&self) -> &Socket {
@@ -194,7 +210,16 @@
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
- unsupported()
+ let fd = unsafe {
+ wasi::sock_accept(self.as_inner().as_inner().as_raw_fd() as _, 0).map_err(err2io)?
+ };
+
+ Ok((
+ TcpStream::from_inner(unsafe { Socket::from_raw_fd(fd as _) }),
+ // WASI has no concept of SocketAddr yet
+ // return an unspecified IPv4Addr
+ SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 0),
+ ))
}
pub fn duplicate(&self) -> io::Result<TcpListener> {
@@ -221,8 +246,23 @@
unsupported()
}
- pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
- unsupported()
+ pub fn set_nonblocking(&self, state: bool) -> io::Result<()> {
+ let fdstat = unsafe {
+ wasi::fd_fdstat_get(self.socket().as_inner().as_raw_fd() as wasi::Fd).map_err(err2io)?
+ };
+
+ let mut flags = fdstat.fs_flags;
+
+ if state {
+ flags |= wasi::FDFLAGS_NONBLOCK;
+ } else {
+ flags &= !wasi::FDFLAGS_NONBLOCK;
+ }
+
+ unsafe {
+ wasi::fd_fdstat_set_flags(self.socket().as_inner().as_raw_fd() as wasi::Fd, flags)
+ .map_err(err2io)
+ }
}
pub fn socket(&self) -> &Socket {
diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs
index 2c8f394..4cc0e4e 100644
--- a/library/std/src/sys/wasi/stdio.rs
+++ b/library/std/src/sys/wasi/stdio.rs
@@ -104,7 +104,7 @@
pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
pub fn is_ebadf(err: &io::Error) -> bool {
- err.raw_os_error() == Some(wasi::ERRNO_BADF.into())
+ err.raw_os_error() == Some(wasi::ERRNO_BADF.raw().into())
}
pub fn panic_output() -> Option<impl io::Write> {
diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs
index 2e4e474..e7a6ab4 100644
--- a/library/std/src/sys/wasi/thread.rs
+++ b/library/std/src/sys/wasi/thread.rs
@@ -41,8 +41,7 @@
let in_ = wasi::Subscription {
userdata: USERDATA,
- r#type: wasi::EVENTTYPE_CLOCK,
- u: wasi::SubscriptionU { clock },
+ u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } },
};
unsafe {
let mut event: wasi::Event = mem::zeroed();
@@ -51,7 +50,10 @@
(
Ok(1),
wasi::Event {
- userdata: USERDATA, error: 0, r#type: wasi::EVENTTYPE_CLOCK, ..
+ userdata: USERDATA,
+ error: wasi::ERRNO_SUCCESS,
+ type_: wasi::EVENTTYPE_CLOCK,
+ ..
},
) => {}
_ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
diff --git a/library/std/src/sys/wasi/time.rs b/library/std/src/sys/wasi/time.rs
index 2e720d1..0885856 100644
--- a/library/std/src/sys/wasi/time.rs
+++ b/library/std/src/sys/wasi/time.rs
@@ -10,7 +10,7 @@
pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
-fn current_time(clock: u32) -> Duration {
+fn current_time(clock: wasi::Clockid) -> Duration {
let ts = unsafe {
wasi::clock_time_get(
clock, 1, // precision... seems ignored though?
@@ -25,14 +25,6 @@
Instant(current_time(wasi::CLOCKID_MONOTONIC))
}
- pub const fn zero() -> Instant {
- Instant(Duration::from_secs(0))
- }
-
- pub fn actually_monotonic() -> bool {
- true
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.0.checked_sub(other.0)
}
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 09d3661..c7b6290 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -83,11 +83,13 @@
pub const FILE_ATTRIBUTE_READONLY: DWORD = 0x1;
pub const FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x10;
pub const FILE_ATTRIBUTE_REPARSE_POINT: DWORD = 0x400;
+pub const INVALID_FILE_ATTRIBUTES: DWORD = DWORD::MAX;
pub const FILE_SHARE_DELETE: DWORD = 0x4;
pub const FILE_SHARE_READ: DWORD = 0x1;
pub const FILE_SHARE_WRITE: DWORD = 0x2;
+pub const FILE_OPEN: ULONG = 0x00000001;
pub const FILE_OPEN_REPARSE_POINT: ULONG = 0x200000;
pub const OBJ_DONT_REPARSE: ULONG = 0x1000;
@@ -1074,6 +1076,7 @@
lpBuffer: LPWSTR,
lpFilePart: *mut LPWSTR,
) -> DWORD;
+ pub fn GetFileAttributesW(lpFileName: LPCWSTR) -> DWORD;
}
#[link(name = "ws2_32")]
@@ -1228,15 +1231,20 @@
compat_fn! {
"ntdll":
- pub fn NtOpenFile(
+ pub fn NtCreateFile(
FileHandle: *mut HANDLE,
DesiredAccess: ACCESS_MASK,
ObjectAttributes: *const OBJECT_ATTRIBUTES,
IoStatusBlock: *mut IO_STATUS_BLOCK,
+ AllocationSize: *mut i64,
+ FileAttributes: ULONG,
ShareAccess: ULONG,
- OpenOptions: ULONG
+ CreateDisposition: ULONG,
+ CreateOptions: ULONG,
+ EaBuffer: *mut c_void,
+ EaLength: ULONG
) -> NTSTATUS {
- panic!("`NtOpenFile` not available");
+ panic!("`NtCreateFile` not available");
}
pub fn RtlNtStatusToDosError(
Status: NTSTATUS
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index dd21c6b..cb83ee2 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -460,7 +460,7 @@
}
pub fn duplicate(&self) -> io::Result<File> {
- Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? })
+ Ok(Self { handle: self.handle.try_clone()? })
}
fn reparse_point<'a>(
@@ -511,9 +511,9 @@
)
}
_ => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"Unsupported reparse point type",
+ "Unsupported reparse point type",
));
}
};
@@ -712,11 +712,11 @@
/// Open a link relative to the parent directory, ensure no symlinks are followed.
fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result<File> {
- // This is implemented using the lower level `NtOpenFile` function as
+ // This is implemented using the lower level `NtCreateFile` function as
// unfortunately opening a file relative to a parent is not supported by
// win32 functions. It is however a fundamental feature of the NT kernel.
//
- // See https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntopenfile
+ // See https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntcreatefile
unsafe {
let mut handle = ptr::null_mut();
let mut io_status = c::IO_STATUS_BLOCK::default();
@@ -732,14 +732,19 @@
Attributes: ATTRIBUTES.load(Ordering::Relaxed),
..c::OBJECT_ATTRIBUTES::default()
};
- let status = c::NtOpenFile(
+ let status = c::NtCreateFile(
&mut handle,
access,
&object,
&mut io_status,
+ crate::ptr::null_mut(),
+ 0,
c::FILE_SHARE_DELETE | c::FILE_SHARE_READ | c::FILE_SHARE_WRITE,
+ c::FILE_OPEN,
// If `name` is a symlink then open the link rather than the target.
c::FILE_OPEN_REPARSE_POINT,
+ crate::ptr::null_mut(),
+ 0,
);
// Convert an NTSTATUS to the more familiar Win32 error codes (aka "DosError")
if c::nt_success(status) {
@@ -1124,9 +1129,9 @@
#[cfg(target_vendor = "uwp")]
pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Unsupported,
- &"hard link are not supported on UWP",
+ "hard link are not supported on UWP",
));
}
diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs
index c3a3482..daab39b 100644
--- a/library/std/src/sys/windows/handle.rs
+++ b/library/std/src/sys/windows/handle.rs
@@ -262,26 +262,17 @@
Ok(written as usize)
}
+ pub fn try_clone(&self) -> io::Result<Self> {
+ Ok(Self(self.0.try_clone()?))
+ }
+
pub fn duplicate(
&self,
access: c::DWORD,
inherit: bool,
options: c::DWORD,
- ) -> io::Result<Handle> {
- let mut ret = 0 as c::HANDLE;
- cvt(unsafe {
- let cur_proc = c::GetCurrentProcess();
- c::DuplicateHandle(
- cur_proc,
- self.as_raw_handle(),
- cur_proc,
- &mut ret,
- access,
- inherit as c::BOOL,
- options,
- )
- })?;
- unsafe { Ok(Handle::from_raw_handle(ret)) }
+ ) -> io::Result<Self> {
+ Ok(Self(self.0.duplicate(access, inherit, options)?))
}
}
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index 084af43..dc28817 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -71,6 +71,7 @@
c::ERROR_FILE_NOT_FOUND => return NotFound,
c::ERROR_PATH_NOT_FOUND => return NotFound,
c::ERROR_NO_DATA => return BrokenPipe,
+ c::ERROR_INVALID_NAME => return InvalidFilename,
c::ERROR_INVALID_PARAMETER => return InvalidInput,
c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory,
c::ERROR_SEM_TIMEOUT
@@ -104,7 +105,7 @@
c::ERROR_POSSIBLE_DEADLOCK => return Deadlock,
c::ERROR_NOT_SAME_DEVICE => return CrossesDevices,
c::ERROR_TOO_MANY_LINKS => return TooManyLinks,
- c::ERROR_FILENAME_EXCED_RANGE => return FilenameTooLong,
+ c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename,
_ => {}
}
@@ -160,9 +161,9 @@
fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
let mut maybe_result: Vec<u16> = s.encode_wide().collect();
if unrolled_find_u16s(0, &maybe_result).is_some() {
- return Err(crate::io::Error::new_const(
+ return Err(crate::io::const_io_error!(
ErrorKind::InvalidInput,
- &"strings passed to WinAPI cannot contain NULs",
+ "strings passed to WinAPI cannot contain NULs",
));
}
maybe_result.push(0);
@@ -285,6 +286,7 @@
#[allow(unreachable_code)]
pub fn abort_internal() -> ! {
const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
+ #[cfg(not(miri))] // inline assembly does not work in Miri
unsafe {
cfg_if::cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs
index 9c631e7..aa6400a 100644
--- a/library/std/src/sys/windows/net.rs
+++ b/library/std/src/sys/windows/net.rs
@@ -134,7 +134,7 @@
unsafe {
let socket = Self::from_raw_socket(socket);
- socket.set_no_inherit()?;
+ socket.0.set_no_inherit()?;
Ok(socket)
}
}
@@ -152,9 +152,9 @@
match result {
Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => {
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
@@ -185,9 +185,7 @@
};
match count {
- 0 => {
- Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out"))
- }
+ 0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")),
_ => {
if writefds.fd_count != 1 {
if let Some(e) = self.take_error()? {
@@ -213,52 +211,7 @@
}
pub fn duplicate(&self) -> io::Result<Socket> {
- let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
- let result = unsafe {
- c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
- };
- cvt(result)?;
- let socket = unsafe {
- c::WSASocketW(
- info.iAddressFamily,
- info.iSocketType,
- info.iProtocol,
- &mut info,
- 0,
- c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
- )
- };
-
- if socket != c::INVALID_SOCKET {
- unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) }
- } else {
- let error = unsafe { c::WSAGetLastError() };
-
- if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
- return Err(io::Error::from_raw_os_error(error));
- }
-
- let socket = unsafe {
- c::WSASocketW(
- info.iAddressFamily,
- info.iSocketType,
- info.iProtocol,
- &mut info,
- 0,
- c::WSA_FLAG_OVERLAPPED,
- )
- };
-
- if socket == c::INVALID_SOCKET {
- return Err(last_error());
- }
-
- unsafe {
- let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket));
- socket.set_no_inherit()?;
- Ok(socket)
- }
- }
+ Ok(Self(self.0.try_clone()?))
}
fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
@@ -398,9 +351,9 @@
Some(dur) => {
let timeout = sys::dur2timeout(dur);
if timeout == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
timeout
@@ -421,19 +374,6 @@
}
}
- #[cfg(not(target_vendor = "uwp"))]
- fn set_no_inherit(&self) -> io::Result<()> {
- sys::cvt(unsafe {
- c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0)
- })
- .map(drop)
- }
-
- #[cfg(target_vendor = "uwp")]
- fn set_no_inherit(&self) -> io::Result<()> {
- Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP"))
- }
-
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
let how = match how {
Shutdown::Write => c::SD_SEND,
diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs
index 79e0eaf..e54fcae 100644
--- a/library/std/src/sys/windows/path.rs
+++ b/library/std/src/sys/windows/path.rs
@@ -260,3 +260,19 @@
)?;
Ok(path)
}
+
+/// Make a Windows path absolute.
+pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
+ if path.as_os_str().bytes().starts_with(br"\\?\") {
+ return Ok(path.into());
+ }
+ let path = to_u16s(path)?;
+ let lpfilename = path.as_ptr();
+ fill_utf16_buf(
+ // SAFETY: `fill_utf16_buf` ensures the `buffer` and `size` are valid.
+ // `lpfilename` is a pointer to a null terminated string that is not
+ // invalidated until after `GetFullPathNameW` returns successfully.
+ |buffer, size| unsafe { c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()) },
+ super::os2path,
+ )
+}
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index 5ad5704..fafd141 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -149,7 +149,7 @@
fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
if str.as_ref().encode_wide().any(|b| b == 0) {
- Err(io::Error::new_const(ErrorKind::InvalidInput, &"nul byte found in provided data"))
+ Err(io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data"))
} else {
Ok(str)
}
@@ -369,9 +369,9 @@
) -> io::Result<PathBuf> {
// Early return if there is no filename.
if exe_path.is_empty() || path::has_trailing_slash(exe_path) {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"program path has no file name",
+ "program path has no file name",
));
}
// Test if the file name has the `exe` extension.
@@ -394,7 +394,7 @@
// Append `.exe` if not already there.
path = path::append_suffix(path, EXE_SUFFIX.as_ref());
- if path.try_exists().unwrap_or(false) {
+ if program_exists(&path) {
return Ok(path);
} else {
// It's ok to use `set_extension` here because the intent is to
@@ -415,14 +415,14 @@
if !has_extension {
path.set_extension(EXE_EXTENSION);
}
- if let Ok(true) = path.try_exists() { Some(path) } else { None }
+ if program_exists(&path) { Some(path) } else { None }
});
if let Some(path) = result {
return Ok(path);
}
}
// If we get here then the executable cannot be found.
- Err(io::Error::new_const(io::ErrorKind::NotFound, &"program not found"))
+ Err(io::const_io_error!(io::ErrorKind::NotFound, "program not found"))
}
// Calls `f` for every path that should be used to find an executable.
@@ -485,6 +485,21 @@
None
}
+/// Check if a file exists without following symlinks.
+fn program_exists(path: &Path) -> bool {
+ unsafe {
+ to_u16s(path)
+ .map(|path| {
+ // Getting attributes using `GetFileAttributesW` does not follow symlinks
+ // and it will almost always be successful if the link exists.
+ // There are some exceptions for special system files (e.g. the pagefile)
+ // but these are not executable.
+ c::GetFileAttributesW(path.as_ptr()) != c::INVALID_FILE_ATTRIBUTES
+ })
+ .unwrap_or(false)
+ }
+}
+
impl Stdio {
fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> {
match *self {
@@ -666,6 +681,12 @@
}
}
+impl From<u8> for ExitCode {
+ fn from(code: u8) -> Self {
+ ExitCode(c::DWORD::from(code))
+ }
+}
+
fn zeroed_startupinfo() -> c::STARTUPINFO {
c::STARTUPINFO {
cb: 0,
diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs
index f122176..d18c3d8 100644
--- a/library/std/src/sys/windows/process/tests.rs
+++ b/library/std/src/sys/windows/process/tests.rs
@@ -135,6 +135,8 @@
fn windows_exe_resolver() {
use super::resolve_exe;
use crate::io;
+ use crate::sys::fs::symlink;
+ use crate::sys_common::io::test::tmpdir;
let env_paths = || env::var_os("PATH");
@@ -178,4 +180,13 @@
// The application's directory is also searched.
let current_exe = env::current_exe().unwrap();
assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), empty_paths, None).is_ok());
+
+ // Create a temporary path and add a broken symlink.
+ let temp = tmpdir();
+ let mut exe_path = temp.path().to_owned();
+ exe_path.push("exists.exe");
+ symlink("<DOES NOT EXIST>".as_ref(), &exe_path).unwrap();
+
+ // A broken symlink should still be resolved.
+ assert!(resolve_exe(OsStr::new("exists.exe"), empty_paths, Some(temp.path().as_ref())).is_ok());
}
diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs
index 684b8e3..a001d6b 100644
--- a/library/std/src/sys/windows/stdio.rs
+++ b/library/std/src/sys/windows/stdio.rs
@@ -110,9 +110,9 @@
if data[0] >> 6 != 0b10 {
// not a continuation byte - reject
incomplete_utf8.len = 0;
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
+ "Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
));
}
incomplete_utf8.bytes[incomplete_utf8.len as usize] = data[0];
@@ -132,9 +132,9 @@
return Ok(1);
}
Err(_) => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
+ "Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
));
}
}
@@ -156,9 +156,9 @@
incomplete_utf8.len = 1;
return Ok(1);
} else {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
+ "Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
));
}
}
@@ -364,9 +364,9 @@
}
Err(_) => {
// We can't really do any better than forget all data and return an error.
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Windows stdin in console mode does not support non-UTF-16 input; \
+ "Windows stdin in console mode does not support non-UTF-16 input; \
encountered unpaired surrogate",
));
}
diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs
index 75f70c2..e4bba92 100644
--- a/library/std/src/sys/windows/thread.rs
+++ b/library/std/src/sys/windows/thread.rs
@@ -107,9 +107,9 @@
sysinfo.dwNumberOfProcessors as usize
};
match res {
- 0 => Err(io::Error::new_const(
+ 0 => Err(io::const_io_error!(
io::ErrorKind::NotFound,
- &"The number of hardware threads is not known for the target platform",
+ "The number of hardware threads is not known for the target platform",
)),
cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }),
}
diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs
index 91e4f76..a04908b 100644
--- a/library/std/src/sys/windows/time.rs
+++ b/library/std/src/sys/windows/time.rs
@@ -41,14 +41,6 @@
perf_counter::PerformanceCounterInstant::now().into()
}
- pub fn actually_monotonic() -> bool {
- false
- }
-
- pub const fn zero() -> Instant {
- Instant { t: Duration::from_secs(0) }
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
// On windows there's a threshold below which we consider two timestamps
// equivalent due to measurement error. For more details + doc link,