diff --git a/src/bin/fish.rs b/src/bin/fish.rs index 0b2f32256..06cee4155 100644 --- a/src/bin/fish.rs +++ b/src/bin/fish.rs @@ -41,7 +41,6 @@ fprintf, function, future_feature_flags as features, history::{self, start_private_mode}, io::IoChain, - libc::{getrusage64, timeval64}, nix::{getpid, isatty}, panic::panic_handler, parse_constants::{ParseErrorList, ParseTreeFlags}, @@ -56,12 +55,14 @@ }, reader::{reader_init, reader_read, term_copy_modes}, signal::{signal_clear_cancel, signal_unblock_all}, - threads, topic_monitor, + threads::{self}, + topic_monitor, wchar::prelude::*, wutil::waccess, }; use std::ffi::{CString, OsStr, OsString}; use std::fs::File; +use std::mem::MaybeUninit; use std::os::unix::prelude::*; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -103,20 +104,23 @@ struct FishCmdOpts { } /// Return a timeval converted to milliseconds. -fn tv_to_msec(tv: &timeval64) -> i64 { +#[allow(clippy::unnecessary_cast)] +fn tv_to_msec(tv: &libc::timeval) -> i64 { // milliseconds per second - let mut msec = tv.tv_sec * 1000; + let mut msec = tv.tv_sec as i64 * 1000; // microseconds per millisecond - msec += tv.tv_usec / 1000; + msec += tv.tv_usec as i64 / 1000; msec } fn print_rusage_self() { - let Some(rs) = getrusage64(libc::RUSAGE_SELF) else { + let mut rs = MaybeUninit::uninit(); + if unsafe { libc::getrusage(libc::RUSAGE_SELF, rs.as_mut_ptr()) } != 0 { let s = CString::new("getrusage").unwrap(); unsafe { libc::perror(s.as_ptr()) } return; - }; + } + let rs: libc::rusage = unsafe { rs.assume_init() }; let rss_kb = if cfg!(target_os = "macos") { // mac use bytes. rs.ru_maxrss / 1024 diff --git a/src/env_universal_common.rs b/src/env_universal_common.rs index e065d129c..8ee9d8466 100644 --- a/src/env_universal_common.rs +++ b/src/env_universal_common.rs @@ -799,14 +799,12 @@ fn save(&mut self, directory: &wstr) -> bool { // unlikely to affect users. #[cfg(any(target_os = "linux", target_os = "android"))] { - use crate::libc::{clock_gettime64, futimens64, timespec64}; - #[allow(clippy::useless_conversion)] - let t0 = timespec64 { - tv_sec: 0, - tv_nsec: libc::UTIME_OMIT.try_into().unwrap(), // don't change ctime - }; - if let Some(t1) = clock_gettime64(libc::CLOCK_REALTIME) { - futimens64(private_fd.as_raw_fd(), t0, t1); + let mut times: [libc::timespec; 2] = unsafe { std::mem::zeroed() }; + times[0].tv_nsec = libc::UTIME_OMIT; // don't change ctime + if unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, &mut times[1]) } != 0 { + unsafe { + libc::futimens(private_fd.as_raw_fd(), ×[0]); + } } } diff --git a/src/fd_monitor.rs b/src/fd_monitor.rs index 7257ce629..b0eb30087 100644 --- a/src/fd_monitor.rs +++ b/src/fd_monitor.rs @@ -11,7 +11,6 @@ use crate::fd_readable_set::FdReadableSet; use crate::fds::AutoCloseFd; use crate::flog::FLOG; -use crate::libc::{select64, timeval64}; use crate::threads::assert_is_background_thread; use crate::wutil::perror; use errno::errno; @@ -147,24 +146,26 @@ pub fn post(&self) { /// but guarantees that the next call to wait() will not block. /// Return true if readable, false if not readable, or not interrupted by a signal. pub fn poll(&self, wait: bool /* = false */) -> bool { - let mut timeout = timeval64 { + let mut timeout = libc::timeval { tv_sec: 0, tv_usec: 0, }; let mut fds: libc::fd_set = unsafe { std::mem::zeroed() }; unsafe { libc::FD_ZERO(&mut fds) }; unsafe { libc::FD_SET(self.read_fd(), &mut fds) }; - let res = select64( - self.read_fd() + 1, - &mut fds, - std::ptr::null_mut(), - std::ptr::null_mut(), - if wait { - std::ptr::null_mut() - } else { - &mut timeout - }, - ); + let res = unsafe { + libc::select( + self.read_fd() + 1, + &mut fds, + std::ptr::null_mut(), + std::ptr::null_mut(), + if wait { + std::ptr::null_mut() + } else { + &mut timeout + }, + ) + }; res > 0 } diff --git a/src/fd_readable_set.rs b/src/fd_readable_set.rs index 28479e70f..00f1a2308 100644 --- a/src/fd_readable_set.rs +++ b/src/fd_readable_set.rs @@ -68,21 +68,24 @@ pub fn test(&self, fd: RawFd) -> bool { /// destructively modifies the set. Returns the result of `select()` or `poll()`. pub fn check_readable(&mut self, timeout_usec: u64) -> c_int { let null = std::ptr::null_mut(); - use crate::libc::{select64, timeval64}; if timeout_usec == Self::kNoTimeout { - return select64( - self.nfds_, - &mut self.fdset_, - null, - null, - std::ptr::null_mut(), - ); + unsafe { + return libc::select( + self.nfds_, + &mut self.fdset_, + null, + null, + std::ptr::null_mut(), + ); + } } else { - let mut tvs = timeval64 { - tv_sec: (timeout_usec / kUsecPerSec).try_into().unwrap(), - tv_usec: (timeout_usec % kUsecPerSec).try_into().unwrap(), + let mut tvs = libc::timeval { + tv_sec: (timeout_usec / kUsecPerSec) as libc::time_t, + tv_usec: (timeout_usec % kUsecPerSec) as libc::suseconds_t, }; - return select64(self.nfds_, &mut self.fdset_, null, null, &mut tvs); + unsafe { + return libc::select(self.nfds_, &mut self.fdset_, null, null, &mut tvs); + } } } diff --git a/src/history.rs b/src/history.rs index 67c75335f..3ccc10dd8 100644 --- a/src/history.rs +++ b/src/history.rs @@ -16,7 +16,7 @@ //! 5. The chaos_mode boolean can be set to true to do things like lower buffer sizes which can //! trigger race conditions. This is useful for testing. -use crate::{common::cstr2wcstring, env::EnvVar, libc::localtime64_r, wcstringutil::trim}; +use crate::{common::cstr2wcstring, env::EnvVar, wcstringutil::trim}; use std::{ borrow::Cow, collections::{BTreeMap, HashMap, HashSet, VecDeque}, @@ -1409,8 +1409,10 @@ fn format_history_record( ) -> WString { let mut result = WString::new(); let seconds = time_to_seconds(item.timestamp()); + let seconds = seconds as libc::time_t; + let mut timestamp: libc::tm = unsafe { std::mem::zeroed() }; if let Some(show_time_format) = show_time_format.and_then(|s| CString::new(s).ok()) { - if let Some(timestamp) = localtime64_r(seconds) { + if !unsafe { libc::localtime_r(&seconds, &mut timestamp).is_null() } { const max_tstamp_length: usize = 100; let mut timestamp_str = [0_u8; max_tstamp_length]; // The libc crate fails to declare strftime on BSD. diff --git a/src/input_common.rs b/src/input_common.rs index a8269f2b3..dcdb7ad3f 100644 --- a/src/input_common.rs +++ b/src/input_common.rs @@ -11,7 +11,6 @@ self, alt, canonicalize_control_char, canonicalize_keyed_control_char, function_key, shift, Key, Modifiers, }; -use crate::libc::{pselect64, timespec64}; use crate::reader::{reader_current_data, reader_test_and_clear_interrupted}; use crate::threads::{iothread_port, MainThread}; use crate::universal_notifier::default_notifier; @@ -1094,7 +1093,7 @@ fn readch_timed(&mut self, wait_time_ms: usize) -> Option { const NSEC_PER_MSEC: u64 = 1000 * 1000; const NSEC_PER_SEC: u64 = NSEC_PER_MSEC * 1000; let wait_nsec: u64 = (wait_time_ms as u64) * NSEC_PER_MSEC; - let timeout = timespec64 { + let timeout = libc::timespec { tv_sec: (wait_nsec / NSEC_PER_SEC).try_into().unwrap(), tv_nsec: (wait_nsec % NSEC_PER_SEC).try_into().unwrap(), }; @@ -1106,14 +1105,16 @@ fn readch_timed(&mut self, wait_time_ms: usize) -> Option { libc::FD_ZERO(&mut fdset); libc::FD_SET(in_fd, &mut fdset); }; - let res = pselect64( - in_fd + 1, - &mut fdset, - ptr::null_mut(), - ptr::null_mut(), - &timeout, - &sigs, - ); + let res = unsafe { + libc::pselect( + in_fd + 1, + &mut fdset, + ptr::null_mut(), + ptr::null_mut(), + &timeout, + &sigs, + ) + }; // Prevent signal starvation on WSL causing the `torn_escapes.py` test to fail if is_windows_subsystem_for_linux(WSL::V1) { diff --git a/src/libc.c b/src/libc.c index af23e1ae9..93183e5a1 100644 --- a/src/libc.c +++ b/src/libc.c @@ -1,6 +1,3 @@ -#include -#include -#include #include #include #include @@ -8,20 +5,10 @@ #include #include #include -#include -#include -#include -#include #include #define UNUSED(x) (void)(x) -#define assert_or_die(x) \ - do { \ - assert((x)); \ - if (!(x)) abort(); \ - } while (false) - size_t C_MB_CUR_MAX() { return MB_CUR_MAX; } uint64_t C_ST_LOCAL() { @@ -193,114 +180,3 @@ int C_RLIMIT_NTHR() { return -1; #endif } - -bool C_readdir64(DIR* dirp, const char** d_name, size_t* d_name_len, uint64_t* d_ino, - unsigned char* d_type) { - struct dirent* dent = readdir(dirp); - if (!dent) { - return false; - } - *d_name = dent->d_name; - *d_name_len = sizeof dent->d_name / sizeof **d_name; -#if defined(__BSD__) - *d_ino = dent->d_fileno; -#else - *d_ino = dent->d_ino; -#endif - *d_type = dent->d_type; - return true; -} - -bool C_fstatat64(int dirfd, const char* file, int flag, uint64_t* st_dev, uint64_t* st_ino, - mode_t* st_mode) { - struct stat buf; - if (fstatat(dirfd, file, &buf, flag) == -1) { - return false; - } - *st_dev = buf.st_dev; - *st_ino = buf.st_ino; - *st_mode = buf.st_mode; - return true; -} - -bool C_localtime64_r(int64_t timep, struct tm* result) { - time_t timep_ = timep; - return localtime_r(&timep_, result); -} - -struct timeval64 { - int64_t tv_sec; - int64_t tv_usec; -}; - -int C_select64(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, - struct timeval64* timeout64) { - struct timeval timeout; - if (timeout64) { - timeout.tv_sec = timeout64->tv_sec; - timeout.tv_usec = timeout64->tv_usec; - assert_or_die(timeout.tv_sec == timeout64->tv_sec); - assert_or_die(timeout.tv_usec == timeout64->tv_usec); - } - int result = select(nfds, readfds, writefds, errorfds, timeout64 ? &timeout : NULL); - if (timeout64) { - timeout64->tv_sec = timeout.tv_sec; - timeout64->tv_usec = timeout.tv_usec; - } - return result; -} - -struct timespec64 { - int64_t tv_sec; - int64_t tv_nsec; -}; - -int C_pselect64(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, - struct timespec64* timeout64, const sigset_t* sigmask) { - struct timespec timeout; - if (timeout64) { - timeout.tv_sec = timeout64->tv_sec; - timeout.tv_nsec = timeout64->tv_nsec; - assert_or_die(timeout.tv_sec == timeout64->tv_sec); - assert_or_die(timeout.tv_nsec == timeout64->tv_nsec); - } - return pselect(nfds, readfds, writefds, errorfds, timeout64 ? &timeout : NULL, sigmask); -} - -struct rusage64 { - struct timeval64 ru_utime; - struct timeval64 ru_stime; - int64_t ru_maxrss; - int64_t ru_nsignals; -}; - -int C_getrusage64(int resource, struct rusage64* usage) { - struct rusage tmp; - int result = getrusage(resource, &tmp); - usage->ru_utime.tv_sec = tmp.ru_utime.tv_sec; - usage->ru_utime.tv_usec = tmp.ru_utime.tv_usec; - usage->ru_stime.tv_sec = tmp.ru_stime.tv_sec; - usage->ru_stime.tv_usec = tmp.ru_stime.tv_usec; - usage->ru_maxrss = tmp.ru_maxrss; - usage->ru_nsignals = tmp.ru_nsignals; - return result; -} - -bool C_clock_gettime64(clockid_t clock_id, struct timespec64* tp) { - struct timespec tp_; - if (clock_gettime(clock_id, &tp_) == -1) { - return false; - } - tp->tv_sec = tp_.tv_sec; - tp->tv_nsec = tp_.tv_nsec; - return true; -} - -bool C_futimens64(int fd, struct timespec64 times0, struct timespec64 times1) { - struct timespec times[2]; - times[0].tv_sec = times0.tv_sec; - times[0].tv_nsec = times0.tv_nsec; - times[1].tv_sec = times1.tv_sec; - times[1].tv_nsec = times1.tv_nsec; - return futimens(fd, ×[0]) == 0; -} diff --git a/src/libc.rs b/src/libc.rs index 597140dab..6269f0f7d 100644 --- a/src/libc.rs +++ b/src/libc.rs @@ -1,6 +1,6 @@ -use std::{ffi::CStr, sync::atomic::AtomicPtr}; +use std::sync::atomic::AtomicPtr; -use libc::{c_char, c_int, fd_set}; +use libc::{c_char, c_int}; use once_cell::sync::Lazy; pub static _PATH_BSHELL: AtomicPtr = AtomicPtr::new(std::ptr::null_mut()); @@ -59,165 +59,3 @@ pub fn $cvar() -> $type { CVAR!(C_RLIMIT_KQUEUES, RLIMIT_KQUEUES, i32); CVAR!(C_RLIMIT_NPTS, RLIMIT_NPTS, i32); CVAR!(C_RLIMIT_NTHR, RLIMIT_NTHR, i32); - -pub(crate) fn readdir64(dirp: *mut libc::DIR) -> Option<(*const c_char, usize, u64, u8)> { - let mut d_name = unsafe { std::mem::zeroed() }; - let mut d_name_len = unsafe { std::mem::zeroed() }; - let mut d_ino = unsafe { std::mem::zeroed() }; - let mut d_type = unsafe { std::mem::zeroed() }; - if !unsafe { C_readdir64(dirp, &mut d_name, &mut d_name_len, &mut d_ino, &mut d_type) } { - return None; - } - Some((d_name, d_name_len, d_ino, d_type)) -} -extern "C" { - fn C_readdir64( - dirp: *mut libc::DIR, - d_name: *mut *const c_char, - d_name_len: *mut usize, - d_ino: *mut u64, - d_type: *mut u8, - ) -> bool; -} - -pub(crate) fn fstatat64( - dirfd: c_int, - file: &CStr, - flag: c_int, -) -> Option<(u64, u64, libc::mode_t)> { - let mut st_dev = unsafe { std::mem::zeroed() }; - let mut st_ino = unsafe { std::mem::zeroed() }; - let mut st_mode = unsafe { std::mem::zeroed() }; - if !unsafe { - C_fstatat64( - dirfd, - file.as_ptr(), - flag, - &mut st_dev, - &mut st_ino, - &mut st_mode, - ) - } { - return None; - } - Some((st_dev, st_ino, st_mode)) -} -extern "C" { - fn C_fstatat64( - dirfd: c_int, - file: *const c_char, - flag: c_int, - st_dev: *mut u64, - st_ino: *mut u64, - st_mode: *mut libc::mode_t, - ) -> bool; -} - -pub(crate) fn localtime64_r(timep: i64) -> Option { - let mut timestamp = unsafe { std::mem::zeroed() }; - if !unsafe { C_localtime64_r(timep, &mut timestamp) } { - return None; - } - Some(timestamp) -} -extern "C" { - fn C_localtime64_r(timep: i64, result: *mut libc::tm) -> bool; -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct timeval64 { - pub tv_sec: i64, - pub tv_usec: i64, -} - -pub(crate) fn select64( - nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - errorfds: *mut fd_set, - timeout: *mut timeval64, -) -> c_int { - unsafe { C_select64(nfds, readfds, writefds, errorfds, timeout) } -} -extern "C" { - fn C_select64( - nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - errorfds: *mut fd_set, - timeout: *mut timeval64, - ) -> c_int; -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct timespec64 { - pub tv_sec: i64, - pub tv_nsec: i64, -} - -pub(crate) fn pselect64( - nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - errorfds: *mut fd_set, - timeout: *const timespec64, - sigmask: *const libc::sigset_t, -) -> c_int { - unsafe { C_pselect64(nfds, readfds, writefds, errorfds, timeout, sigmask) } -} -extern "C" { - fn C_pselect64( - nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - errorfds: *mut fd_set, - timeout: *const timespec64, - sigmask: *const libc::sigset_t, - ) -> c_int; -} - -#[repr(C)] -pub struct rusage64 { - pub ru_utime: timeval64, - pub ru_stime: timeval64, - pub ru_maxrss: u64, - pub ru_nsignals: u64, -} - -pub fn getrusage64(resource: c_int) -> Option { - let mut rusage = std::mem::MaybeUninit::uninit(); - let result = unsafe { C_getrusage64(resource, rusage.as_mut_ptr()) }; - // getrusage(2) says the syscall can only fail if the dest address is invalid (EFAULT) or if the - // requested resource type is invalid. Since we're in control of both, we can assume it won't - // fail. In case it does anyway (e.g. OS where the syscall isn't implemented), we can just - // return an empty value. - match result { - 0 => unsafe { Some(rusage.assume_init()) }, - _ => None, - } -} -extern "C" { - fn C_getrusage64(resource: c_int, usage: *mut rusage64) -> c_int; -} - -#[allow(unused)] -pub(crate) fn clock_gettime64(clk_id: libc::clockid_t) -> Option { - let mut tp = unsafe { std::mem::zeroed() }; - if !unsafe { C_clock_gettime64(clk_id, &mut tp) } { - return None; - } - Some(tp) -} -extern "C" { - fn C_clock_gettime64(clk_id: libc::clockid_t, tp: *mut timespec64) -> bool; -} - -#[allow(unused)] -pub(crate) fn futimens64(fd: c_int, time0: timespec64, time1: timespec64) -> bool { - unsafe { C_futimens64(fd, time0, time1) } -} -extern "C" { - fn C_futimens64(fd: c_int, time0: timespec64, time1: timespec64) -> bool; -} diff --git a/src/nix.rs b/src/nix.rs index 2259f92bb..ba0989748 100644 --- a/src/nix.rs +++ b/src/nix.rs @@ -2,10 +2,9 @@ use std::time::Duration; -use crate::libc::timeval64; - -pub(crate) const fn timeval_to_duration(val: &timeval64) -> Duration { - let micros = val.tv_sec * (1E6 as i64) + val.tv_usec; +#[allow(clippy::unnecessary_cast)] +pub const fn timeval_to_duration(val: &libc::timeval) -> Duration { + let micros = val.tv_sec as i64 * (1E6 as i64) + val.tv_usec as i64; Duration::from_micros(micros as u64) } @@ -14,7 +13,7 @@ pub trait TimevalExt { fn as_duration(&self) -> Duration; } -impl TimevalExt for timeval64 { +impl TimevalExt for libc::timeval { fn as_micros(&self) -> i64 { timeval_to_duration(self).as_micros() as i64 } diff --git a/src/tests/env.rs b/src/tests/env.rs index d3b15e6ee..3bee4f0c5 100644 --- a/src/tests/env.rs +++ b/src/tests/env.rs @@ -1,5 +1,4 @@ use crate::env::{EnvMode, EnvStack, EnvVar, EnvVarFlags, Environment}; -use crate::libc::localtime64_r; use crate::tests::prelude::*; use crate::wchar::prelude::*; use crate::wutil::wgetcwd; @@ -64,8 +63,16 @@ fn return_timezone_hour(tstamp: SystemTime, timezone: &wstr) -> libc::c_int { let _var = vars.get(L!("TZ")); - let tstamp = tstamp.duration_since(UNIX_EPOCH).unwrap().as_secs(); - localtime64_r(tstamp.try_into().unwrap()).unwrap().tm_hour + let tstamp: libc::time_t = tstamp + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() + .try_into() + .unwrap(); + let mut local_time: libc::tm = unsafe { std::mem::zeroed() }; + unsafe { libc::localtime_r(&tstamp, &mut local_time) }; + + local_time.tm_hour } /// Verify that setting TZ calls tzset() in the current shell process. diff --git a/src/timer.rs b/src/timer.rs index ba6cf225a..ae09a84e7 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -17,8 +17,6 @@ use std::io::Write; use std::time::{Duration, Instant}; -use crate::libc::{getrusage64, rusage64}; - enum Unit { Minutes, Seconds, @@ -28,8 +26,8 @@ enum Unit { struct TimerSnapshot { wall_time: Instant, - cpu_fish: rusage64, - cpu_children: rusage64, + cpu_fish: libc::rusage, + cpu_children: libc::rusage, } /// Create a `TimerSnapshot` and return a `PrintElapsedOnDrop` object that will print upon @@ -47,12 +45,24 @@ enum RUsage { RChildren, } -fn getrusage(resource: RUsage) -> rusage64 { - getrusage64(match resource { - RUsage::RSelf => libc::RUSAGE_SELF, - RUsage::RChildren => libc::RUSAGE_CHILDREN, - }) - .unwrap_or(unsafe { std::mem::zeroed() }) +/// A safe wrapper around `libc::getrusage()` +fn getrusage(resource: RUsage) -> libc::rusage { + let mut rusage = std::mem::MaybeUninit::uninit(); + let result = unsafe { + match resource { + RUsage::RSelf => libc::getrusage(libc::RUSAGE_SELF, rusage.as_mut_ptr()), + RUsage::RChildren => libc::getrusage(libc::RUSAGE_CHILDREN, rusage.as_mut_ptr()), + } + }; + + // getrusage(2) says the syscall can only fail if the dest address is invalid (EFAULT) or if the + // requested resource type is invalid. Since we're in control of both, we can assume it won't + // fail. In case it does anyway (e.g. OS where the syscall isn't implemented), we can just + // return an empty value. + match result { + 0 => unsafe { rusage.assume_init() }, + _ => unsafe { std::mem::zeroed() }, + } } impl TimerSnapshot { diff --git a/src/wildcard.rs b/src/wildcard.rs index 3bee9f2dc..9c9be1572 100644 --- a/src/wildcard.rs +++ b/src/wildcard.rs @@ -901,7 +901,7 @@ fn descend_unique_hierarchy(&mut self, start_point: &mut WString) -> WString { // Ensure we don't fall into a symlink loop. // Ideally we would compare both devices and inodes, but devices require a stat call, so we // use inodes exclusively. - let mut visited_inodes: HashSet = HashSet::new(); + let mut visited_inodes: HashSet = HashSet::new(); loop { let mut unique_entry = WString::new(); diff --git a/src/wutil/dir_iter.rs b/src/wutil/dir_iter.rs index ce3cb1967..4d47c3801 100644 --- a/src/wutil/dir_iter.rs +++ b/src/wutil/dir_iter.rs @@ -1,6 +1,5 @@ use super::wopendir; use crate::common::{cstr2wcstring, wcs2zstring}; -use crate::libc::{fstatat64, readdir64}; use crate::wchar::{wstr, WString}; use crate::wutil::DevInode; use libc::{ @@ -35,7 +34,7 @@ pub struct DirEntry { pub name: WString, /// inode of this entry. - pub inode: u64, + pub inode: libc::ino_t, // Device, inode pair for this entry, or none if not yet computed. dev_inode: Cell>, @@ -104,13 +103,14 @@ fn do_stat(&self) { return; } let narrow = wcs2zstring(&self.name); - if let Some((st_dev, st_ino, st_mode)) = fstatat64(fd, &narrow, 0) { + let mut s: libc::stat = unsafe { std::mem::zeroed() }; + if unsafe { libc::fstatat(fd, narrow.as_ptr(), &mut s, 0) } == 0 { let dev_inode = DevInode { - device: st_dev, - inode: st_ino, + device: s.st_dev as u64, + inode: s.st_ino as u64, }; self.dev_inode.set(Some(dev_inode)); - self.typ.set(stat_mode_to_entry_type(st_mode)); + self.typ.set(stat_mode_to_entry_type(s.st_mode)); } else { match errno::errno().0 { ELOOP => { @@ -252,7 +252,8 @@ pub fn rewind(&mut self) { #[allow(clippy::should_implement_trait)] pub fn next(&mut self) -> Option> { errno::set_errno(errno::Errno(0)); - let Some((d_name, d_name_len, d_ino, d_type)) = readdir64(self.dir.dir()) else { + let dent = unsafe { libc::readdir(self.dir.dir()).as_ref() }; + let Some(dent) = dent else { // readdir distinguishes between EOF and error via errno. let err = errno::errno().0; if err == 0 { @@ -262,10 +263,9 @@ pub fn next(&mut self) -> Option> { } }; - let d_name = unsafe { slice::from_raw_parts(d_name, d_name_len) }; // dent.d_name is c_char; pretend it's u8. assert!(std::mem::size_of::() == std::mem::size_of::()); - let d_name_cchar = &d_name; + let d_name_cchar = &dent.d_name; let d_name = unsafe { slice::from_raw_parts(d_name_cchar.as_ptr() as *const u8, d_name_cchar.len()) }; @@ -276,12 +276,22 @@ pub fn next(&mut self) -> Option> { return self.next(); } - let nul_pos = d_name.iter().position(|b| *b == 0).unwrap(); - let d_name = &d_name[..nul_pos + 1]; + let nul_pos = dent.d_name.iter().position(|b| *b == 0).unwrap(); + let d_name: Vec = dent.d_name[..nul_pos + 1] + .iter() + .map(|b| *b as u8) + .collect(); self.entry.reset(); - self.entry.name = cstr2wcstring(d_name); - self.entry.inode = d_ino; - let typ = dirent_type_to_entry_type(d_type); + self.entry.name = cstr2wcstring(&d_name); + #[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] + { + self.entry.inode = dent.d_fileno; + } + #[cfg(not(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))] + { + self.entry.inode = dent.d_ino; + } + let typ = dirent_type_to_entry_type(dent.d_type); // Do not store symlinks as we will need to resolve them. if typ != Some(DirEntryType::lnk) { self.entry.typ.set(typ);