Move from libc read/write to nix read/write

Replace std from_raw_fd/into_raw_fd dance with nix write

Fixup notifyd build
This commit is contained in:
PolyMeilex 2024-01-20 18:45:36 +01:00 committed by ridiculousfish
parent 65cf6ada56
commit f3e8272c5d
11 changed files with 107 additions and 119 deletions

View file

@ -285,13 +285,14 @@ fn read_in_chunks(fd: RawFd, buff: &mut WString, split_null: bool, do_seek: bool
while !finished { while !finished {
let mut inbuf = [0_u8; READ_CHUNK_SIZE]; let mut inbuf = [0_u8; READ_CHUNK_SIZE];
let bytes_read = read_blocked(fd, &mut inbuf);
if bytes_read <= 0 { let bytes_read = match read_blocked(fd, &mut inbuf) {
eof = true; Ok(0) | Err(_) => {
break; eof = true;
} break;
let bytes_read = bytes_read as usize; }
Ok(read) => read,
};
let bytes_consumed = inbuf[..bytes_read] let bytes_consumed = inbuf[..bytes_read]
.iter() .iter()
@ -352,9 +353,12 @@ fn read_one_char_at_a_time(
while !finished { while !finished {
let mut b = [0_u8; 1]; let mut b = [0_u8; 1];
if read_blocked(fd, &mut b) <= 0 { match read_blocked(fd, &mut b) {
eof = true; Ok(0) | Err(_) => {
break; eof = true;
break;
}
_ => {}
} }
let b = b[0]; let b = b[0];

View file

@ -18,7 +18,7 @@ use crate::wutil::encoding::{mbrtowc, wcrtomb, zero_mbstate, AT_LEAST_MB_LEN_MAX
use crate::wutil::fish_iswalnum; use crate::wutil::fish_iswalnum;
use bitflags::bitflags; use bitflags::bitflags;
use core::slice; use core::slice;
use libc::{EINTR, EIO, O_WRONLY, SIGTTOU, SIG_IGN, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; use libc::{EIO, O_WRONLY, SIGTTOU, SIG_IGN, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use std::env; use std::env;
@ -1469,10 +1469,10 @@ fn can_be_encoded(wc: char) -> bool {
/// Call read, blocking and repeating on EINTR. Exits on EAGAIN. /// Call read, blocking and repeating on EINTR. Exits on EAGAIN.
/// \return the number of bytes read, or 0 on EOF. On EAGAIN, returns -1 if nothing was read. /// \return the number of bytes read, or 0 on EOF. On EAGAIN, returns -1 if nothing was read.
pub fn read_blocked(fd: RawFd, buf: &mut [u8]) -> isize { pub fn read_blocked(fd: RawFd, buf: &mut [u8]) -> nix::Result<usize> {
loop { loop {
let res = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), buf.len()) }; let res = nix::unistd::read(fd, buf);
if res < 0 && errno::errno().0 == EINTR { if let Err(nix::Error::EINTR) = res {
continue; continue;
} }
return res; return res;
@ -1496,16 +1496,17 @@ pub fn write_loop<Fd: AsRawFd>(fd: &Fd, buf: &[u8]) -> std::io::Result<usize> {
let fd = fd.as_raw_fd(); let fd = fd.as_raw_fd();
let mut total = 0; let mut total = 0;
while total < buf.len() { while total < buf.len() {
let written = match nix::unistd::write(fd, &buf[total..]) {
unsafe { libc::write(fd, buf[total..].as_ptr() as *const _, buf.len() - total) }; Ok(written) => {
if written < 0 { total += written;
let errno = errno::errno().0; }
if matches!(errno, libc::EAGAIN | libc::EINTR) { Err(err) => {
continue; if matches!(err, nix::Error::EAGAIN | nix::Error::EINTR) {
continue;
}
return Err(std::io::Error::from(err));
} }
return Err(std::io::Error::from_raw_os_error(errno));
} }
total += written as usize;
} }
Ok(total) Ok(total)
} }
@ -1517,15 +1518,17 @@ pub fn write_loop<Fd: AsRawFd>(fd: &Fd, buf: &[u8]) -> std::io::Result<usize> {
pub fn read_loop<Fd: AsRawFd>(fd: &Fd, buf: &mut [u8]) -> std::io::Result<usize> { pub fn read_loop<Fd: AsRawFd>(fd: &Fd, buf: &mut [u8]) -> std::io::Result<usize> {
let fd = fd.as_raw_fd(); let fd = fd.as_raw_fd();
loop { loop {
let read = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut _, buf.len()) }; match nix::unistd::read(fd, buf) {
if read < 0 { Ok(read) => {
let errno = errno::errno().0; return Ok(read);
if matches!(errno, libc::EAGAIN | libc::EINTR) { }
continue; Err(err) => {
if matches!(err, nix::Error::EAGAIN | nix::Error::EINTR) {
continue;
}
return Err(std::io::Error::from(err));
} }
return Err(std::io::Error::from_raw_os_error(errno));
} }
return Ok(read as usize);
} }
} }

View file

@ -120,20 +120,21 @@ impl FdEventSignaller {
let c = 1_u8; let c = 1_u8;
let mut ret; let mut ret;
loop { loop {
ret = unsafe { let bytes = c.to_ne_bytes();
libc::write( ret = nix::unistd::write(self.write_fd(), &bytes);
self.write_fd(),
&c as *const _ as *const c_void, match ret {
std::mem::size_of_val(&c), Ok(_) => break,
) Err(nix::Error::EINTR) => continue,
}; Err(_) => break,
if ret >= 0 || errno().0 != EINTR {
break;
} }
} }
// EAGAIN occurs if either the pipe buffer is full or the eventfd overflows (very unlikely).
if ret < 0 && ![EAGAIN, EWOULDBLOCK].contains(&errno().0) { if let Err(err) = ret {
perror("write"); // EAGAIN occurs if either the pipe buffer is full or the eventfd overflows (very unlikely).
if ![nix::Error::EAGAIN, nix::Error::EWOULDBLOCK].contains(&err) {
perror("write");
}
} }
} }

View file

@ -33,23 +33,13 @@ pub struct AutoCloseFd {
impl Read for AutoCloseFd { impl Read for AutoCloseFd {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
unsafe { nix::unistd::read(self.as_raw_fd(), buf).map_err(std::io::Error::from)
match libc::read(self.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len()) {
-1 => Err(std::io::Error::from_raw_os_error(errno::errno().0)),
bytes => Ok(bytes as usize),
}
}
} }
} }
impl Write for AutoCloseFd { impl Write for AutoCloseFd {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
unsafe { nix::unistd::write(self.as_raw_fd(), buf).map_err(std::io::Error::from)
match libc::write(self.as_raw_fd(), buf.as_ptr() as *const _, buf.len()) {
-1 => Err(std::io::Error::from_raw_os_error(errno::errno().0)),
bytes => Ok(bytes as usize),
}
}
} }
fn flush(&mut self) -> std::io::Result<()> { fn flush(&mut self) -> std::io::Result<()> {

View file

@ -84,9 +84,7 @@ pub fn flog_impl_async_safe(fd: i32, s: impl FloggableDisplayAsyncSafe) {
let bytes: &[u8] = s.to_flog_str_async_safe(&mut storage); let bytes: &[u8] = s.to_flog_str_async_safe(&mut storage);
// Note we deliberately do not retry on signals, etc. // Note we deliberately do not retry on signals, etc.
// This is used to report error messages after fork() in the child process. // This is used to report error messages after fork() in the child process.
unsafe { let _ = nix::unistd::write(fd, bytes);
let _ = libc::write(fd, bytes.as_ptr() as *const libc::c_void, bytes.len());
}
} }
/// Variant of FLOG which is async-safe to use after fork(). /// Variant of FLOG which is async-safe to use after fork().

View file

@ -7,10 +7,9 @@ use std::{
time::{Duration, SystemTime, UNIX_EPOCH}, time::{Duration, SystemTime, UNIX_EPOCH},
}; };
use errno::errno;
use libc::{ use libc::{
c_void, lseek, mmap, munmap, EINTR, MAP_ANONYMOUS, MAP_FAILED, MAP_PRIVATE, PROT_READ, lseek, mmap, munmap, MAP_ANONYMOUS, MAP_FAILED, MAP_PRIVATE, PROT_READ, PROT_WRITE, SEEK_END,
PROT_WRITE, SEEK_END, SEEK_SET, SEEK_SET,
}; };
use super::{HistoryItem, PersistenceMode}; use super::{HistoryItem, PersistenceMode};
@ -137,7 +136,7 @@ impl HistoryFileContents {
if unsafe { lseek(fd, 0, SEEK_SET) } != 0 { if unsafe { lseek(fd, 0, SEEK_SET) } != 0 {
return None; return None;
} }
if !read_from_fd(fd, region.as_mut()) { if read_from_fd(fd, region.as_mut()).is_err() {
return None; return None;
} }
} }
@ -230,25 +229,19 @@ fn should_mmap() -> bool {
/// Read from `fd` to fill `dest`, zeroing any unused space. /// Read from `fd` to fill `dest`, zeroing any unused space.
// Return true on success, false on failure. // Return true on success, false on failure.
fn read_from_fd(fd: RawFd, dest: &mut [u8]) -> bool { fn read_from_fd(fd: RawFd, mut dest: &mut [u8]) -> nix::Result<()> {
let mut remaining = dest.len(); while !dest.is_empty() {
let mut nread = 0; match nix::unistd::read(fd, dest) {
while remaining > 0 { Ok(0) => break,
let amt = Ok(amt) => {
unsafe { libc::read(fd, (&mut dest[nread]) as *mut u8 as *mut c_void, remaining) }; dest = &mut dest[amt..];
if amt < 0 {
if errno().0 != EINTR {
return false;
} }
} else if amt == 0 { Err(nix::Error::EINTR) => continue,
break; Err(err) => return Err(err),
} else {
remaining -= amt as usize;
nread += amt as usize;
} }
} }
dest[nread..].fill(0u8); dest.fill(0u8);
true Ok(())
} }
fn replace_all(s: &mut Vec<u8>, needle: &[u8], replacement: &[u8]) { fn replace_all(s: &mut Vec<u8>, needle: &[u8], replacement: &[u8]) {

View file

@ -294,7 +294,7 @@ fn readb(in_fd: RawFd) -> ReadbResult {
// Check stdin. // Check stdin.
if fdset.test(in_fd) { if fdset.test(in_fd) {
let mut arr: [u8; 1] = [0]; let mut arr: [u8; 1] = [0];
if read_blocked(in_fd, &mut arr) != 1 { if read_blocked(in_fd, &mut arr) != Ok(1) {
// The terminal has been closed. // The terminal has been closed.
return ReadbResult::Eof; return ReadbResult::Eof;
} }

View file

@ -13,9 +13,9 @@
//! end of the list is reached, at which point regular searching will commence. //! end of the list is reached, at which point regular searching will commence.
use libc::{ use libc::{
c_char, c_int, c_void, EAGAIN, ECHO, EINTR, EIO, EISDIR, ENOTTY, EPERM, ESRCH, EWOULDBLOCK, c_char, c_int, ECHO, EINTR, EIO, EISDIR, ENOTTY, EPERM, ESRCH, ICANON, ICRNL, IEXTEN, INLCR,
ICANON, ICRNL, IEXTEN, INLCR, IXOFF, IXON, ONLCR, OPOST, O_NONBLOCK, O_RDONLY, SIGINT, SIGTTIN, IXOFF, IXON, ONLCR, OPOST, O_NONBLOCK, O_RDONLY, SIGINT, SIGTTIN, STDIN_FILENO, STDOUT_FILENO,
STDIN_FILENO, STDOUT_FILENO, S_IFDIR, TCSANOW, VMIN, VQUIT, VSUSP, VTIME, _POSIX_VDISABLE, S_IFDIR, TCSANOW, VMIN, VQUIT, VSUSP, VTIME, _POSIX_VDISABLE,
}; };
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
@ -688,27 +688,31 @@ fn read_ni(parser: &Parser, fd: RawFd, io: &IoChain) -> i32 {
let mut fd_contents = Vec::with_capacity(usize::try_from(buf.st_size).unwrap()); let mut fd_contents = Vec::with_capacity(usize::try_from(buf.st_size).unwrap());
loop { loop {
let mut buff = [0_u8; 4096]; let mut buff = [0_u8; 4096];
let amt = unsafe { libc::read(fd, &mut buff[0] as *mut _ as *mut c_void, buff.len()) };
if amt > 0 { match nix::unistd::read(fd, &mut buff) {
fd_contents.extend_from_slice(&buff[..usize::try_from(amt).unwrap()]); Ok(0) => {
} else if amt == 0 { // EOF.
// EOF. break;
break; }
} else { Ok(amt) => {
assert!(amt == -1); fd_contents.extend_from_slice(&buff[..amt]);
let err = errno(); }
if err.0 == EINTR { Err(err) => {
continue; if err == nix::Error::EINTR {
} else if err.0 == EAGAIN || err.0 == EWOULDBLOCK && make_fd_blocking(fd).is_ok() { continue;
// We succeeded in making the fd blocking, keep going. } else if err == nix::Error::EAGAIN
continue; || err == nix::Error::EWOULDBLOCK && make_fd_blocking(fd).is_ok()
} else { {
// Fatal error. // We succeeded in making the fd blocking, keep going.
FLOG!( continue;
error, } else {
wgettext_fmt!("Unable to read input file: %s", err.to_string()) // Fatal error.
); FLOG!(
return 1; error,
wgettext_fmt!("Unable to read input file: %s", err.to_string())
);
return 1;
}
} }
} }
} }

View file

@ -76,9 +76,8 @@ impl ItemMaker {
} }
ItemWakeReason::Readable => { ItemWakeReason::Readable => {
let mut buf = [0u8; 1024]; let mut buf = [0u8; 1024];
let amt = let res = nix::unistd::read(fd.as_raw_fd(), &mut buf);
unsafe { libc::read(fd.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len()) }; let amt = res.expect("read error!");
assert_ne!(amt, -1, "read error!");
self.length_read.fetch_add(amt as usize, Ordering::Relaxed); self.length_read.fetch_add(amt as usize, Ordering::Relaxed);
was_closed = amt == 0; was_closed = amt == 0;
} }

View file

@ -114,16 +114,16 @@ impl UniversalNotifier for NotifydNotifier {
let mut read_something = false; let mut read_something = false;
let mut buff: [u8; 64] = [0; 64]; let mut buff: [u8; 64] = [0; 64];
loop { loop {
let amt_read = unsafe { let res = nix::unistd::read(self.notify_fd, &mut buff);
libc::read(
self.notify_fd, if let Ok(amt_read) = res {
buff.as_mut_ptr() as *mut libc::c_void, read_something |= amt_read > 0;
buff.len(), }
)
}; match res {
read_something = read_something || amt_read > 0; Ok(amt_read) if amt_read != buff.len() => break,
if amt_read != buff.len() as isize { Err(_) => break,
break; _ => continue,
} }
} }
FLOGF!( FLOGF!(

View file

@ -401,12 +401,8 @@ pub fn wrename(old_name: &wstr, new_name: &wstr) -> libc::c_int {
unsafe { libc::rename(old_narrow.as_ptr(), new_narrow.as_ptr()) } unsafe { libc::rename(old_narrow.as_ptr(), new_narrow.as_ptr()) }
} }
pub fn write_to_fd(input: &[u8], fd: RawFd) -> std::io::Result<usize> { pub fn write_to_fd(input: &[u8], fd: RawFd) -> nix::Result<usize> {
let mut file = unsafe { std::fs::File::from_raw_fd(fd) }; nix::unistd::write(fd, input)
let amt = file.write(input);
// Ensure the file is not closed.
file.into_raw_fd();
amt
} }
/// Write a wide string to a file descriptor. This avoids doing any additional allocation. /// Write a wide string to a file descriptor. This avoids doing any additional allocation.