initial (and somewhat bonked) powershell support, cargo update
This commit is contained in:
parent
62562a0b69
commit
40a90308a5
4 changed files with 103 additions and 20 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -265,9 +265,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.89"
|
version = "0.2.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "538c092e5586f4cdd7dd8078c4a79220e3e168880218124dcbce860f0ea938c6"
|
checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
|
@ -650,9 +650,9 @@ checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.3.1"
|
version = "2.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"same-file",
|
"same-file",
|
||||||
"winapi",
|
"winapi",
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
//! The various formats that [fif](crate) can output to.
|
//! The various formats that [fif](crate) can output to.
|
||||||
|
|
||||||
use std::io::{self, Write};
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
use std::io::{self, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use snailquote::escape;
|
use snailquote::escape;
|
||||||
|
|
||||||
use crate::scan_error::ScanError;
|
use crate::scan_error::ScanError;
|
||||||
use crate::{Findings, BACKEND};
|
use crate::{Findings, BACKEND};
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
/// The current version of fif, as defined in Cargo.toml.
|
/// The current version of fif, as defined in Cargo.toml.
|
||||||
const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
|
const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
|
||||||
|
@ -36,6 +37,12 @@ impl<'a> From<&'a Path> for Writable<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a OsStr> for Writable<'a> {
|
||||||
|
fn from(p: &'a OsStr) -> Writable<'a> {
|
||||||
|
Writable::Path(p.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn smart_write<W: Write>(f: &mut W, writeables: &[Writable]) -> io::Result<()> {
|
fn smart_write<W: Write>(f: &mut W, writeables: &[Writable]) -> io::Result<()> {
|
||||||
// ehhhh
|
// ehhhh
|
||||||
for writeable in writeables {
|
for writeable in writeables {
|
||||||
|
@ -47,13 +54,15 @@ fn smart_write<W: Write>(f: &mut W, writeables: &[Writable]) -> io::Result<()> {
|
||||||
if let Some(string) = path.to_str() {
|
if let Some(string) = path.to_str() {
|
||||||
write!(f, "{}", escape(string))?
|
write!(f, "{}", escape(string))?
|
||||||
} else {
|
} else {
|
||||||
write!(f, "'''")?;
|
write!(f, "'")?;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
f.write_all(&*path.as_os_str().as_bytes())?;
|
f.write_all(&*path.as_os_str().as_bytes())?;
|
||||||
|
// TODO: implement bonked strings for windows
|
||||||
|
// something like:
|
||||||
|
// f.write_all(&*path.as_os_str().encode_wide().collect::<Vec<u16>>())?;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
write!(f, "{}", path.as_os_str().to_string_lossy())?; // TODO: implement bonked strings for windows
|
write!(f, "{}", path.as_os_str().to_string_lossy())?;
|
||||||
// f.write_all(&*path.as_os_str().encode_wide().collect::<Vec<u16>>())?;
|
write!(f, "'")?
|
||||||
write!(f, "'''")?
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,3 +167,62 @@ impl Format for Script {
|
||||||
writeln!(f, "\necho 'Done.'")
|
writeln!(f, "\necho 'Done.'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// PowerShell script.
|
||||||
|
pub struct PowerShell {}
|
||||||
|
|
||||||
|
impl Format for PowerShell {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rename<W: Write>(&self, f: &mut W, from: &Path, to: &Path) -> io::Result<()> {
|
||||||
|
// unfortunately there doesn't seem to be an equivalent of sh's `mv -i` -- passing the '-Confirm' flag will prompt
|
||||||
|
// the user to confirm every single rename, and using Move-Item -Force will always overwrite without prompting.
|
||||||
|
// there doesn't seem to be a way to rename the file, prompting only if the target already exists.
|
||||||
|
smart_write(
|
||||||
|
f,
|
||||||
|
&[
|
||||||
|
"Rename-Item -Path ".into(),
|
||||||
|
from.into(),
|
||||||
|
" -NewName ".into(),
|
||||||
|
to.file_name().unwrap().into(),
|
||||||
|
Writable::Newline,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn no_known_extension<W: Write>(&self, f: &mut W, path: &Path) -> io::Result<()> {
|
||||||
|
smart_write(
|
||||||
|
f,
|
||||||
|
&["Write-Output @'\nNo known extension for ".into(), path.into(), "\n'@".into()],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unreadable<W: Write>(&self, f: &mut W, path: &Path) -> io::Result<()> {
|
||||||
|
smart_write(
|
||||||
|
f,
|
||||||
|
&["Write-Output @'\nFailed to read ".into(), path.into(), "\n'@".into()],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unknown_type<W: Write>(&self, f: &mut W, path: &Path) -> io::Result<()> {
|
||||||
|
smart_write(
|
||||||
|
f,
|
||||||
|
&["<# Failed to detect mime type for ".into(), path.into(), "#>".into()],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn header<W: Write>(&self, _: &Entries, f: &mut W) -> io::Result<()> {
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"#!/usr/bin/env pwsh\n# Generated by fif {} ({} backend)",
|
||||||
|
VERSION.unwrap_or("???"),
|
||||||
|
BACKEND
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn footer<W: Write>(&self, _: &Entries, f: &mut W) -> io::Result<()> {
|
||||||
|
writeln!(f, "\nWrite-Output 'Done!'")
|
||||||
|
}
|
||||||
|
}
|
22
src/main.rs
22
src/main.rs
|
@ -27,7 +27,7 @@ use smartstring::alias::String;
|
||||||
use walkdir::{DirEntry, WalkDir};
|
use walkdir::{DirEntry, WalkDir};
|
||||||
|
|
||||||
use crate::findings::Findings;
|
use crate::findings::Findings;
|
||||||
use crate::formats::{Format, Script};
|
use crate::formats::{Format, Script, PowerShell};
|
||||||
use crate::mime_db::MimeDb;
|
use crate::mime_db::MimeDb;
|
||||||
use crate::parameters::{OutputFormat, ScanOpts};
|
use crate::parameters::{OutputFormat, ScanOpts};
|
||||||
use crate::scan_error::ScanError;
|
use crate::scan_error::ScanError;
|
||||||
|
@ -125,15 +125,17 @@ fn main() {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
match args.output_format {
|
let mut buffered_stdout = BufWriter::new(stdout());
|
||||||
OutputFormat::Script => {
|
|
||||||
let s = Script::new();
|
let result = match args.output_format {
|
||||||
if s.write_all(&results, &mut BufWriter::new(stdout().lock())).is_err() {
|
OutputFormat::Script => Script::new().write_all(&results, &mut buffered_stdout),
|
||||||
error!("Failed to write to stdout.");
|
OutputFormat::PowerShell | OutputFormat::Powershell => PowerShell::new().write_all(&results, &mut buffered_stdout),
|
||||||
exit(exitcode::IOERR);
|
OutputFormat::Text => todo!()
|
||||||
}
|
};
|
||||||
}
|
|
||||||
OutputFormat::Text => todo!(),
|
if result.is_err() {
|
||||||
|
error!("Failed to write to stdout.");
|
||||||
|
exit(exitcode::IOERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Done");
|
debug!("Done");
|
||||||
|
|
|
@ -5,11 +5,24 @@ use std::path::PathBuf;
|
||||||
use crate::extension_set::ExtensionSet;
|
use crate::extension_set::ExtensionSet;
|
||||||
use clap::{AppSettings, Clap};
|
use clap::{AppSettings, Clap};
|
||||||
use smartstring::{LazyCompact, SmartString};
|
use smartstring::{LazyCompact, SmartString};
|
||||||
|
use cfg_if::cfg_if;
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(windows)] {
|
||||||
|
const DEFAULT_FORMAT: &str = "powershell";
|
||||||
|
} else {
|
||||||
|
const DEFAULT_FORMAT: &str = "script";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clap, PartialEq, Debug)]
|
#[derive(Clap, PartialEq, Debug)]
|
||||||
pub enum OutputFormat {
|
pub enum OutputFormat {
|
||||||
/// A Bourne shell compatible script.
|
/// A Bourne shell compatible script.
|
||||||
Script,
|
Script,
|
||||||
|
/// A PowerShell script.
|
||||||
|
PowerShell,
|
||||||
|
/// Also a PowerShell script, with different casing to allow for `fif -o powershell`.
|
||||||
|
Powershell,
|
||||||
/// Plain text.
|
/// Plain text.
|
||||||
Text,
|
Text,
|
||||||
}
|
}
|
||||||
|
@ -52,7 +65,7 @@ pub struct Parameters {
|
||||||
pub scan_extensionless: bool,
|
pub scan_extensionless: bool,
|
||||||
|
|
||||||
/// Output format to use
|
/// Output format to use
|
||||||
#[clap(short, long, default_value = "script", arg_enum)]
|
#[clap(short, long, default_value = DEFAULT_FORMAT, arg_enum)]
|
||||||
pub output_format: OutputFormat,
|
pub output_format: OutputFormat,
|
||||||
|
|
||||||
/// Directory to process
|
/// Directory to process
|
||||||
|
|
Loading…
Reference in a new issue