Repository: sharkdp/fd (language: rust)

Issue:
help: mention that fd detects executables by file permissions
Detecting an executable efficiently is not simple: https://stackoverflow.com/questions/4458120/search-for-executable-files-using-find-command

fd uses the executable bit of the file permissions, which should be mentioned in the help page.
help: mention that fd detects executables by file permissions
Detecting an executable efficiently is not simple: https://stackoverflow.com/questions/4458120/search-for-executable-files-using-find-command

fd uses the executable bit of the file permissions, which should be mentioned in the help page.


Discussion / hints:
I was not aware of this behavior. I think we should probably change the behavior of `fd --type executable` here to follow what `find -executable` does. What do others think?
I'd be in favor of that.  We can use the same library we do on Windows since https://github.com/sharkdp/fd/pull/1061
I was not aware of this behavior. I think we should probably change the behavior of `fd --type executable` here to follow what `find -executable` does. What do others think?
I'd be in favor of that.  We can use the same library we do on Windows since https://github.com/sharkdp/fd/pull/1061

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4cfd1f458..064edc818 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
 # Upcoming release
 
+## Features
+
+
+## Changes
+
+- Breaking: On Unix-like systems, `--type executable` now additionally checks if
+  the file is executable by the current user, see #1106 and #1169 (@ptipiak)
+
+
+## Bugfixes
+
+
+## Other
+
+
+
 # v8.5.3
 
 ## Bugfixes
diff --git a/Cargo.toml b/Cargo.toml
index cda9e755e..3659c05ae 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -51,6 +51,7 @@ chrono = "0.4"
 once_cell = "1.15.0"
 crossbeam-channel = "0.5.6"
 clap_complete = {version = "4.0.5", optional = true}
+faccess = "0.2.4"
 
 [dependencies.clap]
 version = "4.0.22"
@@ -63,9 +64,6 @@ nix = { version = "0.24.2", default-features = false, features = ["signal"] }
 [target.'cfg(all(unix, not(target_os = "redox")))'.dependencies]
 libc = "0.2"
 
-[target.'cfg(windows)'.dependencies]
-faccess = "0.2.4"
-
 # FIXME: Re-enable jemalloc on macOS
 # jemalloc is currently disabled on macOS due to a bug in jemalloc in combination with macOS
 # Catalina. See https://github.com/sharkdp/fd/issues/498 for details.
diff --git a/src/cli.rs b/src/cli.rs
index 09630a6e3..e6a9743bd 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -643,6 +643,7 @@ pub enum FileType {
     Directory,
     #[value(alias = "l")]
     Symlink,
+    /// A file which is executable by the current effective user
     #[value(alias = "x")]
     Executable,
     #[value(alias = "e")]
diff --git a/src/filesystem.rs b/src/filesystem.rs
index 2e79591c1..b7895c0b6 100644
--- a/src/filesystem.rs
+++ b/src/filesystem.rs
@@ -4,12 +4,9 @@ use std::ffi::OsStr;
 use std::fs;
 use std::io;
 #[cfg(any(unix, target_os = "redox"))]
-use std::os::unix::fs::{FileTypeExt, PermissionsExt};
+use std::os::unix::fs::FileTypeExt;
 use std::path::{Path, PathBuf};
 
-#[cfg(windows)]
-use faccess::PathExt as _;
-
 use normpath::PathExt;
 
 use crate::dir_entry;
@@ -44,16 +41,6 @@ pub fn is_existing_directory(path: &Path) -> bool {
     path.is_dir() && (path.file_name().is_some() || path.normalize().is_ok())
 }
 
-#[cfg(any(unix, target_os = "redox"))]
-pub fn is_executable(_: &Path, md: &fs::Metadata) -> bool {
-    md.permissions().mode() & 0o111 != 0
-}
-
-#[cfg(windows)]
-pub fn is_executable(path: &Path, _: &fs::Metadata) -> bool {
-    path.executable()
-}
-
 pub fn is_empty(entry: &dir_entry::DirEntry) -> bool {
     if let Some(file_type) = entry.file_type() {
         if file_type.is_dir() {
diff --git a/src/filetypes.rs b/src/filetypes.rs
index 42e95d2a5..c34cc490f 100644
--- a/src/filetypes.rs
+++ b/src/filetypes.rs
@@ -1,6 +1,8 @@
 use crate::dir_entry;
 use crate::filesystem;
 
+use faccess::PathExt;
+
 /// Whether or not to show
 #[derive(Default)]
 pub struct FileTypes {
@@ -21,11 +23,7 @@ impl FileTypes {
                 || (!self.symlinks && entry_type.is_symlink())
                 || (!self.sockets && filesystem::is_socket(*entry_type))
                 || (!self.pipes && filesystem::is_pipe(*entry_type))
-                || (self.executables_only
-                    && !entry
-                        .metadata()
-                        .map(|md| filesystem::is_executable(entry.path(), md))
-                        .unwrap_or(false))
+                || (self.executables_only && !entry.path().executable())
                 || (self.empty_only && !filesystem::is_empty(entry))
                 || !(entry_type.is_file()
                     || entry_type.is_dir()


Test patch: