mirror of
https://github.com/sharkdp/fd.git
synced 2024-11-16 00:48:28 +01:00
Merge pull request #1164 from tmccombs/owner-without-panic
Fix panic when using --owner
This commit is contained in:
commit
99d1db8cb3
3 changed files with 70 additions and 16 deletions
|
@ -1,13 +1,13 @@
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct OwnerFilter {
|
pub struct OwnerFilter {
|
||||||
uid: Check<u32>,
|
uid: Check<u32>,
|
||||||
gid: Check<u32>,
|
gid: Check<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
enum Check<T> {
|
enum Check<T> {
|
||||||
Equal(T),
|
Equal(T),
|
||||||
NotEq(T),
|
NotEq(T),
|
||||||
|
@ -15,10 +15,15 @@ enum Check<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OwnerFilter {
|
impl OwnerFilter {
|
||||||
|
const IGNORE: Self = OwnerFilter {
|
||||||
|
uid: Check::Ignore,
|
||||||
|
gid: Check::Ignore,
|
||||||
|
};
|
||||||
|
|
||||||
/// Parses an owner constraint
|
/// Parses an owner constraint
|
||||||
/// Returns an error if the string is invalid
|
/// Returns an error if the string is invalid
|
||||||
/// Returns Ok(None) when string is acceptable but a noop (such as "" or ":")
|
/// Returns Ok(None) when string is acceptable but a noop (such as "" or ":")
|
||||||
pub fn from_string(input: &str) -> Result<Option<Self>> {
|
pub fn from_string(input: &str) -> Result<Self> {
|
||||||
let mut it = input.split(':');
|
let mut it = input.split(':');
|
||||||
let (fst, snd) = (it.next(), it.next());
|
let (fst, snd) = (it.next(), it.next());
|
||||||
|
|
||||||
|
@ -42,10 +47,15 @@ impl OwnerFilter {
|
||||||
.ok_or_else(|| anyhow!("'{}' is not a recognized group name", s))
|
.ok_or_else(|| anyhow!("'{}' is not a recognized group name", s))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if let (Check::Ignore, Check::Ignore) = (uid, gid) {
|
Ok(OwnerFilter { uid, gid })
|
||||||
Ok(None)
|
}
|
||||||
|
|
||||||
|
/// If self is a no-op (ignore both uid and gid) then return `None`, otherwise wrap in a `Some`
|
||||||
|
pub fn filter_ignore(self) -> Option<Self> {
|
||||||
|
if self == Self::IGNORE {
|
||||||
|
None
|
||||||
} else {
|
} else {
|
||||||
Ok(Some(OwnerFilter { uid, gid }))
|
Some(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,16 +116,16 @@ mod owner_parsing {
|
||||||
|
|
||||||
use super::Check::*;
|
use super::Check::*;
|
||||||
owner_tests! {
|
owner_tests! {
|
||||||
empty: "" => Ok(None),
|
empty: "" => Ok(OwnerFilter::IGNORE),
|
||||||
uid_only: "5" => Ok(Some(OwnerFilter { uid: Equal(5), gid: Ignore })),
|
uid_only: "5" => Ok(OwnerFilter { uid: Equal(5), gid: Ignore }),
|
||||||
uid_gid: "9:3" => Ok(Some(OwnerFilter { uid: Equal(9), gid: Equal(3) })),
|
uid_gid: "9:3" => Ok(OwnerFilter { uid: Equal(9), gid: Equal(3) }),
|
||||||
gid_only: ":8" => Ok(Some(OwnerFilter { uid: Ignore, gid: Equal(8) })),
|
gid_only: ":8" => Ok(OwnerFilter { uid: Ignore, gid: Equal(8) }),
|
||||||
colon_only: ":" => Ok(None),
|
colon_only: ":" => Ok(OwnerFilter::IGNORE),
|
||||||
trailing: "5:" => Ok(Some(OwnerFilter { uid: Equal(5), gid: Ignore })),
|
trailing: "5:" => Ok(OwnerFilter { uid: Equal(5), gid: Ignore }),
|
||||||
|
|
||||||
uid_negate: "!5" => Ok(Some(OwnerFilter { uid: NotEq(5), gid: Ignore })),
|
uid_negate: "!5" => Ok(OwnerFilter { uid: NotEq(5), gid: Ignore }),
|
||||||
both_negate:"!4:!3" => Ok(Some(OwnerFilter { uid: NotEq(4), gid: NotEq(3) })),
|
both_negate:"!4:!3" => Ok(OwnerFilter { uid: NotEq(4), gid: NotEq(3) }),
|
||||||
uid_not_gid:"6:!8" => Ok(Some(OwnerFilter { uid: Equal(6), gid: NotEq(8) })),
|
uid_not_gid:"6:!8" => Ok(OwnerFilter { uid: Equal(6), gid: NotEq(8) }),
|
||||||
|
|
||||||
more_colons:"3:5:" => Err(_),
|
more_colons:"3:5:" => Err(_),
|
||||||
only_colons:"::" => Err(_),
|
only_colons:"::" => Err(_),
|
||||||
|
|
|
@ -184,7 +184,7 @@ fn construct_config(mut opts: Opts, pattern_regex: &str) -> Result<Config> {
|
||||||
let size_limits = std::mem::take(&mut opts.size);
|
let size_limits = std::mem::take(&mut opts.size);
|
||||||
let time_constraints = extract_time_constraints(&opts)?;
|
let time_constraints = extract_time_constraints(&opts)?;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let owner_constraint: Option<OwnerFilter> = opts.owner;
|
let owner_constraint: Option<OwnerFilter> = opts.owner.and_then(OwnerFilter::filter_ignore);
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let ansi_colors_support =
|
let ansi_colors_support =
|
||||||
|
|
|
@ -1919,6 +1919,50 @@ fn test_modified_absolute() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[test]
|
||||||
|
fn test_owner_ignore_all() {
|
||||||
|
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
|
||||||
|
te.assert_output(&["--owner", ":", "a.foo"], "a.foo");
|
||||||
|
te.assert_output(&["--owner", "", "a.foo"], "a.foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[test]
|
||||||
|
fn test_owner_current_user() {
|
||||||
|
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
|
||||||
|
let uid = users::get_current_uid();
|
||||||
|
te.assert_output(&["--owner", &uid.to_string(), "a.foo"], "a.foo");
|
||||||
|
if let Some(username) = users::get_current_username().map(|u| u.into_string().unwrap()) {
|
||||||
|
te.assert_output(&["--owner", &username, "a.foo"], "a.foo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[test]
|
||||||
|
fn test_owner_current_group() {
|
||||||
|
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
|
||||||
|
let gid = users::get_current_gid();
|
||||||
|
te.assert_output(&["--owner", &format!(":{}", gid), "a.foo"], "a.foo");
|
||||||
|
if let Some(groupname) = users::get_current_groupname().map(|u| u.into_string().unwrap()) {
|
||||||
|
te.assert_output(&["--owner", &format!(":{}", groupname), "a.foo"], "a.foo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
#[test]
|
||||||
|
fn test_owner_root() {
|
||||||
|
// This test assumes the current user isn't root
|
||||||
|
if users::get_current_uid() == 0 || users::get_current_gid() == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
|
||||||
|
te.assert_output(&["--owner", "root", "a.foo"], "");
|
||||||
|
te.assert_output(&["--owner", "0", "a.foo"], "");
|
||||||
|
te.assert_output(&["--owner", ":root", "a.foo"], "");
|
||||||
|
te.assert_output(&["--owner", ":0", "a.foo"], "");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_custom_path_separator() {
|
fn test_custom_path_separator() {
|
||||||
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
|
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
|
||||||
|
|
Loading…
Reference in a new issue