From ab6f1b3e13c8e35667a245065131af51b71dd30a Mon Sep 17 00:00:00 2001 From: Max Kofler Date: Fri, 8 Dec 2023 11:44:13 +0000 Subject: [PATCH] util::fs::script --- src/util/fs/fsentry.rs | 14 +++++++++ src/util/fs/fsentry/script.rs | 56 +++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/util/fs/fsentry/script.rs diff --git a/src/util/fs/fsentry.rs b/src/util/fs/fsentry.rs index 7516799..16a3277 100644 --- a/src/util/fs/fsentry.rs +++ b/src/util/fs/fsentry.rs @@ -15,11 +15,16 @@ pub use directory::*; mod elf; pub use elf::*; +mod script; +pub use script::*; + /// A filesystem entry #[derive(Clone)] pub enum FSEntry { /// An ELF file ELF(ELFFile), + /// A script file + Script(ScriptFile), /// A symlink Symlink(OsString), /// Some other file @@ -67,6 +72,14 @@ impl FSEntry { .e_context(|| format!("Parsing ELF file {}", path.to_string_lossy()))?; return Ok(Self::ELF(f)); + } else if infer::text::is_shellscript(&buf) { + trace!("[infer] SCR : {}", &path.to_string_lossy()); + + let f = ScriptFile::parse(&path, name).e_context(|| { + format!("Parsing SCRIPT file {}", path.to_string_lossy()) + })?; + + return Ok(Self::Script(f)); } } } @@ -82,6 +95,7 @@ impl FSEntry { pub fn name(&self) -> &OsStr { match self { Self::ELF(n) => &n.name, + Self::Script(n) => &n.name, Self::Symlink(n) => n, Self::OtherFile(n) => n, Self::Directory(d) => &d.name, diff --git a/src/util/fs/fsentry/script.rs b/src/util/fs/fsentry/script.rs new file mode 100644 index 0000000..5b3c77f --- /dev/null +++ b/src/util/fs/fsentry/script.rs @@ -0,0 +1,56 @@ +use std::{ + collections::LinkedList, + ffi::OsString, + fs::File, + io::{BufRead, BufReader}, + path::{Path, PathBuf}, +}; + +use crate::error::{Error, ErrorExt}; + +/// A fs entry that is a script (has a shbang at its start) +#[derive(Clone)] +pub struct ScriptFile { + /// The name of the file + pub name: OsString, + + /// The interpreter for the file + /// (, ) + pub interpreter: Option<(PathBuf, Vec)>, +} + +impl ScriptFile { + /// Parses an `ELFFile` from the provided path + /// # Arguments + /// * `path` - The path to parse the file from + pub fn parse(path: &Path, name: OsString) -> Result { + let context = || format!("Parsing SCRIPT file {}", path.to_string_lossy()); + + // Read the first line + let first_line = { + let mut file = BufReader::new(File::open(path).e_context(context)?); + let mut shbang = String::new(); + file.read_line(&mut shbang).e_context(context)?; + shbang + }; + + // Remove the shbang from the start ('#!') + let first_line = first_line.trim_start_matches("#!"); + + // Split the line into its pieces + let mut split: LinkedList = first_line + .split(' ') + .map(|s| OsString::from(s.trim())) + .collect(); + + // Split the interpreter path from its arguments + let interpreter = split.pop_front().map(|i| { + ( + PathBuf::from(i), + split.into_iter().collect::>(), + ) + }); + + Ok(Self { name, interpreter }) + } +}