diff --git a/libtransmission/file-win32.cc b/libtransmission/file-win32.cc index 656a45a9b..a6fb06633 100644 --- a/libtransmission/file-win32.cc +++ b/libtransmission/file-win32.cc @@ -5,8 +5,8 @@ #include #include -#include -#include /* isalpha() */ +#include // for isalpha() +#include #include #include /* SHCreateDirectoryEx() */ @@ -145,88 +145,61 @@ static bool is_valid_path(std::string_view path) return path.find_first_of("<>:\"|?*"sv) == path.npos; } -static wchar_t* path_to_native_path(char const* path) +namespace { - if (path == nullptr) +namespace path_to_native_path_helpers +{ + +auto path_to_fixed_native_path(std::string_view path) +{ + auto wide_path = tr_win32_utf8_to_native(path); + + // convert '/' to '\' + static auto constexpr Convert = [](wchar_t wch) { - return nullptr; - } + return wch == L'/' ? L'\\' : wch; + }; + std::transform(std::begin(wide_path), std::end(wide_path), std::begin(wide_path), Convert); - /* Extending maximum path length limit up to ~32K. See "Naming Files, Paths, and Namespaces" - (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx) for more info */ - - bool const is_relative = tr_sys_path_is_relative(path); - bool const is_unc = is_unc_path(path); - - /* `-2` for UNC since we overwrite existing prefix slashes */ - int const extra_chars_before = is_relative ? - 0 : - (is_unc ? TR_N_ELEMENTS(native_unc_path_prefix) - 2 : TR_N_ELEMENTS(native_local_path_prefix)); - - /* TODO (?): TR_ASSERT(!is_relative); */ - - int real_result_size = 0; - wchar_t* const wide_path = tr_win32_utf8_to_native_ex(path, -1, extra_chars_before, 0, &real_result_size); - - if (wide_path == nullptr) + // squash multiple consecutive separators into one to avoid ERROR_INVALID_NAME + static auto constexpr Equal = [](wchar_t a, wchar_t b) { - return nullptr; - } - - real_result_size += extra_chars_before; - - /* Relative paths cannot be used with "\\?\" prefixes. This also means that relative paths are - limited to ~260 chars... but we should rarely work with relative paths in the first place */ - if (!is_relative) - { - if (is_unc) - { - /* UNC path: "\\server\share" -> "\\?\UNC\server\share" */ - memcpy(wide_path, native_unc_path_prefix, sizeof(native_unc_path_prefix)); - } - else - { - /* Local path: "C:" -> "\\?\C:" */ - memcpy(wide_path, native_local_path_prefix, sizeof(native_local_path_prefix)); - } - } - - /* Automatic '/' to '\' conversion is disabled for "\\?\"-prefixed paths */ - wchar_t* p = wide_path + extra_chars_before; - - while ((p = wcschr(p, L'/')) != nullptr) - { - *p++ = L'\\'; - } - - /* Squash multiple consecutive path separators into one to avoid ERROR_INVALID_NAME */ - wchar_t* first_conseq_sep = wide_path + extra_chars_before; - - while ((first_conseq_sep = std::wcsstr(first_conseq_sep, L"\\\\")) != nullptr) - { - wchar_t const* last_conseq_sep = first_conseq_sep + 1; - while (*(last_conseq_sep + 1) == L'\\') - { - ++last_conseq_sep; - } - - std::copy_n(last_conseq_sep, real_result_size - (last_conseq_sep - wide_path) + 1, first_conseq_sep); - real_result_size -= last_conseq_sep - first_conseq_sep; - } + return a == b && a == L'\\'; + }; + auto const tmp = wide_path; + wide_path.clear(); + std::unique_copy(std::begin(tmp), std::end(tmp), std::back_inserter(wide_path), Equal); return wide_path; } -static std::wstring path_to_native_path_wstr(std::string_view path) +} // namespace path_to_native_path_helpers +} // namespace + +/* Extending maximum path length limit up to ~32K. See "Naming Files, Paths, and Namespaces" + https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx for more info */ +static auto path_to_native_path(std::string_view path) { - if (auto* const rawptr = path_to_native_path(tr_pathbuf{ path }); rawptr != nullptr) + using namespace path_to_native_path_helpers; + + if (is_unc_path(path)) { - auto ret = std::wstring{ rawptr }; - tr_free(rawptr); - return ret; + // UNC path: "\\server\share" -> "\\?\UNC\server\share" + path.remove_prefix(2); // remove path's UNC prefix slashes + auto wide_path = path_to_fixed_native_path(path); + wide_path.insert(0, NativeUncPathPrefix); + return wide_path; } - return {}; + if (!tr_sys_path_is_relative(path)) + { + // local path: "C:" -> "\\?\C:" + auto wide_path = path_to_fixed_native_path(path); + wide_path.insert(0, NativeLocalPathPrefix); + return wide_path; + } + + return path_to_fixed_native_path(path); } static std::string native_path_to_path(std::wstring_view wide_path) @@ -257,7 +230,7 @@ static tr_sys_file_t open_file(std::string_view path, DWORD access, DWORD dispos { tr_sys_file_t ret = TR_BAD_SYS_FILE; - if (auto const wide_path = path_to_native_path_wstr(path); !std::empty(wide_path)) + if (auto const wide_path = path_to_native_path(path); !std::empty(wide_path)) { ret = CreateFileW( wide_path.c_str(), @@ -281,7 +254,7 @@ static bool create_dir(std::string_view path, int flags, int /*permissions*/, bo { bool ret; DWORD error_code = ERROR_SUCCESS; - auto const wide_path = path_to_native_path_wstr(path); + auto const wide_path = path_to_native_path(path); if ((flags & TR_SYS_DIR_CREATE_PARENTS) != 0) { @@ -374,7 +347,7 @@ bool tr_sys_path_exists(char const* path, tr_error** error) bool ret = false; HANDLE handle = INVALID_HANDLE_VALUE; - if (auto const wide_path = path_to_native_path_wstr(path); !std::empty(wide_path)) + if (auto const wide_path = path_to_native_path(path); !std::empty(wide_path)) { DWORD attributes = GetFileAttributesW(wide_path.c_str()); @@ -407,7 +380,7 @@ bool tr_sys_path_exists(char const* path, tr_error** error) std::optional tr_sys_path_get_info(std::string_view path, int flags, tr_error** error) { - if (auto const wide_path = path_to_native_path_wstr(path); std::empty(wide_path)) + if (auto const wide_path = path_to_native_path(path); std::empty(wide_path)) { // do nothing } @@ -469,8 +442,8 @@ bool tr_sys_path_is_same(char const* path1, char const* path2, tr_error** error) HANDLE handle2 = INVALID_HANDLE_VALUE; BY_HANDLE_FILE_INFORMATION fi1, fi2; - auto const wide_path1 = path_to_native_path_wstr(path1); - auto const wide_path2 = path_to_native_path_wstr(path2); + auto const wide_path1 = path_to_native_path(path1); + auto const wide_path2 = path_to_native_path(path2); if (std::empty(wide_path1) || std::empty(wide_path2)) { @@ -517,7 +490,7 @@ std::string tr_sys_path_resolve(std::string_view path, tr_error** error) { auto ret = std::string{}; - if (auto const wide_path = path_to_native_path_wstr(path); !std::empty(wide_path)) + if (auto const wide_path = path_to_native_path(path); !std::empty(wide_path)) { if (auto const handle = CreateFileW( wide_path.c_str(), @@ -726,8 +699,8 @@ bool tr_sys_path_rename(char const* src_path, char const* dst_path, tr_error** e TR_ASSERT(dst_path != nullptr); bool ret = false; - auto const wide_src_path = path_to_native_path_wstr(src_path); - auto const wide_dst_path = path_to_native_path_wstr(dst_path); + auto const wide_src_path = path_to_native_path(src_path); + auto const wide_dst_path = path_to_native_path(dst_path); if (!std::empty(wide_src_path) && !std::empty(wide_dst_path)) { @@ -766,8 +739,8 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err TR_ASSERT(src_path != nullptr); TR_ASSERT(dst_path != nullptr); - auto const wide_src_path = path_to_native_path_wstr(src_path); - auto const wide_dst_path = path_to_native_path_wstr(dst_path); + auto const wide_src_path = path_to_native_path(src_path); + auto const wide_dst_path = path_to_native_path(dst_path); if (std::empty(wide_src_path) || std::empty(wide_dst_path)) { set_system_error(error, ERROR_INVALID_PARAMETER); @@ -791,7 +764,7 @@ bool tr_sys_path_remove(char const* path, tr_error** error) bool ret = false; - if (auto const wide_path = path_to_native_path_wstr(path); !std::empty(wide_path)) + if (auto const wide_path = path_to_native_path(path); !std::empty(wide_path)) { DWORD const attributes = GetFileAttributesW(wide_path.c_str()); @@ -1367,7 +1340,7 @@ tr_sys_dir_t tr_sys_dir_open(char const* path, tr_error** error) static_assert(TR_BAD_SYS_DIR == nullptr, "values should match"); #endif - auto pattern = path_to_native_path_wstr(path); + auto pattern = path_to_native_path(path); if (std::empty(pattern)) { set_system_error(error, GetLastError()); diff --git a/libtransmission/subprocess-posix.cc b/libtransmission/subprocess-posix.cc index 042f445a6..01816344c 100644 --- a/libtransmission/subprocess-posix.cc +++ b/libtransmission/subprocess-posix.cc @@ -16,10 +16,12 @@ #include #include "transmission.h" + #include "error.h" #include "subprocess.h" #include "tr-assert.h" #include "tr-macros.h" +#include "tr-strbuf.h" #include "utils.h" using namespace std::literals; @@ -50,7 +52,7 @@ static void set_system_error(tr_error** error, int code, std::string_view what) static bool tr_spawn_async_in_child( char const* const* cmd, std::map const& env, - char const* work_dir, + std::string_view work_dir, int pipe_fd) { auto key_sz = std::string{}; @@ -67,7 +69,7 @@ static bool tr_spawn_async_in_child( } } - if (work_dir != nullptr && chdir(work_dir) == -1) + if (!std::empty(work_dir) && chdir(tr_pathbuf{ work_dir }) == -1) { goto FAIL; } @@ -120,7 +122,7 @@ static bool tr_spawn_async_in_parent(int pipe_fd, tr_error** error) bool tr_spawn_async( char const* const* cmd, std::map const& env, - char const* work_dir, + std::string_view work_dir, tr_error** error) { static bool sigchld_handler_set = false; diff --git a/libtransmission/subprocess-win32.cc b/libtransmission/subprocess-win32.cc index 7c6e28177..7f01abfe4 100644 --- a/libtransmission/subprocess-win32.cc +++ b/libtransmission/subprocess-win32.cc @@ -9,9 +9,11 @@ #include #include #include +#include #include #include +#include // for wchar_t support #include @@ -23,13 +25,16 @@ using namespace std::literals; -enum tr_app_type +namespace { - TR_APP_TYPE_EXE, - TR_APP_TYPE_BATCH + +enum class tr_app_type +{ + EXE, + BATCH }; -static void set_system_error(tr_error** error, DWORD code, std::string_view what) +void set_system_error(tr_error** error, DWORD code, std::string_view what) { if (error == nullptr) { @@ -46,206 +51,97 @@ static void set_system_error(tr_error** error, DWORD code, std::string_view what } } -static void append_to_env_block(wchar_t** env_block, size_t* env_block_len, wchar_t const* part, size_t part_len) +// "The sort is case-insensitive, Unicode order, without regard to locale" © MSDN +class WStrICompare { - *env_block = tr_renew(wchar_t, *env_block, *env_block_len + part_len + 1); - wmemcpy(*env_block + *env_block_len, part, part_len); - *env_block_len += part_len; -} - -static bool parse_env_block_part(wchar_t const* part, size_t* full_len, size_t* name_len) -{ - TR_ASSERT(part != nullptr); - - auto const* const equals_pos = wcschr(part, L'='); - - if (equals_pos == nullptr) +public: + [[nodiscard]] auto compare(std::wstring_view a, std::wstring_view b) const noexcept // <=> { - /* Invalid part */ - return false; - } + int diff = wcsnicmp(std::data(a), std::data(b), std::min(std::size(a), std::size(b))); - ptrdiff_t const my_name_len = equals_pos - part; - - if (my_name_len > SIZE_MAX) - { - /* Invalid part */ - return false; - } - - if (full_len != nullptr) - { - /* Includes terminating '\0' */ - *full_len = wcslen(part) + 1; - } - - if (name_len != nullptr) - { - *name_len = (size_t)my_name_len; - } - - return true; -} - -static int compare_wide_strings_ci(wchar_t const* lhs, size_t lhs_len, wchar_t const* rhs, size_t rhs_len) -{ - int diff = wcsnicmp(lhs, rhs, std::min(lhs_len, rhs_len)); - - if (diff == 0) - { - diff = lhs_len < rhs_len ? -1 : (lhs_len > rhs_len ? 1 : 0); - } - - return diff; -} - -static int compare_env_part_names(void const* vlhs, void const* vrhs) -{ - int ret = 0; - auto const* const* const lhs = reinterpret_cast(vlhs); - auto const* const* const rhs = reinterpret_cast(vrhs); - - size_t lhs_part_len; - size_t lhs_name_len; - - if (parse_env_block_part(*lhs, &lhs_part_len, &lhs_name_len)) - { - size_t rhs_part_len; - size_t rhs_name_len; - - if (parse_env_block_part(*rhs, &rhs_part_len, &rhs_name_len)) + if (diff == 0) { - ret = compare_wide_strings_ci(*lhs, lhs_name_len, *rhs, rhs_name_len); + diff = std::size(a) < std::size(b) ? -1 : (std::size(a) > std::size(b) ? 1 : 0); } + + return diff; } + [[nodiscard]] auto operator()(std::wstring_view a, std::wstring_view b) const noexcept // < + { + return compare(a, b) < 0; + } +}; + +using SortedWideEnv = std::map; + +/* + * Var1=Value1\0 + * Var2=Value2\0 + * Var3=Value3\0 + * ... + * VarN=ValueN\0\0 + */ +auto to_env_string(SortedWideEnv const& wide_env) +{ + auto ret = std::vector{}; + + for (auto const& [key, val] : wide_env) + { + fmt::format_to(std::back_inserter(ret), FMT_STRING(L"{:s}={:s}"), key, val); + ret.insert(std::end(ret), L'\0'); + } + + ret.insert(std::end(ret), L'\0'); + return ret; } -static wchar_t** to_wide_env(std::map const& env) +/* + * Var1=Value1\0 + * Var2=Value2\0 + * Var3=Value3\0 + * ... + * VarN=ValueN\0\0 + */ +auto parse_env_string(wchar_t const* env) { - auto const part_count = std::size(env); - wchar_t** const wide_env = tr_new(wchar_t*, part_count + 1); + auto sorted = SortedWideEnv{}; - int i = 0; - for (auto const& [key, val] : env) + for (;;) { - auto const line = fmt::format(FMT_STRING("{:s}={:s}"), key, val); - wide_env[i++] = tr_win32_utf8_to_native(std::data(line), std::size(line)); - } - wide_env[i] = nullptr; - TR_ASSERT(i == part_count); - - /* "The sort is case-insensitive, Unicode order, without regard to locale" © MSDN */ - qsort(wide_env, part_count, sizeof(wchar_t*), &compare_env_part_names); - - return wide_env; -} - -static void tr_free_ptrv(void* const* p) -{ - if (p == nullptr) - { - return; - } - - while (*p != nullptr) - { - tr_free(*p); - ++p; - } -} - -static bool create_env_block(std::map const& env, wchar_t** env_block, tr_error** error) -{ - wchar_t** wide_env = to_wide_env(env); - - if (wide_env == nullptr) - { - *env_block = nullptr; - return true; - } - - wchar_t* const old_env_block = GetEnvironmentStringsW(); - - if (old_env_block == nullptr) - { - set_system_error(error, GetLastError(), "Call to GetEnvironmentStrings()"); - return false; - } - - *env_block = nullptr; - - wchar_t const* old_part = old_env_block; - size_t env_block_len = 0; - - for (size_t i = 0; wide_env[i] != nullptr; ++i) - { - wchar_t const* const part = wide_env[i]; - - size_t part_len; - size_t name_len; - - if (!parse_env_block_part(part, &part_len, &name_len)) + auto const line = std::wstring_view{ env }; + if (std::empty(line)) { - continue; + break; } - while (*old_part != L'\0') + if (auto const pos = line.find(L'='); pos != std::string_view::npos) { - size_t old_part_len; - size_t old_name_len; - - if (!parse_env_block_part(old_part, &old_part_len, &old_name_len)) - { - continue; - } - - int const name_diff = compare_wide_strings_ci(old_part, old_name_len, part, name_len); - - if (name_diff < 0) - { - append_to_env_block(env_block, &env_block_len, old_part, old_part_len); - } - - if (name_diff <= 0) - { - old_part += old_part_len; - } - - if (name_diff >= 0) - { - break; - } + sorted.insert_or_assign(std::wstring{ line.substr(0, pos) }, std::wstring{ line.substr(pos + 1) }); } - append_to_env_block(env_block, &env_block_len, part, part_len); + env += std::size(line) + 1 /*'\0'*/; } - while (*old_part != L'\0') - { - size_t old_part_len; - - if (!parse_env_block_part(old_part, &old_part_len, nullptr)) - { - continue; - } - - append_to_env_block(env_block, &env_block_len, old_part, old_part_len); - old_part += old_part_len; - } - - (*env_block)[env_block_len] = '\0'; - - FreeEnvironmentStringsW(old_env_block); - - tr_free_ptrv((void* const*)wide_env); - tr_free(wide_env); - - return true; + return sorted; } -static void append_argument(char** arguments, char const* argument) +auto get_current_env() +{ + auto env = SortedWideEnv{}; + + if (auto* pwch = GetEnvironmentStringsW(); pwch != nullptr) + { + env = parse_env_string(pwch); + + FreeEnvironmentStringsW(pwch); + } + + return env; +} + +void append_argument(char** arguments, char const* argument) { size_t arguments_len = *arguments != nullptr ? strlen(*arguments) : 0u; size_t const argument_len = strlen(argument); @@ -304,7 +200,7 @@ static void append_argument(char** arguments, char const* argument) *(dst++) = '\0'; } -static bool contains_batch_metachars(char const* text) +bool contains_batch_metachars(char const* text) { /* First part - chars explicitly documented by `cmd.exe /?` as "special" */ return strpbrk( @@ -313,26 +209,28 @@ static bool contains_batch_metachars(char const* text) "%!^\"") != nullptr; } -static enum tr_app_type get_app_type(char const* app) +auto get_app_type(char const* app) { - if (tr_str_has_suffix(app, ".cmd") || tr_str_has_suffix(app, ".bat")) + auto const lower = tr_strlower(app); + + if (tr_strvEndsWith(lower, ".cmd") || tr_strvEndsWith(lower, ".bat")) { - return TR_APP_TYPE_BATCH; + return tr_app_type::BATCH; } /* TODO: Support other types? */ - return TR_APP_TYPE_EXE; + return tr_app_type::EXE; } -static void append_app_launcher_arguments(enum tr_app_type app_type, char** args) +void append_app_launcher_arguments(tr_app_type app_type, char** args) { switch (app_type) { - case TR_APP_TYPE_EXE: + case tr_app_type::EXE: break; - case TR_APP_TYPE_BATCH: + case tr_app_type::BATCH: append_argument(args, "cmd.exe"); append_argument(args, "/d"); append_argument(args, "/e:off"); @@ -342,64 +240,65 @@ static void append_app_launcher_arguments(enum tr_app_type app_type, char** args break; default: - TR_ASSERT_MSG(false, fmt::format(FMT_STRING("unsupported application type {:d}"), app_type)); + TR_ASSERT_MSG(false, "unsupported application type"); break; } } -static bool construct_cmd_line(char const* const* cmd, wchar_t** cmd_line) +std::wstring construct_cmd_line(char const* const* cmd) { - enum tr_app_type const app_type = get_app_type(cmd[0]); + auto const app_type = get_app_type(cmd[0]); char* args = nullptr; - size_t arg_count = 0; - bool ret = false; append_app_launcher_arguments(app_type, &args); for (size_t i = 0; cmd[i] != nullptr; ++i) { - if (app_type == TR_APP_TYPE_BATCH && i > 0 && contains_batch_metachars(cmd[i])) + if (app_type == tr_app_type::BATCH && i > 0 && contains_batch_metachars(cmd[i])) { /* FIXME: My attempts to escape them one or another way didn't lead to anything good so far */ - goto cleanup; + tr_free(args); + args = nullptr; + break; } append_argument(&args, cmd[i]); - ++arg_count; } - *cmd_line = args != nullptr ? tr_win32_utf8_to_native(args, -1) : nullptr; + if (args != nullptr) + { + auto cmd_line = tr_win32_utf8_to_native(args); + tr_free(args); + return cmd_line; + } - ret = true; - -cleanup: - tr_free(args); - return ret; + return {}; } +} // namespace + bool tr_spawn_async( char const* const* cmd, std::map const& env, - char const* work_dir, + std::string_view work_dir, tr_error** error) { - wchar_t* env_block = nullptr; - - if (!create_env_block(env, &env_block, error)) + // full_env = current_env + env; + auto full_env = get_current_env(); + for (auto const& [key, val] : env) { - return false; + full_env.insert_or_assign(tr_win32_utf8_to_native(key), tr_win32_utf8_to_native(val)); } - wchar_t* cmd_line; - - if (!construct_cmd_line(cmd, &cmd_line)) + auto cmd_line = construct_cmd_line(cmd); + if (std::empty(cmd_line)) { set_system_error(error, ERROR_INVALID_PARAMETER, "Constructing command line"); return false; } - wchar_t* current_dir = work_dir != nullptr ? tr_win32_utf8_to_native(work_dir, -1) : nullptr; + auto const current_dir = tr_win32_utf8_to_native(work_dir); auto si = STARTUPINFOW{}; si.cb = sizeof(si); @@ -410,13 +309,13 @@ bool tr_spawn_async( bool const ret = CreateProcessW( nullptr, - cmd_line, + std::data(cmd_line), nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW | CREATE_DEFAULT_ERROR_MODE, - env_block, - current_dir, + std::empty(full_env) ? nullptr : to_env_string(full_env).data(), + std::empty(current_dir) ? nullptr : current_dir.c_str(), &si, &pi); @@ -430,9 +329,5 @@ bool tr_spawn_async( set_system_error(error, GetLastError(), "Call to CreateProcess()"); } - tr_free(current_dir); - tr_free(cmd_line); - tr_free(env_block); - return ret; } diff --git a/libtransmission/subprocess.h b/libtransmission/subprocess.h index 33b14a23e..7dd8bec4e 100644 --- a/libtransmission/subprocess.h +++ b/libtransmission/subprocess.h @@ -13,5 +13,5 @@ struct tr_error; bool tr_spawn_async( char const* const* cmd, std::map const& env, - char const* work_dir, + std::string_view work_dir, tr_error** error); diff --git a/libtransmission/utils.cc b/libtransmission/utils.cc index 3993d4e22..80dc05e91 100644 --- a/libtransmission/utils.cc +++ b/libtransmission/utils.cc @@ -521,7 +521,7 @@ std::string tr_win32_native_to_utf8(std::wstring_view in) return out; } -char* tr_win32_native_to_utf8(wchar_t const* text, int text_size) +static char* tr_win32_native_to_utf8(wchar_t const* text, int text_size) { if (text == nullptr) { @@ -545,56 +545,6 @@ std::wstring tr_win32_utf8_to_native(std::string_view in) return out; } -wchar_t* tr_win32_utf8_to_native(char const* text, int text_size) -{ - return tr_win32_utf8_to_native_ex(text, text_size, 0, 0, nullptr); -} - -wchar_t* tr_win32_utf8_to_native_ex( - char const* text, - int text_size, - int extra_chars_before, - int extra_chars_after, - int* real_result_size) -{ - wchar_t* ret = nullptr; - int size; - - if (text_size == -1) - { - text_size = strlen(text); - } - - size = MultiByteToWideChar(CP_UTF8, 0, text, text_size, nullptr, 0); - - if (size == 0) - { - goto fail; - } - - ret = tr_new(wchar_t, size + extra_chars_before + extra_chars_after + 1); - size = MultiByteToWideChar(CP_UTF8, 0, text, text_size, ret + extra_chars_before, size); - - if (size == 0) - { - goto fail; - } - - ret[size + extra_chars_before + extra_chars_after] = L'\0'; - - if (real_result_size != nullptr) - { - *real_result_size = size; - } - - return ret; - -fail: - tr_free(ret); - - return nullptr; -} - std::string tr_win32_format_message(uint32_t code) { wchar_t* wide_text = nullptr; @@ -630,7 +580,7 @@ std::string tr_win32_format_message(uint32_t code) return text; } -void tr_win32_make_args_utf8(int* argc, char*** argv) +static void tr_win32_make_args_utf8(int* argc, char*** argv) { int my_argc; wchar_t** my_wide_argv; diff --git a/libtransmission/utils.h b/libtransmission/utils.h index f69993114..c0e4fadf9 100644 --- a/libtransmission/utils.h +++ b/libtransmission/utils.h @@ -119,21 +119,10 @@ bool tr_utf8_validate(std::string_view sv, char const** good_end); #ifdef _WIN32 +std::string tr_win32_format_message(uint32_t code); std::string tr_win32_native_to_utf8(std::wstring_view); std::wstring tr_win32_utf8_to_native(std::string_view); -char* tr_win32_native_to_utf8(wchar_t const* text, int text_size); -wchar_t* tr_win32_utf8_to_native(char const* text, int text_size); -wchar_t* tr_win32_utf8_to_native_ex( - char const* text, - int text_size, - int extra_chars_before, - int extra_chars_after, - int* real_result_size); -std::string tr_win32_format_message(uint32_t code); - -void tr_win32_make_args_utf8(int* argc, char*** argv); - int tr_main_win32(int argc, char** argv, int (*real_main)(int, char**)); #define tr_main(...) \ diff --git a/libtransmission/variant-benc.cc b/libtransmission/variant-benc.cc index 06635be76..09dae4d06 100644 --- a/libtransmission/variant-benc.cc +++ b/libtransmission/variant-benc.cc @@ -67,7 +67,8 @@ std::optional ParseInt(std::string_view* benc) } // leading zeroes are not allowed - if ((walk[0] == '0' && (isdigit(walk[1]) != 0)) || (walk[0] == '-' && walk[1] == '0' && (isdigit(walk[2]) != 0))) + if ((walk[0] == '0' && (isdigit(static_cast(walk[1])) != 0)) || + (walk[0] == '-' && walk[1] == '0' && (isdigit(static_cast(walk[2])) != 0))) { return {}; } diff --git a/tests/libtransmission/subprocess-test.cc b/tests/libtransmission/subprocess-test.cc index d45fbac0a..22b459759 100644 --- a/tests/libtransmission/subprocess-test.cc +++ b/tests/libtransmission/subprocess-test.cc @@ -87,7 +87,7 @@ TEST_P(SubprocessTest, SpawnAsyncMissingExec) auto args = std::array{ missing_exe_path.data(), nullptr }; tr_error* error = nullptr; - auto const ret = tr_spawn_async(std::data(args), {}, nullptr, &error); + auto const ret = tr_spawn_async(std::data(args), {}, {}, &error); EXPECT_FALSE(ret); EXPECT_NE(nullptr, error); EXPECT_NE(0, error->code); @@ -116,7 +116,7 @@ TEST_P(SubprocessTest, SpawnAsyncArgs) nullptr }; tr_error* error = nullptr; - bool const ret = tr_spawn_async(std::data(args), {}, nullptr, &error); + bool const ret = tr_spawn_async(std::data(args), {}, {}, &error); EXPECT_TRUE(ret) << args[0] << ' ' << args[1]; EXPECT_EQ(nullptr, error) << *error; @@ -197,7 +197,7 @@ TEST_P(SubprocessTest, SpawnAsyncEnv) setenv("ZOO", "tar", 1 /*true*/); // overridden tr_error* error = nullptr; - bool const ret = tr_spawn_async(std::data(args), env, nullptr, &error); + bool const ret = tr_spawn_async(std::data(args), env, {}, &error); EXPECT_TRUE(ret); EXPECT_EQ(nullptr, error) << *error; @@ -245,7 +245,7 @@ TEST_P(SubprocessTest, SpawnAsyncCwdExplicit) auto const args = std::array{ self_path_.c_str(), result_path.data(), arg_dump_cwd_.data(), nullptr }; tr_error* error = nullptr; - bool const ret = tr_spawn_async(std::data(args), {}, test_dir.c_str(), &error); + bool const ret = tr_spawn_async(std::data(args), {}, test_dir, &error); EXPECT_TRUE(ret); EXPECT_EQ(nullptr, error) << *error; @@ -273,7 +273,7 @@ TEST_P(SubprocessTest, SpawnAsyncCwdInherit) auto const args = std::array{ self_path_.c_str(), result_path.data(), arg_dump_cwd_.data(), nullptr }; tr_error* error = nullptr; - auto const ret = tr_spawn_async(std::data(args), {}, nullptr, &error); + auto const ret = tr_spawn_async(std::data(args), {}, {}, &error); EXPECT_TRUE(ret); EXPECT_EQ(nullptr, error) << *error;