From 6a92a40f4b803517c6c5a58d505d997f5fc5c500 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Fri, 29 Aug 2025 14:17:13 +0300 Subject: [PATCH] [MSVCRT] Reimplement system/_wsystem The new implementation is closely based on UCRT code and passes all tests for Vista+. --- dll/win32/msvcrt/CMakeLists.txt | 1 + dll/win32/msvcrt/process.c | 2 + dll/win32/msvcrt/reactos/system.cpp | 123 ++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 dll/win32/msvcrt/reactos/system.cpp diff --git a/dll/win32/msvcrt/CMakeLists.txt b/dll/win32/msvcrt/CMakeLists.txt index 768b891db5b..193341cdcc4 100644 --- a/dll/win32/msvcrt/CMakeLists.txt +++ b/dll/win32/msvcrt/CMakeLists.txt @@ -131,6 +131,7 @@ list(APPEND MSVCRT_SOURCE ${msvcrt_shared_asm} reactos/chkesp_failed.c reactos/misc.c + reactos/system.cpp concurrency.c console.c ctype.c diff --git a/dll/win32/msvcrt/process.c b/dll/win32/msvcrt/process.c index 64d824270d7..2a9c92822d2 100644 --- a/dll/win32/msvcrt/process.c +++ b/dll/win32/msvcrt/process.c @@ -1245,6 +1245,7 @@ int CDECL _pclose(FILE* file) return i; } +#ifndef __REACTOS__ /********************************************************************* * _wsystem (MSVCRT.@) * @@ -1308,6 +1309,7 @@ int CDECL system(const char* cmd) } return res; } +#endif /********************************************************************* * _loaddll (MSVCRT.@) diff --git a/dll/win32/msvcrt/reactos/system.cpp b/dll/win32/msvcrt/reactos/system.cpp new file mode 100644 index 00000000000..26c119b6dd0 --- /dev/null +++ b/dll/win32/msvcrt/reactos/system.cpp @@ -0,0 +1,123 @@ +/* + * PROJECT: ReactOS msvcrt + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Implementation of system / _wsystem + * COPYRIGHT: Copyright (c) Microsoft Corporation. All rights reserved. + * COPYRIGHT: Copyright 2025 Timo Kreuzer + */ + +#include +#include +#include +#include + +extern "C" int _cdecl _access_s(const char* filename, int mode); +extern "C" int _cdecl _waccess_s(const wchar_t* filename, int mode); + +int _cdecl _taccess_s(const char* filename, int mode) +{ + return _access_s(filename, mode); +} + +int _cdecl _taccess_s(const wchar_t* filename, int mode) +{ + return _waccess_s(filename, mode); +} + +char* __cdecl _tgetenv(_In_z_ char const* _VarName) +{ + return getenv(_VarName); +} + +wchar_t* __cdecl _tgetenv(_In_z_ wchar_t const* _VarName) +{ + return _wgetenv(_VarName); +} + +intptr_t __cdecl _tspawnve(int flags, const char* name, const char* const* argv, + const char* const* envv) +{ + return _spawnve(flags, name, argv, envv); +} + +intptr_t __cdecl _tspawnve(int flags, const wchar_t* name, const wchar_t* const* argv, + const wchar_t* const* envv) +{ + return _wspawnve(flags, name, argv, envv); +} + +intptr_t __cdecl _tspawnvpe(int flags, const char* name, const char* const* argv, + const char* const* envv) +{ + return _spawnvpe(flags, name, argv, envv); +} + +intptr_t __cdecl _tspawnvpe(int flags, const wchar_t* name, const wchar_t* const* argv, + const wchar_t* const* envv) +{ + return _wspawnvpe(flags, name, argv, envv); +} + +template +static int __cdecl common_system(Character const* const command) throw() +{ + static Character const comspec_name[] = { 'C', 'O', 'M', 'S', 'P', 'E', 'C', '\0' }; // "COMSPEC" + static Character const cmd_exe[] = { 'c', 'm', 'd', '.', 'e', 'x', 'e', '\0' }; // "cmd.exe" + static Character const slash_c[] = { '/', 'c', '\0' }; // "/c" + + Character const * comspec_value = _tgetenv(comspec_name); + + // If the command is null, return TRUE only if %COMSPEC% is set and the file + // to which it points exists. + if (!command) + { + if (!comspec_value) + return 0; + + return _taccess_s(comspec_value, 0) == 0; + } + + Character const* arguments[4] = + { + comspec_value, + slash_c, + command, + nullptr + }; + + if (comspec_value) + { + errno_t const saved_errno = errno; + errno = 0; + + int const result = static_cast(_tspawnve(_P_WAIT, arguments[0], arguments, nullptr)); + if (result != -1) + { + errno = saved_errno; + return result; + } + + if (errno != ENOENT && errno != EACCES) + { + return result; + } + + // If the error wasn't one of those two errors, try again with cmd.exe... + errno = saved_errno; + } + + arguments[0] = cmd_exe; + return static_cast(_tspawnvpe(_P_WAIT, arguments[0], arguments, nullptr)); + + return 0; +} + +extern "C" int __cdecl system(char const* const command) +{ + return common_system(command); +} + +extern "C" int __cdecl _wsystem(wchar_t const* const command) +{ + return common_system(command); +}