diff options
| author | Saikari <[email protected]> | 2026-01-29 12:24:27 +0300 |
|---|---|---|
| committer | Saikari <[email protected]> | 2026-01-29 12:24:27 +0300 |
| commit | be399abceea8da01cbcd2e5391bc6aead52cfcfe (patch) | |
| tree | fd2592b035938ea622a720add6165dc1baddb124 | |
| parent | 38a8b6998f5ef826725ed565b46d50f097840ed0 (diff) | |
Add is_pefile function to check for PE file signatures on Windows
| -rw-r--r-- | core/src/xmake/engine.c | 2 | ||||
| -rw-r--r-- | core/src/xmake/winos/is_pefile.c | 94 | ||||
| -rw-r--r-- | xmake/core/base/os.lua | 38 |
3 files changed, 123 insertions, 11 deletions
diff --git a/core/src/xmake/engine.c b/core/src/xmake/engine.c index a77cc4a9b..3356e4456 100644 --- a/core/src/xmake/engine.c +++ b/core/src/xmake/engine.c @@ -278,6 +278,7 @@ tb_int_t xm_winos_registry_query(lua_State *lua); tb_int_t xm_winos_registry_keys(lua_State *lua); tb_int_t xm_winos_registry_values(lua_State *lua); tb_int_t xm_winos_short_path(lua_State *lua); +tb_int_t xm_winos_is_pefile(lua_State *lua); #endif // the utf8 functions @@ -482,6 +483,7 @@ static luaL_Reg const g_winos_functions[] = { { "registry_keys", xm_winos_registry_keys }, { "registry_values", xm_winos_registry_values }, { "short_path", xm_winos_short_path }, + { "is_pe_file", xm_winos_is_pefile }, { tb_null, tb_null }, }; #endif diff --git a/core/src/xmake/winos/is_pefile.c b/core/src/xmake/winos/is_pefile.c new file mode 100644 index 000000000..8b2016421 --- /dev/null +++ b/core/src/xmake/winos/is_pefile.c @@ -0,0 +1,94 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file is_pefile.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "is_pefile" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* is pe file? + * + * local is_pe = winos.is_pefile(filepath) + */ +tb_int_t xm_winos_is_pefile(lua_State *lua) { + + // check + tb_assert_and_check_return_val(lua, 0); + + // get the arguments + tb_char_t const *filepath = luaL_checkstring(lua, 1); + tb_check_return_val(filepath, 0); + + // check pe file + tb_bool_t ok = tb_false; + tb_stream_ref_t stream = tb_stream_init_from_file(filepath, TB_FILE_MODE_RO); + if (stream) { + + // open stream + if (tb_stream_open(stream)) { + + // check mz signature + tb_byte_t data[4]; + if (tb_stream_read(stream, data, 2) == 2 && data[0] == 'M' && data[1] == 'Z') { + + // seek to pe header offset (0x3c) + if (tb_stream_seek(stream, 0x3c)) { + + // read the pe header offset + if (tb_stream_read(stream, data, 4) == 4) { + + // get the pe header offset + tb_uint32_t offset = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + if (offset) { + + // seek to the pe header + if (tb_stream_seek(stream, offset)) { + + // check pe signature + if (tb_stream_read(stream, data, 4) == 4 && + data[0] == 'P' && data[1] == 'E' && data[2] == 0 && data[3] == 0) { + ok = tb_true; + } + } + } + } + } + } + } + + // exit stream + tb_stream_exit(stream); + } + + // return result + lua_pushboolean(lua, ok); + return 1; +} diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua index 6c4c1fa48..351dbd68c 100644 --- a/xmake/core/base/os.lua +++ b/xmake/core/base/os.lua @@ -1151,23 +1151,39 @@ end function os.isexec(filepath) assert(filepath) - -- TODO - -- check permission + if os.host() == "windows" then + local exts = {".exe", ".cmd", ".bat", ".ps1", ".sh"} + if os.isfile(filepath) then + -- detect file extension first + local extension = path.extension(filepath):lower() + if extension then + if table.contains(exts, extension) then + return true + end + end - -- check executable program exist - if os.isfile(filepath) then - if os.host() == "windows" then - return true - else - return os._access(filepath, "x") + -- detect file header + if winos.is_pefile(filepath) then + return true + end + + -- detect shebang scripts + local file = io.open(filepath, "rb") + if file then + local header = file:read(2) + file:close() + if header == "#!" then + return true + end + end end - end - if os.host() == "windows" then - for _, suffix in ipairs({".exe", ".cmd", ".bat", ".ps1"}) do + for _, suffix in ipairs(exts) do if os.isfile(filepath .. suffix) then return true end end + elseif os.isfile(filepath) then + return os._access(filepath, "x") end return false end |
