From ca6e8de50bf35f303baffd9d3262831ace9927ae Mon Sep 17 00:00:00 2001 From: Kyler Clay Date: Mon, 19 May 2025 00:03:50 -0400 Subject: [PATCH] Reduced the amount of time that file redirections stay open --- src/parse/mod.rs | 155 +++++++++++------------------------------------ src/procio.rs | 29 ++++++--- 2 files changed, 56 insertions(+), 128 deletions(-) diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 8eb27d8..902ee3c 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -716,43 +716,7 @@ impl ParseStream { } if !from_func_def { - while self.check_redir() { - let tk = self.next_tk().unwrap(); - node_tks.push(tk.clone()); - let redir_bldr = tk.span.as_str().parse::().unwrap(); - if redir_bldr.io_mode.is_none() { - let path_tk = self.next_tk(); - - if path_tk.clone().is_none_or(|tk| tk.class == TkRule::EOI) { - return Err( - ShErr::full( - ShErrKind::ParseErr, - "Expected a filename after this redirection", - tk.span.clone() - ) - ) - }; - - let path_tk = path_tk.unwrap(); - node_tks.push(path_tk.clone()); - let redir_class = redir_bldr.class.unwrap(); - let pathbuf = PathBuf::from(path_tk.span.as_str()); - - let Ok(file) = get_redir_file(redir_class, pathbuf) else { - self.panic_mode(&mut node_tks); - return Err(parse_err_full( - "Error opening file for redirection", - &path_tk.span - ) - ); - }; - - let io_mode = IoMode::file(redir_bldr.tgt_fd.unwrap(), file); - let redir_bldr = redir_bldr.with_io_mode(io_mode); - let redir = redir_bldr.build(); - redirs.push(redir); - } - } + self.parse_redir(&mut redirs, &mut node_tks)?; } let node = Node { @@ -763,6 +727,37 @@ impl ParseStream { }; Ok(Some(node)) } + fn parse_redir(&mut self, redirs: &mut Vec, node_tks: &mut Vec) -> ShResult<()> { + while self.check_redir() { + let tk = self.next_tk().unwrap(); + node_tks.push(tk.clone()); + let redir_bldr = tk.span.as_str().parse::().unwrap(); + if redir_bldr.io_mode.is_none() { + let path_tk = self.next_tk(); + + if path_tk.clone().is_none_or(|tk| tk.class == TkRule::EOI) { + return Err( + ShErr::full( + ShErrKind::ParseErr, + "Expected a filename after this redirection", + tk.span.clone() + ) + ) + }; + + let path_tk = path_tk.unwrap(); + node_tks.push(path_tk.clone()); + let redir_class = redir_bldr.class.unwrap(); + let pathbuf = PathBuf::from(path_tk.span.as_str()); + + let io_mode = IoMode::file(redir_bldr.tgt_fd.unwrap(), pathbuf, redir_class); + let redir_bldr = redir_bldr.with_io_mode(io_mode); + let redir = redir_bldr.build(); + redirs.push(redir); + } + } + Ok(()) + } fn parse_case(&mut self) -> ShResult> { // Needs a pattern token // Followed by any number of CaseNodes @@ -938,42 +933,7 @@ impl ParseStream { } node_tks.push(self.next_tk().unwrap()); - while self.check_redir() { - let tk = self.next_tk().unwrap(); - node_tks.push(tk.clone()); - let redir_bldr = tk.span.as_str().parse::().unwrap(); - if redir_bldr.io_mode.is_none() { - let path_tk = self.next_tk(); - - if path_tk.clone().is_none_or(|tk| tk.class == TkRule::EOI) { - return Err( - ShErr::full( - ShErrKind::ParseErr, - "Expected a filename after this redirection", - tk.span.clone() - ) - ) - }; - - let path_tk = path_tk.unwrap(); - node_tks.push(path_tk.clone()); - let redir_class = redir_bldr.class.unwrap(); - let pathbuf = PathBuf::from(path_tk.span.as_str()); - - let Ok(file) = get_redir_file(redir_class, pathbuf) else { - self.panic_mode(&mut node_tks); - return Err(parse_err_full( - "Error opening file for redirection", - &path_tk.span - )); - }; - - let io_mode = IoMode::file(redir_bldr.tgt_fd.unwrap(), file); - let redir_bldr = redir_bldr.with_io_mode(io_mode); - let redir = redir_bldr.build(); - redirs.push(redir); - } - } + self.parse_redir(&mut redirs, &mut node_tks)?; self.assert_separator(&mut node_tks)?; @@ -1040,42 +1000,7 @@ impl ParseStream { } node_tks.push(self.next_tk().unwrap()); - while self.check_redir() { - let tk = self.next_tk().unwrap(); - node_tks.push(tk.clone()); - let redir_bldr = tk.span.as_str().parse::().unwrap(); - if redir_bldr.io_mode.is_none() { - let path_tk = self.next_tk(); - - if path_tk.clone().is_none_or(|tk| tk.class == TkRule::EOI) { - return Err( - ShErr::full( - ShErrKind::ParseErr, - "Expected a filename after this redirection", - tk.span.clone() - ) - ) - }; - - let path_tk = path_tk.unwrap(); - node_tks.push(path_tk.clone()); - let redir_class = redir_bldr.class.unwrap(); - let pathbuf = PathBuf::from(path_tk.span.as_str()); - - let Ok(file) = get_redir_file(redir_class, pathbuf) else { - self.panic_mode(&mut node_tks); - return Err(parse_err_full( - "Error opening file for redirection", - &path_tk.span - )); - }; - - let io_mode = IoMode::file(redir_bldr.tgt_fd.unwrap(), file); - let redir_bldr = redir_bldr.with_io_mode(io_mode); - let redir = redir_bldr.build(); - redirs.push(redir); - } - } + self.parse_redir(&mut redirs, &mut node_tks)?; let node = Node { class: NdRule::ForNode { vars, arr, body }, @@ -1256,15 +1181,7 @@ impl ParseStream { let redir_class = redir_bldr.class.unwrap(); let pathbuf = PathBuf::from(path_tk.span.as_str()); - let Ok(file) = get_redir_file(redir_class, pathbuf) else { - self.panic_mode(&mut node_tks); - return Err(parse_err_full( - "Error opening file for redirection", - &path_tk.span - )); - }; - - let io_mode = IoMode::file(redir_bldr.tgt_fd.unwrap(), file); + let io_mode = IoMode::file(redir_bldr.tgt_fd.unwrap(), pathbuf, redir_class); let redir_bldr = redir_bldr.with_io_mode(io_mode); let redir = redir_bldr.build(); redirs.push(redir); @@ -1421,7 +1338,7 @@ fn node_is_punctuated(tokens: &[Tk]) -> bool { }) } -fn get_redir_file(class: RedirType, path: PathBuf) -> ShResult { +pub fn get_redir_file(class: RedirType, path: PathBuf) -> ShResult { let result = match class { RedirType::Input => { OpenOptions::new() diff --git a/src/procio.rs b/src/procio.rs index ebb2fce..5a82edf 100644 --- a/src/procio.rs +++ b/src/procio.rs @@ -1,6 +1,6 @@ use std::{fmt::Debug, ops::{Deref, DerefMut}}; -use crate::{libsh::{error::{ShErr, ShErrKind, ShResult}, utils::RedirVecUtils}, parse::Redir, prelude::*}; +use crate::{libsh::{error::{ShErr, ShErrKind, ShResult}, utils::RedirVecUtils}, parse::{get_redir_file, Redir, RedirType}, prelude::*}; // Credit to fish-shell for many of the implementation ideas present in this module // https://fishshell.com/ @@ -8,7 +8,7 @@ use crate::{libsh::{error::{ShErr, ShErrKind, ShResult}, utils::RedirVecUtils}, #[derive(Clone,Debug)] pub enum IoMode { Fd { tgt_fd: RawFd, src_fd: Arc }, - File { tgt_fd: RawFd, file: Arc }, + File { tgt_fd: RawFd, path: PathBuf, mode: RedirType }, Pipe { tgt_fd: RawFd, pipe: Arc }, Buffer { buf: String, pipe: Arc } } @@ -18,9 +18,8 @@ impl IoMode { let src_fd = unsafe { OwnedFd::from_raw_fd(src_fd).into() }; Self::Fd { tgt_fd, src_fd } } - pub fn file(tgt_fd: RawFd, file: File) -> Self { - let file = file.into(); - Self::File { tgt_fd, file } + pub fn file(tgt_fd: RawFd, path: PathBuf, mode: RedirType) -> Self { + Self::File { tgt_fd, path, mode } } pub fn pipe(tgt_fd: RawFd, pipe: OwnedFd) -> Self { let pipe = pipe.into(); @@ -28,20 +27,27 @@ impl IoMode { } pub fn tgt_fd(&self) -> RawFd { match self { - IoMode::Fd { tgt_fd, src_fd: _ } | - IoMode::File { tgt_fd, file: _ } | - IoMode::Pipe { tgt_fd, pipe: _ } => *tgt_fd, + IoMode::Fd { tgt_fd, .. } | + IoMode::File { tgt_fd, .. } | + IoMode::Pipe { tgt_fd, .. } => *tgt_fd, _ => panic!() } } pub fn src_fd(&self) -> RawFd { match self { IoMode::Fd { tgt_fd: _, src_fd } => src_fd.as_raw_fd(), - IoMode::File { tgt_fd: _, file } => file.as_raw_fd(), + IoMode::File {..} => panic!("Attempted to obtain src_fd from file before opening"), IoMode::Pipe { tgt_fd: _, pipe } => pipe.as_raw_fd(), _ => panic!() } } + pub fn open_file(mut self) -> ShResult { + if let IoMode::File { tgt_fd, path, mode } = self { + let file = get_redir_file(mode, path)?; + self = IoMode::Fd { tgt_fd, src_fd: Arc::new(OwnedFd::from(file)) } + } + Ok(self) + } pub fn get_pipes() -> (Self,Self) { let (rpipe,wpipe) = pipe().unwrap(); ( @@ -149,6 +155,11 @@ impl<'e> IoFrame { self.save(); for redir in &mut self.redirs { let io_mode = &mut redir.io_mode; + flog!(DEBUG, io_mode); + if let IoMode::File {..} = io_mode { + *io_mode = io_mode.clone().open_file()?; + }; + flog!(DEBUG, io_mode); let tgt_fd = io_mode.tgt_fd(); let src_fd = io_mode.src_fd(); dup2(src_fd, tgt_fd)?;