Skip to content

Commit

Permalink
Auto merge of #34776 - cuviper:solaris-readdir, r=alexcrichton
Browse files Browse the repository at this point in the history
std: fix `readdir` errors for solaris

A `NULL` from `readdir` could be the end of stream or an error.  The only
way to know is to check `errno`, so it must be set to a known value first,
like a 0 that POSIX will never use.

This currently only matters for solaris targets, as the other unix platforms
are using `readdir_r` with a direct error return indication.  However, this is
getting deprecated (#34668) so they should all eventually switch to `readdir`.

This PR adds `set_errno`, uses it to clear the value before calling `readdir`,
then checks it again after to see the reason for a `NULL`.  A few other small
fixes are included just to get solaris compiling at all.

I couldn't get cross-compilation completely going, so I don't have a good way
to test this beyond a smoke-test cargo build of std.  I'd appreciate input from
someone more familiar with solaris -- cc @nbaksalyar?
  • Loading branch information
bors authored Jul 14, 2016
2 parents 3dbbe2f + 79fb552 commit 935bd76
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 23 deletions.
12 changes: 8 additions & 4 deletions src/libstd/sys/common/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,23 @@ use time::Duration;

#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "openbsd", target_os = "netbsd"))]
target_os = "openbsd", target_os = "netbsd",
target_os = "solaris"))]
use sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "openbsd", target_os = "netbsd")))]
target_os = "openbsd", target_os = "netbsd",
target_os = "solaris")))]
use sys::net::netc::IPV6_ADD_MEMBERSHIP;
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "openbsd", target_os = "netbsd"))]
target_os = "openbsd", target_os = "netbsd",
target_os = "solaris"))]
use sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "openbsd", target_os = "netbsd")))]
target_os = "openbsd", target_os = "netbsd",
target_os = "solaris")))]
use sys::net::netc::IPV6_DROP_MEMBERSHIP;

////////////////////////////////////////////////////////////////////////////////
Expand Down
8 changes: 7 additions & 1 deletion src/libstd/sys/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,15 @@ impl Iterator for ReadDir {
// of the thread safety, on Illumos the readdir(3C) function is safe to use
// in threaded applications and it is generally preferred over the
// readdir_r(3C) function.
super::os::set_errno(0);
let entry_ptr = libc::readdir(self.dirp.0);
if entry_ptr.is_null() {
return None
// 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.
return match super::os::errno() {
0 => None,
e => Some(Err(Error::from_raw_os_error(e))),
}
}

let name = (*entry_ptr).d_name.as_ptr();
Expand Down
41 changes: 25 additions & 16 deletions src/libstd/sys/unix/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,28 +35,37 @@ use vec;
const TMPBUF_SZ: usize = 128;
static ENV_LOCK: Mutex = Mutex::new();


extern {
#[cfg_attr(any(target_os = "linux", target_os = "emscripten"),
link_name = "__errno_location")]
#[cfg_attr(any(target_os = "bitrig",
target_os = "netbsd",
target_os = "openbsd",
target_os = "android",
target_env = "newlib"),
link_name = "__errno")]
#[cfg_attr(target_os = "solaris", link_name = "___errno")]
#[cfg_attr(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd"),
link_name = "__error")]
fn errno_location() -> *mut c_int;
}

/// Returns the platform-specific value of errno
#[cfg(not(target_os = "dragonfly"))]
pub fn errno() -> i32 {
extern {
#[cfg_attr(any(target_os = "linux", target_os = "emscripten"),
link_name = "__errno_location")]
#[cfg_attr(any(target_os = "bitrig",
target_os = "netbsd",
target_os = "openbsd",
target_os = "android",
target_env = "newlib"),
link_name = "__errno")]
#[cfg_attr(target_os = "solaris", link_name = "___errno")]
#[cfg_attr(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd"),
link_name = "__error")]
fn errno_location() -> *const c_int;
unsafe {
(*errno_location()) as i32
}
}

/// Sets the platform-specific value of errno
#[cfg(target_os = "solaris")] // only needed for readdir so far
pub fn set_errno(e: i32) {
unsafe {
(*errno_location()) as i32
*errno_location() = e as c_int
}
}

Expand Down
1 change: 0 additions & 1 deletion src/libstd/sys/unix/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use prelude::v1::*;

use alloc::boxed::FnBox;
use cmp;
#[cfg(not(any(target_env = "newlib", target_os = "solaris")))]
use ffi::CStr;
use io;
use libc;
Expand Down

0 comments on commit 935bd76

Please sign in to comment.