Skip to content

Commit

Permalink
common: Windows Unicode CLI support
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
petrutlucian94 committed Nov 22, 2023
1 parent e877333 commit 750a948
Show file tree
Hide file tree
Showing 13 changed files with 47 additions and 14 deletions.
4 changes: 2 additions & 2 deletions mingw_conf.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 5 additions & 3 deletions src/common/win32/SubProcess.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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};

Expand Down Expand Up @@ -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 */
Expand Down
8 changes: 8 additions & 0 deletions src/common/win32/code_page.manifest
Original file line number Diff line number Diff line change
@@ -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 changes: 2 additions & 0 deletions src/common/win32/code_page.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include <winuser.h>
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "code_page.manifest"
3 changes: 2 additions & 1 deletion src/dokan/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
2 changes: 2 additions & 0 deletions src/dokan/ceph_dokan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions src/tools/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down
3 changes: 3 additions & 0 deletions src/tools/rados/rados.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions src/tools/rbd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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>)
Expand Down
3 changes: 3 additions & 0 deletions src/tools/rbd/rbd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
5 changes: 4 additions & 1 deletion src/tools/rbd_wnbd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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}")
Expand Down
13 changes: 8 additions & 5 deletions src/tools/rbd_wnbd/rbd_wnbd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -407,11 +407,12 @@ 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(),
NULL, NULL, FALSE, DETACHED_PROCESS,
NULL, NULL, &si, &pi)) {
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();
derr << "CreateProcess failed: " << win32_strerror(err) << dendl;
exit_code = -ECHILD;
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions win32_deps_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down

0 comments on commit 750a948

Please sign in to comment.