소스 검색

find: Allow unit suffixes to be used with the `-size` option

The argument supplied to the `-size` option may now be one of the
following suffixes:

* b: 512-byte blocks. This is the default unit if no suffix is used.
* c: bytes
* w: two-byte words
* k: kibibytes (1024 bytes)
* M: mebibytes (1024 kibibytes)
* G: gibibytes (1024 mebibytes)

Sizes are rounded to the specified unit before comparison. The unit
suffixes are case-sensitive.
Tim Ledbetter 1 년 전
부모
커밋
aa7c2f1f0d
2개의 변경된 파일46개의 추가작업 그리고 14개의 파일을 삭제
  1. 12 3
      Base/usr/share/man/man1/find.md
  2. 34 11
      Userland/Utilities/find.cpp

+ 12 - 3
Base/usr/share/man/man1/find.md

@@ -32,9 +32,18 @@ specified commands, a `-print` command is implicitly appended.
   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[c]`: Checks if the file has the given size in 512-byte blocks,
-  rounded up. If the size is followed by the `c` character, checks if the file
-  has the given size in bytes.
+* `-size number[bcwkMG]`: Checks if the file uses the specified `n` units of
+space rounded up to the nearest whole unit.
+  
+  The unit of space may be specified by any of these suffixes:
+
+  * `b`: 512-byte blocks. This is the default unit if no suffix is used.
+  * `c`: bytes
+  * `w`: two-byte words
+  * `k`: kibibytes (1024 bytes)
+  * `M`: mebibytes (1024 kibibytes)
+  * `G`: gibibytes (1024 mebibytes)
+
 * `-name pattern`: Checks if the file name matches the given global-style
   pattern (case sensitive).
 * `-iname pattern`: Checks if the file name matches the given global-style

+ 34 - 11
Userland/Utilities/find.cpp

@@ -226,28 +226,51 @@ public:
     SizeCommand(char const* arg)
     {
         StringView view { arg, strlen(arg) };
-        if (view.ends_with('c')) {
-            m_is_bytes = true;
+        auto suffix = view[view.length() - 1];
+        if (!is_ascii_digit(suffix)) {
+            switch (suffix) {
+            case 'c':
+                m_unit_size = 1;
+                break;
+            case 'w':
+                m_unit_size = 2;
+                break;
+            case 'k':
+                m_unit_size = KiB;
+                break;
+            case 'M':
+                m_unit_size = MiB;
+                break;
+            case 'G':
+                m_unit_size = GiB;
+                break;
+            case 'b':
+                // The behavior of this suffix is the same as no suffix.
+                break;
+            default:
+                fatal_error("Invalid -size type '{}'", suffix);
+            }
+
             view = view.substring_view(0, view.length() - 1);
         }
-        auto number = view.to_uint();
-        if (!number.has_value())
+        auto number = view.to_uint<u64>();
+        if (!number.has_value() || number.value() > AK::NumericLimits<off_t>::max())
             fatal_error("Invalid size: \033[1m{}", arg);
-        m_size = number.value();
+        m_number_of_units = number.value();
     }
 
 private:
     virtual bool evaluate(const struct stat& stat) const override
     {
-        if (m_is_bytes)
-            return stat.st_size == m_size;
+        if (m_unit_size == 1)
+            return stat.st_size == m_number_of_units;
 
-        auto size_divided_by_512_rounded_up = (stat.st_size + 511) / 512;
-        return size_divided_by_512_rounded_up == m_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;
     }
 
-    off_t m_size { 0 };
-    bool m_is_bytes { false };
+    off_t m_number_of_units { 0 };
+    off_t m_unit_size { 512 };
 };
 
 class NameCommand : public Command {