From 42c35bcab59d85d378f895aa8741b82b1b16b719 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 15 Jun 2022 09:23:36 +0200 Subject: [PATCH] dircolors: escape "'" and ":" --- src/uu/dircolors/src/dircolors.rs | 36 +++++++++++++++++++++++++++++++ tests/by-util/test_dircolors.rs | 10 +++++++++ 2 files changed, 46 insertions(+) diff --git a/src/uu/dircolors/src/dircolors.rs b/src/uu/dircolors/src/dircolors.rs index d175ccfb363..610df51825f 100644 --- a/src/uu/dircolors/src/dircolors.rs +++ b/src/uu/dircolors/src/dircolors.rs @@ -344,6 +344,8 @@ where continue; } + let line = escape(line); + let (key, val) = line.split_two(); if val.is_empty() { return Err(format!( @@ -411,3 +413,37 @@ where Ok(result) } + +/// Escape single quotes because they are not allowed between single quotes in shell code, and code +/// enclosed by single quotes is what is returned by `parse()`. +/// +/// We also escape ":" to make the "quote" test pass in the GNU test suite: +/// https://github.com/coreutils/coreutils/blob/master/tests/misc/dircolors.pl +fn escape(s: &str) -> String { + let mut result = String::new(); + let mut previous = ' '; + + for c in s.chars() { + match c { + '\'' => result.push_str("'\\''"), + ':' if previous != '\\' => result.push_str("\\:"), + _ => result.push_str(&c.to_string()), + } + previous = c; + } + + result +} + +#[cfg(test)] +mod tests { + use super::escape; + + #[test] + fn test_escape() { + assert_eq!("", escape("")); + assert_eq!("'\\''", escape("'")); + assert_eq!("\\:", escape(":")); + assert_eq!("\\:", escape("\\:")); + } +} diff --git a/tests/by-util/test_dircolors.rs b/tests/by-util/test_dircolors.rs index f34f5573bb9..2a93cbfa9c5 100644 --- a/tests/by-util/test_dircolors.rs +++ b/tests/by-util/test_dircolors.rs @@ -141,6 +141,16 @@ fn test_stdin() { .no_stderr(); } +#[test] +fn test_quoting() { + new_ucmd!() + .pipe_in("exec 'echo Hello;:'\n") + .args(&["-b", "-"]) + .succeeds() + .stdout_is("LS_COLORS='ex='\\''echo Hello;\\:'\\'':';\nexport LS_COLORS\n") + .no_stderr(); +} + #[test] fn test_extra_operand() { new_ucmd!()