Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@devmanuelli
Copy link

Extends the --owner filter to support finding files with no valid
user/group by using the 'orphan' keyword. This provides equivalent
functionality to find's -nouser and -nogroup flags.

Examples:
fd --owner orphan # equivalent to find -nouser
fd --owner :orphan # equivalent to find -nogroup
fd --owner orphan:orphan # both -nouser and -nogroup

Implementation:

  • Added Check::Orphaned variant to owner filter
  • Extended OwnerFilter::from_string to recognize 'orphan' keyword
  • Updated OwnerFilter::matches to check if uid/gid maps to valid user/group
  • Added unit tests for orphan parsing

Extends the --owner filter to support finding files with no valid
user/group by using the 'orphan' keyword. This provides equivalent
functionality to find's -nouser and -nogroup flags.

Examples:
  fd --owner orphan       # equivalent to find -nouser
  fd --owner :orphan      # equivalent to find -nogroup
  fd --owner orphan:orphan # both -nouser and -nogroup

Implementation:
- Added Check::Orphaned variant to owner filter
- Extended OwnerFilter::from_string to recognize 'orphan' keyword
- Updated OwnerFilter::matches to check if uid/gid maps to valid user/group
- Added unit tests for orphan parsing

self.uid.check(md.uid()) && self.gid.check(md.gid())
let uid_match = match self.uid {
Check::Orphaned => User::from_uid(md.uid().into()).ok().flatten().is_none(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth using a cache, so we don't have to do a lookup for every single file. We could probably even use a Set of uids known not to be orphaned.

Check::Equal(x) => v == *x,
Check::NotEq(x) => v != *x,
Check::Ignore => true,
Check::Orphaned => unreachable!("Orphaned check handled in OwnerFilter::matches"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really like how the caller is responsible for handling this separately. It would be nice if we could just include a Set of allowed ids in the Orphaned vairant, but I think on some systems, the user ids could be dynamic, and reading from /etc/passwd isn't sufficient.

Another option could be to have the Orphaned variant include a function to check if an id exists, or even just a value indicating if it is for user ids or group ids.

both_negate:"!4:!3" => Ok(OwnerFilter { uid: NotEq(4), gid: NotEq(3) }),
uid_not_gid:"6:!8" => Ok(OwnerFilter { uid: Equal(6), gid: NotEq(8) }),

orphan_uid: "orphan" => Ok(OwnerFilter { uid: Orphaned, gid: Ignore }),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible that a user or group is actually named "orphan". I think it would probably be better to use a a different option, or maybe use something that isn't a valid username like "-".

src/cli.rs Outdated
/// Filter files by their user and/or group.
/// Format: [(user|uid)][:(group|gid)]. Either side is optional.
/// Precede either side with a '!' to exclude files instead.
/// Use 'orphan' to match files with no valid user/group.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we move forward with this, you'll also need to update the man page and CHANGELOG

Changes based on maintainer feedback:
- Changed keyword from 'orphan' to '-' to avoid conflicts with actual usernames
- Refactored Check::Orphan to include validator function (fn(u32) -> bool)
- Simplified matches() to use check() uniformly - no special case handling
- Added caching with LazyLock<Mutex<HashSet>> to avoid repeated uid/gid lookups
- Updated documentation (man page and CHANGELOG)

The new design stores the validation logic in the Orphan variant itself,
making it self-contained and consistent with other Check variants.
All checks now go through the generic check() method.
@devmanuelli
Copy link
Author

Addressed all feedback: changed keyword to -, added validator function to Orphan variant for self-contained checking, added caching, and updated docs.

@devmanuelli
Copy link
Author

bump @tmccombs

@devmanuelli
Copy link
Author

@tmccombs I should have fixed it

@devmanuelli
Copy link
Author

bump @tmccombs is there sth I should fix?

use std::sync::{LazyLock, Mutex};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
static VALID_UIDS: LazyLock<Mutex<HashSet<u32>>> = LazyLock::new(|| Mutex::new(HashSet::new()));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not be performant. I'd use a thread-local instead. You should also use something like a HashMap<u32, bool> so that you can cache both negative and positive results.

Copy link
Collaborator

@tmccombs tmccombs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly looks good. Just address @tavianator's comment.

- Replace LazyLock<Mutex<HashSet>> with thread_local RefCell<HashMap>
- Cache both positive and negative lookup results
- Avoids mutex contention in parallel traversal
@devmanuelli
Copy link
Author

@tavianator I should have addressed ur review in the last commit

@devmanuelli
Copy link
Author

Mostly looks good

@tmccombs
if there is something smelly just tell me

@devmanuelli
Copy link
Author

@tavianator bump. ty in advance

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants