Skip to content

Commit a04b499

Browse files
authored
Merge pull request #521 from tavianator/user-group-ids
find: User/group ID fixes
2 parents 81c39aa + de42f9b commit a04b499

File tree

4 files changed

+105
-143
lines changed

4 files changed

+105
-143
lines changed

src/find/matchers/group.rs

Lines changed: 18 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,71 +3,47 @@
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
55

6-
use super::{Matcher, MatcherIO, WalkEntry};
6+
use super::{ComparableValue, Matcher, MatcherIO, WalkEntry};
77

88
#[cfg(unix)]
99
use nix::unistd::Group;
1010
#[cfg(unix)]
1111
use std::os::unix::fs::MetadataExt;
1212

1313
pub struct GroupMatcher {
14-
gid: Option<u32>,
14+
gid: ComparableValue,
1515
}
1616

1717
impl GroupMatcher {
1818
#[cfg(unix)]
19-
pub fn from_group_name(group: &str) -> Self {
19+
pub fn from_group_name(group: &str) -> Option<Self> {
2020
// get gid from group name
21-
let Ok(group) = Group::from_name(group) else {
22-
return Self { gid: None };
23-
};
24-
25-
let Some(group) = group else {
26-
// This if branch is to determine whether a certain group exists in the system.
27-
// If a certain group does not exist in the system,
28-
// the result will need to be returned according to
29-
// the flag bit of whether to invert the result.
30-
return Self { gid: None };
31-
};
32-
33-
Self {
34-
gid: Some(group.gid.as_raw()),
35-
}
21+
let group = Group::from_name(group).ok()??;
22+
let gid = group.gid.as_raw();
23+
Some(Self::from_gid(gid))
3624
}
3725

38-
#[cfg(unix)]
3926
pub fn from_gid(gid: u32) -> Self {
40-
Self { gid: Some(gid) }
27+
Self::from_comparable(ComparableValue::EqualTo(gid as u64))
4128
}
4229

43-
#[cfg(windows)]
44-
pub fn from_group_name(_group: &str) -> GroupMatcher {
45-
GroupMatcher { gid: None }
30+
pub fn from_comparable(gid: ComparableValue) -> Self {
31+
Self { gid }
4632
}
4733

4834
#[cfg(windows)]
49-
pub fn from_gid(_gid: u32) -> GroupMatcher {
50-
GroupMatcher { gid: None }
51-
}
52-
53-
pub fn gid(&self) -> &Option<u32> {
54-
&self.gid
35+
pub fn from_group_name(_group: &str) -> Option<Self> {
36+
None
5537
}
5638
}
5739

5840
impl Matcher for GroupMatcher {
5941
#[cfg(unix)]
6042
fn matches(&self, file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
61-
let Ok(metadata) = file_info.metadata() else {
62-
return false;
63-
};
64-
65-
let file_gid = metadata.gid();
66-
67-
// When matching the -group parameter in find/matcher/mod.rs,
68-
// it has been judged that the group does not exist and an error is returned.
69-
// So use unwarp() directly here.
70-
self.gid.unwrap() == file_gid
43+
match file_info.metadata() {
44+
Ok(metadata) => self.gid.matches(metadata.gid().into()),
45+
Err(_) => false,
46+
}
7147
}
7248

7349
#[cfg(windows)]
@@ -136,7 +112,8 @@ mod tests {
136112
.unwrap()
137113
.name;
138114

139-
let matcher = super::GroupMatcher::from_group_name(file_group.as_str());
115+
let matcher =
116+
super::GroupMatcher::from_group_name(file_group.as_str()).expect("group should exist");
140117
assert!(
141118
matcher.matches(&file_info, &mut matcher_io),
142119
"group should match"
@@ -146,18 +123,13 @@ mod tests {
146123
let time_string = Local::now().format("%Y%m%d%H%M%S").to_string();
147124
let matcher = GroupMatcher::from_group_name(time_string.as_str());
148125
assert!(
149-
matcher.gid().is_none(),
126+
matcher.is_none(),
150127
"group name {} should not exist",
151128
time_string
152129
);
153130

154131
// Testing group id
155132
let matcher = GroupMatcher::from_gid(file_gid);
156-
assert!(
157-
matcher.gid().is_some(),
158-
"group id {} should exist",
159-
file_gid
160-
);
161133
assert!(
162134
matcher.matches(&file_info, &mut matcher_io),
163135
"group id should match"

src/find/matchers/mod.rs

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -717,29 +717,20 @@ fn build_matcher_tree(
717717
}
718718

719719
i += 1;
720-
let matcher = UserMatcher::from_user_name(user);
721-
match matcher.uid() {
722-
Some(_) => Some(matcher.into_box()),
723-
None => {
724-
return Err(From::from(format!(
725-
"{} is not the name of a known user",
726-
user
727-
)))
728-
}
729-
}
720+
let matcher = UserMatcher::from_user_name(user)
721+
.or_else(|| Some(UserMatcher::from_uid(user.parse::<u32>().ok()?)))
722+
.ok_or_else(|| format!("{user} is not the name of a known user"))?;
723+
Some(matcher.into_box())
730724
}
731725
"-nouser" => Some(NoUserMatcher {}.into_box()),
732726
"-uid" => {
733727
if i >= args.len() - 1 {
734728
return Err(From::from(format!("missing argument to {}", args[i])));
735729
}
736730
// check if the argument is a number
737-
let uid = args[i + 1].parse::<u32>();
738-
if uid.is_err() {
739-
return Err(From::from(format!("{} is not a number", args[i + 1])));
740-
}
731+
let uid = convert_arg_to_comparable_value(args[i], args[i + 1])?;
741732
i += 1;
742-
Some(UserMatcher::from_uid(uid.unwrap()).into_box())
733+
Some(UserMatcher::from_comparable(uid).into_box())
743734
}
744735
"-group" => {
745736
if i >= args.len() - 1 {
@@ -755,32 +746,20 @@ fn build_matcher_tree(
755746
}
756747

757748
i += 1;
758-
let matcher = GroupMatcher::from_group_name(group);
759-
match matcher.gid() {
760-
Some(_) => Some(matcher.into_box()),
761-
None => {
762-
return Err(From::from(format!(
763-
"{} is not the name of an existing group",
764-
group
765-
)))
766-
}
767-
}
749+
let matcher = GroupMatcher::from_group_name(group)
750+
.or_else(|| Some(GroupMatcher::from_gid(group.parse::<u32>().ok()?)))
751+
.ok_or_else(|| format!("{group} is not the name of an existing group"))?;
752+
Some(matcher.into_box())
768753
}
769754
"-nogroup" => Some(NoGroupMatcher {}.into_box()),
770755
"-gid" => {
771756
if i >= args.len() - 1 {
772757
return Err(From::from(format!("missing argument to {}", args[i])));
773758
}
774759
// check if the argument is a number
775-
let gid = args[i + 1].parse::<u32>();
776-
if gid.is_err() {
777-
return Err(From::from(format!(
778-
"find: invalid argument `{}' to `-gid'",
779-
args[i + 1]
780-
)));
781-
}
760+
let gid = convert_arg_to_comparable_value(args[i], args[i + 1])?;
782761
i += 1;
783-
Some(GroupMatcher::from_gid(gid.unwrap()).into_box())
762+
Some(GroupMatcher::from_comparable(gid).into_box())
784763
}
785764
"-executable" => Some(AccessMatcher::Executable.into_box()),
786765
"-perm" => {

src/find/matchers/user.rs

Lines changed: 17 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,71 +3,47 @@
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
55

6-
use super::{Matcher, MatcherIO, WalkEntry};
6+
use super::{ComparableValue, Matcher, MatcherIO, WalkEntry};
77

88
#[cfg(unix)]
99
use nix::unistd::User;
1010
#[cfg(unix)]
1111
use std::os::unix::fs::MetadataExt;
1212

1313
pub struct UserMatcher {
14-
uid: Option<u32>,
14+
uid: ComparableValue,
1515
}
1616

1717
impl UserMatcher {
1818
#[cfg(unix)]
19-
pub fn from_user_name(user: &str) -> Self {
19+
pub fn from_user_name(user: &str) -> Option<Self> {
2020
// get uid from user name
21-
let Ok(user) = User::from_name(user) else {
22-
return Self { uid: None };
23-
};
24-
25-
let Some(user) = user else {
26-
// This if branch is to determine whether a certain user exists in the system.
27-
// If a certain user does not exist in the system,
28-
// the result will need to be returned according to
29-
// the flag bit of whether to invert the result.
30-
return Self { uid: None };
31-
};
32-
33-
Self {
34-
uid: Some(user.uid.as_raw()),
35-
}
21+
let user = User::from_name(user).ok()??;
22+
let uid = user.uid.as_raw();
23+
Some(Self::from_uid(uid))
3624
}
3725

38-
#[cfg(unix)]
3926
pub fn from_uid(uid: u32) -> Self {
40-
Self { uid: Some(uid) }
27+
Self::from_comparable(ComparableValue::EqualTo(uid as u64))
4128
}
4229

43-
#[cfg(windows)]
44-
pub fn from_user_name(_user: &str) -> UserMatcher {
45-
UserMatcher { uid: None }
30+
pub fn from_comparable(uid: ComparableValue) -> Self {
31+
Self { uid }
4632
}
4733

4834
#[cfg(windows)]
49-
pub fn from_uid(_uid: u32) -> UserMatcher {
50-
UserMatcher { uid: None }
51-
}
52-
53-
pub fn uid(&self) -> &Option<u32> {
54-
&self.uid
35+
pub fn from_user_name(_user: &str) -> Option<Self> {
36+
None
5537
}
5638
}
5739

5840
impl Matcher for UserMatcher {
5941
#[cfg(unix)]
6042
fn matches(&self, file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
61-
let Ok(metadata) = file_info.metadata() else {
62-
return false;
63-
};
64-
65-
let file_uid = metadata.uid();
66-
67-
// When matching the -user parameter in find/matcher/mod.rs,
68-
// it has been judged that the user does not exist and an error is returned.
69-
// So use unwarp() directly here.
70-
self.uid.unwrap() == file_uid
43+
match file_info.metadata() {
44+
Ok(metadata) => self.uid.matches(metadata.uid().into()),
45+
Err(_) => false,
46+
}
7147
}
7248

7349
#[cfg(windows)]
@@ -134,7 +110,7 @@ mod tests {
134110
.unwrap()
135111
.name;
136112

137-
let matcher = UserMatcher::from_user_name(file_user.as_str());
113+
let matcher = UserMatcher::from_user_name(file_user.as_str()).expect("user should exist");
138114
assert!(
139115
matcher.matches(&file_info, &mut matcher_io),
140116
"user should be the same"
@@ -144,14 +120,13 @@ mod tests {
144120
let time_string = Local::now().format("%Y%m%d%H%M%S").to_string();
145121
let matcher = UserMatcher::from_user_name(time_string.as_str());
146122
assert!(
147-
matcher.uid().is_none(),
123+
matcher.is_none(),
148124
"user {} should not be the same",
149125
time_string
150126
);
151127

152128
// Testing user id
153129
let matcher = UserMatcher::from_uid(file_uid);
154-
assert!(matcher.uid().is_some(), "user id {} should exist", file_uid);
155130
assert!(
156131
matcher.matches(&file_info, &mut matcher_io),
157132
"user id should match"

src/find/mod.rs

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,17 +1163,35 @@ mod tests {
11631163
);
11641164

11651165
// test uid
1166-
let deps = FakeDependencies::new();
1167-
let rc = find_main(
1168-
&[
1169-
"find",
1170-
"./test_data/simple/subdir",
1171-
"-uid",
1172-
&uid.to_string(),
1173-
],
1174-
&deps,
1175-
);
1176-
assert_eq!(rc, 0);
1166+
for arg in ["-uid", "-user"] {
1167+
let deps = FakeDependencies::new();
1168+
let rc = find_main(
1169+
&["find", "./test_data/simple/subdir", arg, &uid.to_string()],
1170+
&deps,
1171+
);
1172+
assert_eq!(rc, 0);
1173+
}
1174+
1175+
// test -uid +N, -uid -N
1176+
if uid > 0 {
1177+
let deps = FakeDependencies::new();
1178+
let rc = find_main(
1179+
&[
1180+
"find",
1181+
"./test_data/simple/subdir",
1182+
"-uid",
1183+
&format!("+{}", uid - 1),
1184+
"-uid",
1185+
&format!("-{}", uid + 1),
1186+
],
1187+
&deps,
1188+
);
1189+
assert_eq!(rc, 0);
1190+
assert_eq!(
1191+
deps.get_output_as_string(),
1192+
"./test_data/simple/subdir\n./test_data/simple/subdir/ABBBC\n"
1193+
);
1194+
}
11771195

11781196
// test empty uid
11791197
let deps = FakeDependencies::new();
@@ -1233,17 +1251,35 @@ mod tests {
12331251
);
12341252

12351253
// test gid
1236-
let deps = FakeDependencies::new();
1237-
let rc = find_main(
1238-
&[
1239-
"find",
1240-
"./test_data/simple/subdir",
1241-
"-gid",
1242-
gid.to_string().as_str(),
1243-
],
1244-
&deps,
1245-
);
1246-
assert_eq!(rc, 0);
1254+
for arg in ["-gid", "-group"] {
1255+
let deps = FakeDependencies::new();
1256+
let rc = find_main(
1257+
&["find", "./test_data/simple/subdir", arg, &gid.to_string()],
1258+
&deps,
1259+
);
1260+
assert_eq!(rc, 0);
1261+
}
1262+
1263+
// test -gid +N, -gid -N
1264+
if gid > 0 {
1265+
let deps = FakeDependencies::new();
1266+
let rc = find_main(
1267+
&[
1268+
"find",
1269+
"./test_data/simple/subdir",
1270+
"-gid",
1271+
&format!("+{}", gid - 1),
1272+
"-gid",
1273+
&format!("-{}", gid + 1),
1274+
],
1275+
&deps,
1276+
);
1277+
assert_eq!(rc, 0);
1278+
assert_eq!(
1279+
deps.get_output_as_string(),
1280+
"./test_data/simple/subdir\n./test_data/simple/subdir/ABBBC\n"
1281+
);
1282+
}
12471283

12481284
// test empty gid
12491285
let deps = FakeDependencies::new();

0 commit comments

Comments
 (0)