mirror of
https://github.com/ceph/ceph
synced 2026-08-01 22:45:39 +00:00
common: Windows Unicode CLI support
Windows CLI arguments use either ANSI (main()) or UTF-16 (wmain()).
Meanwhile, Ceph libraries expect UTF-8 and raise exceptions when
trying to use Unicode CLI arguments or log Unicode output:
rbd.exe create test_unicode_șțăâ --size=32M
terminate called after throwing an instance of 'std::runtime_error'
what(): invalid utf8
We'll use a Windows application manifest, setting the "activeCodePage"
property [1][2]. This enables the Windows UCRT UTF-8 mode so that
functions that receive char* arguments will expect UTF-8 instead of ANSI,
including main(). One exception is CreateProcess, which will need the
UTF-16 form (CreateProcessW).
Despite the locale being set to utf-8, we'll have to explicitly set
the console output to utf-8 using SetConsoleOutputCP(CP_UTF8).
In order to use the UTF-8 locale, we'll have to switch the mingw-llvm
runtime from msvcrt to ucrt.
This also fixes ceph-dokan crashes that currently occur when non-ANSI
paths are logged.
[1] https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests#activecodepage
[2] https://learn.microsoft.com/en-us/windows/apps/design/globalizing/use-utf8-code-page
Signed-off-by: Lucian Petrut <lpetrut@cloudbasesolutions.com>
This commit is contained in:
parent
e877333f07
commit
750a9483d1
@ -129,8 +129,8 @@ EOL
|
||||
if [[ -n $USE_MINGW_LLVM ]]; then
|
||||
cat >> $MINGW_CMAKE_FILE <<EOL
|
||||
add_definitions(-I$mingwX64IncludeDir)
|
||||
add_definitions(-march=native)
|
||||
add_definitions(-Wno-unknown-attributes)
|
||||
add_compile_options(-march=native)
|
||||
add_compile_options(-Wno-unknown-attributes)
|
||||
EOL
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
|
||||
#include "common/SubProcess.h"
|
||||
#include "common/errno.h"
|
||||
#include "common/win32/wstring.h"
|
||||
#include "include/ceph_assert.h"
|
||||
#include "include/compat.h"
|
||||
|
||||
@ -174,8 +175,9 @@ int SubProcess::spawn() {
|
||||
for (auto& arg : cmd_args) {
|
||||
cmdline << " " << std::quoted(arg);
|
||||
}
|
||||
std::wstring cmdline_w = to_wstring(cmdline.str());
|
||||
|
||||
STARTUPINFO si = {0};
|
||||
STARTUPINFOW si = {0};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
SECURITY_ATTRIBUTES sa = {0};
|
||||
|
||||
@ -224,8 +226,8 @@ int SubProcess::spawn() {
|
||||
// We've transfered ownership from those handles.
|
||||
stdin_w = stdout_r = stderr_r = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (!CreateProcess(
|
||||
NULL, const_cast<char*>(cmdline.str().c_str()),
|
||||
if (!CreateProcessW(
|
||||
NULL, const_cast<wchar_t*>(cmdline_w.c_str()),
|
||||
NULL, NULL, /* No special security attributes */
|
||||
1, /* Inherit handles marked as inheritable */
|
||||
0, /* No special flags */
|
||||
|
||||
8
src/common/win32/code_page.manifest
Normal file
8
src/common/win32/code_page.manifest
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<application>
|
||||
<windowsSettings>
|
||||
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
2
src/common/win32/code_page.rc
Normal file
2
src/common/win32/code_page.rc
Normal file
@ -0,0 +1,2 @@
|
||||
#include <winuser.h>
|
||||
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "code_page.manifest"
|
||||
@ -2,7 +2,8 @@ set(ceph_dokan_srcs
|
||||
ceph_dokan.cc
|
||||
dbg.cc
|
||||
utils.cc
|
||||
options.cc)
|
||||
options.cc
|
||||
../common/win32/code_page.rc)
|
||||
add_executable(ceph-dokan ${ceph_dokan_srcs})
|
||||
target_link_libraries(ceph-dokan ${DOKAN_LIBRARIES}
|
||||
${GSSAPI_LIBRARIES}
|
||||
|
||||
@ -1043,6 +1043,8 @@ boost::intrusive_ptr<CephContext> do_global_init(
|
||||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
|
||||
if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE)) {
|
||||
cerr << "Couldn't initialize console event handler." << std::endl;
|
||||
return -EINVAL;
|
||||
|
||||
@ -6,6 +6,9 @@ set(rados_srcs
|
||||
${PROJECT_SOURCE_DIR}/src/common/util.cc
|
||||
${PROJECT_SOURCE_DIR}/src/common/obj_bencher.cc
|
||||
${PROJECT_SOURCE_DIR}/src/osd/ECUtil.cc)
|
||||
if(WIN32)
|
||||
list(APPEND rados_srcs ../common/win32/code_page.rc)
|
||||
endif()
|
||||
add_executable(rados ${rados_srcs})
|
||||
|
||||
target_link_libraries(rados librados global ${BLKID_LIBRARIES} ${CMAKE_DL_LIBS})
|
||||
|
||||
@ -4047,6 +4047,9 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
auto args = argv_to_vec(argc, argv);
|
||||
if (args.empty()) {
|
||||
cerr << argv[0] << ": -h or --help for usage" << std::endl;
|
||||
|
||||
@ -55,6 +55,9 @@ set(rbd_srcs
|
||||
action/Ubbd.cc
|
||||
action/Watch.cc
|
||||
action/Wnbd.cc)
|
||||
if(WIN32)
|
||||
list(APPEND rbd_srcs ../../common/win32/code_page.rc)
|
||||
endif()
|
||||
|
||||
add_executable(rbd ${rbd_srcs}
|
||||
$<TARGET_OBJECTS:common_texttable_obj>)
|
||||
|
||||
@ -5,6 +5,9 @@
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
rbd::Shell shell;
|
||||
return shell.execute(argc, argv);
|
||||
}
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
add_executable(rbd-wnbd rbd_wnbd.cc wnbd_handler.cc wnbd_wmi.cc)
|
||||
add_executable(
|
||||
rbd-wnbd
|
||||
rbd_wnbd.cc wnbd_handler.cc wnbd_wmi.cc
|
||||
../../common/win32/code_page.rc)
|
||||
set_target_properties(
|
||||
rbd-wnbd PROPERTIES COMPILE_FLAGS
|
||||
"-fpermissive -I${WNBD_INCLUDE_DIRS}")
|
||||
|
||||
@ -331,7 +331,7 @@ int send_map_request(std::string arguments) {
|
||||
// which will allow it to communicate the mapping status
|
||||
int map_device_using_suprocess(std::string arguments, int timeout_ms)
|
||||
{
|
||||
STARTUPINFO si;
|
||||
STARTUPINFOW si;
|
||||
PROCESS_INFORMATION pi;
|
||||
char ch;
|
||||
DWORD err = 0, status = 0;
|
||||
@ -407,9 +407,10 @@ int map_device_using_suprocess(std::string arguments, int timeout_ms)
|
||||
|
||||
dout(5) << __func__ << ": command line: " << command_line.str() << dendl;
|
||||
|
||||
GetStartupInfo(&si);
|
||||
GetStartupInfoW(&si);
|
||||
// Create a detached child
|
||||
if (!CreateProcess(NULL, (char*)command_line.str().c_str(),
|
||||
if (!CreateProcessW(
|
||||
NULL, const_cast<wchar_t*>(to_wstring(command_line.str()).c_str()),
|
||||
NULL, NULL, FALSE, DETACHED_PROCESS,
|
||||
NULL, NULL, &si, &pi)) {
|
||||
err = GetLastError();
|
||||
@ -1904,6 +1905,8 @@ int main(int argc, const char *argv[])
|
||||
SetConsoleCtrlHandler(console_handler_routine, true);
|
||||
// Avoid the Windows Error Reporting dialog.
|
||||
SetErrorMode(GetErrorMode() | SEM_NOGPFAULTERRORBOX);
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
|
||||
int r = rbd_wnbd(argc, argv);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
|
||||
@ -40,8 +40,8 @@ dokanTag="v2.0.5.1000"
|
||||
dokanSrcDir="${depsSrcDir}/dokany"
|
||||
dokanLibDir="${depsToolsetDir}/dokany/lib"
|
||||
|
||||
mingwLlvmUrl="https://github.com/mstorsjo/llvm-mingw/releases/download/20230320/llvm-mingw-20230320-msvcrt-ubuntu-18.04-x86_64.tar.xz"
|
||||
mingwLlvmSha256Sum="bc97745e702fb9e8f2a16f7d09dd5061ceeef16554dd12e542f619ce937e8d7a"
|
||||
mingwLlvmUrl="https://github.com/mstorsjo/llvm-mingw/releases/download/20230320/llvm-mingw-20230320-ucrt-ubuntu-18.04-x86_64.tar.xz"
|
||||
mingwLlvmSha256Sum="bc367753dea829d219be32e2e64e2d15d03158ce8e700ae5210ca3d78e6a07ea"
|
||||
mingwLlvmDir="${DEPS_DIR}/mingw-llvm"
|
||||
|
||||
function _make() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user