Add CI configuration for clang-tidy on Windows (#6997)

* Add CI configuration for clang-tidy on Windows

* Fix issues reported by clang-tidy on Windows

* Workaround clang-tidy defects on Windows

* Fix C-style casts (which clang-tidy didn't report)
This commit is contained in:
Mike Gelfand 2024-07-16 22:13:29 +01:00 committed by GitHub
parent e334f3c37f
commit c21ee87eea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 331 additions and 218 deletions

View File

@ -0,0 +1,61 @@
name: Prepare Win32 build dependencies
inputs:
arch:
description: Architecture (x86, x64)
required: true
type:
description: Type (CoreDeps, Deps)
required: true
runs:
using: composite
steps:
- name: Get Build Tools
shell: pwsh
run: |
$DepsPrefix = (Join-Path (Get-Item .).Root.Name "${{ inputs.arch }}-prefix")
"DEPS_PREFIX=${DepsPrefix}" | Out-File $Env:GITHUB_ENV -Append
(Join-Path $DepsPrefix bin) | Out-File $Env:GITHUB_PATH -Append
choco install `
jom `
nasm `
nodejs
& "C:\Program Files\OpenSSL\unins000.exe" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- | Out-Host
(Join-Path $Env:ProgramFiles NASM) | Out-File $Env:GITHUB_PATH -Append
(Join-Path (Get-Item -Path "${Env:ProgramFiles(x86)}\WiX Toolset v3.*")[0].FullName bin) | Out-File $Env:GITHUB_PATH -Append
Install-Module -Name Pscx -RequiredVersion 4.0.0-beta4 -AllowPrerelease -Force
- name: Get Cache Key
id: cache-key
shell: pwsh
run: |
try {
$DepsHash = & (Join-Path . src release windows main.ps1) -Mode DepsHash -BuildArch ${{ inputs.arch }} -BuildPart ${{ inputs.type }}
"hash=${DepsHash}" | Out-File $Env:GITHUB_OUTPUT -Append
} catch {
Write-Error ("{1}{0}{2}{0}{3}" -f [Environment]::NewLine, $_.ToString(), $_.InvocationInfo.PositionMessage, $_.ScriptStackTrace) -ErrorAction Continue
exit 1
}
- name: Restore Cache
uses: actions/cache/restore@v4
id: restore-cache
with:
path: ${{ env.DEPS_PREFIX }}
key: ${{ github.job }}-${{ inputs.arch }}-${{ steps.cache-key.outputs.hash }}
- name: Build Dependencies
if: steps.restore-cache.outputs.cache-hit != 'true'
shell: pwsh
run: |
try {
& (Join-Path . src release windows main.ps1) -Mode Build -BuildArch ${{ inputs.arch }} -BuildPart ${{ inputs.type }}
} catch {
Write-Error ("{1}{0}{2}{0}{3}" -f [Environment]::NewLine, $_.ToString(), $_.InvocationInfo.PositionMessage, $_.ScriptStackTrace) -ErrorAction Continue
exit 1
}
- name: Save Cache
if: steps.restore-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
id: cache
with:
path: ${{ env.DEPS_PREFIX }}
key: ${{ github.job }}-${{ inputs.arch }}-${{ steps.cache-key.outputs.hash }}

View File

@ -272,6 +272,43 @@ jobs:
run: | run: |
if grep 'warning:' makelog; then exit 1; fi if grep 'warning:' makelog; then exit 1; fi
clang-tidy-libtransmission-win32:
runs-on: windows-2022
needs: [ what-to-make ]
if: ${{ needs.what-to-make.outputs.test-style == 'true' }}
steps:
- name: Show Configuration
run: |
echo '${{ toJSON(needs) }}'
echo '${{ toJSON(runner) }}'
- name: Get Source
uses: actions/checkout@v4
with:
submodules: recursive
path: src
- name: Prepare Build Deps
uses: ./src/.github/actions/prepare-deps-win32
with:
arch: x64
type: CoreDeps
- name: Configure
run: |
Import-VisualStudioVars -VisualStudioVersion 2022 -Architecture x64
cmake `
-S src `
-B obj `
-G Ninja `
-DCMAKE_BUILD_TYPE=Debug `
-DCMAKE_PREFIX_PATH="${Env:DEPS_PREFIX}" `
-DRUN_CLANG_TIDY=ON
- name: Make
run: |
Import-VisualStudioVars -VisualStudioVersion 2022 -Architecture x64
cmake --build obj --config Debug --target transmission.lib 2>&1 | tee makelog
- name: Test for warnings
run: |
if (Select-String -Path makelog -Pattern 'warning:') { exit 1 }
macos-14-arm64: macos-14-arm64:
runs-on: macos-14 runs-on: macos-14
needs: [ what-to-make ] needs: [ what-to-make ]
@ -458,51 +495,16 @@ jobs:
run: | run: |
echo '${{ toJSON(needs) }}' echo '${{ toJSON(needs) }}'
echo '${{ toJSON(runner) }}' echo '${{ toJSON(runner) }}'
- name: Get Build Tools
run: |
$DepsPrefix = (Join-Path (Get-Item .).Root.Name "${{ matrix.arch }}-prefix")
"DEPS_PREFIX=${DepsPrefix}" | Out-File $Env:GITHUB_ENV -Append
(Join-Path $DepsPrefix bin) | Out-File $Env:GITHUB_PATH -Append
choco install `
jom `
nasm `
nodejs
& "C:\Program Files\OpenSSL\unins000.exe" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- | Out-Host
(Join-Path $Env:ProgramFiles NASM) | Out-File $Env:GITHUB_PATH -Append
(Join-Path (Get-Item -Path "${Env:ProgramFiles(x86)}\WiX Toolset v3.*")[0].FullName bin) | Out-File $Env:GITHUB_PATH -Append
Install-Module -Name Pscx -RequiredVersion 4.0.0-beta4 -AllowPrerelease -Force
- name: Get Source - name: Get Source
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
path: src path: src
submodules: recursive submodules: recursive
- name: Get Cache Key - name: Prepare Build Deps
id: cache-key uses: ./src/.github/actions/prepare-deps-win32
run: |
try {
$DepsHash = & (Join-Path . src release windows main.ps1) -Mode DepsHash -BuildArch ${{ matrix.arch }}
"hash=${DepsHash}" | Out-File $Env:GITHUB_OUTPUT -Append
} catch {
Write-Error ("{1}{0}{2}{0}{3}" -f [Environment]::NewLine, $_.ToString(), $_.InvocationInfo.PositionMessage, $_.ScriptStackTrace) -ErrorAction Continue
exit 1
}
- name: Get Cache
uses: actions/cache@v4
id: cache
with: with:
path: ${{ env.DEPS_PREFIX }} arch: ${{ matrix.arch }}
key: ${{ github.job }}-${{ matrix.arch }}-${{ steps.cache-key.outputs.hash }} type: Deps
- name: Build Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: |
try {
& (Join-Path . src release windows main.ps1) -Mode Build -BuildArch ${{ matrix.arch }} -BuildPart Deps
} catch {
Write-Error ("{1}{0}{2}{0}{3}" -f [Environment]::NewLine, $_.ToString(), $_.InvocationInfo.PositionMessage, $_.ScriptStackTrace) -ErrorAction Continue
exit 1
}
- name: Configure - name: Configure
run: | run: |
Import-VisualStudioVars -VisualStudioVersion 2022 -Architecture ${{ matrix.arch }} Import-VisualStudioVars -VisualStudioVersion 2022 -Architecture ${{ matrix.arch }}

View File

@ -14,20 +14,32 @@
#define ERROR_DIRECTORY_NOT_SUPPORTED 336 #define ERROR_DIRECTORY_NOT_SUPPORTED 336
#endif #endif
#define TR_ERROR_IS_ENOENT(code) ((code) == ERROR_FILE_NOT_FOUND || (code) == ERROR_PATH_NOT_FOUND)
#define TR_ERROR_IS_ENOSPC(code) ((code) == ERROR_DISK_FULL)
#define TR_ERROR_EINVAL ERROR_INVALID_PARAMETER #define TR_ERROR_EINVAL ERROR_INVALID_PARAMETER
#define TR_ERROR_EISDIR ERROR_DIRECTORY_NOT_SUPPORTED #define TR_ERROR_EISDIR ERROR_DIRECTORY_NOT_SUPPORTED
#else /* _WIN32 */ #else /* _WIN32 */
#include <errno.h> #include <cerrno>
#define TR_ERROR_IS_ENOENT(code) ((code) == ENOENT)
#define TR_ERROR_IS_ENOSPC(code) ((code) == ENOSPC)
#define TR_ERROR_EINVAL EINVAL #define TR_ERROR_EINVAL EINVAL
#define TR_ERROR_EISDIR EISDIR #define TR_ERROR_EISDIR EISDIR
#endif /* _WIN32 */ #endif /* _WIN32 */
constexpr inline bool tr_error_is_enoent(int code) noexcept
{
#ifdef _WIN32
return code == ERROR_FILE_NOT_FOUND || code == ERROR_PATH_NOT_FOUND;
#else
return code == ENOENT;
#endif
}
constexpr inline bool tr_error_is_enospc(int code) noexcept
{
#ifdef _WIN32
return code == ERROR_DISK_FULL;
#else
return code == ENOSPC;
#endif
}

View File

@ -452,13 +452,13 @@ extern "C"
if (auto const wide_path = tr_win32_utf8_to_native(path); !std::empty(wide_path)) if (auto const wide_path = tr_win32_utf8_to_native(path); !std::empty(wide_path))
{ {
ULARGE_INTEGER freeBytesAvailable; ULARGE_INTEGER free_bytes_available;
ULARGE_INTEGER totalBytesAvailable; ULARGE_INTEGER total_bytes_available;
if (GetDiskFreeSpaceExW(wide_path.c_str(), &freeBytesAvailable, &totalBytesAvailable, nullptr)) if (GetDiskFreeSpaceExW(wide_path.c_str(), &free_bytes_available, &total_bytes_available, nullptr) != 0)
{ {
ret.free = freeBytesAvailable.QuadPart; ret.free = free_bytes_available.QuadPart;
ret.total = totalBytesAvailable.QuadPart; ret.total = total_bytes_available.QuadPart;
} }
} }

View File

@ -27,14 +27,6 @@
using namespace std::literals; using namespace std::literals;
#ifndef MAXSIZE_T
#define MAXSIZE_T ((SIZE_T) ~((SIZE_T)0))
#endif
/* MSDN (http://msdn.microsoft.com/en-us/library/2k2xf226.aspx) only mentions
"i64" suffix for C code, but no warning is issued */
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
struct tr_sys_dir_win32 struct tr_sys_dir_win32
{ {
std::wstring pattern; std::wstring pattern;
@ -45,6 +37,8 @@ struct tr_sys_dir_win32
namespace namespace
{ {
auto constexpr DeltaEpochInMicrosecs = UINT64_C(11644473600000000);
auto constexpr NativeLocalPathPrefix = L"\\\\?\\"sv; auto constexpr NativeLocalPathPrefix = L"\\\\?\\"sv;
auto constexpr NativeUncPathPrefix = L"\\\\?\\UNC\\"sv; auto constexpr NativeUncPathPrefix = L"\\\\?\\UNC\\"sv;
@ -72,11 +66,16 @@ constexpr time_t filetime_to_unix_time(FILETIME const& t)
tmp <<= 32; tmp <<= 32;
tmp |= t.dwLowDateTime; tmp |= t.dwLowDateTime;
tmp /= 10; /* to microseconds */ tmp /= 10; /* to microseconds */
tmp -= DELTA_EPOCH_IN_MICROSECS; tmp -= DeltaEpochInMicrosecs;
return tmp / 1000000UL; return tmp / 1000000UL;
} }
constexpr bool to_bool(BOOL value) noexcept
{
return value != FALSE;
}
constexpr auto stat_to_sys_path_info(DWORD attributes, DWORD size_low, DWORD size_high, FILETIME const& mtime) constexpr auto stat_to_sys_path_info(DWORD attributes, DWORD size_low, DWORD size_high, FILETIME const& mtime)
{ {
auto info = tr_sys_path_info{}; auto info = tr_sys_path_info{};
@ -103,7 +102,7 @@ constexpr auto stat_to_sys_path_info(DWORD attributes, DWORD size_low, DWORD siz
return info; return info;
} }
auto constexpr Slashes = "\\/"sv; auto constexpr Slashes = R"(\/)"sv;
constexpr bool is_slash(char c) constexpr bool is_slash(char c)
{ {
@ -119,27 +118,22 @@ bool is_valid_path(std::string_view path)
{ {
if (is_unc_path(path)) if (is_unc_path(path))
{ {
if (path[2] != '\0' && !isalnum(path[2])) if (path[2] != '\0' && isalnum(path[2]) == 0)
{ {
return false; return false;
} }
} }
else else if (auto const pos = path.find(':'); pos != std::string_view::npos)
{ {
auto pos = path.find(':'); if (pos != 1 || isalpha(path[0]) == 0)
if (pos != path.npos)
{
if (pos != 1 || !isalpha(path[0]))
{ {
return false; return false;
} }
path.remove_prefix(2); path.remove_prefix(2);
} }
}
return path.find_first_of("<>:\"|?*"sv) == path.npos; return path.find_first_of(R"(<>:"|?*)"sv) == std::string_view::npos;
} }
auto path_to_fixed_native_path(std::string_view path) auto path_to_fixed_native_path(std::string_view path)
@ -200,7 +194,7 @@ std::string native_path_to_path(std::wstring_view wide_path)
{ {
wide_path.remove_prefix(std::size(NativeUncPathPrefix)); wide_path.remove_prefix(std::size(NativeUncPathPrefix));
auto path = tr_win32_native_to_utf8(wide_path); auto path = tr_win32_native_to_utf8(wide_path);
path.insert(0, "\\\\"sv); path.insert(0, R"(\\)"sv);
return path; return path;
} }
@ -239,7 +233,7 @@ tr_sys_file_t open_file(std::string_view path, DWORD access, DWORD disposition,
bool create_dir(std::string_view path, int flags, int /*permissions*/, bool okay_if_exists, tr_error* error) bool create_dir(std::string_view path, int flags, int /*permissions*/, bool okay_if_exists, tr_error* error)
{ {
bool ret; bool ret = false;
DWORD error_code = ERROR_SUCCESS; DWORD error_code = ERROR_SUCCESS;
auto const wide_path = path_to_native_path(path); auto const wide_path = path_to_native_path(path);
@ -256,7 +250,7 @@ bool create_dir(std::string_view path, int flags, int /*permissions*/, bool okay
} }
else else
{ {
ret = CreateDirectoryW(wide_path.c_str(), nullptr); ret = to_bool(CreateDirectoryW(wide_path.c_str(), nullptr));
if (!ret) if (!ret)
{ {
@ -282,14 +276,10 @@ bool create_dir(std::string_view path, int flags, int /*permissions*/, bool okay
return ret; return ret;
} }
void create_temp_path( template<typename CallbackT>
char* path_template, void create_temp_path(char* path_template, CallbackT&& callback, tr_error* error)
void (*callback)(char const* path, void* param, tr_error* error),
void* callback_param,
tr_error* error)
{ {
TR_ASSERT(path_template != nullptr); TR_ASSERT(path_template != nullptr);
TR_ASSERT(callback != nullptr);
auto path = std::string{ path_template }; auto path = std::string{ path_template };
auto path_size = std::size(path); auto path_size = std::size(path);
@ -313,7 +303,7 @@ void create_temp_path(
local_error = {}; local_error = {};
(*callback)(path.c_str(), callback_param, &local_error); callback(path.c_str(), &local_error);
if (!local_error) if (!local_error)
{ {
@ -336,7 +326,7 @@ std::optional<tr_sys_path_info> tr_sys_file_get_info_(tr_sys_file_t handle, tr_e
TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(handle != TR_BAD_SYS_FILE);
auto attributes = BY_HANDLE_FILE_INFORMATION{}; auto attributes = BY_HANDLE_FILE_INFORMATION{};
if (GetFileInformationByHandle(handle, &attributes)) if (to_bool(GetFileInformationByHandle(handle, &attributes)))
{ {
return stat_to_sys_path_info( return stat_to_sys_path_info(
attributes.dwFileAttributes, attributes.dwFileAttributes,
@ -367,7 +357,7 @@ std::optional<BY_HANDLE_FILE_INFORMATION> get_file_info(char const* path, tr_err
// TODO: Use GetFileInformationByHandleEx on >= Server 2012 // TODO: Use GetFileInformationByHandleEx on >= Server 2012
auto info = BY_HANDLE_FILE_INFORMATION{}; auto info = BY_HANDLE_FILE_INFORMATION{};
if (!GetFileInformationByHandle(handle, &info)) if (!to_bool(GetFileInformationByHandle(handle, &info)))
{ {
set_system_error_if_file_found(error, GetLastError()); set_system_error_if_file_found(error, GetLastError());
CloseHandle(handle); CloseHandle(handle);
@ -378,23 +368,6 @@ std::optional<BY_HANDLE_FILE_INFORMATION> get_file_info(char const* path, tr_err
return info; return info;
} }
void file_open_temp_callback(char const* path, void* param, tr_error* error)
{
auto* const result = static_cast<tr_sys_file_t*>(param);
TR_ASSERT(result != nullptr);
*result = open_file(path, GENERIC_READ | GENERIC_WRITE, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, error);
}
void dir_create_temp_callback(char const* path, void* param, tr_error* error)
{
auto* const result = static_cast<bool*>(param);
TR_ASSERT(result != nullptr);
*result = create_dir(path, 0, 0, false, error);
}
} // namespace } // namespace
bool tr_sys_path_exists(char const* path, tr_error* error) bool tr_sys_path_exists(char const* path, tr_error* error)
@ -406,7 +379,7 @@ bool tr_sys_path_exists(char const* path, tr_error* error)
if (auto const wide_path = path_to_native_path(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()); DWORD const attributes = GetFileAttributesW(wide_path.c_str());
if (attributes != INVALID_FILE_ATTRIBUTES) if (attributes != INVALID_FILE_ATTRIBUTES)
{ {
@ -444,7 +417,7 @@ std::optional<tr_sys_path_info> tr_sys_path_get_info(std::string_view path, int
else if ((flags & TR_SYS_PATH_NO_FOLLOW) != 0) else if ((flags & TR_SYS_PATH_NO_FOLLOW) != 0)
{ {
auto attributes = WIN32_FILE_ATTRIBUTE_DATA{}; auto attributes = WIN32_FILE_ATTRIBUTE_DATA{};
if (GetFileAttributesExW(wide_path.c_str(), GetFileExInfoStandard, &attributes)) if (to_bool(GetFileAttributesExW(wide_path.c_str(), GetFileExInfoStandard, &attributes)))
{ {
return stat_to_sys_path_info( return stat_to_sys_path_info(
attributes.dwFileAttributes, attributes.dwFileAttributes,
@ -475,13 +448,13 @@ bool tr_sys_path_is_relative(std::string_view path)
} }
/* Local path: `X:` */ /* Local path: `X:` */
if (std::size(path) == 2 && isalpha(path[0]) && path[1] == ':') if (std::size(path) == 2 && isalpha(path[0]) != 0 && path[1] == ':')
{ {
return false; return false;
} }
/* Local path: `X:\...`. */ /* Local path: `X:\...`. */
if (std::size(path) > 2 && isalpha(path[0]) && path[1] == ':' && is_slash(path[2])) if (std::size(path) > 2 && isalpha(path[0]) != 0 && path[1] == ':' && is_slash(path[2]))
{ {
return false; return false;
} }
@ -584,15 +557,18 @@ std::string_view tr_sys_path_basename(std::string_view path, tr_error* error)
return !std::empty(path) ? path : "/"sv; return !std::empty(path) ? path : "/"sv;
} }
[[nodiscard]] static bool isWindowsDeviceRoot(char ch) noexcept namespace
{
[[nodiscard]] bool isWindowsDeviceRoot(char ch) noexcept
{ {
return isalpha(static_cast<int>(ch)) != 0; return isalpha(static_cast<int>(ch)) != 0;
} }
[[nodiscard]] static constexpr bool isPathSeparator(char ch) noexcept [[nodiscard]] constexpr bool isPathSeparator(char ch) noexcept
{ {
return ch == '/' || ch == '\\'; return ch == '/' || ch == '\\';
} }
} // namespace
// This function is adapted from Node.js's path.win32.dirname() function, // This function is adapted from Node.js's path.win32.dirname() function,
// which is copyrighted by Joyent, Inc. and other Node contributors // which is copyrighted by Joyent, Inc. and other Node contributors
@ -674,7 +650,7 @@ std::string_view tr_sys_path_dirname(std::string_view path)
} }
auto end = std::string_view::npos; auto end = std::string_view::npos;
auto matched_slash = bool{ true }; auto matched_slash = true;
for (std::string_view::size_type i = len - 1; i >= offset; --i) for (std::string_view::size_type i = len - 1; i >= offset; --i)
{ {
if (isPathSeparator(path[i])) if (isPathSeparator(path[i]))
@ -720,25 +696,19 @@ bool tr_sys_path_rename(char const* src_path, char const* dst_path, tr_error* er
if (!std::empty(wide_src_path) && !std::empty(wide_dst_path)) if (!std::empty(wide_src_path) && !std::empty(wide_dst_path))
{ {
DWORD flags = MOVEFILE_REPLACE_EXISTING; DWORD flags = MOVEFILE_REPLACE_EXISTING;
DWORD attributes;
attributes = GetFileAttributesW(wide_src_path.c_str()); if (auto const src_attributes = GetFileAttributesW(wide_src_path.c_str());
src_attributes != INVALID_FILE_ATTRIBUTES && (src_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
if (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{ {
flags = 0; flags = 0;
} }
else else if (auto const dst_attributes = GetFileAttributesW(wide_dst_path.c_str());
{ dst_attributes != INVALID_FILE_ATTRIBUTES && (dst_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
attributes = GetFileAttributesW(wide_dst_path.c_str());
if (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{ {
flags = 0; flags = 0;
} }
}
ret = MoveFileExW(wide_src_path.c_str(), wide_dst_path.c_str(), flags); ret = to_bool(MoveFileExW(wide_src_path.c_str(), wide_dst_path.c_str(), flags));
} }
if (!ret) if (!ret)
@ -764,7 +734,7 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error* erro
auto cancel = BOOL{ FALSE }; auto cancel = BOOL{ FALSE };
DWORD const flags = COPY_FILE_ALLOW_DECRYPTED_DESTINATION | COPY_FILE_FAIL_IF_EXISTS; DWORD const flags = COPY_FILE_ALLOW_DECRYPTED_DESTINATION | COPY_FILE_FAIL_IF_EXISTS;
if (CopyFileExW(wide_src_path.c_str(), wide_dst_path.c_str(), nullptr, nullptr, &cancel, flags) == 0) if (!to_bool(CopyFileExW(wide_src_path.c_str(), wide_dst_path.c_str(), nullptr, nullptr, &cancel, flags)))
{ {
set_system_error(error, GetLastError()); set_system_error(error, GetLastError());
return false; return false;
@ -787,11 +757,11 @@ bool tr_sys_path_remove(char const* path, tr_error* error)
{ {
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{ {
ret = RemoveDirectoryW(wide_path.c_str()); ret = to_bool(RemoveDirectoryW(wide_path.c_str()));
} }
else else
{ {
ret = DeleteFileW(wide_path.c_str()); ret = to_bool(DeleteFileW(wide_path.c_str()));
} }
} }
} }
@ -824,11 +794,9 @@ tr_sys_file_t tr_sys_file_open(char const* path, int flags, int /*permissions*/,
TR_ASSERT(path != nullptr); TR_ASSERT(path != nullptr);
TR_ASSERT((flags & (TR_SYS_FILE_READ | TR_SYS_FILE_WRITE)) != 0); TR_ASSERT((flags & (TR_SYS_FILE_READ | TR_SYS_FILE_WRITE)) != 0);
tr_sys_file_t ret;
DWORD native_access = 0; DWORD native_access = 0;
DWORD native_disposition = OPEN_EXISTING; DWORD native_disposition = OPEN_EXISTING;
DWORD native_flags = FILE_ATTRIBUTE_NORMAL; DWORD native_flags = FILE_ATTRIBUTE_NORMAL;
bool success;
if ((flags & TR_SYS_FILE_READ) != 0) if ((flags & TR_SYS_FILE_READ) != 0)
{ {
@ -854,9 +822,8 @@ tr_sys_file_t tr_sys_file_open(char const* path, int flags, int /*permissions*/,
native_flags |= FILE_FLAG_SEQUENTIAL_SCAN; native_flags |= FILE_FLAG_SEQUENTIAL_SCAN;
} }
ret = open_file(path, native_access, native_disposition, native_flags, error); auto ret = open_file(path, native_access, native_disposition, native_flags, error);
auto success = ret != TR_BAD_SYS_FILE;
success = ret != TR_BAD_SYS_FILE;
if (success && (flags & TR_SYS_FILE_APPEND) != 0) if (success && (flags & TR_SYS_FILE_APPEND) != 0)
{ {
@ -880,7 +847,11 @@ tr_sys_file_t tr_sys_file_open_temp(char* path_template, tr_error* error)
tr_sys_file_t ret = TR_BAD_SYS_FILE; tr_sys_file_t ret = TR_BAD_SYS_FILE;
create_temp_path(path_template, file_open_temp_callback, &ret, error); create_temp_path(
path_template,
[&ret](char const* path, tr_error* error)
{ ret = open_file(path, GENERIC_READ | GENERIC_WRITE, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, error); },
error);
return ret; return ret;
} }
@ -889,7 +860,7 @@ bool tr_sys_file_close(tr_sys_file_t handle, tr_error* error)
{ {
TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(handle != TR_BAD_SYS_FILE);
bool ret = CloseHandle(handle); bool const ret = to_bool(CloseHandle(handle));
if (!ret) if (!ret)
{ {
@ -911,9 +882,9 @@ bool tr_sys_file_read(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_
} }
bool ret = false; bool ret = false;
DWORD my_bytes_read; DWORD my_bytes_read = 0;
if (ReadFile(handle, buffer, (DWORD)size, &my_bytes_read, nullptr)) if (to_bool(ReadFile(handle, buffer, static_cast<DWORD>(size), &my_bytes_read, nullptr)))
{ {
if (bytes_read != nullptr) if (bytes_read != nullptr)
{ {
@ -948,15 +919,14 @@ bool tr_sys_file_read_at(
} }
bool ret = false; bool ret = false;
OVERLAPPED overlapped; auto overlapped = OVERLAPPED{};
DWORD my_bytes_read; DWORD my_bytes_read = 0;
overlapped.Offset = (DWORD)offset; overlapped.Offset = static_cast<DWORD>(offset);
offset >>= 32; overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
overlapped.OffsetHigh = (DWORD)offset;
overlapped.hEvent = nullptr; overlapped.hEvent = nullptr;
if (ReadFile(handle, buffer, (DWORD)size, &my_bytes_read, &overlapped)) if (to_bool(ReadFile(handle, buffer, static_cast<DWORD>(size), &my_bytes_read, &overlapped)))
{ {
if (bytes_read != nullptr) if (bytes_read != nullptr)
{ {
@ -985,9 +955,9 @@ bool tr_sys_file_write(tr_sys_file_t handle, void const* buffer, uint64_t size,
} }
bool ret = false; bool ret = false;
DWORD my_bytes_written; DWORD my_bytes_written = 0;
if (WriteFile(handle, buffer, (DWORD)size, &my_bytes_written, nullptr)) if (to_bool(WriteFile(handle, buffer, static_cast<DWORD>(size), &my_bytes_written, nullptr)))
{ {
if (bytes_written != nullptr) if (bytes_written != nullptr)
{ {
@ -1022,15 +992,14 @@ bool tr_sys_file_write_at(
} }
bool ret = false; bool ret = false;
OVERLAPPED overlapped; auto overlapped = OVERLAPPED{};
DWORD my_bytes_written; DWORD my_bytes_written = 0;
overlapped.Offset = (DWORD)offset; overlapped.Offset = static_cast<DWORD>(offset);
offset >>= 32; overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
overlapped.OffsetHigh = (DWORD)offset;
overlapped.hEvent = nullptr; overlapped.hEvent = nullptr;
if (WriteFile(handle, buffer, (DWORD)size, &my_bytes_written, &overlapped)) if (to_bool(WriteFile(handle, buffer, static_cast<DWORD>(size), &my_bytes_written, &overlapped)))
{ {
if (bytes_written != nullptr) if (bytes_written != nullptr)
{ {
@ -1054,7 +1023,7 @@ bool tr_sys_file_truncate(tr_sys_file_t handle, uint64_t size, tr_error* error)
FILE_END_OF_FILE_INFO info; FILE_END_OF_FILE_INFO info;
info.EndOfFile.QuadPart = size; info.EndOfFile.QuadPart = size;
bool ret = SetFileInformationByHandle(handle, FileEndOfFileInfo, &info, sizeof(info)); bool const ret = to_bool(SetFileInformationByHandle(handle, FileEndOfFileInfo, &info, sizeof(info)));
if (!ret) if (!ret)
{ {
@ -1070,9 +1039,9 @@ bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, tr_
if ((flags & TR_SYS_FILE_PREALLOC_SPARSE) != 0) if ((flags & TR_SYS_FILE_PREALLOC_SPARSE) != 0)
{ {
DWORD tmp; DWORD tmp = 0;
if (!DeviceIoControl(handle, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &tmp, nullptr)) if (!to_bool(DeviceIoControl(handle, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &tmp, nullptr)))
{ {
set_system_error(error, GetLastError()); set_system_error(error, GetLastError());
return false; return false;
@ -1089,7 +1058,7 @@ bool tr_sys_file_lock(tr_sys_file_t handle, int operation, tr_error* error)
TR_ASSERT( TR_ASSERT(
!!(operation & TR_SYS_FILE_LOCK_SH) + !!(operation & TR_SYS_FILE_LOCK_EX) + !!(operation & TR_SYS_FILE_LOCK_UN) == 1); !!(operation & TR_SYS_FILE_LOCK_SH) + !!(operation & TR_SYS_FILE_LOCK_EX) + !!(operation & TR_SYS_FILE_LOCK_UN) == 1);
bool ret; bool ret = false;
auto overlapped = OVERLAPPED{}; auto overlapped = OVERLAPPED{};
if ((operation & TR_SYS_FILE_LOCK_UN) == 0) if ((operation & TR_SYS_FILE_LOCK_UN) == 0)
@ -1150,7 +1119,10 @@ bool tr_sys_dir_create_temp(char* path_template, tr_error* error)
bool ret = false; bool ret = false;
create_temp_path(path_template, dir_create_temp_callback, &ret, error); create_temp_path(
path_template,
[&ret](char const* path, tr_error* error) { ret = create_dir(path, 0, 0, false, error); },
error);
return ret; return ret;
} }
@ -1195,7 +1167,7 @@ char const* tr_sys_dir_read_name(tr_sys_dir_t handle, tr_error* error)
} }
else else
{ {
if (!FindNextFileW(handle->find_handle, &handle->find_data)) if (!to_bool(FindNextFileW(handle->find_handle, &handle->find_data)))
{ {
error_code = GetLastError(); error_code = GetLastError();
} }
@ -1221,7 +1193,7 @@ bool tr_sys_dir_close(tr_sys_dir_t handle, tr_error* error)
{ {
TR_ASSERT(handle != TR_BAD_SYS_DIR); TR_ASSERT(handle != TR_BAD_SYS_DIR);
bool ret = FindClose(handle->find_handle); bool const ret = to_bool(FindClose(handle->find_handle));
if (!ret) if (!ret)
{ {

View File

@ -46,7 +46,7 @@ bool preallocate_file_sparse(tr_sys_file_t fd, uint64_t length, tr_error* error)
tr_logAddDebug(fmt::format("Fast preallocation failed: {} ({})", local_error.message(), local_error.code())); tr_logAddDebug(fmt::format("Fast preallocation failed: {} ({})", local_error.message(), local_error.code()));
if (!TR_ERROR_IS_ENOSPC(local_error.code())) if (!tr_error_is_enospc(local_error.code()))
{ {
static char constexpr Zero = '\0'; static char constexpr Zero = '\0';
@ -86,7 +86,7 @@ bool preallocate_file_full(tr_sys_file_t fd, uint64_t length, tr_error* error)
tr_logAddDebug(fmt::format("Full preallocation failed: {} ({})", local_error.message(), local_error.code())); tr_logAddDebug(fmt::format("Full preallocation failed: {} ({})", local_error.message(), local_error.code()));
if (!TR_ERROR_IS_ENOSPC(local_error.code())) if (!tr_error_is_enospc(local_error.code()))
{ {
auto buf = std::array<uint8_t, 4096>{}; auto buf = std::array<uint8_t, 4096>{};
bool success = true; bool success = true;

View File

@ -26,12 +26,12 @@ struct tr_peer;
class ActiveRequests::Impl class ActiveRequests::Impl
{ {
public: public:
size_t size() const [[nodiscard]] size_t size() const
{ {
return size_; return size_;
} }
size_t count(tr_peer const* peer) const [[nodiscard]] size_t count(tr_peer const* peer) const
{ {
auto const it = count_.find(peer); auto const it = count_.find(peer);
return it != std::end(count_) ? it->second : size_t{}; return it != std::end(count_) ? it->second : size_t{};

View File

@ -608,40 +608,40 @@ private:
// --- // ---
size_t protocol_send_keepalive() const; size_t protocol_send_keepalive() const; // NOLINT(modernize-use-nodiscard)
template<typename... Args> template<typename... Args>
size_t protocol_send_message(uint8_t type, Args const&... args) const; size_t protocol_send_message(uint8_t type, Args const&... args) const;
size_t protocol_send_reject(peer_request const& req) const size_t protocol_send_reject(peer_request const& req) const // NOLINT(modernize-use-nodiscard)
{ {
TR_ASSERT(io_->supports_fext()); TR_ASSERT(io_->supports_fext());
return protocol_send_message(BtPeerMsgs::FextReject, req.index, req.offset, req.length); return protocol_send_message(BtPeerMsgs::FextReject, req.index, req.offset, req.length);
} }
size_t protocol_send_cancel(peer_request const& req) const size_t protocol_send_cancel(peer_request const& req) const // NOLINT(modernize-use-nodiscard)
{ {
return protocol_send_message(BtPeerMsgs::Cancel, req.index, req.offset, req.length); return protocol_send_message(BtPeerMsgs::Cancel, req.index, req.offset, req.length);
} }
size_t protocol_send_request(peer_request const& req) const size_t protocol_send_request(peer_request const& req) const // NOLINT(modernize-use-nodiscard)
{ {
TR_ASSERT(is_valid_request(req)); TR_ASSERT(is_valid_request(req));
return protocol_send_message(BtPeerMsgs::Request, req.index, req.offset, req.length); return protocol_send_message(BtPeerMsgs::Request, req.index, req.offset, req.length);
} }
size_t protocol_send_dht_port(tr_port const port) const size_t protocol_send_dht_port(tr_port const port) const // NOLINT(modernize-use-nodiscard)
{ {
return protocol_send_message(BtPeerMsgs::DhtPort, port.host()); return protocol_send_message(BtPeerMsgs::DhtPort, port.host());
} }
size_t protocol_send_have(tr_piece_index_t const index) const size_t protocol_send_have(tr_piece_index_t const index) const // NOLINT(modernize-use-nodiscard)
{ {
static_assert(sizeof(tr_piece_index_t) == sizeof(uint32_t)); static_assert(sizeof(tr_piece_index_t) == sizeof(uint32_t));
return protocol_send_message(BtPeerMsgs::Have, index); return protocol_send_message(BtPeerMsgs::Have, index);
} }
size_t protocol_send_choke(bool const choke) const size_t protocol_send_choke(bool const choke) const // NOLINT(modernize-use-nodiscard)
{ {
return protocol_send_message(choke ? BtPeerMsgs::Choke : BtPeerMsgs::Unchoke); return protocol_send_message(choke ? BtPeerMsgs::Choke : BtPeerMsgs::Unchoke);
} }

View File

@ -54,7 +54,7 @@ namespace
#ifdef _WIN32 #ifdef _WIN32
std::string win32_get_known_folder_ex(REFKNOWNFOLDERID folder_id, DWORD flags) std::string win32_get_known_folder_ex(REFKNOWNFOLDERID folder_id, DWORD flags)
{ {
if (PWSTR path; SHGetKnownFolderPath(folder_id, flags | KF_FLAG_DONT_UNEXPAND, nullptr, &path) == S_OK) if (PWSTR path = nullptr; SHGetKnownFolderPath(folder_id, flags | KF_FLAG_DONT_UNEXPAND, nullptr, &path) == S_OK)
{ {
auto ret = tr_win32_native_to_utf8(path); auto ret = tr_win32_native_to_utf8(path);
CoTaskMemFree(path); CoTaskMemFree(path);

View File

@ -128,7 +128,7 @@ bool tr_session_id::is_local(std::string_view session_id) noexcept
auto error = tr_error{}; auto error = tr_error{};
if (auto lockfile_fd = tr_sys_file_open(lockfile_path, TR_SYS_FILE_READ, 0, &error); lockfile_fd == TR_BAD_SYS_FILE) if (auto lockfile_fd = tr_sys_file_open(lockfile_path, TR_SYS_FILE_READ, 0, &error); lockfile_fd == TR_BAD_SYS_FILE)
{ {
if (TR_ERROR_IS_ENOENT(error.code())) if (tr_error_is_enoent(error.code()))
{ {
error = {}; error = {};
} }

View File

@ -101,10 +101,19 @@ int cond_wait(void* vcond, void* vlock, struct timeval const* tv)
return success == std::cv_status::timeout ? 1 : 0; return success == std::cv_status::timeout ? 1 : 0;
} }
#if defined(_WIN32) && defined(__clang_analyzer__)
// See https://github.com/llvm/llvm-project/issues/98823
#define WORKAROUND_CLANG_TIDY_GH98823
#endif
unsigned long thread_current_id() unsigned long thread_current_id()
{ {
#ifndef WORKAROUND_CLANG_TIDY_GH98823
thread_local auto const hashed = std::hash<std::thread::id>()(std::this_thread::get_id()); thread_local auto const hashed = std::hash<std::thread::id>()(std::this_thread::get_id());
return hashed; return hashed;
#else
return 0;
#endif
} }
void init_evthreads_once() void init_evthreads_once()

View File

@ -11,7 +11,6 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <tuple>
#include <utility> #include <utility>
struct event_base; struct event_base;

View File

@ -29,7 +29,7 @@ using namespace std::literals;
namespace namespace
{ {
enum class tr_app_type enum class tr_app_type : uint8_t
{ {
EXE, EXE,
BATCH BATCH
@ -52,17 +52,22 @@ void set_system_error(tr_error* error, DWORD code, std::string_view what)
} }
} }
constexpr bool to_bool(BOOL value) noexcept
{
return value != FALSE;
}
// "The sort is case-insensitive, Unicode order, without regard to locale" © MSDN // "The sort is case-insensitive, Unicode order, without regard to locale" © MSDN
class WStrICompare class WStrICompare
{ {
public: public:
[[nodiscard]] auto compare(std::wstring_view a, std::wstring_view b) const noexcept // <=> [[nodiscard]] static auto compare(std::wstring_view a, std::wstring_view b) noexcept // <=>
{ {
int diff = wcsnicmp(std::data(a), std::data(b), std::min(std::size(a), std::size(b))); int diff = wcsnicmp(std::data(a), std::data(b), std::min(std::size(a), std::size(b)));
if (diff == 0) if (diff == 0)
{ {
diff = std::size(a) < std::size(b) ? -1 : (std::size(a) > std::size(b) ? 1 : 0); diff = tr_compare_3way(std::size(a), std::size(b));
} }
return diff; return diff;
@ -178,6 +183,9 @@ void append_argument(std::string& arguments, char const* argument)
case '"': case '"':
backslash_count = backslash_count * 2 + 1; backslash_count = backslash_count * 2 + 1;
break; break;
default:
break;
} }
if (backslash_count != 0) if (backslash_count != 0)
@ -298,7 +306,7 @@ bool tr_spawn_async(
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
bool const ret = CreateProcessW( bool const ret = to_bool(CreateProcessW(
nullptr, nullptr,
std::data(cmd_line), std::data(cmd_line),
nullptr, nullptr,
@ -308,7 +316,7 @@ bool tr_spawn_async(
std::empty(full_env) ? nullptr : to_env_string(full_env).data(), std::empty(full_env) ? nullptr : to_env_string(full_env).data(),
std::empty(current_dir) ? nullptr : current_dir.c_str(), std::empty(current_dir) ? nullptr : current_dir.c_str(),
&si, &si,
&pi); &pi));
if (ret) if (ret)
{ {

View File

@ -90,6 +90,7 @@ extern "C"
int dht_sendto(int sockfd, void const* buf, int len, int flags, struct sockaddr const* to, int tolen) int dht_sendto(int sockfd, void const* buf, int len, int flags, struct sockaddr const* to, int tolen)
{ {
// NOLINTNEXTLINE(readability-redundant-casting)
return static_cast<int>(sendto(sockfd, static_cast<char const*>(buf), len, flags, to, tolen)); return static_cast<int>(sendto(sockfd, static_cast<char const*>(buf), len, flags, to, tolen));
} }

View File

@ -75,21 +75,32 @@ Config::Units<StorageUnits> Config::Storage{ Config::Base::Kilo, "B"sv, "kB"sv,
// --- // ---
#if defined(_WIN32) && defined(__clang_analyzer__)
// See https://github.com/llvm/llvm-project/issues/44701
#define WORKAROUND_CLANG_TIDY_GH44701
#endif
std::optional<std::locale> tr_locale_set_global(char const* locale_name) noexcept std::optional<std::locale> tr_locale_set_global(char const* locale_name) noexcept
{ {
#ifndef WORKAROUND_CLANG_TIDY_GH44701
try try
#endif
{ {
return tr_locale_set_global(std::locale{ locale_name }); return tr_locale_set_global(std::locale{ locale_name });
} }
#ifndef WORKAROUND_CLANG_TIDY_GH44701
catch (std::runtime_error const&) catch (std::runtime_error const&)
{ {
return {}; return {};
} }
#endif
} }
std::optional<std::locale> tr_locale_set_global(std::locale const& locale) noexcept std::optional<std::locale> tr_locale_set_global(std::locale const& locale) noexcept
{ {
#ifndef WORKAROUND_CLANG_TIDY_GH44701
try try
#endif
{ {
auto old_locale = std::locale::global(locale); auto old_locale = std::locale::global(locale);
@ -98,10 +109,12 @@ std::optional<std::locale> tr_locale_set_global(std::locale const& locale) noexc
return old_locale; return old_locale;
} }
#ifndef WORKAROUND_CLANG_TIDY_GH44701
catch (std::exception const&) catch (std::exception const&)
{ {
return {}; return {};
} }
#endif
} }
// --- // ---
@ -336,7 +349,7 @@ std::string tr_win32_format_message(uint32_t code)
nullptr, nullptr,
code, code,
0, 0,
(LPWSTR)&wide_text, reinterpret_cast<LPWSTR>(&wide_text),
0, 0,
nullptr); nullptr);
@ -355,7 +368,7 @@ std::string tr_win32_format_message(uint32_t code)
LocalFree(wide_text); LocalFree(wide_text);
// Most (all?) messages contain "\r\n" in the end, chop it // Most (all?) messages contain "\r\n" in the end, chop it
while (!std::empty(text) && isspace(text.back())) while (!std::empty(text) && isspace(text.back()) != 0)
{ {
text.resize(text.size() - 1); text.resize(text.size() - 1);
} }
@ -370,7 +383,7 @@ namespace tr_main_win32_impl
std::optional<std::vector<std::string>> win32MakeUtf8Argv() std::optional<std::vector<std::string>> win32MakeUtf8Argv()
{ {
int argc; int argc = 0;
auto argv = std::vector<std::string>{}; auto argv = std::vector<std::string>{};
if (wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); wargv != nullptr) if (wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); wargv != nullptr)
{ {
@ -390,7 +403,7 @@ std::optional<std::vector<std::string>> win32MakeUtf8Argv()
argv.emplace_back(std::move(str)); argv.emplace_back(std::move(str));
} }
LocalFree(wargv); LocalFree(reinterpret_cast<HLOCAL>(wargv));
} }
if (static_cast<int>(std::size(argv)) == argc) if (static_cast<int>(std::size(argv)) == argc)

View File

@ -34,6 +34,11 @@ namespace libtransmission
namespace namespace
{ {
constexpr bool to_bool(BOOL value) noexcept
{
return value != FALSE;
}
BOOL tr_get_overlapped_result_ex( BOOL tr_get_overlapped_result_ex(
HANDLE handle, HANDLE handle,
LPOVERLAPPED overlapped, LPOVERLAPPED overlapped,
@ -48,7 +53,7 @@ BOOL tr_get_overlapped_result_ex(
if (!is_real_impl_valid) if (!is_real_impl_valid)
{ {
real_impl = (impl_t)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetOverlappedResultEx"); real_impl = reinterpret_cast<impl_t>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetOverlappedResultEx"));
is_real_impl_valid = true; is_real_impl_valid = true;
} }
@ -142,14 +147,15 @@ private:
return; return;
} }
if ((fd_ = CreateFileW( fd_ = CreateFileW(
wide_path.c_str(), wide_path.c_str(),
FILE_LIST_DIRECTORY, FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr, nullptr,
OPEN_EXISTING, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
nullptr)) == INVALID_HANDLE_VALUE) nullptr);
if (fd_ == INVALID_HANDLE_VALUE)
{ {
tr_logAddError(fmt::format(_("Couldn't read '{path}'"), fmt::arg("path", path))); tr_logAddError(fmt::format(_("Couldn't read '{path}'"), fmt::arg("path", path)));
return; return;
@ -157,7 +163,15 @@ private:
overlapped_.Pointer = this; overlapped_.Pointer = this;
if (!ReadDirectoryChangesW(fd_, buffer_, sizeof(buffer_), false, Win32WatchMask, nullptr, &overlapped_, nullptr)) if (!to_bool(ReadDirectoryChangesW(
fd_,
std::data(buffer_),
std::size(buffer_),
FALSE,
Win32WatchMask,
nullptr,
&overlapped_,
nullptr)))
{ {
tr_logAddError(fmt::format(_("Couldn't read '{path}'"), fmt::arg("path", path))); tr_logAddError(fmt::format(_("Couldn't read '{path}'"), fmt::arg("path", path)));
return; return;
@ -188,7 +202,8 @@ private:
bufferevent_setcb(event_, &Win32Watchdir::onBufferEvent, nullptr, nullptr, this); bufferevent_setcb(event_, &Win32Watchdir::onBufferEvent, nullptr, nullptr, this);
bufferevent_enable(event_, EV_READ); bufferevent_enable(event_, EV_READ);
thread_ = (HANDLE)_beginthreadex(nullptr, 0, Win32Watchdir::staticThreadFunc, this, 0, nullptr); // NOLINTNEXTLINE(performance-no-int-to-ptr)
thread_ = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, Win32Watchdir::staticThreadFunc, this, 0, nullptr));
if (thread_ == nullptr) if (thread_ == nullptr)
{ {
tr_logAddError(_("Couldn't create thread")); tr_logAddError(_("Couldn't create thread"));
@ -203,22 +218,31 @@ private:
unsigned int threadFunc() unsigned int threadFunc()
{ {
DWORD bytes_transferred; DWORD bytes_transferred = 0;
while (tr_get_overlapped_result_ex(fd_, &overlapped_, &bytes_transferred, INFINITE, FALSE)) while (to_bool(tr_get_overlapped_result_ex(fd_, &overlapped_, &bytes_transferred, INFINITE, FALSE)))
{ {
PFILE_NOTIFY_INFORMATION info = (PFILE_NOTIFY_INFORMATION)buffer_; auto* info = reinterpret_cast<PFILE_NOTIFY_INFORMATION>(std::data(buffer_));
while (info->NextEntryOffset != 0) while (info->NextEntryOffset != 0)
{ {
*((BYTE**)&info) += info->NextEntryOffset; *reinterpret_cast<BYTE**>(&info) += info->NextEntryOffset;
} }
info->NextEntryOffset = bytes_transferred - ((BYTE*)info - (BYTE*)buffer_); info->NextEntryOffset = bytes_transferred -
(reinterpret_cast<BYTE*>(info) - reinterpret_cast<BYTE*>(std::data(buffer_)));
send(notify_pipe_[1], (char const*)buffer_, bytes_transferred, 0); send(notify_pipe_[1], reinterpret_cast<char const*>(std::data(buffer_)), bytes_transferred, 0);
if (!ReadDirectoryChangesW(fd_, buffer_, sizeof(buffer_), FALSE, Win32WatchMask, nullptr, &overlapped_, nullptr)) if (!to_bool(ReadDirectoryChangesW(
fd_,
std::data(buffer_),
std::size(buffer_),
FALSE,
Win32WatchMask,
nullptr,
&overlapped_,
nullptr)))
{ {
tr_logAddError(_("Couldn't read directory changes")); tr_logAddError(_("Couldn't read directory changes"));
return 0; return 0;
@ -249,7 +273,7 @@ private:
auto buffer = std::vector<char>{}; auto buffer = std::vector<char>{};
buffer.resize(sizeof(FILE_NOTIFY_INFORMATION) + name_size); buffer.resize(sizeof(FILE_NOTIFY_INFORMATION) + name_size);
PFILE_NOTIFY_INFORMATION ev = (PFILE_NOTIFY_INFORMATION)std::data(buffer); auto* ev = reinterpret_cast<PFILE_NOTIFY_INFORMATION>(std::data(buffer));
size_t const header_size = offsetof(FILE_NOTIFY_INFORMATION, FileName); size_t const header_size = offsetof(FILE_NOTIFY_INFORMATION, FileName);
@ -263,7 +287,7 @@ private:
break; break;
} }
if (nread == (size_t)-1) if (nread == static_cast<size_t>(-1))
{ {
auto const error_code = errno; auto const error_code = errno;
tr_logAddError(fmt::format( tr_logAddError(fmt::format(
@ -292,12 +316,12 @@ private:
{ {
name_size = nleft; name_size = nleft;
buffer.resize(sizeof(FILE_NOTIFY_INFORMATION) + name_size); buffer.resize(sizeof(FILE_NOTIFY_INFORMATION) + name_size);
ev = (PFILE_NOTIFY_INFORMATION)std::data(buffer); ev = reinterpret_cast<PFILE_NOTIFY_INFORMATION>(std::data(buffer));
} }
// consume entire name into buffer // consume entire name into buffer
nread = bufferevent_read(event, &buffer[header_size], nleft); nread = bufferevent_read(event, &buffer[header_size], nleft);
if (nread == (size_t)-1) if (nread == static_cast<size_t>(-1))
{ {
auto const error_code = errno; auto const error_code = errno;
tr_logAddError(fmt::format( tr_logAddError(fmt::format(
@ -330,7 +354,7 @@ private:
HANDLE fd_ = INVALID_HANDLE_VALUE; HANDLE fd_ = INVALID_HANDLE_VALUE;
OVERLAPPED overlapped_ = {}; OVERLAPPED overlapped_ = {};
DWORD buffer_[8 * 1024 / sizeof(DWORD)]; std::array<DWORD, 8 * 1024 / sizeof(DWORD)> buffer_ = {};
std::array<evutil_socket_t, 2> notify_pipe_{ static_cast<evutil_socket_t>(-1), static_cast<evutil_socket_t>(-1) }; std::array<evutil_socket_t, 2> notify_pipe_{ static_cast<evutil_socket_t>(-1), static_cast<evutil_socket_t>(-1) };
struct bufferevent* event_ = nullptr; struct bufferevent* event_ = nullptr;
HANDLE thread_ = {}; HANDLE thread_ = {};
@ -342,9 +366,9 @@ std::unique_ptr<Watchdir> Watchdir::create(
std::string_view dirname, std::string_view dirname,
Callback callback, Callback callback,
TimerMaker& timer_maker, TimerMaker& timer_maker,
struct event_base* event_base) struct event_base* evbase)
{ {
return std::make_unique<Win32Watchdir>(dirname, std::move(callback), timer_maker, event_base); return std::make_unique<Win32Watchdir>(dirname, std::move(callback), timer_maker, evbase);
} }
} // namespace libtransmission } // namespace libtransmission

View File

@ -46,7 +46,7 @@ namespace
auto error = tr_error{}; auto error = tr_error{};
auto const info = tr_sys_path_get_info(path, 0, &error); auto const info = tr_sys_path_get_info(path, 0, &error);
if (error && !TR_ERROR_IS_ENOENT(error.code())) if (error && !tr_error_is_enoent(error.code()))
{ {
tr_logAddWarn(fmt::format( tr_logAddWarn(fmt::format(
_("Skipping '{path}': {error} ({error_code})"), _("Skipping '{path}': {error} ({error_code})"),

View File

@ -129,7 +129,7 @@ CURLcode ssl_context_func(CURL* /*curl*/, void* ssl_ctx, void* /*user_data*/)
for (auto& sys_store_name : SysStoreNames) for (auto& sys_store_name : SysStoreNames)
{ {
HCERTSTORE const sys_cert_store = CertOpenSystemStoreW(0, sys_store_name); auto* const sys_cert_store = CertOpenSystemStoreW(0, sys_store_name);
if (sys_cert_store == nullptr) if (sys_cert_store == nullptr)
{ {
continue; continue;
@ -145,7 +145,7 @@ CURLcode ssl_context_func(CURL* /*curl*/, void* ssl_ctx, void* /*user_data*/)
break; break;
} }
tr_x509_cert_t const cert = tr_x509_cert_new(sys_cert->pbCertEncoded, sys_cert->cbCertEncoded); auto* const cert = tr_x509_cert_new(sys_cert->pbCertEncoded, sys_cert->cbCertEncoded);
if (cert == nullptr) if (cert == nullptr)
{ {
continue; continue;
@ -406,7 +406,7 @@ public:
// if unset: steady-state, all is good // if unset: steady-state, all is good
// if set: do not accept new tasks // if set: do not accept new tasks
// if set and deadline reached: kill all remaining tasks // if set and deadline reached: kill all remaining tasks
std::atomic<time_t> deadline_ = {}; std::atomic<time_t> deadline_ = {}; // NOLINT(readability-redundant-member-init)
[[nodiscard]] auto deadline() const [[nodiscard]] auto deadline() const
{ {

View File

@ -10,7 +10,7 @@ Param(
[string] $BuildArch, [string] $BuildArch,
[Parameter()] [Parameter()]
[ValidateSet('All', 'Deps', 'App')] [ValidateSet('All', 'CoreDeps', 'Deps', 'App')]
[string] $BuildPart = 'All', [string] $BuildPart = 'All',
[Parameter()] [Parameter()]
@ -258,14 +258,23 @@ if (-not $SourceDir) {
if ($Mode -eq 'DepsHash') { if ($Mode -eq 'DepsHash') {
Import-Script Toolchain Import-Script Toolchain
$Names = @( $Names = @()
Invoke-Build Expat -CacheArchiveNameOnly
Invoke-Build DBus -CacheArchiveNameOnly if (@('All', 'CoreDeps', 'Deps') -contains $BuildPart) {
$Names = $Names + @(
Invoke-Build Zlib -CacheArchiveNameOnly Invoke-Build Zlib -CacheArchiveNameOnly
Invoke-Build OpenSsl -CacheArchiveNameOnly Invoke-Build OpenSsl -CacheArchiveNameOnly
Invoke-Build Curl -CacheArchiveNameOnly Invoke-Build Curl -CacheArchiveNameOnly
)
}
if (@('All', 'Deps') -contains $BuildPart) {
$Names = $Names + @(
Invoke-Build Expat -CacheArchiveNameOnly
Invoke-Build DBus -CacheArchiveNameOnly
Invoke-Build Qt$UseQtVersion -CacheArchiveNameOnly Invoke-Build Qt$UseQtVersion -CacheArchiveNameOnly
) )
}
Write-Output (Get-StringHash ($Names -join ':')) Write-Output (Get-StringHash ($Names -join ':'))
} }
@ -285,12 +294,15 @@ if ($Mode -eq 'Build') {
$Env:CMAKE_CXX_COMPILER_LAUNCHER = '' $Env:CMAKE_CXX_COMPILER_LAUNCHER = ''
} }
if (@('All', 'Deps') -contains $BuildPart) { if (@('All', 'CoreDeps', 'Deps') -contains $BuildPart) {
Invoke-Build Expat
Invoke-Build DBus
Invoke-Build Zlib Invoke-Build Zlib
Invoke-Build OpenSsl Invoke-Build OpenSsl
Invoke-Build Curl Invoke-Build Curl
}
if (@('All', 'Deps') -contains $BuildPart) {
Invoke-Build Expat
Invoke-Build DBus
Invoke-Build Qt$UseQtVersion Invoke-Build Qt$UseQtVersion
} }