Repository: sharkdp/fd (language: rust)

Issue:
-t executable flags can't show windows executable 
### `-t executable` flags can't show windows executable 

![图片](https://user-images.githubusercontent.com/51036094/175789762-8fb2d8c8-1208-48de-9893-70cbc0ee285a.png)




Discussion / hints:
Indeed: https://github.com/sharkdp/fd/blob/f227bb291ae9e5890309bea45e55df2795441656/src/filesystem.rs#L49-L52

We could use https://crates.io/crates/faccess for this, since the [implementation](https://github.com/Freaky/faccess/blob/d7f2b450862281e6e842b6cec02730572e53a5ae/src/lib.rs#L126-L375) is pretty long.
Sounds good to me, if this dependency is reasonable in terms of code size & compile time. Or would we put it behind a `cfg(windows)` and use our own implementation for non-Windows systems?
I remember we had a similar discussion concerning "hidden" files on Windows. If I recall correctly, Windows has some notion of hidden files that also involves filesystem attributes?

Edit: right, we already support this: https://github.com/sharkdp/fd/pull/478 At some point, the `ignore` crate added this feature, IIRC.
> Sounds good to me, if this dependency is reasonable in terms of code size & compile time. Or would we put it behind a `cfg(windows)` and use our own implementation for non-Windows systems?

It would technically be a breaking change on Unix.  `-t x` looks at permission bits only, while `faccessat()` checks if the current user actually has permissions.  So a mode 700 file owned by someone else is `-t x` but not `-executable` according to `find`.  Maybe it's okay to change this though?

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 89ff83964..1b39d965d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
 
 ## Features
 
+- `--type executable`/`-t` now works on Windows, see #1051 and #1061
 
 ## Bugfixes
 
diff --git a/Cargo.lock b/Cargo.lock
index 339c04f40..6e5a30cac 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -176,6 +176,17 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "faccess"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ae66425802d6a903e268ae1a08b8c38ba143520f227a205edf4e9c7e3e26d5"
+dependencies = [
+ "bitflags",
+ "libc",
+ "winapi",
+]
+
 [[package]]
 name = "fd-find"
 version = "8.4.0"
@@ -190,6 +201,7 @@ dependencies = [
  "ctrlc",
  "diff",
  "dirs-next",
+ "faccess",
  "filetime",
  "globset",
  "humantime",
diff --git a/Cargo.toml b/Cargo.toml
index 530d34d24..4a55296e8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -63,6 +63,9 @@ nix = { version = "0.24.1", 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/filesystem.rs b/src/filesystem.rs
index a025895e8..2e79591c1 100644
--- a/src/filesystem.rs
+++ b/src/filesystem.rs
@@ -7,6 +7,9 @@ use std::io;
 use std::os::unix::fs::{FileTypeExt, PermissionsExt};
 use std::path::{Path, PathBuf};
 
+#[cfg(windows)]
+use faccess::PathExt as _;
+
 use normpath::PathExt;
 
 use crate::dir_entry;
@@ -42,13 +45,13 @@ pub fn is_existing_directory(path: &Path) -> bool {
 }
 
 #[cfg(any(unix, target_os = "redox"))]
-pub fn is_executable(md: &fs::Metadata) -> bool {
+pub fn is_executable(_: &Path, md: &fs::Metadata) -> bool {
     md.permissions().mode() & 0o111 != 0
 }
 
 #[cfg(windows)]
-pub fn is_executable(_: &fs::Metadata) -> bool {
-    false
+pub fn is_executable(path: &Path, _: &fs::Metadata) -> bool {
+    path.executable()
 }
 
 pub fn is_empty(entry: &dir_entry::DirEntry) -> bool {
diff --git a/src/filetypes.rs b/src/filetypes.rs
index 1209549ff..42e95d2a5 100644
--- a/src/filetypes.rs
+++ b/src/filetypes.rs
@@ -24,7 +24,7 @@ impl FileTypes {
                 || (self.executables_only
                     && !entry
                         .metadata()
-                        .map(filesystem::is_executable)
+                        .map(|md| filesystem::is_executable(entry.path(), md))
                         .unwrap_or(false))
                 || (self.empty_only && !filesystem::is_empty(entry))
                 || !(entry_type.is_file()


Test patch: