diff --git a/src/fs.rs b/src/fs.rs index f42916b034..3f2b4265b0 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -3,9 +3,11 @@ use crate::{ error::{Errno, ResultExt}, header::{ fcntl::O_CREAT, + sys_stat::stat, unistd::{SEEK_CUR, SEEK_END, SEEK_SET}, }, io, + out::Out, platform::{Pal, Sys, types::*}, }; use core::ops::Deref; @@ -57,6 +59,12 @@ impl File { Sys::ftruncate(self.fd, size as off_t).map_err(Errno::sync) } + pub fn fstat(&self) -> Result { + let mut file_st = stat::default(); + Sys::fstat(self.fd, Out::from_mut(&mut file_st)).map_err(Errno::sync)?; + Ok(file_st) + } + pub fn try_clone(&self) -> io::Result { Ok(Self::new(Sys::dup(self.fd)?)) } diff --git a/src/platform/redox/exec.rs b/src/platform/redox/exec.rs index da0a0d9087..3590413c62 100644 --- a/src/platform/redox/exec.rs +++ b/src/platform/redox/exec.rs @@ -74,12 +74,46 @@ pub fn execve( ) -> Result { // NOTE: We must omit O_CLOEXEC and close manually, otherwise it will be closed before we // have even read it! - let (mut image_file, arg0) = match exec { - Executable::AtPath(path) => ( - File::open(path, O_RDONLY as c_int).map_err(|_| Error::new(ENOENT))?, - path.to_bytes(), - ), - Executable::InFd { file, arg0 } => (file, arg0), + let (mut image_file, stat, arg0) = match exec { + Executable::AtPath(path) => { + let Ok(src_fd) = File::open(path, O_RDONLY as c_int) else { + return Err(Error::new(ENOENT)); + }; + + let mut src_stat = Stat::default(); + redox_rt::sys::fstat(*src_fd as usize, &mut src_stat)?; + + #[cfg(feature = "ld_so_cache")] + let src_fd = { + let mtime_sec = src_stat.st_mtime; + let mtime_nsec = src_stat.st_mtime_nsec; + + let safe_path = path.to_str().unwrap_or("").replace('/', "_"); + let shm_path_owned = format!( + "/scheme/shm/ld.so.cache.{}.{}.{}\0", + safe_path, mtime_sec, mtime_nsec + ); + let shm_path = + unsafe { CStr::from_bytes_with_nul_unchecked(shm_path_owned.as_bytes()) }; + + let mut file_opt = None; + if let Ok(shm_fd) = File::open(shm_path, O_RDONLY as c_int) { + if let Ok(shm_stat) = shm_fd.fstat() + && shm_stat.st_size > 0 + { + file_opt = Some(shm_fd); + } + } + file_opt.unwrap_or(src_fd) + }; + + (src_fd, src_stat, path.to_bytes()) + } + Executable::InFd { file, arg0 } => { + let mut stat = Stat::default(); + redox_rt::sys::fstat(*file as usize, &mut stat)?; + (file, stat, arg0) + } }; // With execve now being implemented in userspace, we need to check ourselves that this @@ -93,8 +127,6 @@ pub fn execve( // TODO: At some point we might have capabilities limiting the ability to allocate // executable memory. - let mut stat = Stat::default(); - redox_rt::sys::fstat(*image_file as usize, &mut stat)?; let Resugid { ruid, rgid, .. } = redox_rt::sys::posix_getresugid(); let mode = if ruid == stat.st_uid {