diff options
| author | 2023-01-16 16:28:02 -0800 | |
|---|---|---|
| committer | 2023-01-16 16:28:02 -0800 | |
| commit | 7dd28bbdd99b31cc88abe4b309ed52aff64be9c2 (patch) | |
| tree | ae3b2c0ae4d790995801a59de78fdb3fd5c896af /src | |
| parent | d54e23ca33cc95199a58d958abf990d9a6e1eb26 (diff) | |
| download | bun-7dd28bbdd99b31cc88abe4b309ed52aff64be9c2.tar.gz bun-7dd28bbdd99b31cc88abe4b309ed52aff64be9c2.tar.zst bun-7dd28bbdd99b31cc88abe4b309ed52aff64be9c2.zip | |
Fix `which` returning directories sometimes
Diffstat (limited to 'src')
| -rw-r--r-- | src/bun.js/bindings/c-bindings.cpp | 23 | ||||
| -rw-r--r-- | src/which.zig | 6 | 
2 files changed, 25 insertions, 4 deletions
| diff --git a/src/bun.js/bindings/c-bindings.cpp b/src/bun.js/bindings/c-bindings.cpp index aee5f5425..d37dd12cb 100644 --- a/src/bun.js/bindings/c-bindings.cpp +++ b/src/bun.js/bindings/c-bindings.cpp @@ -1,6 +1,9 @@  // when we don't want to use @cInclude, we can just stick wrapper functions here  #include <sys/resource.h>  #include <cstdint> +#include <unistd.h> +#include <sys/fcntl.h> +#include <sys/stat.h>  extern "C" int32_t get_process_priority(uint32_t pid)  { @@ -11,3 +14,23 @@ extern "C" int32_t set_process_priority(uint32_t pid, int32_t priority)  {      return setpriority(PRIO_PROCESS, pid, priority);  } + +extern "C" bool is_executable_file(const char* path) +{ + +#ifdef __APPLE__ +    // O_EXEC is macOS specific +    int fd = open(path, O_EXEC, O_CLOEXEC); +    if (fd < 0) +        return false; +    close(fd); +    return true; +#endif + +    struct stat st; +    if (stat(path, &st) != 0) +        return false; + +    // regular file and user can execute +    return S_ISREG(st.st_mode) && (st.st_mode & S_IXUSR); +} diff --git a/src/which.zig b/src/which.zig index 6c0828e7b..abf5d57f7 100644 --- a/src/which.zig +++ b/src/which.zig @@ -10,11 +10,9 @@ fn isValid(buf: *[bun.MAX_PATH_BYTES]u8, segment: []const u8, bin: []const u8) ?      return @intCast(u16, filepath.len);  } +extern "C" fn is_executable_file(path: [*:0]const u8) bool;  fn checkPath(filepath: [:0]const u8) bool { -    // TODO: is there a single system call for executable AND file? -    std.os.accessZ(filepath, std.os.X_OK) catch return false; -    std.os.accessZ(filepath, std.os.F_OK) catch return false; -    return true; +    return is_executable_file(filepath);  }  // Like /usr/bin/which but without needing to exec a child process | 
