diff --git a/src/common.rs b/src/common.rs index c1001c7ef..49b51df13 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1410,27 +1410,6 @@ macro_rules! write_to_output { }}; } -/// A rusty port of the C++ `read_loop()` function from `common.cpp`. This should be deprecated in -/// favor of native rust read/write methods at some point. -/// -/// Returns the number of bytes read or an IO error. -pub fn read_loop(fd: &Fd, buf: &mut [u8]) -> std::io::Result { - let fd = fd.as_raw_fd(); - loop { - match nix::unistd::read(fd, buf) { - Ok(read) => { - return Ok(read); - } - Err(err) => { - if matches!(err, nix::Error::EAGAIN | nix::Error::EINTR) { - continue; - } - return Err(std::io::Error::from(err)); - } - } - } -} - /// Write the given paragraph of output, redoing linebreaks to fit `termsize`. pub fn reformat_for_screen(msg: &wstr, termsize: &Termsize) -> WString { let mut buff = WString::new(); diff --git a/src/env_universal_common.rs b/src/env_universal_common.rs index 139a7505e..183200609 100644 --- a/src/env_universal_common.rs +++ b/src/env_universal_common.rs @@ -1,7 +1,7 @@ #![allow(clippy::bad_bit_mask)] use crate::common::{ - read_loop, str2wcstring, timef, unescape_string, valid_var_name, wcs2zstring, UnescapeFlags, + str2wcstring, timef, unescape_string, valid_var_name, wcs2zstring, UnescapeFlags, UnescapeStringStyle, }; use crate::env::{EnvVar, EnvVarFlags, VarTable}; @@ -23,9 +23,9 @@ use std::collections::HashSet; use std::ffi::CString; use std::fs::File; -use std::io::Write; +use std::io::{Read, Write}; use std::mem::MaybeUninit; -use std::os::fd::{AsRawFd, RawFd}; +use std::os::fd::AsRawFd; use std::os::unix::prelude::MetadataExt; // Pull in the O_EXLOCK constant if it is defined, otherwise set it to 0. @@ -370,7 +370,7 @@ fn load_from_path(&mut self, callbacks: &mut CallbackDataList) -> bool { } fn load_from_path_narrow(&mut self, callbacks: &mut CallbackDataList) -> bool { - // Check to see if the file is unchanged. We do this again in load_from_fd, but this avoids + // Check to see if the file is unchanged. We do this again in load_from_file, but this avoids // opening the file unnecessarily. if self.last_read_file_id != INVALID_FILE_ID && file_id_for_path_narrow(&self.narrow_vars_path) == self.last_read_file_id @@ -399,7 +399,7 @@ fn load_from_file(&mut self, file: &mut File, callbacks: &mut CallbackDataList) } else { // Read a variables table from the file. let mut new_vars = VarTable::new(); - let format = Self::read_message_internal(file.as_raw_fd(), &mut new_vars); + let format = Self::read_message_internal(file, &mut new_vars); // Hacky: if the read format is in the future, avoid overwriting the file: never try to // save. @@ -726,20 +726,20 @@ fn parse_message_2x_internal(msg: &wstr, vars: &mut VarTable, storage: &mut WStr } } - fn read_message_internal(fd: RawFd, vars: &mut VarTable) -> UvarFormat { - // Read everything from the fd. Put a sane limit on it. + fn read_message_internal(file: &File, vars: &mut VarTable) -> UvarFormat { let mut contents = vec![]; - let mut buffer = [0_u8; 4096]; - while contents.len() < MAX_READ_SIZE { - match read_loop(&fd, &mut buffer) { - Ok(0) | Err(_) => break, - Ok(amt) => contents.extend_from_slice(&buffer[..amt]), - } + // Read everything from the file. Put a sane limit on it. + // TODO: Ideally, the cast should be checked at compile time. + if let Err(e) = file + .take(u64::try_from(MAX_READ_SIZE).expect("MAX_READ_SIZE must fit into u64")) + .read_to_end(&mut contents) + { + FLOG!(warning, "Failed to read file:", e); } // Handle overlong files. - if contents.len() > MAX_READ_SIZE { - contents.truncate(MAX_READ_SIZE); + // We read at most `MAX_READ_SIZE` bytes due to the `take`. + if contents.len() == MAX_READ_SIZE { // Back up to a newline. let newline = contents.iter().rposition(|c| *c == b'\n').unwrap_or(0); contents.truncate(newline);