瀏覽代碼

Userland: Simplify recursion in find(1)

Now walk_tree() itself checks whether it should descend into a file
(if the file is a directory) or not.
Sergey Bugaev 3 年之前
父節點
當前提交
d4232d5ee2
共有 1 個文件被更改,包括 21 次插入6 次删除
  1. 21 6
      Userland/Utilities/find.cpp

+ 21 - 6
Userland/Utilities/find.cpp

@@ -461,9 +461,28 @@ static void walk_tree(const FileData& root_data, Command& command)
 {
     command.evaluate(root_data);
 
+    // We should try to read directory entries if either:
+    // * This is a directory.
+    // * This is a symlink (that could point to a directory),
+    //   and we're following symlinks.
+    struct stat stat;
+    int rc = fstatat(root_data.dirfd, root_data.basename, &stat, AT_SYMLINK_NOFOLLOW);
+    if (rc < 0)
+        return;
+    if (!S_ISDIR(stat.st_mode) && (!g_follow_symlinks || !S_ISLNK(stat.st_mode)))
+        return;
+
     int dirfd = openat(root_data.dirfd, root_data.basename, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
-    if (dirfd < 0 && errno == ENOTDIR)
+    if (dirfd < 0) {
+        if (errno == ENOTDIR) {
+            // Above we decided to try to open this file because it could
+            // be a directory, but turns out it's not. This is fine though.
+            return;
+        }
+        perror(root_data.full_path.string().characters());
+        g_there_was_an_error = true;
         return;
+    }
 
     DIR* dir = fdopendir(dirfd);
 
@@ -481,11 +500,7 @@ static void walk_tree(const FileData& root_data, Command& command)
             dirfd,
             dirent->d_name,
         };
-        struct stat stat;
-        if (g_follow_symlinks || fstatat(dirfd, dirent->d_name, &stat, AT_SYMLINK_NOFOLLOW) < 0 || !S_ISLNK(stat.st_mode))
-            walk_tree(file_data, command);
-        else
-            command.evaluate(file_data);
+        walk_tree(file_data, command);
     }
 
     if (errno != 0) {