find: Allow '+' and '-' prefix for -links
and -size
options
The presence of this prefix denotes that the value being tested is strictly greater than or less than the given numeric value.
This commit is contained in:
parent
773a64aa5a
commit
331991f9c4
Notes:
sideshowbarker
2024-07-17 22:09:47 +09:00
Author: https://github.com/tcl3 Commit: https://github.com/SerenityOS/serenity/commit/331991f9c4 Pull-request: https://github.com/SerenityOS/serenity/pull/20962
2 changed files with 78 additions and 15 deletions
|
@ -27,13 +27,17 @@ specified commands, a `-print` command is implicitly appended.
|
|||
* `-type t`: Checks if the file is of the specified type, which must be one of
|
||||
`b` (for block device), `c` (character device), `d` (directory), `l` (symbolic
|
||||
link), `p` (FIFO), `f` (regular file), and `s` (socket).
|
||||
* `-links number`: Checks if the file has the given number of hard links.
|
||||
* `-links [-|+]number`: Checks if the file has the given number of hard links.
|
||||
* `-user name`: Checks if the file is owned by the given user. Instead of a user
|
||||
name, a numerical UID may be specified.
|
||||
* `-group name`: Checks if the file is owned by the given group. Instead of a
|
||||
group name, a numerical GID may be specified.
|
||||
* `-size number[bcwkMG]`: Checks if the file uses the specified `n` units of
|
||||
space rounded up to the nearest whole unit.
|
||||
* `-size [-|+]number[bcwkMG]`: Checks if the file uses the specified `n` units of
|
||||
space rounded up to the nearest whole unit.
|
||||
|
||||
The '+' and '-' prefixes denote greater than and less than, i.e an exact size
|
||||
of `n` units doesn't match. Sizes are always rounded up to the nearest unit,
|
||||
empty files, while the latter will match files from 0 to 1,048,575 bytes.
|
||||
|
||||
The unit of space may be specified by any of these suffixes:
|
||||
|
||||
|
@ -83,6 +87,11 @@ operators:
|
|||
* `command1 -a command2`, `command1 command2`: Logical AND.
|
||||
* `( command )`: Groups commands together for operator priority purposes.
|
||||
|
||||
Commands which take a numeric argument `n` (`-links` and `-size` for example),
|
||||
may be prefixed by a plus sign ('+') or a minus sign ('-'). A plus sign means
|
||||
"grater than `n`", while a minus sign means "less than `n`". A numeric argument
|
||||
with no prefix means "exactly equal".
|
||||
|
||||
## Examples
|
||||
|
||||
```sh
|
||||
|
|
|
@ -94,6 +94,59 @@ struct FileData {
|
|||
}
|
||||
};
|
||||
|
||||
template<Unsigned T>
|
||||
class NumericRange {
|
||||
public:
|
||||
NumericRange() = default;
|
||||
|
||||
static ErrorOr<NumericRange<T>> parse(StringView arg)
|
||||
{
|
||||
if (arg.is_empty())
|
||||
return Error::from_errno(EINVAL);
|
||||
|
||||
auto comparison_type = ComparisonType::Equal;
|
||||
if (arg[0] == '-') {
|
||||
comparison_type = ComparisonType::LessThan;
|
||||
arg = arg.substring_view(1);
|
||||
} else if (arg[0] == '+') {
|
||||
comparison_type = ComparisonType::GreaterThan;
|
||||
arg = arg.substring_view(1);
|
||||
}
|
||||
|
||||
auto maybe_value = arg.to_uint<T>();
|
||||
if (!maybe_value.has_value())
|
||||
return Error::from_errno(EINVAL);
|
||||
|
||||
return NumericRange<T>(maybe_value.release_value(), comparison_type);
|
||||
}
|
||||
|
||||
bool contains(T other) const
|
||||
{
|
||||
if (m_comparison_type == ComparisonType::LessThan)
|
||||
return other < m_value;
|
||||
if (m_comparison_type == ComparisonType::GreaterThan)
|
||||
return other > m_value;
|
||||
|
||||
return other == m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
enum class ComparisonType {
|
||||
Equal,
|
||||
LessThan,
|
||||
GreaterThan
|
||||
};
|
||||
|
||||
NumericRange(T value, ComparisonType comparison_type)
|
||||
: m_value(value)
|
||||
, m_comparison_type(comparison_type)
|
||||
{
|
||||
}
|
||||
|
||||
T m_value {};
|
||||
ComparisonType m_comparison_type { ComparisonType::Equal };
|
||||
};
|
||||
|
||||
class Command {
|
||||
public:
|
||||
virtual ~Command() = default;
|
||||
|
@ -163,19 +216,20 @@ class LinksCommand final : public StatCommand {
|
|||
public:
|
||||
LinksCommand(char const* arg)
|
||||
{
|
||||
auto number = StringView { arg, strlen(arg) }.to_uint();
|
||||
if (!number.has_value())
|
||||
StringView arg_string { arg, strlen(arg) };
|
||||
auto links_or_error = NumericRange<nlink_t>::parse(arg_string);
|
||||
if (links_or_error.is_error())
|
||||
fatal_error("Invalid number: \033[1m{}", arg);
|
||||
m_links = number.value();
|
||||
m_links = links_or_error.release_value();
|
||||
}
|
||||
|
||||
private:
|
||||
virtual bool evaluate(const struct stat& stat) const override
|
||||
{
|
||||
return stat.st_nlink == m_links;
|
||||
return m_links.contains(stat.st_nlink);
|
||||
}
|
||||
|
||||
nlink_t m_links { 0 };
|
||||
NumericRange<nlink_t> m_links {};
|
||||
};
|
||||
|
||||
class UserCommand final : public StatCommand {
|
||||
|
@ -258,24 +312,24 @@ public:
|
|||
|
||||
view = view.substring_view(0, view.length() - 1);
|
||||
}
|
||||
auto number = view.to_uint<u64>();
|
||||
if (!number.has_value() || number.value() > AK::NumericLimits<off_t>::max())
|
||||
auto number_or_error = NumericRange<u64>::parse(view);
|
||||
if (number_or_error.is_error())
|
||||
fatal_error("Invalid size: \033[1m{}", arg);
|
||||
m_number_of_units = number.value();
|
||||
m_number_of_units = number_or_error.release_value();
|
||||
}
|
||||
|
||||
private:
|
||||
virtual bool evaluate(const struct stat& stat) const override
|
||||
{
|
||||
if (m_unit_size == 1)
|
||||
return stat.st_size == m_number_of_units;
|
||||
return m_number_of_units.contains(stat.st_size);
|
||||
|
||||
auto size_divided_by_unit_rounded_up = (stat.st_size + m_unit_size - 1) / m_unit_size;
|
||||
return size_divided_by_unit_rounded_up == m_number_of_units;
|
||||
return m_number_of_units.contains(size_divided_by_unit_rounded_up);
|
||||
}
|
||||
|
||||
off_t m_number_of_units { 0 };
|
||||
off_t m_unit_size { 512 };
|
||||
NumericRange<u64> m_number_of_units {};
|
||||
u64 m_unit_size { 512 };
|
||||
};
|
||||
|
||||
class EmptyCommand final : public Command {
|
||||
|
|
Loading…
Add table
Reference in a new issue