From 396fe6157a606a798aa7be94f3beeb62ea0b5049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Thu, 22 May 2025 20:30:48 +0200 Subject: [PATCH 1/8] Remove old vsbuild folder. --- vsbuild/asmjit.vcxproj | 281 ---------- vsbuild/asmjit.vcxproj.filters | 192 ------- vsbuild/common.props | 22 - vsbuild/external_dependencies.props | 21 - vsbuild/platform_x64.props | 41 -- vsbuild/platform_x86.props | 38 -- vsbuild/shared.vcxproj | 333 ------------ vsbuild/shared.vcxproj.filters | 99 ---- vsbuild/shared_common.props | 17 - vsbuild/shared_test.vcxproj | 96 ---- vsbuild/shared_test.vcxproj.filters | 22 - vsbuild/spdlog.vcxproj | 316 ----------- vsbuild/spdlog.vcxproj.filters | 109 ---- vsbuild/stage_helper.cmd | 19 - vsbuild/staging_paths.props | 54 -- vsbuild/test_common.props | 27 - vsbuild/test_file_operations.vcxproj | 115 ---- vsbuild/test_file_operations.vcxproj.filters | 45 -- vsbuild/testinject_bin.vcxproj | 119 ---- vsbuild/testinject_bin.vcxproj.filters | 22 - vsbuild/testinject_dll.vcxproj | 96 ---- vsbuild/testinject_dll.vcxproj.filters | 27 - vsbuild/thooklib.vcxproj | 283 ---------- vsbuild/thooklib.vcxproj.filters | 42 -- vsbuild/thooklib_test.vcxproj | 137 ----- vsbuild/thooklib_test.vcxproj.filters | 22 - vsbuild/tinjectlib.vcxproj | 243 --------- vsbuild/tinjectlib.vcxproj.filters | 21 - vsbuild/tinjectlib_test.vcxproj | 130 ----- vsbuild/tinjectlib_test.vcxproj.filters | 22 - vsbuild/tvfs_test.vcxproj | 110 ---- vsbuild/tvfs_test.vcxproj.filters | 22 - vsbuild/udis86.vcxproj | 365 ------------- vsbuild/udis86.vcxproj.filters | 57 -- vsbuild/usvfs.sln | 406 -------------- vsbuild/usvfs_common.props | 15 - vsbuild/usvfs_dll.vcxproj | 506 ------------------ vsbuild/usvfs_dll.vcxproj.filters | 104 ---- vsbuild/usvfs_global_test.vcxproj | 97 ---- vsbuild/usvfs_global_test.vcxproj.filters | 25 - vsbuild/usvfs_global_test_runner.vcxproj | 116 ---- .../usvfs_global_test_runner.vcxproj.filters | 30 -- vsbuild/usvfs_helper.vcxproj | 250 --------- vsbuild/usvfs_helper.vcxproj.filters | 18 - vsbuild/usvfs_proxy.vcxproj | 344 ------------ vsbuild/usvfs_proxy.vcxproj.filters | 18 - vsbuild/usvfs_test.vcxproj | 114 ---- vsbuild/usvfs_test.vcxproj.filters | 36 -- vsbuild/usvfs_test_runner.vcxproj | 98 ---- vsbuild/usvfs_test_runner.vcxproj.filters | 22 - 50 files changed, 5764 deletions(-) delete mode 100644 vsbuild/asmjit.vcxproj delete mode 100644 vsbuild/asmjit.vcxproj.filters delete mode 100644 vsbuild/common.props delete mode 100644 vsbuild/external_dependencies.props delete mode 100644 vsbuild/platform_x64.props delete mode 100644 vsbuild/platform_x86.props delete mode 100644 vsbuild/shared.vcxproj delete mode 100644 vsbuild/shared.vcxproj.filters delete mode 100644 vsbuild/shared_common.props delete mode 100644 vsbuild/shared_test.vcxproj delete mode 100644 vsbuild/shared_test.vcxproj.filters delete mode 100644 vsbuild/spdlog.vcxproj delete mode 100644 vsbuild/spdlog.vcxproj.filters delete mode 100644 vsbuild/stage_helper.cmd delete mode 100644 vsbuild/staging_paths.props delete mode 100644 vsbuild/test_common.props delete mode 100644 vsbuild/test_file_operations.vcxproj delete mode 100644 vsbuild/test_file_operations.vcxproj.filters delete mode 100644 vsbuild/testinject_bin.vcxproj delete mode 100644 vsbuild/testinject_bin.vcxproj.filters delete mode 100644 vsbuild/testinject_dll.vcxproj delete mode 100644 vsbuild/testinject_dll.vcxproj.filters delete mode 100644 vsbuild/thooklib.vcxproj delete mode 100644 vsbuild/thooklib.vcxproj.filters delete mode 100644 vsbuild/thooklib_test.vcxproj delete mode 100644 vsbuild/thooklib_test.vcxproj.filters delete mode 100644 vsbuild/tinjectlib.vcxproj delete mode 100644 vsbuild/tinjectlib.vcxproj.filters delete mode 100644 vsbuild/tinjectlib_test.vcxproj delete mode 100644 vsbuild/tinjectlib_test.vcxproj.filters delete mode 100644 vsbuild/tvfs_test.vcxproj delete mode 100644 vsbuild/tvfs_test.vcxproj.filters delete mode 100644 vsbuild/udis86.vcxproj delete mode 100644 vsbuild/udis86.vcxproj.filters delete mode 100644 vsbuild/usvfs.sln delete mode 100644 vsbuild/usvfs_common.props delete mode 100644 vsbuild/usvfs_dll.vcxproj delete mode 100644 vsbuild/usvfs_dll.vcxproj.filters delete mode 100644 vsbuild/usvfs_global_test.vcxproj delete mode 100644 vsbuild/usvfs_global_test.vcxproj.filters delete mode 100644 vsbuild/usvfs_global_test_runner.vcxproj delete mode 100644 vsbuild/usvfs_global_test_runner.vcxproj.filters delete mode 100644 vsbuild/usvfs_helper.vcxproj delete mode 100644 vsbuild/usvfs_helper.vcxproj.filters delete mode 100644 vsbuild/usvfs_proxy.vcxproj delete mode 100644 vsbuild/usvfs_proxy.vcxproj.filters delete mode 100644 vsbuild/usvfs_test.vcxproj delete mode 100644 vsbuild/usvfs_test.vcxproj.filters delete mode 100644 vsbuild/usvfs_test_runner.vcxproj delete mode 100644 vsbuild/usvfs_test_runner.vcxproj.filters diff --git a/vsbuild/asmjit.vcxproj b/vsbuild/asmjit.vcxproj deleted file mode 100644 index d39d8f9..0000000 --- a/vsbuild/asmjit.vcxproj +++ /dev/null @@ -1,281 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - Release - Win32 - - - Release - x64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 15.0 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2} - asmjit - 10.0 - - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Disabled - ASMJIT_STATIC;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - stdcpp14 - Default - - - - - Disabled - ASMJIT_STATIC;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - stdcpp14 - Default - - - - - Disabled - ASMJIT_STATIC;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - stdcpp14 - Default - - - - - Disabled - ASMJIT_STATIC;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - stdcpp14 - Default - - - - - MaxSpeed - true - true - ASMJIT_STATIC;%(PreprocessorDefinitions) - - - true - true - - - - - MaxSpeed - true - true - ASMJIT_STATIC;%(PreprocessorDefinitions) - MultiThreadedDLL - - - true - true - - - - - MaxSpeed - true - true - ASMJIT_STATIC;%(PreprocessorDefinitions) - - - true - true - - - - - MaxSpeed - true - true - ASMJIT_STATIC;%(PreprocessorDefinitions) - MultiThreadedDLL - - - true - true - - - - - - \ No newline at end of file diff --git a/vsbuild/asmjit.vcxproj.filters b/vsbuild/asmjit.vcxproj.filters deleted file mode 100644 index 21b946d..0000000 --- a/vsbuild/asmjit.vcxproj.filters +++ /dev/null @@ -1,192 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {5a4afbfd-90a1-4d0d-8fa9-468bfb33226b} - - - {68687f3c-aa7c-4237-b863-d4107fd5c8a1} - - - {820334a2-4f01-4b6a-80be-c723689ee220} - - - {535280e2-f8e7-4f75-923f-da0f3bf18f03} - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\base - - - Header Files\x86 - - - Header Files\x86 - - - Header Files\x86 - - - Header Files\x86 - - - Header Files\x86 - - - Header Files\x86 - - - - - Source Files\base - - - Source Files\base - - - Source Files\base - - - Source Files\base - - - Source Files\base - - - Source Files\base - - - Source Files\base - - - Source Files\base - - - Source Files\base - - - Source Files\base - - - Source Files\base - - - Source Files\base - - - Source Files\base - - - Source Files\base - - - Source Files\base - - - Source Files\x86 - - - Source Files\x86 - - - Source Files\x86 - - - Source Files\x86 - - - Source Files\x86 - - - Source Files\x86 - - - Source Files\x86 - - - \ No newline at end of file diff --git a/vsbuild/common.props b/vsbuild/common.props deleted file mode 100644 index 6cda5ee..0000000 --- a/vsbuild/common.props +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - $(Configuration)\$(Platform)\ - $(Configuration)\$(Platform)\$(ProjectName)\ - - - - MultiThreaded - false - true - _WINDOWS;NDEBUG;BOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE;BOOST_INTERPROCESS_SHARED_DIR_FUNC;%(PreprocessorDefinitions) - stdcpp20 - - - comsuppw.lib;%(AdditionalDependencies) - - - - \ No newline at end of file diff --git a/vsbuild/external_dependencies.props b/vsbuild/external_dependencies.props deleted file mode 100644 index 0b3d567..0000000 --- a/vsbuild/external_dependencies.props +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - ..\..\boost_1_88_0 - $(BOOST_PATH) - ..\..\googletest - - - - - - $(BOOST_PATH) - - - $(GTEST_PATH) - - - diff --git a/vsbuild/platform_x64.props b/vsbuild/platform_x64.props deleted file mode 100644 index 9507a68..0000000 --- a/vsbuild/platform_x64.props +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - $(STAGING_PATH_64) - $(STAGING_DLL_64) - $(STAGING_LIB_64) - $(STAGING_EXE_64) - $(STAGING_PDB_64) - - - - - _WIN64;%(PreprocessorDefinitions) - - - $(BOOST_PATH)\lib64-msvc-14.3\lib;%(AdditionalLibraryDirectories) - - - - - $(PLATFORM_32) - - - $(STAGING_PATH) - - - $(STAGING_DLL) - - - $(STAGING_LIB) - - - $(STAGING_EXE) - - - $(STAGING_PDB) - - - \ No newline at end of file diff --git a/vsbuild/platform_x86.props b/vsbuild/platform_x86.props deleted file mode 100644 index e97a4bc..0000000 --- a/vsbuild/platform_x86.props +++ /dev/null @@ -1,38 +0,0 @@ - - - - - _32 - $(STAGING_PATH_32) - $(STAGING_DLL_32) - $(STAGING_LIB_32) - $(STAGING_EXE_32) - $(STAGING_PDB_32) - - - - - $(BOOST_PATH)\lib32-msvc-14.3\lib;%(AdditionalLibraryDirectories) - - - - - $(PLATFORM_32) - - - $(STAGING_PATH) - - - $(STAGING_DLL) - - - $(STAGING_LIB) - - - $(STAGING_EXE) - - - $(STAGING_PDB) - - - \ No newline at end of file diff --git a/vsbuild/shared.vcxproj b/vsbuild/shared.vcxproj deleted file mode 100644 index 95fdeca..0000000 --- a/vsbuild/shared.vcxproj +++ /dev/null @@ -1,333 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - Release - Win32 - - - Release - x64 - - - - 15.0 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51} - shared - 10.0 - - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Disabled - stdcpp20 - Use - pch.h - pch.h - Default - USVFS_BUILD_TESTS;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - TurnOffAllWarnings - ..\include;%(AdditionalIncludeDirectories) - Level2 - - - - - Disabled - stdcpp20 - Use - pch.h - pch.h - Default - %(PreprocessorDefinitions) - MultiThreadedDebugDLL - TurnOffAllWarnings - ..\include;%(AdditionalIncludeDirectories) - Level2 - - - - - Disabled - stdcpp20 - Use - pch.h - pch.h - Default - USVFS_BUILD_TESTS;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - TurnOffAllWarnings - ..\include;%(AdditionalIncludeDirectories) - Level2 - - - - - Disabled - stdcpp20 - Use - pch.h - pch.h - Default - %(PreprocessorDefinitions) - MultiThreadedDebugDLL - TurnOffAllWarnings - ..\include;%(AdditionalIncludeDirectories) - Level2 - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - Use - pch.h - pch.h - TurnOffAllWarnings - ..\include;%(AdditionalIncludeDirectories) - Level2 - - - true - true - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - Use - pch.h - pch.h - USVFS_BUILD_TESTS;%(PreprocessorDefinitions) - MultiThreadedDLL - TurnOffAllWarnings - ..\include;%(AdditionalIncludeDirectories) - Level2 - - - true - true - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - Use - pch.h - pch.h - TurnOffAllWarnings - ..\include;%(AdditionalIncludeDirectories) - Level2 - - - true - true - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - Use - pch.h - pch.h - USVFS_BUILD_TESTS;%(PreprocessorDefinitions) - MultiThreadedDLL - TurnOffAllWarnings - ..\include;%(AdditionalIncludeDirectories) - /external:I$(BOOST_PATH) %(AdditionalOptions) - Level2 - - - true - true - - - - - - - - - Create - Create - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vsbuild/shared.vcxproj.filters b/vsbuild/shared.vcxproj.filters deleted file mode 100644 index fdd56fd..0000000 --- a/vsbuild/shared.vcxproj.filters +++ /dev/null @@ -1,99 +0,0 @@ - - - - - {3094d463-adf3-47ed-ad6c-644cfede79f8} - - - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - \ No newline at end of file diff --git a/vsbuild/shared_common.props b/vsbuild/shared_common.props deleted file mode 100644 index 5a12d25..0000000 --- a/vsbuild/shared_common.props +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - ..\include;$(BOOST_PATH);..\spdlog\include;%(AdditionalIncludeDirectories) - SPDLOG_USE_STD_FORMAT;SPDLOG_NO_NAME;SPDLOG_NO_REGISTRY_MUTEX;NOMINMAX;%(PreprocessorDefinitions) - /external:I$(BOOST_PATH) %(AdditionalOptions) - - - - \ No newline at end of file diff --git a/vsbuild/shared_test.vcxproj b/vsbuild/shared_test.vcxproj deleted file mode 100644 index 1417d22..0000000 --- a/vsbuild/shared_test.vcxproj +++ /dev/null @@ -1,96 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - - 15.0 - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8} - sharedtest - 10.0 - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - Disabled - Default - pch.h - MultiThreadedDebugDLL - - - Console - - - - - MaxSpeed - true - true - pch.h - MultiThreadedDLL - - - true - true - Console - - - - - - - - {2bb3300b-f08a-4063-95c4-8a0fadae6c51} - - - - - - \ No newline at end of file diff --git a/vsbuild/shared_test.vcxproj.filters b/vsbuild/shared_test.vcxproj.filters deleted file mode 100644 index 44b21ea..0000000 --- a/vsbuild/shared_test.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/vsbuild/spdlog.vcxproj b/vsbuild/spdlog.vcxproj deleted file mode 100644 index e1ef781..0000000 --- a/vsbuild/spdlog.vcxproj +++ /dev/null @@ -1,316 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - Release - Win32 - - - Release - x64 - - - - 15.0 - {CDADDEC0-B72B-43B4-831F-72BA85B72805} - spdlog - 10.0 - - - - Application - true - v143 - MultiByte - - - Application - true - v143 - MultiByte - - - Application - false - v143 - true - MultiByte - - - Application - false - v143 - true - MultiByte - - - Application - true - v143 - MultiByte - - - Application - true - v143 - MultiByte - - - Application - false - v143 - true - MultiByte - - - Application - false - v143 - true - MultiByte - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MaxSpeed - true - true - true - - - true - true - - - - - MaxSpeed - true - true - true - - - true - true - - - - - Disabled - true - - - - - Disabled - true - - - - - Disabled - true - - - - - Disabled - true - - - - - MaxSpeed - true - true - true - - - true - true - - - - - MaxSpeed - true - true - true - - - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vsbuild/spdlog.vcxproj.filters b/vsbuild/spdlog.vcxproj.filters deleted file mode 100644 index c75f3c7..0000000 --- a/vsbuild/spdlog.vcxproj.filters +++ /dev/null @@ -1,109 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {22f3bf95-4a07-4d0e-bfee-1d6d88a4b0ac} - - - {b954eb35-ef39-489d-9bd4-6555141d2a00} - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files\details - - - Header Files\details - - - Header Files\details - - - Header Files\details - - - Header Files\details - - - Header Files\details - - - Header Files\details - - - Header Files\details - - - Header Files\details - - - Header Files\details - - - Header Files\details - - - Header Files\details - - - Header Files\details - - - Header Files\sinks - - - Header Files\sinks - - - Header Files\sinks - - - Header Files\sinks - - - Header Files\sinks - - - Header Files\sinks - - - Header Files\sinks - - - Header Files\sinks - - - Header Files\sinks - - - \ No newline at end of file diff --git a/vsbuild/stage_helper.cmd b/vsbuild/stage_helper.cmd deleted file mode 100644 index 5604776..0000000 --- a/vsbuild/stage_helper.cmd +++ /dev/null @@ -1,19 +0,0 @@ -@echo off -echo ^> Staging %1 ... -shift - -:loop -set src=%~1 -set dest=%~2 -if "%src%"=="" goto done -if "%dest%"=="" goto error -echo f | xcopy /F/Y "%src%" "%dest%" | find " -> " -shift -shift -goto loop - -:error -echo stage_helper: source "%1" has no destination?! -exit /b 1 - -:done diff --git a/vsbuild/staging_paths.props b/vsbuild/staging_paths.props deleted file mode 100644 index e73ea36..0000000 --- a/vsbuild/staging_paths.props +++ /dev/null @@ -1,54 +0,0 @@ - - - - - ..\..\.. - $(STAGING_BASE)\install - $(STAGING_BASE)\install - $(STAGING_PATH_32)\bin - $(STAGING_PATH_64)\bin - $(STAGING_PATH_32)\libs - $(STAGING_PATH_64)\libs - $(STAGING_PATH_32)\bin - $(STAGING_PATH_64)\bin - $(STAGING_PATH_32)\pdb - $(STAGING_PATH_64)\pdb - - - - - - $(STAGING_BASE) - - - $(STAGING_PATH_32) - - - $(STAGING_PATH_64) - - - $(STAGING_DLL_32) - - - $(STAGING_DLL_64) - - - $(STAGING_LIB_32) - - - $(STAGING_LIB_64) - - - $(STAGING_EXE_32) - - - $(STAGING_EXE_64) - - - $(STAGING_PDB_32) - - - $(STAGING_PDB_64) - - - \ No newline at end of file diff --git a/vsbuild/test_common.props b/vsbuild/test_common.props deleted file mode 100644 index 2812bdc..0000000 --- a/vsbuild/test_common.props +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - ..\test\bin\ - $(ProjectName)_$(PlatformShortName) - - - - %(AdditionalIncludeDirectories);$(GTEST_PATH)\googletest\include - USVFS_BUILD_TESTS;UNITTEST;%(PreprocessorDefinitions) - - - - %(AdditionalLibraryDirectories);$(GTEST_LIBDIR);$(GTEST_PATH)\build\$(Platform)\Release\lib - - - %(AdditionalLibraryDirectories);$(GTEST_LIBDIR);$(GTEST_PATH)\build\$(Platform)\Debug\lib - - gtest.lib;%(AdditionalDependencies) - - - - \ No newline at end of file diff --git a/vsbuild/test_file_operations.vcxproj b/vsbuild/test_file_operations.vcxproj deleted file mode 100644 index 85a616c..0000000 --- a/vsbuild/test_file_operations.vcxproj +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - - - 15.0 - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A} - testfileoperations - 10.0 - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - - ntdll.lib;%(AdditionalDependencies) - - - - - Disabled - Default - pch.h - MultiThreadedDebugDLL - - - Console - - - - - MaxSpeed - true - true - pch.h - MultiThreadedDLL - - - true - true - Console - - - - - - - - - - - {2bb3300b-f08a-4063-95c4-8a0fadae6c51} - - - - - - - - - - - - \ No newline at end of file diff --git a/vsbuild/test_file_operations.vcxproj.filters b/vsbuild/test_file_operations.vcxproj.filters deleted file mode 100644 index 1f7f129..0000000 --- a/vsbuild/test_file_operations.vcxproj.filters +++ /dev/null @@ -1,45 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/vsbuild/testinject_bin.vcxproj b/vsbuild/testinject_bin.vcxproj deleted file mode 100644 index a7810e9..0000000 --- a/vsbuild/testinject_bin.vcxproj +++ /dev/null @@ -1,119 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - - 15.0 - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A} - testinjectbin - 10.0 - - - - Application - true - v143 - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - Disabled - Default - pch.h - MultiThreadedDebugDLL - - - Console - - - - - MaxSpeed - true - true - pch.h - MultiThreadedDLL - - - true - true - Console - - - - - - - - - \ No newline at end of file diff --git a/vsbuild/testinject_bin.vcxproj.filters b/vsbuild/testinject_bin.vcxproj.filters deleted file mode 100644 index 45deb2c..0000000 --- a/vsbuild/testinject_bin.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/vsbuild/testinject_dll.vcxproj b/vsbuild/testinject_dll.vcxproj deleted file mode 100644 index 1173c9f..0000000 --- a/vsbuild/testinject_dll.vcxproj +++ /dev/null @@ -1,96 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - - 15.0 - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280} - testinjectdll - 10.0 - - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - - - - - - - - Disabled - Default - pch.h - MultiThreadedDebugDLL - - - Console - - - - - MaxSpeed - true - true - pch.h - MultiThreadedDLL - - - true - true - Console - - - - - - - - - - - - \ No newline at end of file diff --git a/vsbuild/testinject_dll.vcxproj.filters b/vsbuild/testinject_dll.vcxproj.filters deleted file mode 100644 index bb4c678..0000000 --- a/vsbuild/testinject_dll.vcxproj.filters +++ /dev/null @@ -1,27 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - - - Header Files - - - \ No newline at end of file diff --git a/vsbuild/thooklib.vcxproj b/vsbuild/thooklib.vcxproj deleted file mode 100644 index d1575b7..0000000 --- a/vsbuild/thooklib.vcxproj +++ /dev/null @@ -1,283 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - Release - Win32 - - - Release - x64 - - - - 15.0 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E} - thooklib - 10.0 - - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Disabled - stdcpp20 - Use - pch.h - pch.h - Default - MultiThreadedDebugDLL - - - - - Disabled - stdcpp20 - Use - pch.h - pch.h - Default - MultiThreadedDebugDLL - - - - - Disabled - stdcpp20 - Use - pch.h - pch.h - Default - MultiThreadedDebugDLL - - - - - Disabled - stdcpp20 - Use - pch.h - pch.h - Default - MultiThreadedDebugDLL - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - Use - pch.h - pch.h - - - true - true - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - Use - pch.h - pch.h - MultiThreadedDLL - - - true - true - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - Use - pch.h - pch.h - - - true - true - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - Use - pch.h - pch.h - MultiThreadedDLL - - - true - true - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - Create - Create - - - - - - - - - \ No newline at end of file diff --git a/vsbuild/thooklib.vcxproj.filters b/vsbuild/thooklib.vcxproj.filters deleted file mode 100644 index 2d36f2f..0000000 --- a/vsbuild/thooklib.vcxproj.filters +++ /dev/null @@ -1,42 +0,0 @@ - - - - - {1f0d703e-09c9-4159-9b2b-da442a342fce} - - - - - src - - - src - - - src - - - src - - - src - - - - - src - - - src - - - src - - - src - - - src - - - \ No newline at end of file diff --git a/vsbuild/thooklib_test.vcxproj b/vsbuild/thooklib_test.vcxproj deleted file mode 100644 index aac7ff6..0000000 --- a/vsbuild/thooklib_test.vcxproj +++ /dev/null @@ -1,137 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - - 15.0 - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33} - thooklibtest - 10.0 - - - - Application - true - v143 - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - - - - - Disabled - Default - pch.h - MultiThreadedDebugDLL - - - Console - - - - - MaxSpeed - true - true - pch.h - MultiThreadedDLL - - - true - true - Console - - - - - - - - {5338b9d6-c2a9-4ded-b7e8-31292b96cbf2} - - - {2bb3300b-f08a-4063-95c4-8a0fadae6c51} - - - {1ce90f86-126e-40ab-bd8b-08b25fd2e68e} - - - {5b0e078a-d196-4ebb-bd6e-dcfb48b15e90} - - - - - - \ No newline at end of file diff --git a/vsbuild/thooklib_test.vcxproj.filters b/vsbuild/thooklib_test.vcxproj.filters deleted file mode 100644 index 74d92c2..0000000 --- a/vsbuild/thooklib_test.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/vsbuild/tinjectlib.vcxproj b/vsbuild/tinjectlib.vcxproj deleted file mode 100644 index 080c68e..0000000 --- a/vsbuild/tinjectlib.vcxproj +++ /dev/null @@ -1,243 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - Release - Win32 - - - Release - x64 - - - - 15.0 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05} - tinjectlib - 10.0 - - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Disabled - stdcpp20 - Default - MultiThreadedDebugDLL - - - - - Disabled - stdcpp20 - Default - MultiThreadedDebugDLL - - - - - Disabled - stdcpp20 - Default - MultiThreadedDebugDLL - - - - - Disabled - stdcpp20 - Default - MultiThreadedDebugDLL - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - - - true - true - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - MultiThreadedDLL - - - true - true - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - - - true - true - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - MultiThreadedDLL - - - true - true - - - - - - - - - - - - - \ No newline at end of file diff --git a/vsbuild/tinjectlib.vcxproj.filters b/vsbuild/tinjectlib.vcxproj.filters deleted file mode 100644 index 7356815..0000000 --- a/vsbuild/tinjectlib.vcxproj.filters +++ /dev/null @@ -1,21 +0,0 @@ - - - - - {cf5cdb23-5c38-4157-9092-7ba16724436c} - - - - - src - - - src - - - - - src - - - \ No newline at end of file diff --git a/vsbuild/tinjectlib_test.vcxproj b/vsbuild/tinjectlib_test.vcxproj deleted file mode 100644 index 81d0732..0000000 --- a/vsbuild/tinjectlib_test.vcxproj +++ /dev/null @@ -1,130 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - - 15.0 - {5F393577-7E8E-43A4-B476-BFCC78147D0D} - tinjectlibtest - 10.0 - - - - Application - true - v143 - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - Disabled - Default - pch.h - MultiThreadedDebugDLL - - - Console - - - - - MaxSpeed - true - true - pch.h - MultiThreadedDLL - - - true - true - Console - - - - - - - - {5338b9d6-c2a9-4ded-b7e8-31292b96cbf2} - - - {2bb3300b-f08a-4063-95c4-8a0fadae6c51} - - - {d18d0b1c-37b4-48a8-88c0-399de2815c05} - - - - - - \ No newline at end of file diff --git a/vsbuild/tinjectlib_test.vcxproj.filters b/vsbuild/tinjectlib_test.vcxproj.filters deleted file mode 100644 index d6726ff..0000000 --- a/vsbuild/tinjectlib_test.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/vsbuild/tvfs_test.vcxproj b/vsbuild/tvfs_test.vcxproj deleted file mode 100644 index ef57cc5..0000000 --- a/vsbuild/tvfs_test.vcxproj +++ /dev/null @@ -1,110 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - - 15.0 - {1DDD14EC-2274-4793-803E-B64D278AFD7A} - usvfstest - 10.0 - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - Disabled - Default - pch.h - MultiThreadedDebugDLL - ..\src\usvfs_dll;%(AdditionalIncludeDirectories) - - - Console - usvfs_$(PlatformShortName).dll - - - - - MaxSpeed - true - true - pch.h - MultiThreadedDLL - ..\src\usvfs_dll;%(AdditionalIncludeDirectories) - - - true - true - Console - usvfs_$(PlatformShortName).dll - - - - - - - - {2bb3300b-f08a-4063-95c4-8a0fadae6c51} - - - {cdaddec0-b72b-43b4-831f-72ba85b72805} - - - {562b0058-4701-4284-8b40-d87648a3f64c} - - - - - - diff --git a/vsbuild/tvfs_test.vcxproj.filters b/vsbuild/tvfs_test.vcxproj.filters deleted file mode 100644 index fdb0f00..0000000 --- a/vsbuild/tvfs_test.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/vsbuild/udis86.vcxproj b/vsbuild/udis86.vcxproj deleted file mode 100644 index ccd7dd3..0000000 --- a/vsbuild/udis86.vcxproj +++ /dev/null @@ -1,365 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - Release - Win32 - - - Release - x64 - - - - 15.0 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90} - udis86 - 10.0 - - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PrepareForBuild - - - PrepareForBuild - - - PrepareForBuild - - - PrepareForBuild - - - PrepareForBuild - - - PrepareForBuild - - - PrepareForBuild - - - PrepareForBuild - - - - Disabled - C:\Games\MO2\build\usvfs_clean\udis86\libudis86;%(AdditionalIncludeDirectories) - MultiThreadedDebug - stdcpp17 - Default - - - python ..\udis86\scripts\ud_itab.py ..\udis86\docs\x86\optable.xml ..\udis86\libudis86 - - - Building udis86 optable - - - ..\udis86\libudis86\itab.c;..\udis86\libudis86\itab.h - - - ..\udis86\docs\x86\optable.xml;..\udis86\scripts\ud_itab.py;..\udis86\scripts\ud_opcode.py - - - - - Disabled - C:\Games\MO2\build\usvfs_clean\udis86\libudis86;%(AdditionalIncludeDirectories) - MultiThreadedDebug - stdcpp17 - Default - - - python ..\udis86\scripts\ud_itab.py ..\udis86\docs\x86\optable.xml ..\udis86\libudis86 - - - Building udis86 optable - - - ..\udis86\libudis86\itab.c;..\udis86\libudis86\itab.h - - - ..\udis86\docs\x86\optable.xml;..\udis86\scripts\ud_itab.py;..\udis86\scripts\ud_opcode.py - - - - - Disabled - C:\Games\MO2\build\usvfs_clean\udis86\libudis86;%(AdditionalIncludeDirectories) - MultiThreadedDebug - stdcpp17 - Default - - - python ..\udis86\scripts\ud_itab.py ..\udis86\docs\x86\optable.xml ..\udis86\libudis86 - - - Building udis86 optable - - - ..\udis86\libudis86\itab.c;..\udis86\libudis86\itab.h - - - ..\udis86\docs\x86\optable.xml;..\udis86\scripts\ud_itab.py;..\udis86\scripts\ud_opcode.py - - - - - Disabled - C:\Games\MO2\build\usvfs_clean\udis86\libudis86;%(AdditionalIncludeDirectories) - MultiThreadedDebug - stdcpp17 - Default - - - python ..\udis86\scripts\ud_itab.py ..\udis86\docs\x86\optable.xml ..\udis86\libudis86 - - - Building udis86 optable - - - ..\udis86\libudis86\itab.c;..\udis86\libudis86\itab.h - - - ..\udis86\docs\x86\optable.xml;..\udis86\scripts\ud_itab.py;..\udis86\scripts\ud_opcode.py - - - - - MaxSpeed - true - true - C:\Games\MO2\build\usvfs_clean\udis86\libudis86;%(AdditionalIncludeDirectories) - - - true - true - - - python ..\udis86\scripts\ud_itab.py ..\udis86\docs\x86\optable.xml ..\udis86\libudis86 - - - Building udis86 optable - - - ..\udis86\libudis86\itab.c;..\udis86\libudis86\itab.h - - - ..\udis86\docs\x86\optable.xml;..\udis86\scripts\ud_itab.py;..\udis86\scripts\ud_opcode.py - - - - - MaxSpeed - true - true - C:\Games\MO2\build\usvfs_clean\udis86\libudis86;%(AdditionalIncludeDirectories) - - - true - true - - - python ..\udis86\scripts\ud_itab.py ..\udis86\docs\x86\optable.xml ..\udis86\libudis86 - - - Building udis86 optable - - - ..\udis86\libudis86\itab.c;..\udis86\libudis86\itab.h - - - ..\udis86\docs\x86\optable.xml;..\udis86\scripts\ud_itab.py;..\udis86\scripts\ud_opcode.py - - - - - MaxSpeed - true - true - C:\Games\MO2\build\usvfs_clean\udis86\libudis86;%(AdditionalIncludeDirectories) - - - true - true - - - python ..\udis86\scripts\ud_itab.py ..\udis86\docs\x86\optable.xml ..\udis86\libudis86 - - - Building udis86 optable - - - ..\udis86\libudis86\itab.c;..\udis86\libudis86\itab.h - - - ..\udis86\docs\x86\optable.xml;..\udis86\scripts\ud_itab.py;..\udis86\scripts\ud_opcode.py - - - - - MaxSpeed - true - true - C:\Games\MO2\build\usvfs_clean\udis86\libudis86;%(AdditionalIncludeDirectories) - - - true - true - - - python ..\udis86\scripts\ud_itab.py ..\udis86\docs\x86\optable.xml ..\udis86\libudis86 - - - Building udis86 optable - - - ..\udis86\libudis86\itab.c;..\udis86\libudis86\itab.h - - - ..\udis86\docs\x86\optable.xml;..\udis86\scripts\ud_itab.py;..\udis86\scripts\ud_opcode.py - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vsbuild/udis86.vcxproj.filters b/vsbuild/udis86.vcxproj.filters deleted file mode 100644 index 660f57b..0000000 --- a/vsbuild/udis86.vcxproj.filters +++ /dev/null @@ -1,57 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/vsbuild/usvfs.sln b/vsbuild/usvfs.sln deleted file mode 100644 index 0703e1a..0000000 --- a/vsbuild/usvfs.sln +++ /dev/null @@ -1,406 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.10.34916.146 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared", "shared.vcxproj", "{2BB3300B-F08A-4063-95C4-8A0FADAE6C51}" - ProjectSection(ProjectDependencies) = postProject - {CDADDEC0-B72B-43B4-831F-72BA85B72805} = {CDADDEC0-B72B-43B4-831F-72BA85B72805} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared_test", "shared_test.vcxproj", "{26B28EFA-5EEB-45AC-AF8F-C20F478070F8}" - ProjectSection(ProjectDependencies) = postProject - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51} = {2BB3300B-F08A-4063-95C4-8A0FADAE6C51} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testinject_bin", "testinject_bin.vcxproj", "{5705ABC8-8CF4-4A1C-AACF-22554B38E04A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testinject_dll", "testinject_dll.vcxproj", "{D536BD2F-BA2D-4C70-A2F8-EF08580F8280}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "thooklib", "thooklib.vcxproj", "{1CE90F86-126E-40AB-BD8B-08B25FD2E68E}" - ProjectSection(ProjectDependencies) = postProject - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51} = {2BB3300B-F08A-4063-95C4-8A0FADAE6C51} - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2} = {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2} - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90} = {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "thooklib_test", "thooklib_test.vcxproj", "{931A68BE-AF5F-48C9-AFAE-C8DC08103E33}" - ProjectSection(ProjectDependencies) = postProject - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E} = {1CE90F86-126E-40AB-BD8B-08B25FD2E68E} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinjectlib", "tinjectlib.vcxproj", "{D18D0B1C-37B4-48A8-88C0-399DE2815C05}" - ProjectSection(ProjectDependencies) = postProject - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51} = {2BB3300B-F08A-4063-95C4-8A0FADAE6C51} - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2} = {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinjectlib_test", "tinjectlib_test.vcxproj", "{5F393577-7E8E-43A4-B476-BFCC78147D0D}" - ProjectSection(ProjectDependencies) = postProject - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51} = {2BB3300B-F08A-4063-95C4-8A0FADAE6C51} - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A} = {5705ABC8-8CF4-4A1C-AACF-22554B38E04A} - {D18D0B1C-37B4-48A8-88C0-399DE2815C05} = {D18D0B1C-37B4-48A8-88C0-399DE2815C05} - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280} = {D536BD2F-BA2D-4C70-A2F8-EF08580F8280} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usvfs_dll", "usvfs_dll.vcxproj", "{562B0058-4701-4284-8B40-D87648A3F64C}" - ProjectSection(ProjectDependencies) = postProject - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E} = {1CE90F86-126E-40AB-BD8B-08B25FD2E68E} - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51} = {2BB3300B-F08A-4063-95C4-8A0FADAE6C51} - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6} = {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6} - {D18D0B1C-37B4-48A8-88C0-399DE2815C05} = {D18D0B1C-37B4-48A8-88C0-399DE2815C05} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usvfs_proxy", "usvfs_proxy.vcxproj", "{50AC03C1-BB24-4033-90E6-ABE65BCC13DC}" - ProjectSection(ProjectDependencies) = postProject - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6} = {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usvfs_helper", "usvfs_helper.vcxproj", "{BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}" - ProjectSection(ProjectDependencies) = postProject - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51} = {2BB3300B-F08A-4063-95C4-8A0FADAE6C51} - {D18D0B1C-37B4-48A8-88C0-399DE2815C05} = {D18D0B1C-37B4-48A8-88C0-399DE2815C05} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tvfs_test", "tvfs_test.vcxproj", "{1DDD14EC-2274-4793-803E-B64D278AFD7A}" - ProjectSection(ProjectDependencies) = postProject - {562B0058-4701-4284-8B40-D87648A3F64C} = {562B0058-4701-4284-8B40-D87648A3F64C} - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{EDA9B67D-1E64-4CAB-8391-10712538C821}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{9A2047E2-0EC2-409E-842B-B7B360B2A45F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asmjit", "asmjit.vcxproj", "{5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "udis86", "udis86.vcxproj", "{5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spdlog", "spdlog.vcxproj", "{CDADDEC0-B72B-43B4-831F-72BA85B72805}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_file_operations", "test_file_operations.vcxproj", "{0B2FF5AF-8580-458C-8EF4-10E6B6398D3A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usvfs_test", "usvfs_test.vcxproj", "{CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usvfs_test_runner", "usvfs_test_runner.vcxproj", "{0452CB4D-A906-4717-94AC-7A450E479BE1}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "injection", "injection", "{60262FE7-A84B-4B73-BE5D-0B5886A28BB8}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usvfs_global_test", "usvfs_global_test.vcxproj", "{4A355317-3634-4C98-AFB1-8BA718D54727}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usvfs_global_test_runner", "usvfs_global_test_runner.vcxproj", "{B785B3FB-2F86-4042-94BB-EEE4C30D4EA6}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - DebugTest|x64 = DebugTest|x64 - DebugTest|x86 = DebugTest|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - ReleaseTest|x64 = ReleaseTest|x64 - ReleaseTest|x86 = ReleaseTest|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.Debug|x64.ActiveCfg = Debug|x64 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.Debug|x64.Build.0 = Debug|x64 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.Debug|x86.ActiveCfg = Debug|Win32 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.Debug|x86.Build.0 = Debug|Win32 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.DebugTest|x64.Build.0 = DebugTest|x64 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.DebugTest|x86.Build.0 = DebugTest|Win32 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.Release|x64.ActiveCfg = Release|x64 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.Release|x64.Build.0 = Release|x64 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.Release|x86.ActiveCfg = Release|Win32 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.Release|x86.Build.0 = Release|Win32 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {2BB3300B-F08A-4063-95C4-8A0FADAE6C51}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8}.Debug|x64.ActiveCfg = Debug|x64 - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8}.Debug|x86.ActiveCfg = Debug|Win32 - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8}.DebugTest|x64.Build.0 = DebugTest|x64 - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8}.DebugTest|x86.Build.0 = DebugTest|Win32 - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8}.Release|x64.ActiveCfg = Release|x64 - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8}.Release|x86.ActiveCfg = Release|Win32 - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A}.Debug|x64.ActiveCfg = Debug|x64 - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A}.Debug|x86.ActiveCfg = Debug|Win32 - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A}.DebugTest|x64.Build.0 = DebugTest|x64 - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A}.DebugTest|x86.Build.0 = DebugTest|Win32 - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A}.Release|x64.ActiveCfg = Release|x64 - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A}.Release|x86.ActiveCfg = Release|Win32 - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280}.Debug|x64.ActiveCfg = Debug|x64 - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280}.Debug|x86.ActiveCfg = Debug|Win32 - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280}.DebugTest|x64.Build.0 = DebugTest|x64 - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280}.DebugTest|x86.Build.0 = DebugTest|Win32 - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280}.Release|x64.ActiveCfg = Release|x64 - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280}.Release|x86.ActiveCfg = Release|Win32 - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.Debug|x64.ActiveCfg = Debug|x64 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.Debug|x64.Build.0 = Debug|x64 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.Debug|x86.ActiveCfg = Debug|Win32 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.Debug|x86.Build.0 = Debug|Win32 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.DebugTest|x64.Build.0 = DebugTest|x64 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.DebugTest|x86.Build.0 = DebugTest|Win32 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.Release|x64.ActiveCfg = Release|x64 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.Release|x64.Build.0 = Release|x64 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.Release|x86.ActiveCfg = Release|Win32 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.Release|x86.Build.0 = Release|Win32 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33}.Debug|x64.ActiveCfg = Debug|x64 - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33}.Debug|x86.ActiveCfg = Debug|Win32 - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33}.DebugTest|x64.Build.0 = DebugTest|x64 - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33}.DebugTest|x86.Build.0 = DebugTest|Win32 - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33}.Release|x64.ActiveCfg = Release|x64 - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33}.Release|x86.ActiveCfg = Release|Win32 - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.Debug|x64.ActiveCfg = Debug|x64 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.Debug|x64.Build.0 = Debug|x64 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.Debug|x86.ActiveCfg = Debug|Win32 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.Debug|x86.Build.0 = Debug|Win32 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.DebugTest|x64.Build.0 = DebugTest|x64 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.DebugTest|x86.Build.0 = DebugTest|Win32 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.Release|x64.ActiveCfg = Release|x64 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.Release|x64.Build.0 = Release|x64 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.Release|x86.ActiveCfg = Release|Win32 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.Release|x86.Build.0 = Release|Win32 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {D18D0B1C-37B4-48A8-88C0-399DE2815C05}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {5F393577-7E8E-43A4-B476-BFCC78147D0D}.Debug|x64.ActiveCfg = Debug|x64 - {5F393577-7E8E-43A4-B476-BFCC78147D0D}.Debug|x86.ActiveCfg = Debug|Win32 - {5F393577-7E8E-43A4-B476-BFCC78147D0D}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {5F393577-7E8E-43A4-B476-BFCC78147D0D}.DebugTest|x64.Build.0 = DebugTest|x64 - {5F393577-7E8E-43A4-B476-BFCC78147D0D}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {5F393577-7E8E-43A4-B476-BFCC78147D0D}.DebugTest|x86.Build.0 = DebugTest|Win32 - {5F393577-7E8E-43A4-B476-BFCC78147D0D}.Release|x64.ActiveCfg = Release|x64 - {5F393577-7E8E-43A4-B476-BFCC78147D0D}.Release|x86.ActiveCfg = Release|Win32 - {5F393577-7E8E-43A4-B476-BFCC78147D0D}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {5F393577-7E8E-43A4-B476-BFCC78147D0D}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {5F393577-7E8E-43A4-B476-BFCC78147D0D}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {5F393577-7E8E-43A4-B476-BFCC78147D0D}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {562B0058-4701-4284-8B40-D87648A3F64C}.Debug|x64.ActiveCfg = Debug|x64 - {562B0058-4701-4284-8B40-D87648A3F64C}.Debug|x64.Build.0 = Debug|x64 - {562B0058-4701-4284-8B40-D87648A3F64C}.Debug|x86.ActiveCfg = Debug|Win32 - {562B0058-4701-4284-8B40-D87648A3F64C}.Debug|x86.Build.0 = Debug|Win32 - {562B0058-4701-4284-8B40-D87648A3F64C}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {562B0058-4701-4284-8B40-D87648A3F64C}.DebugTest|x64.Build.0 = DebugTest|x64 - {562B0058-4701-4284-8B40-D87648A3F64C}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {562B0058-4701-4284-8B40-D87648A3F64C}.DebugTest|x86.Build.0 = DebugTest|Win32 - {562B0058-4701-4284-8B40-D87648A3F64C}.Release|x64.ActiveCfg = Release|x64 - {562B0058-4701-4284-8B40-D87648A3F64C}.Release|x64.Build.0 = Release|x64 - {562B0058-4701-4284-8B40-D87648A3F64C}.Release|x86.ActiveCfg = Release|Win32 - {562B0058-4701-4284-8B40-D87648A3F64C}.Release|x86.Build.0 = Release|Win32 - {562B0058-4701-4284-8B40-D87648A3F64C}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {562B0058-4701-4284-8B40-D87648A3F64C}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {562B0058-4701-4284-8B40-D87648A3F64C}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {562B0058-4701-4284-8B40-D87648A3F64C}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.Debug|x64.ActiveCfg = Debug|x64 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.Debug|x64.Build.0 = Debug|x64 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.Debug|x86.ActiveCfg = Debug|Win32 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.Debug|x86.Build.0 = Debug|Win32 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.DebugTest|x64.Build.0 = DebugTest|x64 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.DebugTest|x86.Build.0 = DebugTest|Win32 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.Release|x64.ActiveCfg = Release|x64 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.Release|x64.Build.0 = Release|x64 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.Release|x86.ActiveCfg = Release|Win32 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.Release|x86.Build.0 = Release|Win32 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.Debug|x64.ActiveCfg = Debug|x64 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.Debug|x64.Build.0 = Debug|x64 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.Debug|x86.ActiveCfg = Debug|Win32 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.Debug|x86.Build.0 = Debug|Win32 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.DebugTest|x64.Build.0 = DebugTest|x64 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.DebugTest|x86.Build.0 = DebugTest|Win32 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.Release|x64.ActiveCfg = Release|x64 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.Release|x64.Build.0 = Release|x64 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.Release|x86.ActiveCfg = Release|Win32 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.Release|x86.Build.0 = Release|Win32 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {1DDD14EC-2274-4793-803E-B64D278AFD7A}.Debug|x64.ActiveCfg = Debug|x64 - {1DDD14EC-2274-4793-803E-B64D278AFD7A}.Debug|x86.ActiveCfg = Debug|Win32 - {1DDD14EC-2274-4793-803E-B64D278AFD7A}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {1DDD14EC-2274-4793-803E-B64D278AFD7A}.DebugTest|x64.Build.0 = DebugTest|x64 - {1DDD14EC-2274-4793-803E-B64D278AFD7A}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {1DDD14EC-2274-4793-803E-B64D278AFD7A}.DebugTest|x86.Build.0 = DebugTest|Win32 - {1DDD14EC-2274-4793-803E-B64D278AFD7A}.Release|x64.ActiveCfg = Release|x64 - {1DDD14EC-2274-4793-803E-B64D278AFD7A}.Release|x86.ActiveCfg = Release|Win32 - {1DDD14EC-2274-4793-803E-B64D278AFD7A}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {1DDD14EC-2274-4793-803E-B64D278AFD7A}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {1DDD14EC-2274-4793-803E-B64D278AFD7A}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {1DDD14EC-2274-4793-803E-B64D278AFD7A}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.Debug|x64.ActiveCfg = Debug|x64 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.Debug|x64.Build.0 = Debug|x64 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.Debug|x86.ActiveCfg = Debug|Win32 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.Debug|x86.Build.0 = Debug|Win32 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.DebugTest|x64.Build.0 = DebugTest|x64 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.DebugTest|x86.Build.0 = DebugTest|Win32 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.Release|x64.ActiveCfg = Release|x64 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.Release|x64.Build.0 = Release|x64 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.Release|x86.ActiveCfg = Release|Win32 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.Release|x86.Build.0 = Release|Win32 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.Debug|x64.ActiveCfg = Debug|x64 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.Debug|x64.Build.0 = Debug|x64 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.Debug|x86.ActiveCfg = Debug|Win32 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.Debug|x86.Build.0 = Debug|Win32 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.DebugTest|x64.Build.0 = DebugTest|x64 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.DebugTest|x86.Build.0 = DebugTest|Win32 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.Release|x64.ActiveCfg = Release|x64 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.Release|x64.Build.0 = Release|x64 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.Release|x86.ActiveCfg = Release|Win32 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.Release|x86.Build.0 = Release|Win32 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.Debug|x64.ActiveCfg = Debug|x64 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.Debug|x64.Build.0 = Debug|x64 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.Debug|x86.ActiveCfg = Debug|Win32 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.Debug|x86.Build.0 = Debug|Win32 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.DebugTest|x64.Build.0 = DebugTest|x64 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.DebugTest|x86.Build.0 = DebugTest|Win32 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.Release|x64.ActiveCfg = Release|x64 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.Release|x64.Build.0 = Release|x64 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.Release|x86.ActiveCfg = Release|Win32 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.Release|x86.Build.0 = Release|Win32 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {CDADDEC0-B72B-43B4-831F-72BA85B72805}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A}.Debug|x64.ActiveCfg = Debug|x64 - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A}.Debug|x86.ActiveCfg = Debug|Win32 - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A}.DebugTest|x64.Build.0 = DebugTest|x64 - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A}.DebugTest|x86.Build.0 = DebugTest|Win32 - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A}.Release|x64.ActiveCfg = Release|x64 - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A}.Release|x86.ActiveCfg = Release|Win32 - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B}.Debug|x64.ActiveCfg = Debug|x64 - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B}.Debug|x86.ActiveCfg = Debug|Win32 - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B}.DebugTest|x64.Build.0 = DebugTest|x64 - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B}.DebugTest|x86.Build.0 = DebugTest|Win32 - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B}.Release|x64.ActiveCfg = Release|x64 - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B}.Release|x86.ActiveCfg = Release|Win32 - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {0452CB4D-A906-4717-94AC-7A450E479BE1}.Debug|x64.ActiveCfg = Debug|x64 - {0452CB4D-A906-4717-94AC-7A450E479BE1}.Debug|x86.ActiveCfg = Debug|Win32 - {0452CB4D-A906-4717-94AC-7A450E479BE1}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {0452CB4D-A906-4717-94AC-7A450E479BE1}.DebugTest|x64.Build.0 = DebugTest|x64 - {0452CB4D-A906-4717-94AC-7A450E479BE1}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {0452CB4D-A906-4717-94AC-7A450E479BE1}.DebugTest|x86.Build.0 = DebugTest|Win32 - {0452CB4D-A906-4717-94AC-7A450E479BE1}.Release|x64.ActiveCfg = Release|x64 - {0452CB4D-A906-4717-94AC-7A450E479BE1}.Release|x86.ActiveCfg = Release|Win32 - {0452CB4D-A906-4717-94AC-7A450E479BE1}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {0452CB4D-A906-4717-94AC-7A450E479BE1}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {0452CB4D-A906-4717-94AC-7A450E479BE1}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {0452CB4D-A906-4717-94AC-7A450E479BE1}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {4A355317-3634-4C98-AFB1-8BA718D54727}.Debug|x64.ActiveCfg = DebugTest|x64 - {4A355317-3634-4C98-AFB1-8BA718D54727}.Debug|x86.ActiveCfg = DebugTest|Win32 - {4A355317-3634-4C98-AFB1-8BA718D54727}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {4A355317-3634-4C98-AFB1-8BA718D54727}.DebugTest|x64.Build.0 = DebugTest|x64 - {4A355317-3634-4C98-AFB1-8BA718D54727}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {4A355317-3634-4C98-AFB1-8BA718D54727}.DebugTest|x86.Build.0 = DebugTest|Win32 - {4A355317-3634-4C98-AFB1-8BA718D54727}.Release|x64.ActiveCfg = ReleaseTest|x64 - {4A355317-3634-4C98-AFB1-8BA718D54727}.Release|x86.ActiveCfg = ReleaseTest|Win32 - {4A355317-3634-4C98-AFB1-8BA718D54727}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {4A355317-3634-4C98-AFB1-8BA718D54727}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {4A355317-3634-4C98-AFB1-8BA718D54727}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {4A355317-3634-4C98-AFB1-8BA718D54727}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6}.Debug|x64.ActiveCfg = DebugTest|x64 - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6}.Debug|x86.ActiveCfg = DebugTest|Win32 - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6}.DebugTest|x64.ActiveCfg = DebugTest|x64 - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6}.DebugTest|x64.Build.0 = DebugTest|x64 - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6}.DebugTest|x86.ActiveCfg = DebugTest|Win32 - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6}.DebugTest|x86.Build.0 = DebugTest|Win32 - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6}.Release|x64.ActiveCfg = ReleaseTest|x64 - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6}.Release|x86.ActiveCfg = ReleaseTest|Win32 - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6}.ReleaseTest|x64.ActiveCfg = ReleaseTest|x64 - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6}.ReleaseTest|x64.Build.0 = ReleaseTest|x64 - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6}.ReleaseTest|x86.ActiveCfg = ReleaseTest|Win32 - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6}.ReleaseTest|x86.Build.0 = ReleaseTest|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {26B28EFA-5EEB-45AC-AF8F-C20F478070F8} = {EDA9B67D-1E64-4CAB-8391-10712538C821} - {5705ABC8-8CF4-4A1C-AACF-22554B38E04A} = {EDA9B67D-1E64-4CAB-8391-10712538C821} - {D536BD2F-BA2D-4C70-A2F8-EF08580F8280} = {EDA9B67D-1E64-4CAB-8391-10712538C821} - {1CE90F86-126E-40AB-BD8B-08B25FD2E68E} = {60262FE7-A84B-4B73-BE5D-0B5886A28BB8} - {931A68BE-AF5F-48C9-AFAE-C8DC08103E33} = {EDA9B67D-1E64-4CAB-8391-10712538C821} - {D18D0B1C-37B4-48A8-88C0-399DE2815C05} = {60262FE7-A84B-4B73-BE5D-0B5886A28BB8} - {5F393577-7E8E-43A4-B476-BFCC78147D0D} = {EDA9B67D-1E64-4CAB-8391-10712538C821} - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6} = {60262FE7-A84B-4B73-BE5D-0B5886A28BB8} - {1DDD14EC-2274-4793-803E-B64D278AFD7A} = {EDA9B67D-1E64-4CAB-8391-10712538C821} - {5338B9D6-C2A9-4DED-B7E8-31292B96CBF2} = {9A2047E2-0EC2-409E-842B-B7B360B2A45F} - {5B0E078A-D196-4EBB-BD6E-DCFB48B15E90} = {9A2047E2-0EC2-409E-842B-B7B360B2A45F} - {CDADDEC0-B72B-43B4-831F-72BA85B72805} = {9A2047E2-0EC2-409E-842B-B7B360B2A45F} - {0B2FF5AF-8580-458C-8EF4-10E6B6398D3A} = {EDA9B67D-1E64-4CAB-8391-10712538C821} - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B} = {EDA9B67D-1E64-4CAB-8391-10712538C821} - {0452CB4D-A906-4717-94AC-7A450E479BE1} = {EDA9B67D-1E64-4CAB-8391-10712538C821} - {4A355317-3634-4C98-AFB1-8BA718D54727} = {EDA9B67D-1E64-4CAB-8391-10712538C821} - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6} = {EDA9B67D-1E64-4CAB-8391-10712538C821} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {C416F0AE-21DB-4936-84B9-065D8AEC1597} - EndGlobalSection -EndGlobal diff --git a/vsbuild/usvfs_common.props b/vsbuild/usvfs_common.props deleted file mode 100644 index ef19373..0000000 --- a/vsbuild/usvfs_common.props +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - ..\src\shared;..\src\thooklib;..\src\tinjectlib;..\src\usvfs_helper;..\asmjit\src\asmjit;..\udis86;%(AdditionalIncludeDirectories) - ASMJIT_STATIC;%(PreprocessorDefinitions) - - - - \ No newline at end of file diff --git a/vsbuild/usvfs_dll.vcxproj b/vsbuild/usvfs_dll.vcxproj deleted file mode 100644 index 8e6e5be..0000000 --- a/vsbuild/usvfs_dll.vcxproj +++ /dev/null @@ -1,506 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - Release - Win32 - - - Release - x64 - - - - 15.0 - {562B0058-4701-4284-8B40-D87648A3F64C} - usvfsdll - 10.0 - - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ..\lib\ - usvfs_$(PlatformShortName) - Build - - - ..\lib\ - usvfs_$(PlatformShortName) - Build - - - ..\lib\ - usvfs_$(PlatformShortName) - Build - false - - - ..\lib\ - usvfs_$(PlatformShortName) - Build - false - - - ..\lib\ - usvfs_$(PlatformShortName) - Build - - - ..\lib\ - usvfs_$(PlatformShortName) - Build - - - ..\lib\ - usvfs_$(PlatformShortName) - Build - false - - - ..\lib\ - usvfs_$(PlatformShortName) - Build - false - - - - Disabled - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - Use - pch.h - pch.h - Default - MultiThreadedDebugDLL - stdcpp20 - - - Shlwapi.lib;Version.lib;%(AdditionalDependencies) - - - stage_helper.cmd "$(TargetName)" "$(TargetPath)" "$(STAGING_DLL)\$(TargetFileName)" "$(TargetDir)$(TargetName).lib" "$(STAGING_LIB)\$(TargetName).lib" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(TargetName).pdb" - - - Staging - - - $(STAGING_DLL)\$(TargetFileName) - - - $(TargetPath) - - - - - Disabled - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - Use - pch.h - pch.h - Default - MultiThreadedDebugDLL - stdcpp20 - - - Shlwapi.lib;Version.lib;%(AdditionalDependencies) - - - stage_helper.cmd "$(TargetName)" "$(TargetPath)" "$(STAGING_DLL)\$(TargetFileName)" "$(TargetDir)$(TargetName).lib" "$(STAGING_LIB)\$(TargetName).lib" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(TargetName).pdb" - - - Staging - - - $(STAGING_DLL)\$(TargetFileName) - - - $(TargetPath) - - - - - Disabled - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - Use - pch.h - pch.h - Default - MultiThreadedDebugDLL - stdcpp20 - - - Shlwapi.lib;Version.lib;%(AdditionalDependencies) - - - stage_helper.cmd "$(TargetName)" "$(TargetPath)" "$(STAGING_DLL)\$(TargetFileName)" "$(TargetDir)$(TargetName).lib" "$(STAGING_LIB)\$(TargetName).lib" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(TargetName).pdb" - - - Staging - - - $(STAGING_DLL)\$(TargetFileName) - - - $(TargetPath) - - - - - Disabled - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - Use - pch.h - pch.h - Default - MultiThreadedDebugDLL - stdcpp20 - - - Shlwapi.lib;Version.lib;%(AdditionalDependencies) - - - stage_helper.cmd "$(TargetName)" "$(TargetPath)" "$(STAGING_DLL)\$(TargetFileName)" "$(TargetDir)$(TargetName).lib" "$(STAGING_LIB)\$(TargetName).lib" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(TargetName).pdb" - - - Staging - - - $(STAGING_DLL)\$(TargetFileName) - - - $(TargetPath) - - - - - MaxSpeed - true - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - Default - true - false - stdcpp20 - Use - pch.h - pch.h - - - true - true - Shlwapi.lib;Version.lib;%(AdditionalDependencies) - - - stage_helper.cmd "$(TargetName)" "$(TargetPath)" "$(STAGING_DLL)\$(TargetFileName)" "$(TargetDir)$(TargetName).lib" "$(STAGING_LIB)\$(TargetName).lib" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(TargetName).pdb" - - - Staging - - - $(STAGING_DLL)\$(TargetFileName) - - - $(TargetPath) - - - - - MaxSpeed - true - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - Default - true - false - stdcpp20 - Use - pch.h - pch.h - MultiThreadedDLL - - - true - true - Shlwapi.lib;Version.lib;%(AdditionalDependencies) - - - stage_helper.cmd "$(TargetName)" "$(TargetPath)" "$(STAGING_DLL)\$(TargetFileName)" "$(TargetDir)$(TargetName).lib" "$(STAGING_LIB)\$(TargetName).lib" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(TargetName).pdb" - - - Staging - - - $(STAGING_DLL)\$(TargetFileName) - - - $(TargetPath) - - - - - MaxSpeed - true - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - Default - true - false - stdcpp20 - Use - pch.h - pch.h - - - true - true - Shlwapi.lib;Version.lib;%(AdditionalDependencies) - - - stage_helper.cmd "$(TargetName)" "$(TargetPath)" "$(STAGING_DLL)\$(TargetFileName)" "$(TargetDir)$(TargetName).lib" "$(STAGING_LIB)\$(TargetName).lib" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(TargetName).pdb" - - - Staging - - - $(STAGING_DLL)\$(TargetFileName) - - - $(TargetPath) - - - - - MaxSpeed - true - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - Default - true - false - stdcpp20 - Use - pch.h - pch.h - MultiThreadedDLL - - - true - true - Shlwapi.lib;Version.lib;%(AdditionalDependencies) - - - stage_helper.cmd "$(TargetName)" "$(TargetPath)" "$(STAGING_DLL)\$(TargetFileName)" "$(TargetDir)$(TargetName).lib" "$(STAGING_LIB)\$(TargetName).lib" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(TargetName).pdb" - - - Staging - - - $(STAGING_DLL)\$(TargetFileName) - - - $(TargetPath) - - - - - - - - - - - - - Create - Create - pch.h - pch.h - Create - Create - pch.h - pch.h - Create - Create - pch.h - pch.h - Create - Create - pch.h - pch.h - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {5338b9d6-c2a9-4ded-b7e8-31292b96cbf2} - - - {2bb3300b-f08a-4063-95c4-8a0fadae6c51} - - - {cdaddec0-b72b-43b4-831f-72ba85b72805} - - - {1ce90f86-126e-40ab-bd8b-08b25fd2e68e} - - - {d18d0b1c-37b4-48a8-88c0-399de2815c05} - - - {5b0e078a-d196-4ebb-bd6e-dcfb48b15e90} - - - {ba5b2cac-8b75-4c6b-83c7-ffb963e872b6} - - - - - - \ No newline at end of file diff --git a/vsbuild/usvfs_dll.vcxproj.filters b/vsbuild/usvfs_dll.vcxproj.filters deleted file mode 100644 index d76b33c..0000000 --- a/vsbuild/usvfs_dll.vcxproj.filters +++ /dev/null @@ -1,104 +0,0 @@ - - - - - {1cf28d0c-902d-4938-ae50-5b40e2f58d92} - - - {a6fb7517-d861-4304-81c7-f1f8587a9867} - - - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src\dlls - - - src\dlls - - - src - - - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src\dlls - - - src\dlls - - - - - src - - - \ No newline at end of file diff --git a/vsbuild/usvfs_global_test.vcxproj b/vsbuild/usvfs_global_test.vcxproj deleted file mode 100644 index 3269163..0000000 --- a/vsbuild/usvfs_global_test.vcxproj +++ /dev/null @@ -1,97 +0,0 @@ - - - - - DebugTest - Win32 - - - ReleaseTest - Win32 - - - DebugTest - x64 - - - ReleaseTest - x64 - - - - - - - - - - - 17.0 - Win32Proj - {4a355317-3634-4c98-afb1-8ba718d54727} - usvfsglobaltest - 10.0 - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - Disabled - Default - pch.h - MultiThreadedDebugDLL - - - Console - - - - - MaxSpeed - true - true - pch.h - MultiThreadedDLL - - - true - true - Console - gtest.lib;%(AdditionalDependencies) - - - - - - \ No newline at end of file diff --git a/vsbuild/usvfs_global_test.vcxproj.filters b/vsbuild/usvfs_global_test.vcxproj.filters deleted file mode 100644 index 9b5a872..0000000 --- a/vsbuild/usvfs_global_test.vcxproj.filters +++ /dev/null @@ -1,25 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {7d4fa8c9-4c03-4eaf-82d9-2d53fc06540a} - - - - - src - - - src - - - - - inc - - - \ No newline at end of file diff --git a/vsbuild/usvfs_global_test_runner.vcxproj b/vsbuild/usvfs_global_test_runner.vcxproj deleted file mode 100644 index e08d185..0000000 --- a/vsbuild/usvfs_global_test_runner.vcxproj +++ /dev/null @@ -1,116 +0,0 @@ - - - - - DebugTest - Win32 - - - ReleaseTest - Win32 - - - DebugTest - x64 - - - ReleaseTest - x64 - - - - - - - - - 17.0 - Win32Proj - usvfsglobaltestrunner - 10.0 - {B785B3FB-2F86-4042-94BB-EEE4C30D4EA6} - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - Disabled - Default - pch.h - MultiThreadedDebugDLL - ..\src\usvfs_dll;%(AdditionalIncludeDirectories) - - - Console - usvfs_$(PlatformShortName).dll - - - - - MaxSpeed - true - true - pch.h - MultiThreadedDLL - ..\src\usvfs_dll;%(AdditionalIncludeDirectories) - - - true - true - Console - usvfs_$(PlatformShortName).dll - - - - - {2bb3300b-f08a-4063-95c4-8a0fadae6c51} - - - {cdaddec0-b72b-43b4-831f-72ba85b72805} - - - {562b0058-4701-4284-8b40-d87648a3f64c} - - - {4a355317-3634-4c98-afb1-8ba718d54727} - - - - - - - - - - \ No newline at end of file diff --git a/vsbuild/usvfs_global_test_runner.vcxproj.filters b/vsbuild/usvfs_global_test_runner.vcxproj.filters deleted file mode 100644 index a5640a9..0000000 --- a/vsbuild/usvfs_global_test_runner.vcxproj.filters +++ /dev/null @@ -1,30 +0,0 @@ - - - - - {87a9ca7b-9f75-4770-9cab-e7e1d149c76b} - - - {ca9cea9d-9155-45c4-a9bf-ed98b3f28105} - - - - - src - - - src - - - src - - - - - inc - - - inc - - - \ No newline at end of file diff --git a/vsbuild/usvfs_helper.vcxproj b/vsbuild/usvfs_helper.vcxproj deleted file mode 100644 index 99293c1..0000000 --- a/vsbuild/usvfs_helper.vcxproj +++ /dev/null @@ -1,250 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - Release - Win32 - - - Release - x64 - - - - 15.0 - {BA5B2CAC-8B75-4C6B-83C7-FFB963E872B6} - usvfshelper - 10.0 - - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Disabled - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - stdcpp20 - Default - MultiThreadedDebugDLL - - - - - Disabled - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - stdcpp20 - Default - MultiThreadedDebugDLL - - - - - Disabled - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - stdcpp20 - Default - MultiThreadedDebugDLL - - - - - Disabled - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - stdcpp20 - Default - MultiThreadedDebugDLL - - - - - MaxSpeed - true - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - Default - true - false - stdcpp20 - - - true - true - - - - - MaxSpeed - true - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - Default - true - false - stdcpp20 - MultiThreadedDLL - - - true - true - - - - - MaxSpeed - true - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - Default - true - false - stdcpp20 - - - true - true - - - - - MaxSpeed - true - BUILDING_USVFS_DLL;%(PreprocessorDefinitions) - Default - true - false - stdcpp20 - MultiThreadedDLL - - - true - true - - - - - - - - - - - - \ No newline at end of file diff --git a/vsbuild/usvfs_helper.vcxproj.filters b/vsbuild/usvfs_helper.vcxproj.filters deleted file mode 100644 index 864b3bf..0000000 --- a/vsbuild/usvfs_helper.vcxproj.filters +++ /dev/null @@ -1,18 +0,0 @@ - - - - - {b0361fde-5435-4be8-a12f-cf5367a1dfdc} - - - - - src - - - - - src - - - \ No newline at end of file diff --git a/vsbuild/usvfs_proxy.vcxproj b/vsbuild/usvfs_proxy.vcxproj deleted file mode 100644 index f7bf2f5..0000000 --- a/vsbuild/usvfs_proxy.vcxproj +++ /dev/null @@ -1,344 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - Release - Win32 - - - Release - x64 - - - - 15.0 - {50AC03C1-BB24-4033-90E6-ABE65BCC13DC} - usvfsproxy - 10.0 - - - - Application - true - v143 - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ..\bin\ - $(ProjectName)_$(PlatformShortName) - Build - - - ..\bin\ - $(ProjectName)_$(PlatformShortName) - Build - - - ..\bin\ - $(ProjectName)_$(PlatformShortName) - Build - false - - - ..\bin\ - $(ProjectName)_$(PlatformShortName) - Build - false - - - ..\bin\ - $(ProjectName)_$(PlatformShortName) - - - ..\bin\ - $(ProjectName)_$(PlatformShortName) - - - ..\bin\ - $(ProjectName)_$(PlatformShortName) - false - Build - - - ..\bin\ - $(ProjectName)_$(PlatformShortName) - false - Build - - - - Disabled - Default - stdcpp20 - MultiThreadedDebugDLL - - - Staging - stage_helper.cmd "$(ProjectName)" "$(TargetPath)" "$(STAGING_EXE)\$(ProjectName).exe" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(ProjectName).pdb" - $(STAGING_EXE)\$(ProjectName).exe - $(TargetPath) - - - - - Disabled - Default - stdcpp20 - MultiThreadedDebugDLL - - - Staging - stage_helper.cmd "$(ProjectName)" "$(TargetPath)" "$(STAGING_EXE)\$(ProjectName).exe" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(ProjectName).pdb" - $(STAGING_EXE)\$(ProjectName).exe - $(TargetPath) - - - - - Disabled - Default - stdcpp20 - MultiThreadedDebugDLL - - - - - Disabled - Default - stdcpp20 - MultiThreadedDebugDLL - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - - - true - true - - - Staging - stage_helper.cmd "$(TargetName)" "$(TargetPath)" "$(STAGING_EXE)\$(TargetFileName)" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(TargetName).pdb" - $(STAGING_EXE)\$(TargetFileName) - $(TargetPath) - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - MultiThreadedDLL - - - true - true - - - Staging - stage_helper.cmd "$(TargetName)" "$(TargetPath)" "$(STAGING_EXE)\$(TargetFileName)" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(TargetName).pdb" - $(STAGING_EXE)\$(TargetFileName) - $(TargetPath) - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - - - true - true - - - Staging - $(TargetPath) - $(STAGING_EXE)\$(TargetFileName) - stage_helper.cmd "$(TargetName)" "$(TargetPath)" "$(STAGING_EXE)\$(TargetFileName)" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(TargetName).pdb" - - - - - MaxSpeed - true - Default - true - false - stdcpp20 - MultiThreadedDLL - - - true - true - - - Staging - $(TargetPath) - $(STAGING_EXE)\$(TargetFileName) - stage_helper.cmd "$(TargetName)" "$(TargetPath)" "$(STAGING_EXE)\$(TargetFileName)" "$(TargetDir)$(TargetName).pdb" "$(STAGING_PDB)\$(TargetName).pdb" - - - - - - - - - - - {5338b9d6-c2a9-4ded-b7e8-31292b96cbf2} - - - {2bb3300b-f08a-4063-95c4-8a0fadae6c51} - - - {d18d0b1c-37b4-48a8-88c0-399de2815c05} - - - {562b0058-4701-4284-8b40-d87648a3f64c} - - - {ba5b2cac-8b75-4c6b-83c7-ffb963e872b6} - - - - - - \ No newline at end of file diff --git a/vsbuild/usvfs_proxy.vcxproj.filters b/vsbuild/usvfs_proxy.vcxproj.filters deleted file mode 100644 index 8709614..0000000 --- a/vsbuild/usvfs_proxy.vcxproj.filters +++ /dev/null @@ -1,18 +0,0 @@ - - - - - {604cce95-dbd9-4cea-befb-0ede7b443311} - - - - - src - - - - - src - - - \ No newline at end of file diff --git a/vsbuild/usvfs_test.vcxproj b/vsbuild/usvfs_test.vcxproj deleted file mode 100644 index 5b0f24a..0000000 --- a/vsbuild/usvfs_test.vcxproj +++ /dev/null @@ -1,114 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - - 15.0 - {CEAF96EC-0BAA-4C02-B91B-5C4C49B5455B} - usvfstest - 10.0 - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - Disabled - Default - pch.h - MultiThreadedDebugDLL - ..\src\usvfs_dll;%(AdditionalIncludeDirectories) - - - Console - usvfs_$(PlatformShortName).dll - - - - - MaxSpeed - true - true - pch.h - MultiThreadedDLL - ..\src\usvfs_dll;%(AdditionalIncludeDirectories) - - - true - true - Console - usvfs_$(PlatformShortName).dll - - - - - - - - - - {2bb3300b-f08a-4063-95c4-8a0fadae6c51} - - - {cdaddec0-b72b-43b4-831f-72ba85b72805} - - - {562b0058-4701-4284-8b40-d87648a3f64c} - - - - - - - - - - \ No newline at end of file diff --git a/vsbuild/usvfs_test.vcxproj.filters b/vsbuild/usvfs_test.vcxproj.filters deleted file mode 100644 index 46d0b31..0000000 --- a/vsbuild/usvfs_test.vcxproj.filters +++ /dev/null @@ -1,36 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/vsbuild/usvfs_test_runner.vcxproj b/vsbuild/usvfs_test_runner.vcxproj deleted file mode 100644 index f11dbd2..0000000 --- a/vsbuild/usvfs_test_runner.vcxproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - - DebugTest - Win32 - - - DebugTest - x64 - - - ReleaseTest - Win32 - - - ReleaseTest - x64 - - - - 15.0 - {0452CB4D-A906-4717-94AC-7A450E479BE1} - usvfstestrunner - 10.0 - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - Disabled - Default - pch.h - MultiThreadedDebugDLL - - - Console - - - - - MaxSpeed - true - true - pch.h - MultiThreadedDLL - - - true - true - Console - - - - - {2bb3300b-f08a-4063-95c4-8a0fadae6c51} - - - - - - - - - \ No newline at end of file diff --git a/vsbuild/usvfs_test_runner.vcxproj.filters b/vsbuild/usvfs_test_runner.vcxproj.filters deleted file mode 100644 index 3d0e301..0000000 --- a/vsbuild/usvfs_test_runner.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file From 6e56dd6644a6d3da0443229a128f7d7d1f38ad0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Thu, 22 May 2025 20:33:13 +0200 Subject: [PATCH 2/8] Remove old patches folder. --- ...Boost.S11n-include-missing-algorithm.patch | 25 ----------- patches/boost_patches.patch | 42 ------------------ patches/boost_vector_overflow.patch | 11 ----- patches/patch.exe | Bin 112640 -> 0 bytes patches/type_traits_vs15_fix.patch | 22 --------- ...ix_has_member_function_callable_with.patch | 26 ----------- 6 files changed, 126 deletions(-) delete mode 100644 patches/0005-Boost.S11n-include-missing-algorithm.patch delete mode 100644 patches/boost_patches.patch delete mode 100644 patches/boost_vector_overflow.patch delete mode 100644 patches/patch.exe delete mode 100644 patches/type_traits_vs15_fix.patch delete mode 100644 patches/vc12_fix_has_member_function_callable_with.patch diff --git a/patches/0005-Boost.S11n-include-missing-algorithm.patch b/patches/0005-Boost.S11n-include-missing-algorithm.patch deleted file mode 100644 index d6ded52..0000000 --- a/patches/0005-Boost.S11n-include-missing-algorithm.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 9127260dea5092a7fb845cf24758a7cd07156207 Mon Sep 17 00:00:00 2001 -From: Lars Viklund -Date: Tue, 2 Jul 2013 01:11:29 +0200 -Subject: [PATCH 5/6] Boost.S11n include missing algorithm - ---- - boost/archive/iterators/transform_width.hpp | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/boost/archive/iterators/transform_width.hpp b/boost/archive/iterators/transform_width.hpp -index 3562144..f95c675 100644 ---- a/boost/archive/iterators/transform_width.hpp -+++ b/boost/archive/iterators/transform_width.hpp -@@ -30,6 +30,8 @@ - #include - #include - -+#include -+ - namespace boost { - namespace archive { - namespace iterators { --- -1.8.3.msysgit.0 - diff --git a/patches/boost_patches.patch b/patches/boost_patches.patch deleted file mode 100644 index 8a26e78..0000000 --- a/patches/boost_patches.patch +++ /dev/null @@ -1,42 +0,0 @@ -Index: has_member_function_callable_with.hpp -=================================================================== ---- boost/intrusive/detail/has_member_function_callable_with.hpp (revision 86605) -+++ boost/intrusive/detail/has_member_function_callable_with.hpp (working copy) -@@ -219,10 +219,17 @@ - struct BOOST_PP_CAT(BOOST_PP_CAT(has_member_function_callable_with_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME),_impl) - - { -- template -- static BOOST_PP_CAT(zeroarg_checker_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME) -- Test(BOOST_PP_CAT(zeroarg_checker_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)*); -- -+ #ifdef BOOST_MSVC -+ template -+ static decltype( boost::move_detail::declval().BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME() -+ , boost_intrusive_has_member_function_callable_with::yes_type()) -+ Test(Fun*); -+ #else -+ template -+ static BOOST_PP_CAT(zeroarg_checker_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME) -+ Test(BOOST_PP_CAT(zeroarg_checker_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)*); -+ #endif -+ - template - static boost_intrusive_has_member_function_callable_with::no_type Test(...); - -diff --git a/boost/archive/iterators/transform_width.hpp b/boost/archive/iterators/transform_width.hpp -index 3562144..f95c675 100644 ---- a/boost/archive/iterators/transform_width.hpp -+++ b/boost/archive/iterators/transform_width.hpp -@@ -30,6 +30,8 @@ - #include - #include - -+#include -+ - namespace boost { - namespace archive { - namespace iterators { --- -1.8.3.msysgit.0 - diff --git a/patches/boost_vector_overflow.patch b/patches/boost_vector_overflow.patch deleted file mode 100644 index 8d5ed78..0000000 --- a/patches/boost_vector_overflow.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- boost/container/vector.hpp Thu Dec 22 14:33:14 2016 -+++ boost - Copy/container/vector.hpp Sat Apr 15 13:00:54 2017 -@@ -2255,7 +2255,7 @@ - boost::uintptr_t const capaddr = boost::uintptr_t(this->priv_raw_begin() + c); - boost::uintptr_t const aligned_addr = (addr + szt_align_mask) & ~szt_align_mask; - indexes = reinterpret_cast(aligned_addr); -- std::size_t index_capacity = (aligned_addr >= capaddr) ? 0u : (capaddr - addr)/sizeof(size_type); -+ std::size_t index_capacity = (aligned_addr >= capaddr) ? 0u : (capaddr - aligned_addr)/sizeof(size_type); - - //Capacity is constant, we're not going to change it - if(index_capacity < PosCount){ diff --git a/patches/patch.exe b/patches/patch.exe deleted file mode 100644 index 2df364a03aabdc6acd18f8d0d26cd51fca18f1df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112640 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

qP#2 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 --struct is_copy_constructible -+#if _MSC_VER && !__INTEL_COMPILER -+ struct is_copy_constructible : public std::is_copy_constructible { -+#else -+ struct is_copy_constructible - { - // Intel compiler has problems with SFINAE for copy constructors and deleted functions: - // -@@ -760,6 +763,7 @@ - #else - static const bool value = !has_boost_move_no_copy_constructor_or_assign_type::value; - #endif -+#endif - }; - - diff --git a/patches/vc12_fix_has_member_function_callable_with.patch b/patches/vc12_fix_has_member_function_callable_with.patch deleted file mode 100644 index 6d23f78..0000000 --- a/patches/vc12_fix_has_member_function_callable_with.patch +++ /dev/null @@ -1,26 +0,0 @@ -Index: has_member_function_callable_with.hpp -=================================================================== ---- boost/intrusive/detail/has_member_function_callable_with.hpp (revision 86605) -+++ boost/intrusive/detail/has_member_function_callable_with.hpp (working copy) -@@ -219,10 +219,17 @@ - struct BOOST_PP_CAT(BOOST_PP_CAT(has_member_function_callable_with_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME),_impl) - - { -- template -- static BOOST_PP_CAT(zeroarg_checker_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME) -- Test(BOOST_PP_CAT(zeroarg_checker_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)*); -- -+ #ifdef BOOST_MSVC -+ template -+ static decltype( boost::move_detail::declval().BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME() -+ , boost_intrusive_has_member_function_callable_with::yes_type()) -+ Test(Fun*); -+ #else -+ template -+ static BOOST_PP_CAT(zeroarg_checker_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME) -+ Test(BOOST_PP_CAT(zeroarg_checker_, BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME)*); -+ #endif -+ - template - static boost_intrusive_has_member_function_callable_with::no_type Test(...); - From 1c95b7452585e53ef97954248aed42480d5bb5de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Thu, 22 May 2025 20:47:13 +0200 Subject: [PATCH 3/8] Apply formatting. --- .clang-format | 41 + .gitattributes | 7 + include/usvfs/sharedparameters.h | 55 +- include/usvfs/usvfs.h | 318 ++--- include/usvfs/usvfs_version.h | 12 +- include/usvfs/usvfsparameters.h | 57 +- include/usvfs/usvfsparametersprivate.h | 15 +- licenses/asmjit.txt | 4 +- licenses/boost.txt | 2 +- licenses/cppformat.txt | 2 +- licenses/googletest.txt | 2 +- licenses/qt.txt | 1 - licenses/spdlog.txt | 4 +- licenses/udis86.txt | 28 +- src/shared/addrtools.h | 11 +- src/shared/directory_tree.cpp | 13 +- src/shared/directory_tree.h | 284 ++-- src/shared/exceptionex.cpp | 38 +- src/shared/exceptionex.h | 44 +- src/shared/formatters.h | 39 +- src/shared/loghelpers.cpp | 43 +- src/shared/loghelpers.h | 41 +- src/shared/ntdll_declarations.cpp | 17 +- src/shared/ntdll_declarations.h | 222 ++-- src/shared/pch.h | 20 +- src/shared/shared_memory.h | 11 +- src/shared/shmlogger.cpp | 97 +- src/shared/shmlogger.h | 48 +- src/shared/stringcast.cpp | 11 +- src/shared/stringcast.h | 41 +- src/shared/stringutils.cpp | 21 +- src/shared/stringutils.h | 30 +- src/shared/tree_container.h | 291 ++--- src/shared/unicodestring.cpp | 13 +- src/shared/unicodestring.h | 48 +- src/shared/wildcard.cpp | 34 +- src/shared/wildcard.h | 3 +- src/shared/winapi.cpp | 212 ++- src/shared/winapi.h | 353 ++--- src/shared/windows_sane.h | 3 +- src/thooklib/asmjit_sane.h | 4 +- src/thooklib/hooklib.cpp | 376 +++--- src/thooklib/hooklib.h | 69 +- src/thooklib/ttrampolinepool.cpp | 220 ++-- src/thooklib/ttrampolinepool.h | 101 +- src/thooklib/udis86wrapper.cpp | 75 +- src/thooklib/udis86wrapper.h | 28 +- src/thooklib/utility.cpp | 37 +- src/thooklib/utility.h | 8 +- src/tinjectlib/asmjit_sane.h | 10 +- src/tinjectlib/injectlib.cpp | 238 ++-- src/tinjectlib/injectlib.h | 38 +- src/usvfs_dll/hookcallcontext.cpp | 41 +- src/usvfs_dll/hookcallcontext.h | 51 +- src/usvfs_dll/hookcontext.cpp | 113 +- src/usvfs_dll/hookcontext.h | 125 +- src/usvfs_dll/hookmanager.cpp | 144 ++- src/usvfs_dll/hookmanager.h | 41 +- src/usvfs_dll/hooks/kernel32.cpp | 995 +++++++------- src/usvfs_dll/hooks/kernel32.h | 113 +- src/usvfs_dll/hooks/ntdll.cpp | 1139 ++++++++--------- src/usvfs_dll/hooks/ntdll.h | 104 +- src/usvfs_dll/maptracker.h | 463 ++++--- src/usvfs_dll/redirectiontree.cpp | 2 +- src/usvfs_dll/redirectiontree.h | 69 +- src/usvfs_dll/semaphore.cpp | 15 +- src/usvfs_dll/semaphore.h | 3 - src/usvfs_dll/sharedparameters.cpp | 106 +- src/usvfs_dll/stringcast_boost.h | 28 +- src/usvfs_dll/usvfs.cpp | 395 +++--- src/usvfs_dll/usvfsparameters.cpp | 177 ++- src/usvfs_helper/inject.cpp | 135 +- src/usvfs_helper/inject.h | 22 +- src/usvfs_proxy/main.cpp | 82 +- .../basic/source.postmortem/root1.txt | 2 +- .../basic/source.postmortem/root1w.txt | 2 +- .../basic/source.postmortem/root2.txt | 2 +- .../basic/source.postmortem/root2w.txt | 2 +- .../usvfs_test/basic/source/root1.txt | 2 +- .../usvfs_test/basic/source/root1w.txt | 2 +- .../usvfs_test/basic/source/root2.txt | 2 +- .../usvfs_test/basic/source/root2w.txt | 2 +- test/gtest_utils/gtest_utils.cpp | 2 +- test/gtest_utils/gtest_utils.h | 2 +- test/shared_test/main.cpp | 84 +- test/test_utils/test_helpers.cpp | 380 +++--- test/test_utils/test_helpers.h | 280 ++-- test/thooklib_test/main.cpp | 113 +- test/thooklib_test/test_hooks.cpp | 26 +- test/tinjectlib_test/main.cpp | 65 +- test/tinjectlib_test/testinject_bin/main.cpp | 1 - test/tinjectlib_test/testinject_dll/main.cpp | 22 +- test/tinjectlib_test/testinject_dll/main.h | 9 +- test/tvfs_test/main.cpp | 30 +- .../usvfs_global_test/usvfs_global_test.cpp | 2 +- .../usvfs_global_test_fixture.h | 2 +- .../usvfs_global_test_runner.cpp | 2 +- .../test_file_operations.cpp | 356 +++--- .../test_file_operations/test_filesystem.cpp | 67 +- .../test_file_operations/test_filesystem.h | 52 +- .../test_file_operations/test_ntapi.cpp | 220 ++-- .../test_file_operations/test_ntapi.h | 12 +- .../test_ntdll_declarations.h | 131 +- .../test_file_operations/test_w32api.cpp | 135 +- .../test_file_operations/test_w32api.h | 9 +- .../usvfs_test/usvfs_basic_test.cpp | 311 +++-- .../usvfs_test/usvfs_test.cpp | 141 +- .../usvfs_test/usvfs_test_base.cpp | 446 ++++--- .../usvfs_test/usvfs_test_base.h | 85 +- test/usvfs_test_runner/usvfs_test_runner.cpp | 25 +- 110 files changed, 5690 insertions(+), 5439 deletions(-) create mode 100644 .clang-format create mode 100644 .gitattributes diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..6098e1f --- /dev/null +++ b/.clang-format @@ -0,0 +1,41 @@ +--- +# We'll use defaults from the LLVM style, but with 4 columns indentation. +BasedOnStyle: LLVM +IndentWidth: 2 +--- +Language: Cpp +DeriveLineEnding: false +UseCRLF: true +DerivePointerAlignment: false +PointerAlignment: Left +AlignConsecutiveAssignments: true +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: Empty +AlwaysBreakTemplateDeclarations: Yes +AccessModifierOffset: -2 +AlignTrailingComments: true +SpacesBeforeTrailingComments: 2 +NamespaceIndentation: Inner +MaxEmptyLinesToKeep: 1 +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: false + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: true +ColumnLimit: 88 +ForEachMacros: ['Q_FOREACH', 'foreach'] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f869712 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. +*.cpp text eol=crlf +*.h text eol=crlf diff --git a/include/usvfs/sharedparameters.h b/include/usvfs/sharedparameters.h index 073f4b4..f428dc0 100644 --- a/include/usvfs/sharedparameters.h +++ b/include/usvfs/sharedparameters.h @@ -1,7 +1,7 @@ #pragma once -#include "usvfsparameters.h" #include "dllimport.h" +#include "usvfsparameters.h" #include namespace usvfs @@ -10,9 +10,8 @@ namespace usvfs class ForcedLibrary { public: - ForcedLibrary( - const std::string& processName, const std::string& libraryPath, - const shared::VoidAllocatorT &allocator); + ForcedLibrary(const std::string& processName, const std::string& libraryPath, + const shared::VoidAllocatorT& allocator); std::string processName() const; std::string libraryPath() const; @@ -22,16 +21,15 @@ private: shared::StringT m_libraryPath; }; - class DLLEXPORT SharedParameters { public: - SharedParameters() = delete; - SharedParameters(const SharedParameters &reference) = delete; - SharedParameters &operator=(const SharedParameters &reference) = delete; + SharedParameters() = delete; + SharedParameters(const SharedParameters& reference) = delete; + SharedParameters& operator=(const SharedParameters& reference) = delete; SharedParameters(const usvfsParameters& reference, - const shared::VoidAllocatorT &allocator); + const shared::VoidAllocatorT& allocator); usvfsParameters makeLocal() const; @@ -40,9 +38,9 @@ public: std::string currentInverseSHMName() const; void setSHMNames(const std::string& current, const std::string& inverse); - void setDebugParameters( - LogLevel level, CrashDumpsType dumpType, const std::string& dumpPath, - std::chrono::milliseconds delayProcess); + void setDebugParameters(LogLevel level, CrashDumpsType dumpType, + const std::string& dumpPath, + std::chrono::milliseconds delayProcess); std::size_t userConnected(); std::size_t userDisconnected(); @@ -70,30 +68,29 @@ public: void clearForcedLibraries(); private: - using StringAllocatorT = - shared::VoidAllocatorT::rebind::other; + using StringAllocatorT = shared::VoidAllocatorT::rebind::other; using DWORDAllocatorT = shared::VoidAllocatorT::rebind::other; - using ForcedLibraryAllocatorT = - shared::VoidAllocatorT::rebind::other; + using ForcedLibraryAllocatorT = shared::VoidAllocatorT::rebind::other; + using ProcessBlacklist = + boost::container::flat_set, + StringAllocatorT>; - using ProcessBlacklist = boost::container::flat_set< - shared::StringT, std::less, StringAllocatorT>; + using ProcessList = + boost::container::flat_set, DWORDAllocatorT>; - using ProcessList = boost::container::flat_set< - DWORD, std::less, DWORDAllocatorT>; + using FileSuffixSkipList = + boost::container::flat_set, + StringAllocatorT>; - using FileSuffixSkipList = boost::container::flat_set< - shared::StringT, std::less, StringAllocatorT>; - - using DirectorySkipList = boost::container::flat_set< - shared::StringT, std::less, StringAllocatorT>; - - using ForcedLibraries = boost::container::slist< - ForcedLibrary, ForcedLibraryAllocatorT>; + using DirectorySkipList = + boost::container::flat_set, + StringAllocatorT>; + using ForcedLibraries = + boost::container::slist; mutable bi::interprocess_mutex m_mutex; shared::StringT m_instanceName; @@ -112,4 +109,4 @@ private: ForcedLibraries m_forcedLibraries; }; -} // namespace +} // namespace usvfs diff --git a/include/usvfs/usvfs.h b/include/usvfs/usvfs.h index 97d7ad3..6754922 100644 --- a/include/usvfs/usvfs.h +++ b/include/usvfs/usvfs.h @@ -23,7 +23,6 @@ along with usvfs. If not, see . #include "dllimport.h" #include "usvfsparameters.h" - /* * Virtual operations: * - link file @@ -34,183 +33,200 @@ along with usvfs. If not, see . * - delete directory * Maybe: * - rename/move (= copy + delete) - * - copy-on-write semantics (changes to files are done in a separate copy of the file, the original is kept on disc but hidden) + * - copy-on-write semantics (changes to files are done in a separate copy of the + * file, the original is kept on disc but hidden) */ +static const unsigned int LINKFLAG_FAILIFEXISTS = + 0x00000001; // if set, linking fails in case of an error +static const unsigned int LINKFLAG_MONITORCHANGES = + 0x00000002; // if set, changes to the source directory after the link operation + // will be updated in the virtual fs. only relevant in static + // link directory operations +static const unsigned int LINKFLAG_CREATETARGET = + 0x00000004; // if set, file creation (including move or copy) operations to + // destination will be redirected to the source. Only one createtarget + // can be set for a destination folder so this flag will replace + // the previous create target. + // If there different create-target have been set for an element and + // one of its ancestors, the inner-most create-target is used +static const unsigned int LINKFLAG_RECURSIVE = + 0x00000008; // if set, directories are linked recursively +static const unsigned int LINKFLAG_FAILIFSKIPPED = + 0x00000010; // if set, linking fails if the file or directory is skipped + // files or directories are skipped depending on whats been added to + // the skip file suffixes or skip directories list in + // the sharedparameters class, those lists are checked during virtual + // linking -static const unsigned int LINKFLAG_FAILIFEXISTS = 0x00000001; // if set, linking fails in case of an error -static const unsigned int LINKFLAG_MONITORCHANGES = 0x00000002; // if set, changes to the source directory after the link operation - // will be updated in the virtual fs. only relevant in static - // link directory operations -static const unsigned int LINKFLAG_CREATETARGET = 0x00000004; // if set, file creation (including move or copy) operations to - // destination will be redirected to the source. Only one createtarget - // can be set for a destination folder so this flag will replace - // the previous create target. - // If there different create-target have been set for an element and one of its - // ancestors, the inner-most create-target is used -static const unsigned int LINKFLAG_RECURSIVE = 0x00000008; // if set, directories are linked recursively -static const unsigned int LINKFLAG_FAILIFSKIPPED = 0x00000010; // if set, linking fails if the file or directory is skipped - // files or directories are skipped depending on whats been added to - // the skip file suffixes or skip directories list in - // the sharedparameters class, those lists are checked during virtual linking +extern "C" +{ -extern "C" { + /** + * removes all virtual mappings + */ + DLLEXPORT void WINAPI usvfsClearVirtualMappings(); -/** - * removes all virtual mappings - */ -DLLEXPORT void WINAPI usvfsClearVirtualMappings(); + /** + * link a file virtually + * @note: the directory the destination file resides in has to exist - at least + * virtually. + */ + DLLEXPORT BOOL WINAPI usvfsVirtualLinkFile(LPCWSTR source, LPCWSTR destination, + unsigned int flags); -/** - * link a file virtually - * @note: the directory the destination file resides in has to exist - at least virtually. - */ -DLLEXPORT BOOL WINAPI usvfsVirtualLinkFile(LPCWSTR source, LPCWSTR destination, unsigned int flags); + /** + * link a directory virtually. This static variant recursively links all files + * individually, change notifications are used to update the information. + * @param failIfExists if true, this call fails if the destination directory exists + * (virtually or physically) + */ + DLLEXPORT BOOL WINAPI usvfsVirtualLinkDirectoryStatic(LPCWSTR source, + LPCWSTR destination, + unsigned int flags); -/** - * link a directory virtually. This static variant recursively links all files individually, change notifications - * are used to update the information. - * @param failIfExists if true, this call fails if the destination directory exists (virtually or physically) - */ -DLLEXPORT BOOL WINAPI usvfsVirtualLinkDirectoryStatic(LPCWSTR source, LPCWSTR destination, unsigned int flags); + /** + * connect to a virtual filesystem as a controller, without hooking the calling + * process. Please note that you can only be connected to one vfs, so this will + * silently disconnect from a previous vfs. + */ + DLLEXPORT BOOL WINAPI usvfsConnectVFS(const usvfsParameters* p); -/** - * connect to a virtual filesystem as a controller, without hooking the calling process. Please note that - * you can only be connected to one vfs, so this will silently disconnect from a previous vfs. - */ -DLLEXPORT BOOL WINAPI usvfsConnectVFS(const usvfsParameters* p); + /** + * @brief create a new VFS. This is similar to ConnectVFS except it guarantees + * the vfs is reset before use. + */ + DLLEXPORT BOOL WINAPI usvfsCreateVFS(const usvfsParameters* p); -/** - * @brief create a new VFS. This is similar to ConnectVFS except it guarantees - * the vfs is reset before use. - */ -DLLEXPORT BOOL WINAPI usvfsCreateVFS(const usvfsParameters* p); + /** + * disconnect from a virtual filesystem. This removes hooks if necessary + */ + DLLEXPORT void WINAPI usvfsDisconnectVFS(); -/** - * disconnect from a virtual filesystem. This removes hooks if necessary - */ -DLLEXPORT void WINAPI usvfsDisconnectVFS(); + DLLEXPORT void WINAPI usvfsGetCurrentVFSName(char* buffer, size_t size); -DLLEXPORT void WINAPI usvfsGetCurrentVFSName(char *buffer, size_t size); + /** + * retrieve a list of all processes connected to the vfs + */ + DLLEXPORT BOOL WINAPI usvfsGetVFSProcessList(size_t* count, LPDWORD processIDs); -/** - * retrieve a list of all processes connected to the vfs - */ -DLLEXPORT BOOL WINAPI usvfsGetVFSProcessList(size_t *count, LPDWORD processIDs); + // retrieve a list of all processes connected to the vfs, stores an array + // of `count` elements in `*buffer` + // + // if this returns TRUE and `count` is not 0, the caller must release the buffer + // with `free(*buffer)` + // + // return values: + // - ERROR_INVALID_PARAMETERS: either `count` or `buffer` is NULL + // - ERROR_TOO_MANY_OPEN_FILES: there seems to be way too many usvfs processes + // running, probably some internal error + // - ERROR_NOT_ENOUGH_MEMORY: malloc() failed + // + DLLEXPORT BOOL WINAPI usvfsGetVFSProcessList2(size_t* count, DWORD** buffer); -// retrieve a list of all processes connected to the vfs, stores an array -// of `count` elements in `*buffer` -// -// if this returns TRUE and `count` is not 0, the caller must release the buffer -// with `free(*buffer)` -// -// return values: -// - ERROR_INVALID_PARAMETERS: either `count` or `buffer` is NULL -// - ERROR_TOO_MANY_OPEN_FILES: there seems to be way too many usvfs processes -// running, probably some internal error -// - ERROR_NOT_ENOUGH_MEMORY: malloc() failed -// -DLLEXPORT BOOL WINAPI usvfsGetVFSProcessList2(size_t* count, DWORD** buffer); + /** + * spawn a new process that can see the virtual file system. The signature is + * identical to CreateProcess + */ + DLLEXPORT BOOL WINAPI usvfsCreateProcessHooked( + LPCWSTR lpApplicationName, LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, + DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation); -/** - * spawn a new process that can see the virtual file system. The signature is identical to CreateProcess - */ -DLLEXPORT BOOL WINAPI usvfsCreateProcessHooked( - LPCWSTR lpApplicationName, LPWSTR lpCommandLine, - LPSECURITY_ATTRIBUTES lpProcessAttributes, - LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, - DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, - LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation); + /** + * retrieve a single log message. + * FIXME There is currently no way to unblock from the caller side + * FIXME retrieves log messages from all instances, the logging queue is not separated + */ + DLLEXPORT bool WINAPI usvfsGetLogMessages(LPSTR buffer, size_t size, + bool blocking = false); -/** - * retrieve a single log message. - * FIXME There is currently no way to unblock from the caller side - * FIXME retrieves log messages from all instances, the logging queue is not separated - */ -DLLEXPORT bool WINAPI usvfsGetLogMessages(LPSTR buffer, size_t size, bool blocking = false); + /** + * retrieves a readable representation of the vfs tree + * @param buffer the buffer to write to. this may be null if you only want to + * determine the required buffer size + * @param size pointer to a variable that contains the buffer. After the call + * this value will have been updated to contain the required size, + * even if this is bigger than the buffer size + */ + DLLEXPORT BOOL WINAPI usvfsCreateVFSDump(LPSTR buffer, size_t* size); -/** - * retrieves a readable representation of the vfs tree - * @param buffer the buffer to write to. this may be null if you only want to determine the required - * buffer size - * @param size pointer to a variable that contains the buffer. After the call - * this value will have been updated to contain the required size, - * even if this is bigger than the buffer size - */ -DLLEXPORT BOOL WINAPI usvfsCreateVFSDump(LPSTR buffer, size_t *size); + /** + * adds an executable to the blacklist so it doesn't get exposed to the virtual + * file system + * @param executableName name of the executable + */ + DLLEXPORT VOID WINAPI usvfsBlacklistExecutable(LPCWSTR executableName); -/** - * adds an executable to the blacklist so it doesn't get exposed to the virtual - * file system - * @param executableName name of the executable - */ -DLLEXPORT VOID WINAPI usvfsBlacklistExecutable(LPCWSTR executableName); + /** + * clears the executable blacklist + */ + DLLEXPORT VOID WINAPI usvfsClearExecutableBlacklist(); -/** - * clears the executable blacklist - */ -DLLEXPORT VOID WINAPI usvfsClearExecutableBlacklist(); + /** + * adds a file suffix to a list to skip during file linking + * .txt and some_file.txt are both valid file suffixes, + * not to be confused with file extensions + * @param fileSuffix a valid file suffix + */ + DLLEXPORT VOID WINAPI usvfsAddSkipFileSuffix(LPCWSTR fileSuffix); -/** - * adds a file suffix to a list to skip during file linking - * .txt and some_file.txt are both valid file suffixes, - * not to be confused with file extensions - * @param fileSuffix a valid file suffix - */ -DLLEXPORT VOID WINAPI usvfsAddSkipFileSuffix(LPCWSTR fileSuffix); + /** + * clears the file suffix skip-list + */ + DLLEXPORT VOID WINAPI usvfsClearSkipFileSuffixes(); -/** - * clears the file suffix skip-list - */ -DLLEXPORT VOID WINAPI usvfsClearSkipFileSuffixes(); + /** + * adds a directory name that will be skipped during directory linking. + * Not a path. Any directory matching the name will be skipped, + * regardless of it's path, for example if .git is added, + * any sub-path or root-path containing a .git directory + * will have the .git directory skipped during directory linking + * @param directory name of the directory + */ + DLLEXPORT VOID WINAPI usvfsAddSkipDirectory(LPCWSTR directory); -/** - * adds a directory name that will be skipped during directory linking. - * Not a path. Any directory matching the name will be skipped, - * regardless of it's path, for example if .git is added, - * any sub-path or root-path containing a .git directory - * will have the .git directory skipped during directory linking - * @param directory name of the directory - */ -DLLEXPORT VOID WINAPI usvfsAddSkipDirectory(LPCWSTR directory); + /** + * clears the directory skip-list + */ + DLLEXPORT VOID WINAPI usvfsClearSkipDirectories(); -/** - * clears the directory skip-list - */ -DLLEXPORT VOID WINAPI usvfsClearSkipDirectories(); + /** + * adds a library to be force loaded when the given process is injected + * @param + */ + DLLEXPORT VOID WINAPI usvfsForceLoadLibrary(LPCWSTR processName, LPCWSTR libraryPath); -/** - * adds a library to be force loaded when the given process is injected - * @param - */ -DLLEXPORT VOID WINAPI usvfsForceLoadLibrary(LPCWSTR processName, LPCWSTR libraryPath); + /** + * clears all previous calls to ForceLoadLibrary + */ + DLLEXPORT VOID WINAPI usvfsClearLibraryForceLoads(); -/** - * clears all previous calls to ForceLoadLibrary - */ -DLLEXPORT VOID WINAPI usvfsClearLibraryForceLoads(); + /** + * print debugging info about the vfs. The format is currently not fixed and may + * change between usvfs versions + */ + DLLEXPORT VOID WINAPI usvfsPrintDebugInfo(); -/** - * print debugging info about the vfs. The format is currently not fixed and may - * change between usvfs versions - */ -DLLEXPORT VOID WINAPI usvfsPrintDebugInfo(); + // #if defined(UNITTEST) || defined(_WINDLL) + DLLEXPORT void WINAPI usvfsInitLogging(bool toLocal = false); + // #endif -//#if defined(UNITTEST) || defined(_WINDLL) -DLLEXPORT void WINAPI usvfsInitLogging(bool toLocal = false); -//#endif + /** + * used internally to initialize a process at startup-time as a "slave". Don't call + * directly + */ + DLLEXPORT void __cdecl InitHooks(LPVOID userData, size_t userDataSize); -/** - * used internally to initialize a process at startup-time as a "slave". Don't call directly - */ -DLLEXPORT void __cdecl InitHooks(LPVOID userData, size_t userDataSize); + // the instance and shm names are not updated + // + DLLEXPORT void WINAPI usvfsUpdateParameters(usvfsParameters* p); -// the instance and shm names are not updated -// -DLLEXPORT void WINAPI usvfsUpdateParameters(usvfsParameters* p); - -DLLEXPORT int WINAPI usvfsCreateMiniDump(PEXCEPTION_POINTERS exceptionPtrs, CrashDumpsType type, const wchar_t* dumpPath); - -DLLEXPORT const char* WINAPI usvfsVersionString(); + DLLEXPORT int WINAPI usvfsCreateMiniDump(PEXCEPTION_POINTERS exceptionPtrs, + CrashDumpsType type, + const wchar_t* dumpPath); + DLLEXPORT const char* WINAPI usvfsVersionString(); } diff --git a/include/usvfs/usvfs_version.h b/include/usvfs/usvfs_version.h index 9dfebb1..5848bd4 100644 --- a/include/usvfs/usvfs_version.h +++ b/include/usvfs/usvfs_version.h @@ -18,5 +18,13 @@ #define USVFS_STRINGIFYW_HELPER(x) L## #x #endif -#define USVFS_VERSION_STRING USVFS_STRINGIFY(USVFS_VERSION_MAJOR) "." USVFS_STRINGIFY(USVFS_VERSION_MINOR) "." USVFS_STRINGIFY(USVFS_VERSION_BUILD) "." USVFS_STRINGIFY(USVFS_VERSION_REVISION) USVFS_BUILD_STRING -#define USVFS_VERSION_WSTRING USVFS_STRINGIFYW(USVFS_VERSION_MAJOR) L"." USVFS_STRINGIFYW(USVFS_VERSION_MINOR) L"." USVFS_STRINGIFYW(USVFS_VERSION_BUILD) L"." USVFS_STRINGIFYW(USVFS_VERSION_REVISION) USVFS_BUILD_WSTRING +#define USVFS_VERSION_STRING \ + USVFS_STRINGIFY(USVFS_VERSION_MAJOR) \ + "." USVFS_STRINGIFY(USVFS_VERSION_MINOR) "." USVFS_STRINGIFY( \ + USVFS_VERSION_BUILD) "." USVFS_STRINGIFY(USVFS_VERSION_REVISION) \ + USVFS_BUILD_STRING +#define USVFS_VERSION_WSTRING \ + USVFS_STRINGIFYW(USVFS_VERSION_MAJOR) \ + L"." USVFS_STRINGIFYW(USVFS_VERSION_MINOR) L"." USVFS_STRINGIFYW( \ + USVFS_VERSION_BUILD) L"." USVFS_STRINGIFYW(USVFS_VERSION_REVISION) \ + USVFS_BUILD_WSTRING diff --git a/include/usvfs/usvfsparameters.h b/include/usvfs/usvfsparameters.h index d4c96f2..1351d69 100644 --- a/include/usvfs/usvfsparameters.h +++ b/include/usvfs/usvfsparameters.h @@ -20,11 +20,12 @@ along with usvfs. If not, see . */ #pragma once -#include "logging.h" #include "dllimport.h" +#include "logging.h" #include -enum class CrashDumpsType : uint8_t { +enum class CrashDumpsType : uint8_t +{ None, Mini, Data, @@ -34,34 +35,34 @@ enum class CrashDumpsType : uint8_t { extern "C" { -// deprecated, use usvfsParameters and usvfsCreateParameters() -// -struct USVFSParameters { - char instanceName[65]; - char currentSHMName[65]; - char currentInverseSHMName[65]; - bool debugMode{false}; - LogLevel logLevel{LogLevel::Debug}; - CrashDumpsType crashDumpsType{CrashDumpsType::None}; - char crashDumpsPath[260]; -}; + // deprecated, use usvfsParameters and usvfsCreateParameters() + // + struct USVFSParameters + { + char instanceName[65]; + char currentSHMName[65]; + char currentInverseSHMName[65]; + bool debugMode{false}; + LogLevel logLevel{LogLevel::Debug}; + CrashDumpsType crashDumpsType{CrashDumpsType::None}; + char crashDumpsPath[260]; + }; + struct usvfsParameters; -struct usvfsParameters; + DLLEXPORT usvfsParameters* usvfsCreateParameters(); + DLLEXPORT usvfsParameters* usvfsDupeParameters(usvfsParameters* p); + DLLEXPORT void usvfsCopyParameters(const usvfsParameters* source, + usvfsParameters* dest); + DLLEXPORT void usvfsFreeParameters(usvfsParameters* p); -DLLEXPORT usvfsParameters* usvfsCreateParameters(); -DLLEXPORT usvfsParameters* usvfsDupeParameters(usvfsParameters* p); -DLLEXPORT void usvfsCopyParameters(const usvfsParameters* source, usvfsParameters* dest); -DLLEXPORT void usvfsFreeParameters(usvfsParameters* p); - -DLLEXPORT void usvfsSetInstanceName(usvfsParameters* p, const char* name); -DLLEXPORT void usvfsSetDebugMode(usvfsParameters* p, BOOL debugMode); -DLLEXPORT void usvfsSetLogLevel(usvfsParameters* p, LogLevel level); -DLLEXPORT void usvfsSetCrashDumpType(usvfsParameters* p, CrashDumpsType type); -DLLEXPORT void usvfsSetCrashDumpPath(usvfsParameters* p, const char* path); -DLLEXPORT void usvfsSetProcessDelay(usvfsParameters* p, int milliseconds); - -DLLEXPORT const char* usvfsLogLevelToString(LogLevel lv); -DLLEXPORT const char* usvfsCrashDumpTypeToString(CrashDumpsType t); + DLLEXPORT void usvfsSetInstanceName(usvfsParameters* p, const char* name); + DLLEXPORT void usvfsSetDebugMode(usvfsParameters* p, BOOL debugMode); + DLLEXPORT void usvfsSetLogLevel(usvfsParameters* p, LogLevel level); + DLLEXPORT void usvfsSetCrashDumpType(usvfsParameters* p, CrashDumpsType type); + DLLEXPORT void usvfsSetCrashDumpPath(usvfsParameters* p, const char* path); + DLLEXPORT void usvfsSetProcessDelay(usvfsParameters* p, int milliseconds); + DLLEXPORT const char* usvfsLogLevelToString(LogLevel lv); + DLLEXPORT const char* usvfsCrashDumpTypeToString(CrashDumpsType t); } diff --git a/include/usvfs/usvfsparametersprivate.h b/include/usvfs/usvfsparametersprivate.h index 688d1e0..6c2d5f2 100644 --- a/include/usvfs/usvfsparametersprivate.h +++ b/include/usvfs/usvfsparametersprivate.h @@ -13,18 +13,13 @@ struct usvfsParameters int delayProcessMs; usvfsParameters(); - usvfsParameters(const usvfsParameters&) = default; + usvfsParameters(const usvfsParameters&) = default; usvfsParameters& operator=(const usvfsParameters&) = default; - usvfsParameters( - const char* instanceName, - const char* currentSHMName, - const char* currentInverseSHMName, - bool debugMode, - LogLevel logLevel, - CrashDumpsType crashDumpsType, - const char* crashDumpsPath, - int delayProcessMs); + usvfsParameters(const char* instanceName, const char* currentSHMName, + const char* currentInverseSHMName, bool debugMode, LogLevel logLevel, + CrashDumpsType crashDumpsType, const char* crashDumpsPath, + int delayProcessMs); usvfsParameters(const USVFSParameters& oldParams); diff --git a/licenses/asmjit.txt b/licenses/asmjit.txt index 66ad36f..e340bde 100644 --- a/licenses/asmjit.txt +++ b/licenses/asmjit.txt @@ -1,4 +1,4 @@ -AsmJit - Complete x86/x64 JIT and Remote Assembler for C++ +AsmJit - Complete x86/x64 JIT and Remote Assembler for C++ Copyright (c) 2008-2015, Petr Kobalicek This software is provided 'as-is', without any express or implied @@ -15,4 +15,4 @@ freely, subject to the following restrictions: appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. \ No newline at end of file +3. This notice may not be removed or altered from any source distribution. diff --git a/licenses/boost.txt b/licenses/boost.txt index 127a5bc..36b7cd9 100644 --- a/licenses/boost.txt +++ b/licenses/boost.txt @@ -20,4 +20,4 @@ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. \ No newline at end of file +DEALINGS IN THE SOFTWARE. diff --git a/licenses/cppformat.txt b/licenses/cppformat.txt index 48eb615..8db9a7c 100644 --- a/licenses/cppformat.txt +++ b/licenses/cppformat.txt @@ -6,4 +6,4 @@ Redistribution and use in source and binary forms, with or without modification, Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/googletest.txt b/licenses/googletest.txt index 65c76c5..1941a11 100644 --- a/licenses/googletest.txt +++ b/licenses/googletest.txt @@ -25,4 +25,4 @@ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/qt.txt b/licenses/qt.txt index 4d67bac..87be995 100644 --- a/licenses/qt.txt +++ b/licenses/qt.txt @@ -172,4 +172,3 @@ If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. - diff --git a/licenses/spdlog.txt b/licenses/spdlog.txt index e815ed0..1dfac98 100644 --- a/licenses/spdlog.txt +++ b/licenses/spdlog.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015 Gabi Melman. +Copyright (c) 2015 Gabi Melman. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +THE SOFTWARE. diff --git a/licenses/udis86.txt b/licenses/udis86.txt index 7f6ad7a..80f537d 100644 --- a/licenses/udis86.txt +++ b/licenses/udis86.txt @@ -1,22 +1,22 @@ Copyright (c) 2002-2012, Vivek Thampi All rights reserved. -Redistribution and use in source and binary forms, with or without modification, +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/shared/addrtools.h b/src/shared/addrtools.h index 810014a..b888ebf 100644 --- a/src/shared/addrtools.h +++ b/src/shared/addrtools.h @@ -41,23 +41,24 @@ inline std::ptrdiff_t AddrDiff(LPVOID lhs, LPVOID rhs) return reinterpret_cast(lhs) - reinterpret_cast(rhs); } - // implicitly cast pointer to void*, from there cast to target type. // This is supposed to be safer than directly reinterpret-casting template -inline T void_ptr_cast(void *ptr) +inline T void_ptr_cast(void* ptr) { return reinterpret_cast(ptr); } template <> -inline int64_t void_ptr_cast(void *ptr) { +inline int64_t void_ptr_cast(void* ptr) +{ return reinterpret_cast(ptr); } template <> -inline uint64_t void_ptr_cast(void *ptr) { +inline uint64_t void_ptr_cast(void* ptr) +{ return reinterpret_cast(ptr); } -} // namespace +} // namespace usvfs::shared diff --git a/src/shared/directory_tree.cpp b/src/shared/directory_tree.cpp index 7441210..34cc797 100644 --- a/src/shared/directory_tree.cpp +++ b/src/shared/directory_tree.cpp @@ -24,21 +24,20 @@ along with usvfs. If not, see . namespace usvfs::shared { -fs::path::iterator nextIter( - const fs::path::iterator &iter, const fs::path::iterator &end) +fs::path::iterator nextIter(const fs::path::iterator& iter, + const fs::path::iterator& end) { fs::path::iterator next = iter; advanceIter(next, end); return next; } -void advanceIter( - fs::path::iterator &iter, const fs::path::iterator &end) +void advanceIter(fs::path::iterator& iter, const fs::path::iterator& end) { ++iter; - while (iter != end && - (iter->wstring() == L"/" || iter->wstring() == L"\\" || iter->wstring() == L".")) + while (iter != end && (iter->wstring() == L"/" || iter->wstring() == L"\\" || + iter->wstring() == L".")) ++iter; } -} // namespace +} // namespace usvfs::shared diff --git a/src/shared/directory_tree.h b/src/shared/directory_tree.h index 1f83345..f82187f 100644 --- a/src/shared/directory_tree.h +++ b/src/shared/directory_tree.h @@ -20,17 +20,16 @@ along with usvfs. If not, see . */ #pragma once -#include "shared_memory.h" -#include "logging.h" -#include "stringutils.h" #include "exceptionex.h" +#include "logging.h" +#include "shared_memory.h" +#include "stringutils.h" #include "wildcard.h" // simplify unit tests by allowing access to private members #ifndef PRIVATE #define PRIVATE private -#endif // PRIVATE - +#endif // PRIVATE namespace usvfs::shared { @@ -38,35 +37,36 @@ namespace usvfs::shared template struct SHMDataCreator { - static T create(const U &source, const VoidAllocatorT &allocator) { + static T create(const U& source, const VoidAllocatorT& allocator) + { return T(source, allocator); } }; -template T createData( - const U &source, const VoidAllocatorT &allocator) +template +T createData(const U& source, const VoidAllocatorT& allocator) { return SHMDataCreator::create(source, allocator); } -template T createDataEmpty(const VoidAllocatorT &allocator); +template +T createDataEmpty(const VoidAllocatorT& allocator); -template void dataAssign(T &destination, const T &source); +template +void dataAssign(T& destination, const T& source); // crappy little workaround for fs::path iterating over path separators -fs::path::iterator nextIter( - const fs::path::iterator &iter, const fs::path::iterator &end); - -void advanceIter(fs::path::iterator &iter, const fs::path::iterator &end); +fs::path::iterator nextIter(const fs::path::iterator& iter, + const fs::path::iterator& end); +void advanceIter(fs::path::iterator& iter, const fs::path::iterator& end); // decomposes a path into its components // class DecomposablePath { public: - explicit DecomposablePath(std::string s) - : m_s(std::move(s)), m_begin(0), m_end(0) + explicit DecomposablePath(std::string s) : m_s(std::move(s)), m_begin(0), m_end(0) { m_end = nextSeparator(m_begin); } @@ -109,10 +109,7 @@ public: // the current component, empty when next() returned false // - std::string_view current() const - { - return {m_s.data() + m_begin, m_end - m_begin}; - } + std::string_view current() const { return {m_s.data() + m_begin, m_end - m_begin}; } private: const std::string m_s; @@ -134,9 +131,7 @@ private: } }; - - -namespace bi = boost::interprocess; +namespace bi = boost::interprocess; namespace bmi = boost::multi_index; typedef uint8_t TreeFlags; @@ -145,12 +140,12 @@ static const TreeFlags FLAG_DIRECTORY = 0x01; static const TreeFlags FLAG_DUMMY = 0x02; static const TreeFlags FLAG_FIRSTUSERFLAG = 0x10; -struct MissingThrowT {}; +struct MissingThrowT +{}; static const MissingThrowT MissingThrow = MissingThrowT(); - -template class TreeContainer; - +template +class TreeContainer; template struct mutable_pair @@ -158,32 +153,23 @@ struct mutable_pair typedef T1 first_type; typedef T2 second_type; - mutable_pair(Alloc alloc) : first(T1(alloc)), second(T2(alloc)) - { - } + mutable_pair(Alloc alloc) : first(T1(alloc)), second(T2(alloc)) {} - mutable_pair(const T1 &f, const T2 &s) : first(f), second(s) - { - } + mutable_pair(const T1& f, const T2& s) : first(f), second(s) {} - mutable_pair(const std::pair &p) : first(p.first), second(p.second) - { - } + mutable_pair(const std::pair& p) : first(p.first), second(p.second) {} T1 first; mutable T2 second; }; - template > using mimap = bmi::multi_index_container< - Element, bmi::indexed_by< - bmi::ordered_unique< - bmi::member, Compare> - >, typename Allocator::template rebind::other ->; - + Element, + bmi::indexed_by< + bmi::ordered_unique, Compare>>, + typename Allocator::template rebind::other>; /** * a representation of a directory tree in memory. @@ -199,14 +185,13 @@ public: struct CILess { template - bool operator() (const U &lhs, const V &rhs) const + bool operator()(const U& lhs, const V& rhs) const { const size_t lhsLength = getLength(lhs); const size_t rhsLength = getLength(rhs); - const auto r = _strnicmp( - getCharPtr(lhs), getCharPtr(rhs), - std::min(lhsLength, rhsLength)); + const auto r = + _strnicmp(getCharPtr(lhs), getCharPtr(rhs), std::min(lhsLength, rhsLength)); if (r == 0) { return lhsLength < rhsLength; @@ -216,46 +201,21 @@ public: } private: - const char *getCharPtr(const StringT &s) const - { - return s.c_str(); - } + const char* getCharPtr(const StringT& s) const { return s.c_str(); } - const char *getCharPtr(const std::string &s) const - { - return s.c_str(); - } + const char* getCharPtr(const std::string& s) const { return s.c_str(); } - const char *getCharPtr(const char *s) const - { - return s; - } + const char* getCharPtr(const char* s) const { return s; } - const char *getCharPtr(std::string_view s) const - { - return s.data(); - } + const char* getCharPtr(std::string_view s) const { return s.data(); } + size_t getLength(const StringT& s) const { return s.size(); } - size_t getLength(const StringT& s) const - { - return s.size(); - } + size_t getLength(const std::string& s) const { return s.size(); } - size_t getLength(const std::string& s) const - { - return s.size(); - } + size_t getLength(const char* s) const { return strlen(s); } - size_t getLength(const char *s) const - { - return strlen(s); - } - - size_t getLength(std::string_view s) const - { - return s.size(); - } + size_t getLength(std::string_view s) const { return s.size(); } }; typedef DirectoryTree NodeT; @@ -265,43 +225,35 @@ public: typedef bi::shared_ptr NodePtrT; typedef bi::weak_ptr WeakPtrT; - typedef bi::allocator, SegmentManagerT> NodeEntryAllocatorT; + typedef bi::allocator, SegmentManagerT> + NodeEntryAllocatorT; typedef mimap NodeMapT; typedef typename NodeMapT::iterator file_iterator; typedef typename NodeMapT::const_iterator const_file_iterator; - typedef std::function VisitorFunction; + typedef std::function VisitorFunction; - - DirectoryTree() = delete; - DirectoryTree(const NodeT &reference) = delete; - DirectoryTree(NodeT &&reference) = delete; - NodeT &operator=(NodeT reference) = delete; + DirectoryTree() = delete; + DirectoryTree(const NodeT& reference) = delete; + DirectoryTree(NodeT&& reference) = delete; + NodeT& operator=(NodeT reference) = delete; /** * @brief construct a new node to be inserted in an existing tree **/ - DirectoryTree( - std::string_view name, TreeFlags flags, const NodePtrT &parent, - const NodeDataT &data, const VoidAllocatorT &allocator) : - m_Parent(parent), m_Name(name.begin(), name.end(), allocator), - m_Data(data), m_Nodes(allocator), m_Flags(flags) - { - } + DirectoryTree(std::string_view name, TreeFlags flags, const NodePtrT& parent, + const NodeDataT& data, const VoidAllocatorT& allocator) + : m_Parent(parent), m_Name(name.begin(), name.end(), allocator), m_Data(data), + m_Nodes(allocator), m_Flags(flags) + {} - ~DirectoryTree() - { - m_Nodes.clear(); - } + ~DirectoryTree() { m_Nodes.clear(); } /** * @return parent node */ - NodePtrT parent() const - { - return m_Parent.lock(); - } + NodePtrT parent() const { return m_Parent.lock(); } /** * @return the full path to the node @@ -322,18 +274,12 @@ public: /** * @return data connected to this node **/ - const NodeDataT &data() const - { - return m_Data; - } + const NodeDataT& data() const { return m_Data; } /** * @return name of this node */ - std::string name() const - { - return m_Name.c_str(); - } + std::string name() const { return m_Name.c_str(); } /** * @brief setFlag change a flag for this node @@ -347,26 +293,17 @@ public: /** * @return true if the specified flag is set, false otherwise */ - bool hasFlag(TreeFlags flag) const - { - return (m_Flags & flag) != 0; - } + bool hasFlag(TreeFlags flag) const { return (m_Flags & flag) != 0; } /** * @return true if this node is a directory, false if it's a regular file */ - bool isDirectory() const - { - return hasFlag(FLAG_DIRECTORY); - } + bool isDirectory() const { return hasFlag(FLAG_DIRECTORY); } /** * @return the number of subnodes (directly) below this one */ - size_t numNodes() const - { - return m_Nodes.size(); - } + size_t numNodes() const { return m_Nodes.size(); } /** * @return number of nodes in this (sub-)tree including this one @@ -375,7 +312,7 @@ public: { size_t result = numNodes() + 1; - for (const auto &node : m_Nodes) { + for (const auto& node : m_Nodes) { result += node.second->numNodesRecursive(); } @@ -387,7 +324,7 @@ public: * @param path the path to look up * @return a pointer to the node or a null ptr */ - NodePtrT findNode(const fs::path &path) + NodePtrT findNode(const fs::path& path) { fs::path::iterator iter = path.begin(); return findNode(path, iter); @@ -398,18 +335,19 @@ public: * @param path the path to look up * @return a pointer to the node or a null ptr */ - const NodePtrT findNode(const fs::path &path) const + const NodePtrT findNode(const fs::path& path) const { fs::path::iterator iter = path.begin(); return findNode(path, iter); } /** - * @brief visit the nodes along the specified path (in order) calling the visitor for each + * @brief visit the nodes along the specified path (in order) calling the visitor for + * each * @param path the path to visit * @param visitor a function called for each node */ - void visitPath(const fs::path &path, const VisitorFunction &visitor) const + void visitPath(const fs::path& path, const VisitorFunction& visitor) const { fs::path::iterator iter = path.begin(); visitPath(path, iter, visitor); @@ -494,9 +432,10 @@ public: * @param pattern the pattern to look for * @return a vector of the found nodes */ - std::vector find(const std::string &pattern) const + std::vector find(const std::string& pattern) const { - // determine if there is a prefix in the pattern that indicates a specific directory. + // determine if there is a prefix in the pattern that indicates a specific + // directory. size_t fixedPart = pattern.find_first_of("*?"); if (fixedPart == 0) @@ -509,8 +448,7 @@ public: if (fixedPart != std::string::npos) { // if there is a prefix, search for the node representing that path and // search only on that - NodePtrT node - = findNode(fs::path(pattern.substr(0, fixedPart))); + NodePtrT node = findNode(fs::path(pattern.substr(0, fixedPart))); if (node.get() != nullptr) { node->findLocal(result, pattern.substr(fixedPart + 1)); } @@ -524,51 +462,33 @@ public: /** * @return an iterator to the first leaf **/ - file_iterator filesBegin() - { - return m_Nodes.begin(); - } + file_iterator filesBegin() { return m_Nodes.begin(); } /** * @return a const iterator to the first leaf **/ - const_file_iterator filesBegin() const - { - return m_Nodes.begin(); - } + const_file_iterator filesBegin() const { return m_Nodes.begin(); } /** * @return an iterator one past the last leaf **/ - file_iterator filesEnd() - { - return m_Nodes.end(); - } + file_iterator filesEnd() { return m_Nodes.end(); } /** * @return a const iterator one past the last leaf **/ - const_file_iterator filesEnd() const - { - return m_Nodes.end(); - } + const_file_iterator filesEnd() const { return m_Nodes.end(); } /** * @brief erase the leaf at the specified iterator * @return an iterator to the following file **/ - file_iterator erase(file_iterator iter) - { - return m_Nodes.erase(iter); - } + file_iterator erase(file_iterator iter) { return m_Nodes.erase(iter); } /** * @brief clear all nodes */ - void clear() - { - m_Nodes.clear(); - } + void clear() { m_Nodes.clear(); } void removeFromTree() { @@ -577,17 +497,17 @@ public: auto self = par->m_Nodes.find(m_Name.c_str()); if (self != par->m_Nodes.end()) { par->erase(self); - } - else { - //trying to remove a node that does not exist, most likely because it was already removed in a lower level call. - //this is known to happen when MoveFile has the MOVEFILE_COPY_ALLOWED flag and moving a mapped file. - spdlog::get("usvfs")->warn("Failed to remove inexisting node from tree: {}", m_Name.c_str()); + } else { + // trying to remove a node that does not exist, most likely because it was + // already removed in a lower level call. this is known to happen when MoveFile + // has the MOVEFILE_COPY_ALLOWED flag and moving a mapped file. + spdlog::get("usvfs")->warn("Failed to remove inexisting node from tree: {}", + m_Name.c_str()); } } } -PRIVATE: - void set(StringT key, const NodePtrT &value) + PRIVATE : void set(StringT key, const NodePtrT& value) { auto res = m_Nodes.emplace(std::move(key), value); if (!res.second) { @@ -604,10 +524,10 @@ PRIVATE: } } - NodePtrT findNode(const fs::path &name, fs::path::iterator &iter) + NodePtrT findNode(const fs::path& name, fs::path::iterator& iter) { std::string l = iter->string(); - auto subNode = m_Nodes.find(iter->string()); + auto subNode = m_Nodes.find(iter->string()); advanceIter(iter, name.end()); if (iter == name.end()) { @@ -626,7 +546,7 @@ PRIVATE: } } - const NodePtrT findNode(const fs::path &name, fs::path::iterator &iter) const + const NodePtrT findNode(const fs::path& name, fs::path::iterator& iter) const { auto subNode = m_Nodes.find(iter->string()); advanceIter(iter, name.end()); @@ -647,9 +567,8 @@ PRIVATE: } } - void visitPath( - const fs::path &path, fs::path::iterator &iter, - const VisitorFunction &visitor) const + void visitPath(const fs::path& path, fs::path::iterator& iter, + const VisitorFunction& visitor) const { auto subNode = m_Nodes.find(iter->string()); @@ -662,23 +581,19 @@ PRIVATE: } } - void findLocal(std::vector &output, const std::string &pattern) const + void findLocal(std::vector& output, const std::string& pattern) const { for (auto iter = m_Nodes.begin(); iter != m_Nodes.end(); ++iter) { LPCSTR remainder = nullptr; - if ( pattern.size() > 1 - && (pattern[0] == '*') - && ((pattern[1] == '/') - || (pattern[1] == '\\')) - && iter->second->isDirectory()) - { + if (pattern.size() > 1 && (pattern[0] == '*') && + ((pattern[1] == '/') || (pattern[1] == '\\')) && + iter->second->isDirectory()) { // the star may represent a directory (one directory level, not // multiple!), search in subdirectory iter->second->findLocal(output, pattern.substr(1)); - } - else if ((remainder = wildcard::PartialMatch(iter->second->name().c_str(), pattern.c_str())) != nullptr) - { + } else if ((remainder = wildcard::PartialMatch(iter->second->name().c_str(), + pattern.c_str())) != nullptr) { if ((*remainder == '\0') || (strcmp(remainder, "*") == 0)) { NodePtrT node = iter->second; output.push_back(node); @@ -691,8 +606,7 @@ PRIVATE: } } -PRIVATE: - TreeFlags m_Flags; + PRIVATE : TreeFlags m_Flags; WeakPtrT m_Parent; WeakPtrT m_Self; @@ -703,17 +617,13 @@ PRIVATE: NodeMapT m_Nodes; }; - - template -void dumpTree(std::ostream &stream, const DirectoryTree &tree, - int level = 0) +void dumpTree(std::ostream& stream, const DirectoryTree& tree, int level = 0) { - stream << std::string(level, ' ') << tree.name() << " -> " << tree.data() - << "\n"; + stream << std::string(level, ' ') << tree.name() << " -> " << tree.data() << "\n"; for (auto iter = tree.filesBegin(); iter != tree.filesEnd(); ++iter) { dumpTree(stream, *iter->second, level + 1); } } -} // namespace +} // namespace usvfs::shared diff --git a/src/shared/exceptionex.cpp b/src/shared/exceptionex.cpp index 4ae5e17..4a814b5 100644 --- a/src/shared/exceptionex.cpp +++ b/src/shared/exceptionex.cpp @@ -36,39 +36,47 @@ std::string windows_error::constructMessage(const std::string& input, int inErro // TODO: the message is not english? if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buffer, 0, nullptr) == 0) { + nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&buffer, 0, nullptr) == 0) { finalMessage << " (errorcode " << errorCode << ")"; } else { LPSTR lastChar = buffer + strlen(buffer) - 2; - *lastChar = '\0'; + *lastChar = '\0'; finalMessage << " (" << buffer << " [" << errorCode << "])"; - LocalFree(buffer); // allocated by FormatMessage + LocalFree(buffer); // allocated by FormatMessage } - SetLastError(errorCode); // restore error code because FormatMessage might have modified it + SetLastError( + errorCode); // restore error code because FormatMessage might have modified it return finalMessage.str(); } -} // namespace +} // namespace usvfs::shared - -void logExtInfo(const std::exception &e, LogLevel logLevel) +void logExtInfo(const std::exception& e, LogLevel logLevel) { std::string content; - if (const std::string *msg = boost::get_error_info(e)) { + if (const std::string* msg = boost::get_error_info(e)) { content = *msg; } - if (const DWORD *errorCode = boost::get_error_info(e)) { + if (const DWORD* errorCode = boost::get_error_info(e)) { content = std::string("error: ") + winapi::ex::ansi::errorString(*errorCode); } - switch (logLevel) - { - case LogLevel::Debug: spdlog::get("usvfs")->debug(content); break; - case LogLevel::Info: spdlog::get("usvfs")->info(content); break; - case LogLevel::Warning: spdlog::get("usvfs")->warn(content); break; - case LogLevel::Error: spdlog::get("usvfs")->error(content); break; + switch (logLevel) { + case LogLevel::Debug: + spdlog::get("usvfs")->debug(content); + break; + case LogLevel::Info: + spdlog::get("usvfs")->info(content); + break; + case LogLevel::Warning: + spdlog::get("usvfs")->warn(content); + break; + case LogLevel::Error: + spdlog::get("usvfs")->error(content); + break; } } diff --git a/src/shared/exceptionex.h b/src/shared/exceptionex.h index c2d879d..4c298a5 100644 --- a/src/shared/exceptionex.h +++ b/src/shared/exceptionex.h @@ -35,18 +35,24 @@ struct std_boost_exception : virtual boost::exception, virtual std::exception } }; -struct incompatibility_error : std_boost_exception {}; -struct usage_error : std_boost_exception {}; -struct data_error : std_boost_exception {}; -struct file_not_found_error : std_boost_exception {}; -struct timeout_error : std_boost_exception {}; -struct unknown_error : std_boost_exception {}; -struct node_missing_error : std_boost_exception {}; +struct incompatibility_error : std_boost_exception +{}; +struct usage_error : std_boost_exception +{}; +struct data_error : std_boost_exception +{}; +struct file_not_found_error : std_boost_exception +{}; +struct timeout_error : std_boost_exception +{}; +struct unknown_error : std_boost_exception +{}; +struct node_missing_error : std_boost_exception +{}; #define USVFS_THROW_EXCEPTION(x) BOOST_THROW_EXCEPTION(x) -void logExtInfo(const std::exception &e, LogLevel logLevel = LogLevel::Warning); - +void logExtInfo(const std::exception& e, LogLevel logLevel = LogLevel::Warning); namespace usvfs::shared { @@ -55,14 +61,10 @@ class windows_error : public std::runtime_error { public: windows_error(const std::string& message, int errorcode = GetLastError()) - : runtime_error(constructMessage(message, errorcode)), m_ErrorCode(errorcode) - { - } + : runtime_error(constructMessage(message, errorcode)), m_ErrorCode(errorcode) + {} - int getErrorCode() const - { - return m_ErrorCode; - } + int getErrorCode() const { return m_ErrorCode; } private: int m_ErrorCode; @@ -70,14 +72,10 @@ private: std::string constructMessage(const std::string& input, int errorcode); }; - class guard { public: - explicit guard(std::function f) - : m_f(std::move(f)) - { - } + explicit guard(std::function f) : m_f(std::move(f)) {} ~guard() { @@ -90,10 +88,10 @@ public: guard& operator=(const guard&); private: - std::function m_f; + std::function m_f; }; -} // namespace +} // namespace usvfs::shared #define CONCATENATE_DIRECT(s1, s2) s1##s2 #define CONCATENATE(s1, s2) CONCATENATE_DIRECT(s1, s2) diff --git a/src/shared/formatters.h b/src/shared/formatters.h index caebe10..3d0e47e 100644 --- a/src/shared/formatters.h +++ b/src/shared/formatters.h @@ -27,10 +27,11 @@ along with usvfs. If not, see . // formatters for standard types -namespace usvfs::log { - std::string to_string(LPCWSTR value); - std::string to_string(PCUNICODE_STRING value); -} +namespace usvfs::log +{ +std::string to_string(LPCWSTR value); +std::string to_string(PCUNICODE_STRING value); +} // namespace usvfs::log template requires std::is_enum_v @@ -40,7 +41,7 @@ struct std::formatter : std::formatter FmtContext::iterator format(Enum v, FmtContext& ctx) const { return std::formatter, CharT>::format( - static_cast>(v), ctx); + static_cast>(v), ctx); } }; @@ -85,11 +86,9 @@ struct std::formatter : std::formatter }; template - requires (std::is_pointer_v - && !std::is_same_v - && !std::is_same_v - && !std::is_same_v - && !std::is_same_v) + requires(std::is_pointer_v && !std::is_same_v && + !std::is_same_v && !std::is_same_v && + !std::is_same_v) struct std::formatter : std::formatter { template @@ -99,22 +98,21 @@ struct std::formatter : std::formatter } }; - -namespace usvfs::log +namespace usvfs::log { /** - * a small helper class to wrap any object. The whole point is to give us a way - * to ensure our own operator<< is used in addParam calls - */ + * a small helper class to wrap any object. The whole point is to give us a way + * to ensure our own operator<< is used in addParam calls + */ template class Wrap { public: - explicit Wrap(const T& data) : m_Data(data) { } - Wrap(Wrap&& reference) : m_Data(std::move(reference.m_Data)) { } + explicit Wrap(const T& data) : m_Data(data) {} + Wrap(Wrap&& reference) : m_Data(std::move(reference.m_Data)) {} - Wrap(const Wrap& reference) = delete; + Wrap(const Wrap& reference) = delete; Wrap& operator=(const Wrap& reference) = delete; private: @@ -128,7 +126,7 @@ Wrap wrap(const T& data) return Wrap(data); } -} +} // namespace usvfs::log template <> struct std::formatter, char> : std::formatter @@ -144,7 +142,8 @@ template <> struct std::formatter, char> : std::formatter { template - FmtContext::iterator format(const usvfs::log::Wrap& v, FmtContext& ctx) const + FmtContext::iterator format(const usvfs::log::Wrap& v, + FmtContext& ctx) const { switch (v.m_Data) { case 0x00000000: diff --git a/src/shared/loghelpers.cpp b/src/shared/loghelpers.cpp index 13e0fad..bfcabf1 100644 --- a/src/shared/loghelpers.cpp +++ b/src/shared/loghelpers.cpp @@ -34,7 +34,7 @@ namespace usvfs::log // file for two small functions // // comments from old code, taken as is: -// +// // TODO this does not correctly support surrogate pairs since the size used here // is the number of 16-bit characters in the buffer whereas toNarrow expects the // actual number of characters. It will always underestimate though, so worst @@ -47,17 +47,16 @@ std::string to_string(LPCWSTR value) } try { return ush::string_cast(value, ush::CodePage::UTF8); - } - catch (const std::exception& e) { + } catch (const std::exception& e) { return std::format("", e.what()); } } std::string to_string(PCUNICODE_STRING value) { try { - return ush::string_cast(value->Buffer, ush::CodePage::UTF8, value->Length / sizeof(WCHAR)); - } - catch (const std::exception& e) { + return ush::string_cast(value->Buffer, ush::CodePage::UTF8, + value->Length / sizeof(WCHAR)); + } catch (const std::exception& e) { return std::format("", e.what()); } } @@ -65,23 +64,33 @@ std::string to_string(PCUNICODE_STRING value) spdlog::level::level_enum ConvertLogLevel(LogLevel level) { switch (level) { - case LogLevel::Debug: return spdlog::level::debug; - case LogLevel::Info: return spdlog::level::info; - case LogLevel::Warning: return spdlog::level::warn; - case LogLevel::Error: return spdlog::level::err; - default: return spdlog::level::debug; + case LogLevel::Debug: + return spdlog::level::debug; + case LogLevel::Info: + return spdlog::level::info; + case LogLevel::Warning: + return spdlog::level::warn; + case LogLevel::Error: + return spdlog::level::err; + default: + return spdlog::level::debug; } } LogLevel ConvertLogLevel(spdlog::level::level_enum level) { switch (level) { - case spdlog::level::debug: return LogLevel::Debug; - case spdlog::level::info: return LogLevel::Info; - case spdlog::level::warn: return LogLevel::Warning; - case spdlog::level::err: return LogLevel::Error; - default: return LogLevel::Debug; + case spdlog::level::debug: + return LogLevel::Debug; + case spdlog::level::info: + return LogLevel::Info; + case spdlog::level::warn: + return LogLevel::Warning; + case spdlog::level::err: + return LogLevel::Error; + default: + return LogLevel::Debug; } } -} // namespace +} // namespace usvfs::log diff --git a/src/shared/loghelpers.h b/src/shared/loghelpers.h index d3828b0..071ad9d 100644 --- a/src/shared/loghelpers.h +++ b/src/shared/loghelpers.h @@ -21,10 +21,10 @@ along with usvfs. If not, see . #pragma once #include "dllimport.h" +#include "formatters.h" +#include "ntdll_declarations.h" #include "shmlogger.h" #include "stringutils.h" -#include "ntdll_declarations.h" -#include "formatters.h" namespace usvfs::log { @@ -34,24 +34,22 @@ enum class DisplayStyle : uint8_t Hex = 0x01 }; - class CallLoggerDummy { public: template - CallLoggerDummy &addParam(const char*, const T&, uint8_t style = 0) + CallLoggerDummy& addParam(const char*, const T&, uint8_t style = 0) { return *this; } }; - class CallLogger { public: - explicit CallLogger(const char *function) + explicit CallLogger(const char* function) { - const char *namespaceend = strrchr(function, ':'); + const char* namespaceend = strrchr(function, ':'); if (namespaceend != nullptr) { function = namespaceend + 1; @@ -62,27 +60,23 @@ public: ~CallLogger() { - try - { + try { static std::shared_ptr log = spdlog::get("hooks"); log->debug("{}", m_Message); - } - catch (...) - { + } catch (...) { // suppress all exceptions in destructor } } template - CallLogger &addParam(const char *name, const T &value, uint8_t style = 0); + CallLogger& addParam(const char* name, const T& value, uint8_t style = 0); private: std::string m_Message; }; - template -CallLogger &CallLogger::addParam(const char *name, const T &value, uint8_t style) +CallLogger& CallLogger::addParam(const char* name, const T& value, uint8_t style) { static bool enabled = spdlog::get("hooks")->should_log(spdlog::level::debug); typedef std::underlying_type::type DSType; @@ -91,20 +85,16 @@ CallLogger &CallLogger::addParam(const char *name, const T &value, uint8_t style if constexpr (std::is_pointer_v) { if (value == nullptr) { std::format_to(std::back_inserter(m_Message), "[{}=]", name); - } - else { + } else { std::format_to(std::back_inserter(m_Message), "[{}={}]", name, value); } - } - else if constexpr (std::is_integral_v) { + } else if constexpr (std::is_integral_v) { if (style & static_cast(DisplayStyle::Hex)) { std::format_to(std::back_inserter(m_Message), "[{}={:x}]", name, value); - } - else { + } else { std::format_to(std::back_inserter(m_Message), "[{}={}]", name, value); } - } - else { + } else { std::format_to(std::back_inserter(m_Message), "[{}={}]", name, value); } } @@ -115,7 +105,7 @@ CallLogger &CallLogger::addParam(const char *name, const T &value, uint8_t style spdlog::level::level_enum ConvertLogLevel(LogLevel level); LogLevel ConvertLogLevel(spdlog::level::level_enum level); -} // namespace +} // namespace usvfs::log // prefer the short variant of the function name, without signature. // Fall back to the portable boost macro @@ -128,5 +118,6 @@ LogLevel ConvertLogLevel(spdlog::level::level_enum level); #define LOG_CALL() usvfs::log::CallLogger(__MYFUNC__) #define PARAM(val) addParam(#val, val) -#define PARAMHEX(val) addParam(#val, val, static_cast(usvfs::log::DisplayStyle::Hex)) +#define PARAMHEX(val) \ + addParam(#val, val, static_cast(usvfs::log::DisplayStyle::Hex)) #define PARAMWRAP(val) addParam(#val, usvfs::log::wrap(val)) diff --git a/src/shared/ntdll_declarations.cpp b/src/shared/ntdll_declarations.cpp index b1119f1..b4bf0f5 100644 --- a/src/shared/ntdll_declarations.cpp +++ b/src/shared/ntdll_declarations.cpp @@ -21,7 +21,9 @@ along with usvfs. If not, see . #include "ntdll_declarations.h" #include -#define LOAD_EXT(mod, name) name = reinterpret_cast(::GetProcAddress(mod, #name)); assert(name != nullptr) +#define LOAD_EXT(mod, name) \ + name = reinterpret_cast(::GetProcAddress(mod, #name)); \ + assert(name != nullptr) NtQueryDirectoryFile_type NtQueryDirectoryFile; NtQueryDirectoryFileEx_type NtQueryDirectoryFileEx; @@ -34,14 +36,16 @@ NtOpenFile_type NtOpenFile; NtCreateFile_type NtCreateFile; NtClose_type NtClose; RtlDoesFileExists_U_type RtlDoesFileExists_U; -RtlDosPathNameToRelativeNtPathName_U_WithStatus_type RtlDosPathNameToRelativeNtPathName_U_WithStatus; +RtlDosPathNameToRelativeNtPathName_U_WithStatus_type + RtlDosPathNameToRelativeNtPathName_U_WithStatus; RtlReleaseRelativeName_type RtlReleaseRelativeName; RtlGetVersion_type RtlGetVersion; NtTerminateProcess_type NtTerminateProcess; static bool ntdll_initialized; -void ntdll_declarations_init() { +void ntdll_declarations_init() +{ if (!ntdll_initialized) { HMODULE ntDLLMod = GetModuleHandleW(L"ntdll.dll"); @@ -65,8 +69,7 @@ void ntdll_declarations_init() { } } -static struct __Initializer { - __Initializer() { - ntdll_declarations_init(); - } +static struct __Initializer +{ + __Initializer() { ntdll_declarations_init(); } } __initializer; diff --git a/src/shared/ntdll_declarations.h b/src/shared/ntdll_declarations.h index ca39f77..f92058e 100644 --- a/src/shared/ntdll_declarations.h +++ b/src/shared/ntdll_declarations.h @@ -27,8 +27,10 @@ along with usvfs. If not, see . typedef LONG NTSTATUS; -typedef struct _IO_STATUS_BLOCK { - union { +typedef struct _IO_STATUS_BLOCK +{ + union + { NTSTATUS Status; PVOID Pointer; } DUMMYUNIONNAME; @@ -36,7 +38,8 @@ typedef struct _IO_STATUS_BLOCK { ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; -typedef struct _FILE_DIRECTORY_INFORMATION { +typedef struct _FILE_DIRECTORY_INFORMATION +{ ULONG NextEntryOffset; ULONG FileIndex; LARGE_INTEGER CreationTime; @@ -50,7 +53,8 @@ typedef struct _FILE_DIRECTORY_INFORMATION { WCHAR FileName[1]; } FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; -typedef struct _FILE_FULL_DIR_INFORMATION { +typedef struct _FILE_FULL_DIR_INFORMATION +{ ULONG NextEntryOffset; ULONG FileIndex; LARGE_INTEGER CreationTime; @@ -65,7 +69,8 @@ typedef struct _FILE_FULL_DIR_INFORMATION { WCHAR FileName[1]; } FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION; -typedef struct _FILE_ID_FULL_DIR_INFORMATION { +typedef struct _FILE_ID_FULL_DIR_INFORMATION +{ ULONG NextEntryOffset; ULONG FileIndex; LARGE_INTEGER CreationTime; @@ -81,7 +86,8 @@ typedef struct _FILE_ID_FULL_DIR_INFORMATION { WCHAR FileName[1]; } FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION; -typedef struct _FILE_BOTH_DIR_INFORMATION { +typedef struct _FILE_BOTH_DIR_INFORMATION +{ ULONG NextEntryOffset; ULONG FileIndex; LARGE_INTEGER CreationTime; @@ -98,7 +104,8 @@ typedef struct _FILE_BOTH_DIR_INFORMATION { WCHAR FileName[1]; } FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; -typedef struct _FILE_ID_BOTH_DIR_INFORMATION { +typedef struct _FILE_ID_BOTH_DIR_INFORMATION +{ ULONG NextEntryOffset; ULONG FileIndex; LARGE_INTEGER CreationTime; @@ -134,7 +141,8 @@ typedef struct _FILE_STANDARD_INFORMATION BOOLEAN Directory; } FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; -typedef struct _FILE_NAMES_INFORMATION { +typedef struct _FILE_NAMES_INFORMATION +{ ULONG NextEntryOffset; ULONG FileIndex; ULONG FileNameLength; @@ -190,11 +198,14 @@ typedef struct _FILE_ALL_INFORMATION FILE_NAME_INFORMATION NameInformation; } FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION; -typedef struct _FILE_OBJECTID_INFORMATION { +typedef struct _FILE_OBJECTID_INFORMATION +{ LONGLONG FileReference; UCHAR ObjectId[16]; - union { - struct { + union + { + struct + { UCHAR BirthVolumeId[16]; UCHAR BirthObjectId[16]; UCHAR DomainId[16]; @@ -203,26 +214,28 @@ typedef struct _FILE_OBJECTID_INFORMATION { }; } FILE_OBJECTID_INFORMATION, *PFILE_OBJECTID_INFORMATION; -typedef struct _FILE_REPARSE_POINT_INFORMATION { +typedef struct _FILE_REPARSE_POINT_INFORMATION +{ LONGLONG FileReference; ULONG Tag; } FILE_REPARSE_POINT_INFORMATION, *PFILE_REPARSE_POINT_INFORMATION; // copied from ntstatus.h -#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) -#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) -#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) -#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) -#define STATUS_NO_SUCH_FILE ((NTSTATUS)0xC000000FL) +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) +#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) +#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) +#define STATUS_NO_SUCH_FILE ((NTSTATUS)0xC000000FL) -#define SL_RESTART_SCAN 0x01 -#define SL_RETURN_SINGLE_ENTRY 0x02 -#define SL_INDEX_SPECIFIED 0x04 -#define SL_RETURN_ON_DISK_ENTRIES_ONLY 0x08 +#define SL_RESTART_SCAN 0x01 +#define SL_RETURN_SINGLE_ENTRY 0x02 +#define SL_INDEX_SPECIFIED 0x04 +#define SL_RETURN_ON_DISK_ENTRIES_ONLY 0x08 -#define SL_QUERY_DIRECTORY_MASK 0x0b +#define SL_QUERY_DIRECTORY_MASK 0x0b -typedef enum _FILE_INFORMATION_CLASS { +typedef enum _FILE_INFORMATION_CLASS +{ FileDirectoryInformation = 1, FileFullDirectoryInformation = 2, FileBothDirectoryInformation = 3, @@ -236,28 +249,35 @@ typedef enum _FILE_INFORMATION_CLASS { FileIdBothDirectoryInformation = 37, FileIdFullDirectoryInformation = 38, FileNormalizedNameInformation = 48, -} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; +} FILE_INFORMATION_CLASS, + *PFILE_INFORMATION_CLASS; -typedef enum _MODE { KernelMode, UserMode, MaximumMode } MODE; +typedef enum _MODE +{ + KernelMode, + UserMode, + MaximumMode +} MODE; typedef struct _IO_STATUS_BLOCK IO_STATUS_BLOCK; -typedef struct _IO_STATUS_BLOCK *PIO_STATUS_BLOCK; +typedef struct _IO_STATUS_BLOCK* PIO_STATUS_BLOCK; // typedef VOID (NTAPI *PIO_APC_ROUTINE )(__in PVOID ApcContext, __in // PIO_STATUS_BLOCK IoStatusBlock, __in ULONG Reserved); -typedef VOID(NTAPI *PIO_APC_ROUTINE)(PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, +typedef VOID(NTAPI* PIO_APC_ROUTINE)(PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG Reserved); typedef enum _FILE_INFORMATION_CLASS FILE_INFORMATION_CLASS; -typedef struct _UNICODE_STRING { +typedef struct _UNICODE_STRING +{ USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; -typedef const UNICODE_STRING *PCUNICODE_STRING; +typedef const UNICODE_STRING* PCUNICODE_STRING; -typedef struct _OBJECT_ATTRIBUTES { +typedef struct _OBJECT_ATTRIBUTES +{ ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; @@ -266,7 +286,8 @@ typedef struct _OBJECT_ATTRIBUTES { PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; -typedef enum _POOL_TYPE { +typedef enum _POOL_TYPE +{ NonPagedPool, NonPagedPoolExecute = NonPagedPool, PagedPool, @@ -292,7 +313,8 @@ typedef enum _POOL_TYPE { NonPagedPoolSessionNx = NonPagedPoolNx + 32 } POOL_TYPE; -typedef struct _OBJECT_TYPE_INITIALIZER { +typedef struct _OBJECT_TYPE_INITIALIZER +{ WORD Length; UCHAR ObjectTypeFlags; ULONG CaseInsensitive : 1; @@ -309,18 +331,19 @@ typedef struct _OBJECT_TYPE_INITIALIZER { ULONG DefaultPagedPoolCharge; ULONG DefaultNonPagedPoolCharge; PVOID DumpProcedure; - LONG *OpenProcedure; + LONG* OpenProcedure; PVOID CloseProcedure; PVOID DeleteProcedure; - LONG *ParseProcedure; - LONG *SecurityProcedure; - LONG *QueryNameProcedure; - UCHAR *OkayToCloseProcedure; + LONG* ParseProcedure; + LONG* SecurityProcedure; + LONG* QueryNameProcedure; + UCHAR* OkayToCloseProcedure; } OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER; typedef CCHAR KPROCESSOR_MODE; -typedef struct _OBJECT_HANDLE_INFORMATION { +typedef struct _OBJECT_HANDLE_INFORMATION +{ ULONG HandleAttributes; ACCESS_MASK GrantedAccess; } OBJECT_HANDLE_INFORMATION, *POBJECT_HANDLE_INFORMATION; @@ -337,13 +360,15 @@ typedef enum _OBJECT_INFORMATION_CLASS ObjectTypeInformation = 2 } OBJECT_INFORMATION_CLASS; -typedef struct _RTL_RELATIVE_NAME { +typedef struct _RTL_RELATIVE_NAME +{ UNICODE_STRING RelativeName; - HANDLE ContainingDirectory; - void* CurDirRef; + HANDLE ContainingDirectory; + void* CurDirRef; } RTL_RELATIVE_NAME, *PRTL_RELATIVE_NAME; -typedef struct _FILE_NETWORK_OPEN_INFORMATION { +typedef struct _FILE_NETWORK_OPEN_INFORMATION +{ LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; @@ -353,76 +378,77 @@ typedef struct _FILE_NETWORK_OPEN_INFORMATION { ULONG FileAttributes; } FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION; -#define FILE_DIRECTORY_FILE 0x00000001 -#define FILE_WRITE_THROUGH 0x00000002 -#define FILE_SEQUENTIAL_ONLY 0x00000004 -#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 -#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 -#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 -#define FILE_NON_DIRECTORY_FILE 0x00000040 -#define FILE_CREATE_TREE_CONNECTION 0x00000080 -#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 -#define FILE_NO_EA_KNOWLEDGE 0x00000200 -#define FILE_OPEN_REMOTE_INSTANCE 0x00000400 -#define FILE_RANDOM_ACCESS 0x00000800 -#define FILE_DELETE_ON_CLOSE 0x00001000 -#define FILE_OPEN_BY_FILE_ID 0x00002000 -#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 -#define FILE_NO_COMPRESSION 0x00008000 -#define FILE_OPEN_REQUIRING_OPLOCK 0x00010000 -#define FILE_DISALLOW_EXCLUSIVE 0x00020000 -#define FILE_SESSION_AWARE 0x00040000 -#define FILE_RESERVE_OPFILTER 0x00100000 -#define FILE_OPEN_REPARSE_POINT 0x00200000 -#define FILE_OPEN_NO_RECALL 0x00400000 -#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_REMOTE_INSTANCE 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 +#define FILE_OPEN_REQUIRING_OPLOCK 0x00010000 +#define FILE_DISALLOW_EXCLUSIVE 0x00020000 +#define FILE_SESSION_AWARE 0x00040000 +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_OPEN_REPARSE_POINT 0x00200000 +#define FILE_OPEN_NO_RECALL 0x00400000 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 #define FILE_CONTAINS_EXTENDED_CREATE_INFORMATION 0x10000000 // Nt -using NtQueryDirectoryFile_type = NTSTATUS(WINAPI *)( - HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, - FILE_INFORMATION_CLASS, BOOLEAN, PUNICODE_STRING, BOOLEAN); -using NtQueryDirectoryFileEx_type = NTSTATUS(WINAPI *)( - HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, - FILE_INFORMATION_CLASS, ULONG, PUNICODE_STRING); +using NtQueryDirectoryFile_type = NTSTATUS(WINAPI*)(HANDLE, HANDLE, PIO_APC_ROUTINE, + PVOID, PIO_STATUS_BLOCK, PVOID, + ULONG, FILE_INFORMATION_CLASS, + BOOLEAN, PUNICODE_STRING, BOOLEAN); +using NtQueryDirectoryFileEx_type = NTSTATUS(WINAPI*)(HANDLE, HANDLE, PIO_APC_ROUTINE, + PVOID, PIO_STATUS_BLOCK, PVOID, + ULONG, FILE_INFORMATION_CLASS, + ULONG, PUNICODE_STRING); -using NtQueryFullAttributesFile_type = NTSTATUS(WINAPI *)( - POBJECT_ATTRIBUTES, PFILE_NETWORK_OPEN_INFORMATION); -using NtQueryAttributesFile_type = NTSTATUS(WINAPI *)(POBJECT_ATTRIBUTES, +using NtQueryFullAttributesFile_type = + NTSTATUS(WINAPI*)(POBJECT_ATTRIBUTES, PFILE_NETWORK_OPEN_INFORMATION); +using NtQueryAttributesFile_type = NTSTATUS(WINAPI*)(POBJECT_ATTRIBUTES, PFILE_BASIC_INFORMATION); -using NtQueryObject_type = NTSTATUS (WINAPI *)( - HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, - PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); +using NtQueryObject_type = NTSTATUS(WINAPI*)( + HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, + PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); using NtQueryInformationFile_type = NTSTATUS(WINAPI*)( HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); using NtQueryInformationByName_type = NTSTATUS(WINAPI*)( - HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, - ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); + HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, + ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); -using NtOpenFile_type = NTSTATUS(WINAPI *)(PHANDLE, ACCESS_MASK, - POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, - ULONG, ULONG); -using NtCreateFile_type = NTSTATUS(WINAPI *)(PHANDLE, ACCESS_MASK, - POBJECT_ATTRIBUTES, - PIO_STATUS_BLOCK, PLARGE_INTEGER, - ULONG, ULONG, ULONG, ULONG, PVOID, - ULONG); +using NtOpenFile_type = NTSTATUS(WINAPI*)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, + PIO_STATUS_BLOCK, ULONG, ULONG); +using NtCreateFile_type = NTSTATUS(WINAPI*)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, + PIO_STATUS_BLOCK, PLARGE_INTEGER, ULONG, + ULONG, ULONG, ULONG, PVOID, ULONG); -using NtClose_type = NTSTATUS(WINAPI *)(HANDLE); +using NtClose_type = NTSTATUS(WINAPI*)(HANDLE); -using NtTerminateProcess_type = NTSTATUS(WINAPI *)(HANDLE ProcessHandle, NTSTATUS ExitStatus); +using NtTerminateProcess_type = NTSTATUS(WINAPI*)(HANDLE ProcessHandle, + NTSTATUS ExitStatus); // Rtl -using RtlDoesFileExists_U_type = NTSYSAPI BOOLEAN(NTAPI *)(PCWSTR); -using RtlDosPathNameToRelativeNtPathName_U_WithStatus_type = NTSTATUS(NTAPI *)( - PCWSTR DosFileName, PUNICODE_STRING NtFileName, PWSTR* FilePath, PRTL_RELATIVE_NAME RelativeName); -using RtlReleaseRelativeName_type = void (NTAPI *)(PRTL_RELATIVE_NAME RelativeName); -using RtlGetVersion_type = NTSTATUS (NTAPI *)(PRTL_OSVERSIONINFOW); +using RtlDoesFileExists_U_type = NTSYSAPI BOOLEAN(NTAPI*)(PCWSTR); +using RtlDosPathNameToRelativeNtPathName_U_WithStatus_type = + NTSTATUS(NTAPI*)(PCWSTR DosFileName, PUNICODE_STRING NtFileName, PWSTR* FilePath, + PRTL_RELATIVE_NAME RelativeName); +using RtlReleaseRelativeName_type = void(NTAPI*)(PRTL_RELATIVE_NAME RelativeName); +using RtlGetVersion_type = NTSTATUS(NTAPI*)(PRTL_OSVERSIONINFOW); extern NtQueryDirectoryFile_type NtQueryDirectoryFile; extern NtQueryDirectoryFileEx_type NtQueryDirectoryFileEx; @@ -436,11 +462,13 @@ extern NtCreateFile_type NtCreateFile; extern NtClose_type NtClose; extern NtTerminateProcess_type NtTerminateProcess; extern RtlDoesFileExists_U_type RtlDoesFileExists_U; -extern RtlDosPathNameToRelativeNtPathName_U_WithStatus_type RtlDosPathNameToRelativeNtPathName_U_WithStatus; +extern RtlDosPathNameToRelativeNtPathName_U_WithStatus_type + RtlDosPathNameToRelativeNtPathName_U_WithStatus; extern RtlReleaseRelativeName_type RtlReleaseRelativeName; extern RtlGetVersion_type RtlGetVersion; -// ensures ntdll functions have been initialized (only needed during static objects initialization) +// ensures ntdll functions have been initialized (only needed during static objects +// initialization) void ntdll_declarations_init(); #pragma warning(pop) diff --git a/src/shared/pch.h b/src/shared/pch.h index b3216f4..fed61cf 100644 --- a/src/shared/pch.h +++ b/src/shared/pch.h @@ -34,22 +34,25 @@ #endif #define WIN32_LEAN_AND_MEAN -#include -#include -#include +#include #include +#include +#include +#include +#include #include #include -#include -#include #define BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI 1 #include #include #include #include -#include +#include #include +#include +#include +#include #include #include #include @@ -57,9 +60,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -75,8 +75,8 @@ #include #include #include -#include #include +#include #include #include diff --git a/src/shared/shared_memory.h b/src/shared/shared_memory.h index 5f5ba31..28da34b 100644 --- a/src/shared/shared_memory.h +++ b/src/shared/shared_memory.h @@ -39,14 +39,15 @@ using VoidPointerT = OffsetPtrT; // managed_windows_shared_memory apparently doesn't support sharing between // 64bit and 32bit processes using managed_windows_shared_memory = bi::basic_managed_windows_shared_memory< - char, bi::rbtree_best_fit, bi::iset_index>; + char, bi::rbtree_best_fit, bi::iset_index>; -using SharedMemoryT = managed_windows_shared_memory; +using SharedMemoryT = managed_windows_shared_memory; using SegmentManagerT = SharedMemoryT::segment_manager; -using VoidAllocatorT = boost::container::scoped_allocator_adaptor>; +using VoidAllocatorT = boost::container::scoped_allocator_adaptor< + boost::interprocess::allocator>; using CharAllocatorT = VoidAllocatorT::rebind::other; -using StringT = bc::basic_string, CharAllocatorT> ; +using StringT = bc::basic_string, CharAllocatorT>; -} // namespace +} // namespace usvfs::shared diff --git a/src/shared/shmlogger.cpp b/src/shared/shmlogger.cpp index d3fafda..66512de 100644 --- a/src/shared/shmlogger.cpp +++ b/src/shared/shmlogger.cpp @@ -29,15 +29,15 @@ along with usvfs. If not, see . using namespace boost::interprocess; using namespace boost::posix_time; -SHMLogger *SHMLogger::s_Instance = nullptr; +SHMLogger* SHMLogger::s_Instance = nullptr; SHMLogger::owner_t SHMLogger::owner; SHMLogger::client_t SHMLogger::client; -SHMLogger::SHMLogger(owner_t, const std::string &queueName) - : m_QueueName(queueName) - , m_LogQueue(create_only, queueName.c_str(), MESSAGE_COUNT, MESSAGE_SIZE) - , m_DroppedMessages(0) +SHMLogger::SHMLogger(owner_t, const std::string& queueName) + : m_QueueName(queueName), + m_LogQueue(create_only, queueName.c_str(), MESSAGE_COUNT, MESSAGE_SIZE), + m_DroppedMessages(0) { if (s_Instance != nullptr) { throw std::runtime_error("duplicate shm logger instantiation"); @@ -46,10 +46,9 @@ SHMLogger::SHMLogger(owner_t, const std::string &queueName) } } -SHMLogger::SHMLogger(client_t, const std::string &queueName) - : m_QueueName(queueName) - , m_LogQueue(open_only, queueName.c_str()) - , m_DroppedMessages(0) +SHMLogger::SHMLogger(client_t, const std::string& queueName) + : m_QueueName(queueName), m_LogQueue(open_only, queueName.c_str()), + m_DroppedMessages(0) { if (s_Instance != nullptr) { throw std::runtime_error("duplicate shm logger instantiation"); @@ -64,7 +63,7 @@ SHMLogger::~SHMLogger() message_queue_interop::remove(m_QueueName.c_str()); } -SHMLogger &SHMLogger::create(const char *instanceName) +SHMLogger& SHMLogger::create(const char* instanceName) { if (s_Instance != nullptr) { throw std::runtime_error("duplicate shm logger instantiation"); @@ -72,12 +71,14 @@ SHMLogger &SHMLogger::create(const char *instanceName) std::string queueName = std::string("__shm_sink_") + instanceName; message_queue::remove(queueName.c_str()); new SHMLogger(owner, queueName); - atexit([]() { delete s_Instance; }); + atexit([]() { + delete s_Instance; + }); } return *s_Instance; } -SHMLogger &SHMLogger::open(const char *instanceName) +SHMLogger& SHMLogger::open(const char* instanceName) { if (s_Instance != nullptr) { throw std::runtime_error("duplicate shm logger instantiation"); @@ -90,44 +91,40 @@ SHMLogger &SHMLogger::open(const char *instanceName) void SHMLogger::free() { if (s_Instance != nullptr) { - SHMLogger *temp = s_Instance; + SHMLogger* temp = s_Instance; s_Instance = nullptr; delete temp; } } -bool SHMLogger::tryGet(char *buffer, size_t bufferSize) +bool SHMLogger::tryGet(char* buffer, size_t bufferSize) { message_queue_interop::size_type receivedSize; unsigned int prio; - bool res = m_LogQueue.try_receive( - buffer, static_cast(bufferSize), receivedSize, prio); + bool res = m_LogQueue.try_receive(buffer, static_cast(bufferSize), + receivedSize, prio); if (res) { buffer[std::min(bufferSize - 1, static_cast(receivedSize))] = '\0'; } return res; } -void SHMLogger::get(char *buffer, size_t bufferSize) +void SHMLogger::get(char* buffer, size_t bufferSize) { message_queue_interop::size_type receivedSize; unsigned int prio; - m_LogQueue.receive(buffer, static_cast(bufferSize), - receivedSize, prio); + m_LogQueue.receive(buffer, static_cast(bufferSize), receivedSize, prio); buffer[std::min(bufferSize - 1, static_cast(receivedSize))] = '\0'; } +usvfs::sinks::shm_sink::shm_sink(const char* queueName) + : m_LogQueue(open_only, (std::string("__shm_sink_") + queueName).c_str()), + m_DroppedMessages(0) +{} -usvfs::sinks::shm_sink::shm_sink(const char *queueName) - : m_LogQueue(open_only, (std::string("__shm_sink_") + queueName).c_str()), m_DroppedMessages(0) -{ -} +void usvfs::sinks::shm_sink::flush_() {} -void usvfs::sinks::shm_sink::flush_() -{ -} - -void usvfs::sinks::shm_sink::sink_it_(const spdlog::details::log_msg &msg) +void usvfs::sinks::shm_sink::sink_it_(const spdlog::details::log_msg& msg) { int droppedMessages = m_DroppedMessages.load(std::memory_order_relaxed); if (droppedMessages > 0) { @@ -138,7 +135,7 @@ void usvfs::sinks::shm_sink::sink_it_(const spdlog::details::log_msg &msg) } } - std::string message{ msg.payload }; + std::string message{msg.payload}; // blacklist %USERNAME% because PII static const std::string username = std::string(getenv("USERNAME")); @@ -147,9 +144,8 @@ void usvfs::sinks::shm_sink::sink_it_(const spdlog::details::log_msg &msg) if (message.length() > SHMLogger::MESSAGE_SIZE) { std::vector splitVec; - boost::split(splitVec, message, boost::is_any_of("\r\n"), - boost::token_compress_on); - for (const std::string &line : splitVec) { + boost::split(splitVec, message, boost::is_any_of("\r\n"), boost::token_compress_on); + for (const std::string& line : splitVec) { output(msg.level, line); } } else { @@ -158,7 +154,7 @@ void usvfs::sinks::shm_sink::sink_it_(const spdlog::details::log_msg &msg) } void usvfs::sinks::shm_sink::output(spdlog::level::level_enum lev, - const std::string &message) + const std::string& message) { bool sent = true; @@ -170,23 +166,22 @@ void usvfs::sinks::shm_sink::output(spdlog::level::level_enum lev, // depending on the log level, drop less important messages if the receiver // can't keep up switch (lev) { - case spdlog::level::trace: - case spdlog::level::debug: - case spdlog::level::info: { - // m_LogQueue.send(message.c_str(), count, 0); - sent = m_LogQueue.try_send(message.c_str(), - static_cast(count), 0); - } break; - case spdlog::level::err: - case spdlog::level::critical: { - m_LogQueue.send(message.c_str(), static_cast(count), 0); - } break; - default: { - boost::posix_time::ptime time = microsec_clock::universal_time() - + boost::posix_time::milliseconds(200); - sent = m_LogQueue.timed_send(message.c_str(), - static_cast(count), 0, time); - } break; + case spdlog::level::trace: + case spdlog::level::debug: + case spdlog::level::info: { + // m_LogQueue.send(message.c_str(), count, 0); + sent = m_LogQueue.try_send(message.c_str(), static_cast(count), 0); + } break; + case spdlog::level::err: + case spdlog::level::critical: { + m_LogQueue.send(message.c_str(), static_cast(count), 0); + } break; + default: { + boost::posix_time::ptime time = + microsec_clock::universal_time() + boost::posix_time::milliseconds(200); + sent = m_LogQueue.timed_send(message.c_str(), static_cast(count), 0, + time); + } break; } if (!sent) { @@ -194,7 +189,7 @@ void usvfs::sinks::shm_sink::output(spdlog::level::level_enum lev, } } -void __cdecl boost::interprocess::ipcdetail::get_shared_dir(std::string &shared_dir) +void __cdecl boost::interprocess::ipcdetail::get_shared_dir(std::string& shared_dir) { PWSTR path; if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_ProgramData, 0, NULL, &path))) { diff --git a/src/shared/shmlogger.h b/src/shared/shmlogger.h index d2c27ed..158f941 100644 --- a/src/shared/shmlogger.h +++ b/src/shared/shmlogger.h @@ -20,37 +20,34 @@ along with usvfs. If not, see . */ #pragma once -#include #include +#include #include "logging.h" -#include "windows_sane.h" #include "shared_memory.h" +#include "windows_sane.h" -typedef boost::interprocess::message_queue_t message_queue_interop; +typedef boost::interprocess::message_queue_t + message_queue_interop; namespace usvfs::sinks { class shm_sink : public spdlog::sinks::base_sink { public: - shm_sink(const char *queueName); + shm_sink(const char* queueName); protected: - void sink_it_(const spdlog::details::log_msg& msg) override; void output(spdlog::level::level_enum lev, const std::string& message); void flush_() override; - private: message_queue_interop m_LogQueue; std::atomic m_DroppedMessages; }; - -} // namespace - +} // namespace usvfs::sinks class SHMLogger { @@ -58,16 +55,13 @@ public: static const size_t MESSAGE_COUNT = 1024; static const size_t MESSAGE_SIZE = 512; - static SHMLogger &create(const char *instanceName); - static SHMLogger &open(const char *instanceName); + static SHMLogger& create(const char* instanceName); + static SHMLogger& open(const char* instanceName); static void free(); - static bool isInstantiated() - { - return s_Instance != nullptr; - } + static bool isInstantiated() { return s_Instance != nullptr; } - static inline SHMLogger &instance() + static inline SHMLogger& instance() { if (s_Instance == nullptr) { throw std::runtime_error("shm logger not instantiated"); @@ -76,28 +70,30 @@ public: return *s_Instance; } - void log(LogLevel logLevel, const std::string &message); - bool tryGet(char *buffer, size_t bufferSize); - void get(char *buffer, size_t bufferSize); + void log(LogLevel logLevel, const std::string& message); + bool tryGet(char* buffer, size_t bufferSize); + void get(char* buffer, size_t bufferSize); private: - struct owner_t {}; + struct owner_t + {}; static owner_t owner; - struct client_t {}; + struct client_t + {}; static client_t client; private: - SHMLogger(owner_t, const std::string &instanceName); - SHMLogger(client_t, const std::string &instanceName); + SHMLogger(owner_t, const std::string& instanceName); + SHMLogger(client_t, const std::string& instanceName); - SHMLogger(const SHMLogger&) = delete; - SHMLogger &operator=(const SHMLogger&) = delete; + SHMLogger(const SHMLogger&) = delete; + SHMLogger& operator=(const SHMLogger&) = delete; ~SHMLogger(); private: - static SHMLogger *s_Instance; + static SHMLogger* s_Instance; message_queue_interop m_LogQueue; diff --git a/src/shared/stringcast.cpp b/src/shared/stringcast.cpp index 79335b2..47822d5 100644 --- a/src/shared/stringcast.cpp +++ b/src/shared/stringcast.cpp @@ -26,12 +26,15 @@ namespace usvfs::shared UINT windowsCP(CodePage codePage) { switch (codePage) { - case CodePage::LOCAL: return CP_ACP; - case CodePage::UTF8: return CP_UTF8; - case CodePage::LATIN1: return 850; + case CodePage::LOCAL: + return CP_ACP; + case CodePage::UTF8: + return CP_UTF8; + case CodePage::LATIN1: + return 850; } // this should not be possible in practice throw std::runtime_error("unsupported codePage"); } -} // namespace +} // namespace usvfs::shared diff --git a/src/shared/stringcast.h b/src/shared/stringcast.h index 5d85399..0ce56d1 100644 --- a/src/shared/stringcast.h +++ b/src/shared/stringcast.h @@ -36,25 +36,25 @@ template class string_cast_impl { public: - static ToT cast(const FromT &source, CodePage codePage, size_t sourceLength); + static ToT cast(const FromT& source, CodePage codePage, size_t sourceLength); }; template -ToT string_cast(FromT source - , CodePage codePage = CodePage::LOCAL - , size_t sourceLength = std::numeric_limits::max()) +ToT string_cast(FromT source, CodePage codePage = CodePage::LOCAL, + size_t sourceLength = std::numeric_limits::max()) { return string_cast_impl::cast(source, codePage, sourceLength); } - template class string_cast_impl> { public: - static ToT cast(const std::basic_string &source, CodePage codePage, size_t sourceLength) + static ToT cast(const std::basic_string& source, CodePage codePage, + size_t sourceLength) { - return string_cast_impl::cast(source.c_str(), codePage, sourceLength); + return string_cast_impl::cast(source.c_str(), codePage, + sourceLength); } }; @@ -64,18 +64,17 @@ class string_cast_impl BOOST_STATIC_ASSERT(!boost::is_base_and_derived::value); public: - static ToT cast(CharT *source, CodePage codePage, size_t sourceLength) + static ToT cast(CharT* source, CodePage codePage, size_t sourceLength) { return string_cast_impl::cast(source, codePage, sourceLength); } }; - template class string_cast_impl { public: - static ToT cast(CharT(&source)[N], CodePage codePage, size_t sourceLength) + static ToT cast(CharT (&source)[N], CodePage codePage, size_t sourceLength) { return string_cast_impl::cast(source, codePage, sourceLength); } @@ -83,12 +82,12 @@ public: UINT windowsCP(CodePage codePage); - template <> class string_cast_impl { public: - static std::string cast(const wchar_t * const &source, CodePage codePage, size_t sourceLength) + static std::string cast(const wchar_t* const& source, CodePage codePage, + size_t sourceLength) { std::string result; @@ -101,13 +100,13 @@ public: UINT cp = windowsCP(codePage); // preflight to find out the required buffer size int outLength = WideCharToMultiByte(cp, 0, source, static_cast(sourceLength), - nullptr, 0, nullptr, nullptr); + nullptr, 0, nullptr, nullptr); if (outLength == 0) { throw windows_error("string conversion failed"); } result.resize(outLength); outLength = WideCharToMultiByte(cp, 0, source, static_cast(sourceLength), - &result[0], outLength, nullptr, nullptr); + &result[0], outLength, nullptr, nullptr); if (outLength == 0) { throw windows_error("string conversion failed"); } @@ -121,12 +120,12 @@ public: } }; - template <> class string_cast_impl { public: - static std::wstring cast(const char * const &source, CodePage codePage, size_t sourceLength) + static std::wstring cast(const char* const& source, CodePage codePage, + size_t sourceLength) { std::wstring result; @@ -138,12 +137,14 @@ public: // use utf8 or local 8-bit encoding depending on user choice UINT cp = windowsCP(codePage); // preflight to find out the required source size - int outLength = MultiByteToWideChar(cp, 0, source, static_cast(sourceLength), &result[0], 0); + int outLength = MultiByteToWideChar(cp, 0, source, static_cast(sourceLength), + &result[0], 0); if (outLength == 0) { throw windows_error("string conversion failed"); } result.resize(outLength); - outLength = MultiByteToWideChar(cp, 0, source, static_cast(sourceLength), &result[0], outLength); + outLength = MultiByteToWideChar(cp, 0, source, static_cast(sourceLength), + &result[0], outLength); if (outLength == 0) { throw windows_error("string conversion failed"); } @@ -160,10 +161,10 @@ template <> class string_cast_impl { public: - static std::wstring cast(const wchar_t * const &source, CodePage, size_t) + static std::wstring cast(const wchar_t* const& source, CodePage, size_t) { return std::wstring(source); } }; -} // namespace +} // namespace usvfs::shared diff --git a/src/shared/stringutils.cpp b/src/shared/stringutils.cpp index f07db0d..2ddbf64 100644 --- a/src/shared/stringutils.cpp +++ b/src/shared/stringutils.cpp @@ -24,7 +24,7 @@ along with usvfs. If not, see . namespace usvfs::shared { -void strncpy_sz(char *dest, const char *src, size_t destSize) +void strncpy_sz(char* dest, const char* src, size_t destSize) { if (destSize > 0) { strncpy(dest, src, destSize - 1); @@ -32,7 +32,7 @@ void strncpy_sz(char *dest, const char *src, size_t destSize) } } -void wcsncpy_sz(wchar_t *dest, const wchar_t *src, size_t destSize) +void wcsncpy_sz(wchar_t* dest, const wchar_t* src, size_t destSize) { if ((destSize > 0) && (dest != nullptr)) { wcsncpy(dest, src, destSize - 1); @@ -40,8 +40,7 @@ void wcsncpy_sz(wchar_t *dest, const wchar_t *src, size_t destSize) } } - -bool startswith(const wchar_t *string, const wchar_t *subString) +bool startswith(const wchar_t* string, const wchar_t* subString) { while ((*string != '\0') && (*subString != '\0')) { if (towlower(*string) != towlower(*subString)) { @@ -54,7 +53,7 @@ bool startswith(const wchar_t *string, const wchar_t *subString) return *subString == '\0'; } -static fs::path normalize(const fs::path &path) +static fs::path normalize(const fs::path& path) { fs::path result; @@ -65,12 +64,12 @@ static fs::path normalize(const fs::path &path) result = result.parent_path(); } else if (*iter != ".") { result /= boost::to_lower_copy(iter->string(), loc); - } // single dot is ignored + } // single dot is ignored } return result; } -fs::path make_relative(const fs::path &fromIn, const fs::path &toIn) +fs::path make_relative(const fs::path& fromIn, const fs::path& toIn) { // converting path to lower case to make iterator comparison work correctly // on case-insenstive filesystems @@ -105,9 +104,9 @@ fs::path make_relative(const fs::path &fromIn, const fs::path &toIn) return result; } -std::string to_hex(void *bufferIn, size_t bufferSize) +std::string to_hex(void* bufferIn, size_t bufferSize) { - unsigned char *buffer = static_cast(bufferIn); + unsigned char* buffer = static_cast(bufferIn); std::ostringstream temp; temp << std::hex; for (size_t i = 0; i < bufferSize; ++i) { @@ -121,7 +120,7 @@ std::string to_hex(void *bufferIn, size_t bufferSize) return temp.str(); } -std::wstring to_upper(const std::wstring &input) +std::wstring to_upper(const std::wstring& input) { std::wstring result; result.resize(input.size()); @@ -144,4 +143,4 @@ std::string byte_string(std::size_t n) return s + " B"; } -} // namespace +} // namespace usvfs::shared diff --git a/src/shared/stringutils.h b/src/shared/stringutils.h index 7ff2919..64d0af7 100644 --- a/src/shared/stringutils.h +++ b/src/shared/stringutils.h @@ -23,18 +23,18 @@ along with usvfs. If not, see . namespace usvfs::shared { -void strncpy_sz(char *dest, const char *src, size_t destSize); -void wcsncpy_sz(wchar_t *dest, const wchar_t *src, size_t destSize); +void strncpy_sz(char* dest, const char* src, size_t destSize); +void wcsncpy_sz(wchar_t* dest, const wchar_t* src, size_t destSize); -bool startswith(const wchar_t *string, const wchar_t *subString); +bool startswith(const wchar_t* string, const wchar_t* subString); // Return path when appended to a_From will resolve to same as a_To -fs::path make_relative(const fs::path &from, const fs::path &to); +fs::path make_relative(const fs::path& from, const fs::path& to); -std::string to_hex(void *bufferIn, size_t bufferSize); +std::string to_hex(void* bufferIn, size_t bufferSize); // convert unicode string to upper-case (locale invariant) -std::wstring to_upper(const std::wstring &input); +std::wstring to_upper(const std::wstring& input); // formats a number with thousand separators and B at the end // @@ -42,22 +42,16 @@ std::string byte_string(std::size_t n); class FormatGuard { - std::ostream &m_Stream; + std::ostream& m_Stream; std::ios::fmtflags m_Flags; public: - FormatGuard(std::ostream &stream) - : m_Stream(stream), m_Flags(stream.flags()) - { - } + FormatGuard(std::ostream& stream) : m_Stream(stream), m_Flags(stream.flags()) {} - ~FormatGuard() - { - m_Stream.flags(m_Flags); - } + ~FormatGuard() { m_Stream.flags(m_Flags); } - FormatGuard(const FormatGuard&) = delete; - FormatGuard &operator=(FormatGuard&) = delete; + FormatGuard(const FormatGuard&) = delete; + FormatGuard& operator=(FormatGuard&) = delete; }; -} // namespace +} // namespace usvfs::shared diff --git a/src/shared/tree_container.h b/src/shared/tree_container.h index 16a3e5f..a2f61fa 100644 --- a/src/shared/tree_container.h +++ b/src/shared/tree_container.h @@ -1,7 +1,7 @@ #pragma once -#include "shared_memory.h" #include "directory_tree.h" +#include "shared_memory.h" namespace usvfs::shared { @@ -57,14 +57,17 @@ class TreeContainer { public: /** - * @brief Constructor - * @param SHMName name of the shared memory holding the tree. This should contain the running number - * @param size initial size in bytes of the container. since the tree is resized by doubling this should be - * a power of two. 64k is supposed to be the page size on windows so smaller allocations make little sense - * @note size can't be too small. If initial allocations fail automatic growing won't work - */ + * @brief Constructor + * @param SHMName name of the shared memory holding the tree. This should contain the + * running number + * @param size initial size in bytes of the container. since the tree is resized by + * doubling this should be a power of two. 64k is supposed to be the page size on + * windows so smaller allocations make little sense + * @note size can't be too small. If initial allocations fail automatic growing won't + * work + */ TreeContainer(const std::string& SHMName, size_t size = 64 * 1024) - : m_TreeMeta(nullptr), m_SHMName(SHMName) + : m_TreeMeta(nullptr), m_SHMName(SHMName) { std::locale global_loc = std::locale(); std::locale loc(global_loc, new fs::detail::utf8_codecvt_facet); @@ -84,14 +87,12 @@ public: // to an already existing one createOrOpen(m_SHMName, size); - spdlog::get("usvfs")->info( - "attached to {0} with {1} nodes, size {2}", - m_SHMName, - m_TreeMeta->tree->numNodesRecursive(), - byte_string(m_SHM->get_size())); + spdlog::get("usvfs")->info("attached to {0} with {1} nodes, size {2}", m_SHMName, + m_TreeMeta->tree->numNodesRecursive(), + byte_string(m_SHM->get_size())); } - TreeContainer(const TreeContainer&) = delete; + TreeContainer(const TreeContainer&) = delete; TreeContainer& operator=(const TreeContainer&) = delete; ~TreeContainer() @@ -102,12 +103,9 @@ public: } /** - * @return retrieve an allocator that can be used to create objects in this tree - */ - VoidAllocatorT allocator() - { - return VoidAllocatorT(m_SHM->get_segment_manager()); - } + * @return retrieve an allocator that can be used to create objects in this tree + */ + VoidAllocatorT allocator() { return VoidAllocatorT(m_SHM->get_segment_manager()); } template typename TreeT::DataT create(Arguments&&... args) @@ -115,15 +113,12 @@ public: return TreeT::DataT(std::forward(args)..., allocator()); } - TreeT *operator->() - { - return get(); - } + TreeT* operator->() { return get(); } /** - * @return raw pointer to the managed tree - */ - TreeT *get() + * @return raw pointer to the managed tree + */ + TreeT* get() { if (m_TreeMeta->outdated) { reassign(); @@ -133,9 +128,9 @@ public: } /** - * @return raw const pointer to the managed tree - */ - const TreeT *get() const + * @return raw const pointer to the managed tree + */ + const TreeT* get() const { if (m_TreeMeta->outdated) { // safe const_cast, TreeContainer are never created const @@ -145,49 +140,35 @@ public: return m_TreeMeta->tree.get(); } - const TreeT *operator->() const - { - return get(); - } + const TreeT* operator->() const { return get(); } /** - * @return current name of the managed shared memory - */ - std::string shmName() const - { - return m_SHMName; - } + * @return current name of the managed shared memory + */ + std::string shmName() const { return m_SHMName; } - void clear() - { - m_TreeMeta->tree->clear(); - } + void clear() { m_TreeMeta->tree->clear(); } /** - * @brief add a new file to the tree - * - * @param name name of the file, expected to be relative to this directory - * @param data the file data to attach - * @param flags flags for this files - * @param overwrite if true, the new leaf will overwrite an existing one that compares as "equal" - * @return pointer to the new node or a null ptr - **/ + * @brief add a new file to the tree + * + * @param name name of the file, expected to be relative to this directory + * @param data the file data to attach + * @param flags flags for this files + * @param overwrite if true, the new leaf will overwrite an existing one that compares + *as "equal" + * @return pointer to the new node or a null ptr + **/ template - typename TreeT::NodePtrT addFile( - const fs::path &name, const T &data, - TreeFlags flags = 0, bool overwrite = true) + typename TreeT::NodePtrT addFile(const fs::path& name, const T& data, + TreeFlags flags = 0, bool overwrite = true) { for (;;) { DecomposablePath dp(name.string()); - try - { - return addNode( - m_TreeMeta->tree.get(), dp, - data, overwrite, flags, allocator()); - } - catch (const bi::bad_alloc&) - { + try { + return addNode(m_TreeMeta->tree.get(), dp, data, overwrite, flags, allocator()); + } catch (const bi::bad_alloc&) { } reassign(); @@ -195,52 +176,47 @@ public: } /** - * @brief add a new directory to the tree - * - * @param name name of the file, expected to be relative to this directory - * @param data the file data to attach - * @param flags flags for this files - * @param overwrite if true, the new leaf will overwrite an existing one that compares as "equal" - * @return pointer to the new node or a null ptr - **/ + * @brief add a new directory to the tree + * + * @param name name of the file, expected to be relative to this directory + * @param data the file data to attach + * @param flags flags for this files + * @param overwrite if true, the new leaf will overwrite an existing one that compares + *as "equal" + * @return pointer to the new node or a null ptr + **/ template - typename TreeT::NodePtrT addDirectory( - const fs::path &name, const T &data, - TreeFlags flags = 0, bool overwrite = true) + typename TreeT::NodePtrT addDirectory(const fs::path& name, const T& data, + TreeFlags flags = 0, bool overwrite = true) { for (;;) { DecomposablePath dp(name.string()); - try - { - return addNode( - m_TreeMeta->tree.get(), dp, data, - overwrite, flags | FLAG_DIRECTORY, allocator()); - } - catch (const bi::bad_alloc &) - { + try { + return addNode(m_TreeMeta->tree.get(), dp, data, overwrite, + flags | FLAG_DIRECTORY, allocator()); + } catch (const bi::bad_alloc&) { } reassign(); } } - void getBuffer(void *&buffer, size_t &bufferSize) const + void getBuffer(void*& buffer, size_t& bufferSize) const { - buffer = m_SHM->get_address(); + buffer = m_SHM->get_address(); bufferSize = m_SHM->get_size(); } private: struct TreeMeta { - TreeMeta(const typename TreeT::DataT &data, SegmentManagerT *segmentManager) : - tree(segmentManager->construct(bi::anonymous_instance)( - "", true, TreeT::NodePtrT(), data, VoidAllocatorT(segmentManager))), - referenceCount(0), // reference count only set on top level node - outdated(false) - { - } + TreeMeta(const typename TreeT::DataT& data, SegmentManagerT* segmentManager) + : tree(segmentManager->construct(bi::anonymous_instance)( + "", true, TreeT::NodePtrT(), data, VoidAllocatorT(segmentManager))), + referenceCount(0), // reference count only set on top level node + outdated(false) + {} OffsetPtrT tree; long referenceCount; @@ -250,8 +226,7 @@ private: std::string m_SHMName; std::shared_ptr m_SHM; - TreeMeta *m_TreeMeta; - + TreeMeta* m_TreeMeta; typename TreeT::DataT createEmpty() { @@ -259,42 +234,40 @@ private: } template - TreeT *createSubNode( - const VoidAllocatorT &allocator, std::string_view name, - unsigned long flags, const T &data) + TreeT* createSubNode(const VoidAllocatorT& allocator, std::string_view name, + unsigned long flags, const T& data) { auto* manager = allocator.get_segment_manager(); return manager->construct(bi::anonymous_instance)( - name, flags, TreeT::NodePtrT(), - createData(data, allocator), manager); + name, flags, TreeT::NodePtrT(), + createData(data, allocator), manager); } - typename TreeT::NodePtrT createSubPtr(TreeT *subNode) + typename TreeT::NodePtrT createSubPtr(TreeT* subNode) { - SharedMemoryT::segment_manager *manager = m_SHM->get_segment_manager(); + SharedMemoryT::segment_manager* manager = m_SHM->get_segment_manager(); return TreeT::NodePtrT(subNode, allocator(), TreeT::DeleterT(manager)); } template - typename TreeT::NodePtrT addNode( - TreeT *base, DecomposablePath& path, - const T &data, bool overwrite, unsigned int flags, - const VoidAllocatorT &allocator) + typename TreeT::NodePtrT addNode(TreeT* base, DecomposablePath& path, const T& data, + bool overwrite, unsigned int flags, + const VoidAllocatorT& allocator) { if (!path.peekNext()) { typename TreeT::NodePtrT newNode = base->node(path.current()); if (!newNode) { // last name component, should be the filename - TreeT *node = createSubNode(allocator, path.current(), flags, data); - newNode = createSubPtr(node); - newNode->m_Self = TreeT::WeakPtrT(newNode); + TreeT* node = createSubNode(allocator, path.current(), flags, data); + newNode = createSubPtr(node); + newNode->m_Self = TreeT::WeakPtrT(newNode); newNode->m_Parent = base->m_Self; base->set(StringT(path.current(), allocator), newNode); return newNode; } else if (overwrite) { - newNode->m_Data = createData(data, allocator); + newNode->m_Data = createData(data, allocator); newNode->m_Flags = static_cast(flags); return newNode; } else { @@ -307,58 +280,58 @@ private: if (subNode == base->m_Nodes.end()) { typename TreeT::NodePtrT newNode = createSubPtr(createSubNode( - allocator, path.current(), - FLAG_DIRECTORY | FLAG_DUMMY, createEmpty())); + allocator, path.current(), FLAG_DIRECTORY | FLAG_DUMMY, createEmpty())); - subNode = base->m_Nodes.emplace(StringT(path.current(), allocator), newNode).first; - subNode->second->m_Self = TreeT::WeakPtrT(subNode->second); + subNode = + base->m_Nodes.emplace(StringT(path.current(), allocator), newNode).first; + subNode->second->m_Self = TreeT::WeakPtrT(subNode->second); subNode->second->m_Parent = base->m_Self; } path.next(); - return addNode( - subNode->second.get().get(), path, - data, overwrite, flags, allocator); + return addNode(subNode->second.get().get(), path, data, overwrite, flags, + allocator); } } /** - * @brief copy content of one tree to a different tree (in a different shared memory segment - * @param destination - * @param reference - * @note at the time this is called, destination needs to refer to the shm of "destination" so that - * objects can be allocated in the new tree - */ - void copyTree(TreeT *destination, const TreeT *reference) + * @brief copy content of one tree to a different tree (in a different shared memory + * segment + * @param destination + * @param reference + * @note at the time this is called, destination needs to refer to the shm of + * "destination" so that objects can be allocated in the new tree + */ + void copyTree(TreeT* destination, const TreeT* reference) { VoidAllocatorT allocator = VoidAllocatorT(m_SHM->get_segment_manager()); - destination->m_Flags = reference->m_Flags; + destination->m_Flags = reference->m_Flags; dataAssign(destination->m_Data, reference->m_Data); destination->m_Name.assign(reference->m_Name.c_str()); - for (const auto &kv : reference->m_Nodes) { - TreeT *newNode = createSubNode(allocator, "", true, createEmpty()); + for (const auto& kv : reference->m_Nodes) { + TreeT* newNode = createSubNode(allocator, "", true, createEmpty()); typename TreeT::NodePtrT newNodePtr = createSubPtr(newNode); // need to set self BEFORE recursively copying the subtree, otherwise // how would we assign parent pointers? newNode->m_Self = newNodePtr; - TreeT *source = reinterpret_cast(kv.second.get().get()); + TreeT* source = reinterpret_cast(kv.second.get().get()); copyTree(newNode, source); destination->set(newNode->m_Name, newNodePtr); newNode->m_Parent = destination->m_Self; } } - int increaseRefCount(TreeMeta *treeMeta) + int increaseRefCount(TreeMeta* treeMeta) { bi::scoped_lock lock(treeMeta->mutex); return ++treeMeta->referenceCount; } - int decreaseRefCount(TreeMeta *treeMeta) + int decreaseRefCount(TreeMeta* treeMeta) { bi::scoped_lock lock(treeMeta->mutex); return --treeMeta->referenceCount; @@ -371,21 +344,20 @@ private: SharedMemoryT* newSHM = openSHM(SHMName); if (newSHM) { - spdlog::get("usvfs")->info( - "{} opened in process {}", SHMName, ::GetCurrentProcessId()); + spdlog::get("usvfs")->info("{} opened in process {}", SHMName, + ::GetCurrentProcessId()); } else { newSHM = createSHM(SHMName, size); if (newSHM) { - spdlog::get("usvfs")->info( - "{} created in process {}", SHMName, ::GetCurrentProcessId()); + spdlog::get("usvfs")->info("{} created in process {}", SHMName, + ::GetCurrentProcessId()); } } if (!newSHM) { - spdlog::get("usvfs")->error( - "failed to create or open {} in process {}", - SHMName, ::GetCurrentProcessId()); + spdlog::get("usvfs")->error("failed to create or open {} in process {}", SHMName, + ::GetCurrentProcessId()); throw std::exception("no shm instance"); } @@ -397,13 +369,10 @@ private: // SharedMemoryT* createSHM(const std::string& SHMName, size_t size) { - try - { - return new SharedMemoryT( - bi::create_only, SHMName.c_str(), static_cast(size)); - } - catch (const bi::interprocess_exception&) - { + try { + return new SharedMemoryT(bi::create_only, SHMName.c_str(), + static_cast(size)); + } catch (const bi::interprocess_exception&) { } return nullptr; @@ -413,12 +382,9 @@ private: // SharedMemoryT* openSHM(const std::string& SHMName) { - try - { + try { return new SharedMemoryT(bi::open_only, SHMName.c_str()); - } - catch (const bi::interprocess_exception&) - { + } catch (const bi::interprocess_exception&) { } return nullptr; @@ -430,8 +396,7 @@ private: // // see reassign() // - std::optional activateSHM( - SharedMemoryT *shm, const std::string& SHMName) + std::optional activateSHM(SharedMemoryT* shm, const std::string& SHMName) { std::shared_ptr oldSHM = m_SHM; @@ -439,7 +404,8 @@ private: std::pair res = m_SHM->find("Meta"); if (res.first == nullptr) { - res.first = m_SHM->construct("Meta")(createEmpty(), m_SHM->get_segment_manager()); + res.first = m_SHM->construct("Meta")(createEmpty(), + m_SHM->get_segment_manager()); if (res.first == nullptr) { USVFS_THROW_EXCEPTION(bi::bad_alloc()); } @@ -460,7 +426,7 @@ private: } m_TreeMeta = res.first; - m_SHMName = SHMName; + m_SHMName = SHMName; return deadSHMName; } @@ -479,7 +445,7 @@ private: return match[1].str() + std::to_string(count + 1); } - bool unassign(const std::shared_ptr &shm, TreeMeta *tree) + bool unassign(const std::shared_ptr& shm, TreeMeta* tree) { if (tree == nullptr) { return true; @@ -522,8 +488,8 @@ private: // another process has ran out of memory and started allocating blocks // with higher numbers - spdlog::get("usvfs")->info( - "tree {0} is outdated, looking for another one", m_SHMName); + spdlog::get("usvfs")->info("tree {0} is outdated, looking for another one", + m_SHMName); if (findNewerBlock(deadSHMNames)) { // the new block was found and activated @@ -533,7 +499,7 @@ private: // this block isn't outdated, so reassign() was called because a bad_alloc // exception was thrown spdlog::get("usvfs")->info( - "ran out of memory in tree {0}, will create another one", m_SHMName); + "ran out of memory in tree {0}, will create another one", m_SHMName); } // either the block is full or it's outdated, but no higher block was found; @@ -569,7 +535,7 @@ private: std::string nextName = m_SHMName; - for (int i=0; iinfo("{0} is also outdated", nextName); } else { // shm opened correctly, activated and not outdated, done - spdlog::get("usvfs")->info( - "{0} not outdated, taking it, size now {1}", - nextName, byte_string(m_SHM->get_size())); + spdlog::get("usvfs")->info("{0} not outdated, taking it, size now {1}", + nextName, byte_string(m_SHM->get_size())); return true; } @@ -617,7 +582,7 @@ private: // still run spdlog::get("usvfs")->error( - "found no existing tree above {0}, will create a new one", m_SHMName); + "found no existing tree above {0}, will create a new one", m_SHMName); return false; } @@ -657,9 +622,9 @@ private: deadSHMNames.push_back(*deadSHMName); } - spdlog::get("usvfs")->info( - "tree {0} size now {1}", m_SHMName, byte_string(m_SHM->get_size())); + spdlog::get("usvfs")->info("tree {0} size now {1}", m_SHMName, + byte_string(m_SHM->get_size())); } }; -} // namespace +} // namespace usvfs::shared diff --git a/src/shared/unicodestring.cpp b/src/shared/unicodestring.cpp index c2da0a2..f997e7f 100644 --- a/src/shared/unicodestring.cpp +++ b/src/shared/unicodestring.cpp @@ -19,9 +19,9 @@ You should have received a copy of the GNU General Public License along with usvfs. If not, see . */ #include "unicodestring.h" -#include "stringutils.h" -#include "stringcast.h" #include "logging.h" +#include "stringcast.h" +#include "stringutils.h" namespace usvfs { @@ -58,8 +58,7 @@ UnicodeString& UnicodeString::appendPath(PUNICODE_STRING path) if (appendAt) { m_Buffer.resize(m_Buffer.size() + path->Length / sizeof(WCHAR) + 1); m_Buffer[appendAt++] = L'\\'; - } - else + } else m_Buffer.resize(path->Length / sizeof(WCHAR) + 1); memcpy(&m_Buffer[appendAt], path->Buffer, path->Length); update(); @@ -70,9 +69,9 @@ UnicodeString& UnicodeString::appendPath(PUNICODE_STRING path) void UnicodeString::update() { - m_Data.Length = static_cast(size() * sizeof(WCHAR)); + m_Data.Length = static_cast(size() * sizeof(WCHAR)); m_Data.MaximumLength = static_cast((m_Buffer.capacity() - 1) * sizeof(WCHAR)); - m_Data.Buffer = m_Buffer.data(); + m_Data.Buffer = m_Buffer.data(); } -} \ No newline at end of file +} // namespace usvfs diff --git a/src/shared/unicodestring.h b/src/shared/unicodestring.h index 9b351ca..77071ad 100644 --- a/src/shared/unicodestring.h +++ b/src/shared/unicodestring.h @@ -20,8 +20,8 @@ along with usvfs. If not, see . */ #pragma once -#include "windows_sane.h" #include "ntdll_declarations.h" +#include "windows_sane.h" #include "formatters.h" @@ -34,20 +34,11 @@ namespace usvfs class UnicodeString { public: - UnicodeString() - : m_Buffer(1) - { - update(); - } + UnicodeString() : m_Buffer(1) { update(); } - UnicodeString(const UnicodeString& other) - : m_Buffer(other.m_Buffer) - { - update(); - } + UnicodeString(const UnicodeString& other) : m_Buffer(other.m_Buffer) { update(); } - UnicodeString(UnicodeString&& other) - : m_Buffer(std::move(other.m_Buffer)) + UnicodeString(UnicodeString&& other) : m_Buffer(std::move(other.m_Buffer)) { update(); } @@ -75,37 +66,24 @@ public: * @brief convert to a WinNt Api-style unicode string. This is only valid as long * as the string isn't modified */ - explicit operator PUNICODE_STRING() - { - return &m_Data; - } + explicit operator PUNICODE_STRING() { return &m_Data; } /** * @brief convert to a Win32 Api-style unicode string. This is only valid as long * as the string isn't modified */ - explicit operator LPCWSTR() const - { - return m_Data.Buffer; - } + explicit operator LPCWSTR() const { return m_Data.Buffer; } /** * @return length of the string in 16-bit words (not including zero termination) */ - size_t size() const - { - return m_Buffer.size() - 1; - } + size_t size() const { return m_Buffer.size() - 1; } - wchar_t operator[](size_t pos) const - { - return m_Buffer[pos]; - } + wchar_t operator[](size_t pos) const { return m_Buffer[pos]; } - UnicodeString &appendPath(PUNICODE_STRING path); + UnicodeString& appendPath(PUNICODE_STRING path); private: - friend struct ::std::formatter; void update(); @@ -114,18 +92,18 @@ private: std::vector m_Buffer; }; -} // namespace +} // namespace usvfs template <> -struct std::formatter : std::formatter +struct std::formatter + : std::formatter { template FmtContext::iterator format(const usvfs::UnicodeString& v, FmtContext& ctx) const { if (v.size() == 0) { return std::format_to(ctx.out(), ""); - } - else { + } else { return std::formatter::format(&v.m_Data, ctx); } } diff --git a/src/shared/wildcard.cpp b/src/shared/wildcard.cpp index 28b8147..a2efe6d 100644 --- a/src/shared/wildcard.cpp +++ b/src/shared/wildcard.cpp @@ -19,13 +19,13 @@ You should have received a copy of the GNU General Public License along with usvfs. If not, see . */ #include "wildcard.h" -#include "windows_sane.h" #include "logging.h" +#include "windows_sane.h" static bool IsInnerMatch(LPCWSTR pszString, LPCWSTR pszMatch) { while (*pszMatch != L'\0') { - if ((*pszMatch==L'?') || (*pszMatch==L'>')) { + if ((*pszMatch == L'?') || (*pszMatch == L'>')) { if (!*pszString) { // ? must match exactly one character return false; @@ -33,7 +33,7 @@ static bool IsInnerMatch(LPCWSTR pszString, LPCWSTR pszMatch) ++pszString; ++pszMatch; - } else if ((*pszMatch==L'*') || (*pszMatch==L'<')) { + } else if ((*pszMatch == L'*') || (*pszMatch == L'<')) { if (IsInnerMatch(pszString, pszMatch + 1)) { // * may match empty string or we may have matched something already return true; @@ -43,8 +43,8 @@ static bool IsInnerMatch(LPCWSTR pszString, LPCWSTR pszMatch) // the rest of the string can't be matched } else { - if (CharUpperW(MAKEINTRESOURCEW(MAKELONG(*pszString++, 0))) - !=CharUpperW(MAKEINTRESOURCEW(MAKELONG(*pszMatch++, 0)))) { + if (CharUpperW(MAKEINTRESOURCEW(MAKELONG(*pszString++, 0))) != + CharUpperW(MAKEINTRESOURCEW(MAKELONG(*pszMatch++, 0)))) { // regular chars compare return false; } @@ -89,11 +89,11 @@ static LPCSTR InnerMatch(LPCSTR pszString, LPCSTR pszMatch) // Because we eat one character from the match string, the // recursion will stop. { - LPCSTR remainder = InnerMatch(pszString, pszMatch + 1); - if (remainder != nullptr) { - // we have a match and the * replaces no other character - return remainder; - } + LPCSTR remainder = InnerMatch(pszString, pszMatch + 1); + if (remainder != nullptr) { + // we have a match and the * replaces no other character + return remainder; + } } // 2. Chance we eat the next character and try it again, with a @@ -112,8 +112,8 @@ static LPCSTR InnerMatch(LPCSTR pszString, LPCSTR pszMatch) // Standard compare of 2 chars. Note that *pszSring might be 0 // here, but then we never get a match on *pszMask that has always // a value while inside this loop. - if ( CharUpperA(MAKEINTRESOURCEA(MAKELONG(*pszString++, 0))) - != CharUpperA(MAKEINTRESOURCEA(MAKELONG(*pszMatch++, 0)))) + if (CharUpperA(MAKEINTRESOURCEA(MAKELONG(*pszString++, 0))) != + CharUpperA(MAKEINTRESOURCEA(MAKELONG(*pszMatch++, 0)))) return nullptr; } } @@ -129,7 +129,6 @@ static LPCSTR InnerMatch(LPCSTR pszString, LPCSTR pszMatch) } } - namespace usvfs::shared::wildcard { @@ -149,7 +148,6 @@ bool Match(LPCWSTR pszString, LPCWSTR pszMatch) } } - bool Match(LPCSTR pszString, LPCSTR pszMatch) { if (*pszString == '.') { @@ -177,14 +175,14 @@ LPCSTR PartialMatch(LPCSTR pszString, LPCSTR pszMatch) } else { size_t len = strlen(pszMatch); if ((len > 2) && (strcmp(pszMatch + len - 2, ".*") == 0)) { - // in cmd.exe there seems to be no difference between * and *.* + // in cmd.exe there seems to be no difference between * and + // *.* std::string temp(pszMatch, pszMatch + len - 2); LPCSTR pos = InnerMatch(pszString, temp.c_str()); if (pos != nullptr) { if (*pos == '\0') { return pszMatch + strlen(pszMatch); - } - else { + } else { return pszMatch + (pos - temp.c_str()); } } @@ -193,4 +191,4 @@ LPCSTR PartialMatch(LPCSTR pszString, LPCSTR pszMatch) } } -} // namespace +} // namespace usvfs::shared::wildcard diff --git a/src/shared/wildcard.h b/src/shared/wildcard.h index 8930d40..bf5b4a3 100644 --- a/src/shared/wildcard.h +++ b/src/shared/wildcard.h @@ -51,7 +51,6 @@ bool Match(LPCWSTR pszString, LPCWSTR pszMatch); */ bool Match(LPCSTR pszString, LPCSTR pszMatch); - /** * @brief match string to wildcard windows-style * @param pszString Input string to match @@ -65,4 +64,4 @@ bool Match(LPCSTR pszString, LPCSTR pszMatch); */ LPCSTR PartialMatch(LPCSTR pszString, LPCSTR pszMatch); -} // namespace +} // namespace usvfs::shared::wildcard diff --git a/src/shared/winapi.cpp b/src/shared/winapi.cpp index 693c35f..e28a13c 100644 --- a/src/shared/winapi.cpp +++ b/src/shared/winapi.cpp @@ -19,12 +19,12 @@ You should have received a copy of the GNU General Public License along with usvfs. If not, see . */ #include "winapi.h" -#include "stringutils.h" -#include "stringcast.h" +#include "exceptionex.h" #include "logging.h" #include "ntdll_declarations.h" +#include "stringcast.h" +#include "stringutils.h" #include "unicodestring.h" -#include "exceptionex.h" namespace winapi::ansi { @@ -53,7 +53,7 @@ std::pair getFullPathName(LPCSTR fileName) static const int INIT_SIZE = 128; std::string result; result.resize(INIT_SIZE); - LPSTR filePart = nullptr; + LPSTR filePart = nullptr; DWORD requiredSize = GetFullPathNameA(fileName, INIT_SIZE, &result[0], &filePart); if (requiredSize >= INIT_SIZE) { result.resize(requiredSize); @@ -61,14 +61,12 @@ std::pair getFullPathName(LPCSTR fileName) } if (requiredSize != 0UL) { return std::make_pair(result, std::string(filePart != nullptr ? filePart : "")); - } - else { + } else { return make_pair(result, std::string()); } } -} // namespace - +} // namespace winapi::ansi namespace winapi::wide { @@ -80,9 +78,11 @@ std::wstring getModuleFileName(HMODULE module, HANDLE process) DWORD rc = 0UL; while ((rc = (process == INVALID_HANDLE_VALUE) - ? ::GetModuleFileNameW(module, &result[0], static_cast(result.size())) - : ::GetModuleFileNameExW(process, module, &result[0], static_cast(result.size())) - ) == result.size()) { + ? ::GetModuleFileNameW(module, &result[0], + static_cast(result.size())) + : ::GetModuleFileNameExW(process, module, &result[0], + static_cast(result.size()))) == + result.size()) { result.resize(result.size() * 2); } @@ -107,23 +107,24 @@ std::pair getFullPathName(LPCWSTR fileName) { wchar_t buf1[MAX_PATH]; std::vector buf2; - wchar_t* result = buf1; - LPWSTR filePart = nullptr; + wchar_t* result = buf1; + LPWSTR filePart = nullptr; DWORD requiredSize = GetFullPathNameW(fileName, MAX_PATH, result, &filePart); if (requiredSize >= MAX_PATH) { buf2.resize(requiredSize); - result = &buf2[0]; + result = &buf2[0]; requiredSize = GetFullPathNameW(fileName, requiredSize, result, &filePart); } return make_pair(std::wstring(result, requiredSize), - std::wstring((requiredSize && filePart) ? filePart : L"")); + std::wstring((requiredSize && filePart) ? filePart : L"")); } std::wstring getCurrentDirectory() { // really great api this (::GetCurrentDirectoryW) // - if it succeeds, returns size in characters WITHOUT zero termination - // - if it fails due to buffer too small, returns size in characters WITH zero termination + // - if it fails due to buffer too small, returns size in characters WITH zero + // termination // - if it fails for other reasons, returns 0 std::wstring result; DWORD required = GetCurrentDirectoryW(0, nullptr); @@ -142,15 +143,14 @@ std::wstring getKnownFolderPath(REFKNOWNFOLDERID folderID) ::SHGetKnownFolderPath(folderID, 0, nullptr, &writablePath); - ON_BLOCK_EXIT([writablePath] () { + ON_BLOCK_EXIT([writablePath]() { ::CoTaskMemFree(writablePath); }); return std::wstring(writablePath); } -} // namespace - +} // namespace winapi::wide namespace winapi::ex { @@ -158,26 +158,29 @@ namespace winapi::ex std::pair getSectionRange(HANDLE moduleHandle) { std::pair result; - bool found = false; + bool found = false; uintptr_t exeModule = reinterpret_cast(moduleHandle); if (exeModule == 0) { throw std::runtime_error("failed to determine address range of executable"); } - std::pair totalRange{ UINT_MAX, 0 }; + std::pair totalRange{UINT_MAX, 0}; PIMAGE_DOS_HEADER dosHeader = reinterpret_cast(exeModule); - PIMAGE_NT_HEADERS ntHeader = reinterpret_cast(exeModule + dosHeader->e_lfanew); - PIMAGE_SECTION_HEADER sectionHeader = reinterpret_cast(ntHeader + 1); - for (int i = 0 ; i < ntHeader->FileHeader.NumberOfSections && !found; ++i) { + PIMAGE_NT_HEADERS ntHeader = + reinterpret_cast(exeModule + dosHeader->e_lfanew); + PIMAGE_SECTION_HEADER sectionHeader = + reinterpret_cast(ntHeader + 1); + for (int i = 0; i < ntHeader->FileHeader.NumberOfSections && !found; ++i) { if (memcmp(sectionHeader->Name, ".text", 5) == 0) { - result.first = exeModule + sectionHeader->VirtualAddress; + result.first = exeModule + sectionHeader->VirtualAddress; result.second = result.first + sectionHeader->Misc.VirtualSize; - found = true; + found = true; } else { - uintptr_t start = exeModule + sectionHeader->VirtualAddress; - totalRange.first = std::min(totalRange.first, start); - totalRange.second = std::max(totalRange.second, start + sectionHeader->Misc.VirtualSize); + uintptr_t start = exeModule + sectionHeader->VirtualAddress; + totalRange.first = std::min(totalRange.first, start); + totalRange.second = std::max(totalRange.second, + start + sectionHeader->Misc.VirtualSize); } ++sectionHeader; } @@ -197,17 +200,16 @@ OSVersion getOSVersion() RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo); OSVersion result; - result.major = versionInfo.dwMajorVersion; - result.minor = versionInfo.dwMinorVersion; - result.build = versionInfo.dwBuildNumber; + result.major = versionInfo.dwMajorVersion; + result.minor = versionInfo.dwMinorVersion; + result.build = versionInfo.dwBuildNumber; result.platformid = versionInfo.dwPlatformId; - result.servicpack = versionInfo.wServicePackMajor << 16 - | versionInfo.wServicePackMinor; + result.servicpack = + versionInfo.wServicePackMajor << 16 | versionInfo.wServicePackMinor; return result; } -} // namespace - +} // namespace winapi::ex namespace winapi::ex::ansi { @@ -220,45 +222,42 @@ std::string errorString(DWORD errorCode) DWORD currentErrorCode = GetLastError(); - errorCode = errorCode != std::numeric_limits::max() ? errorCode - : currentErrorCode; + errorCode = + errorCode != std::numeric_limits::max() ? errorCode : currentErrorCode; // TODO: the message is not english? - if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM - , nullptr - , errorCode - , 0 //, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) - , (LPSTR)&buffer - , 0 - , nullptr) == 0) { + if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + nullptr, errorCode, + 0 //, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) + , + (LPSTR)&buffer, 0, nullptr) == 0) { finalMessage << "(unknown error [" << errorCode << "])"; } else { if (buffer != nullptr) { size_t end = strlen(buffer) - 1; - while ((buffer[end] == '\n') - || (buffer[end] == '\r')) { + while ((buffer[end] == '\n') || (buffer[end] == '\r')) { buffer[end--] = '\0'; } finalMessage << "(" << buffer << " [" << errorCode << "])"; - LocalFree(buffer); // allocated by FormatMessage + LocalFree(buffer); // allocated by FormatMessage } } - SetLastError(currentErrorCode); // restore error code because FormatMessage might have modified it + SetLastError(currentErrorCode); // restore error code because FormatMessage might + // have modified it return finalMessage.str(); } -std::string toString(const FILETIME &time) +std::string toString(const FILETIME& time) { SYSTEMTIME temp; FileTimeToSystemTime(&time, &temp); std::ostringstream stream; - stream << temp.wYear << "-" << temp.wMonth << "-" << temp.wDay - << temp.wHour << ":" << temp.wMinute << ":" << temp.wSecond; + stream << temp.wYear << "-" << temp.wMonth << "-" << temp.wDay << temp.wHour << ":" + << temp.wMinute << ":" << temp.wSecond; return stream.str(); } - LPCSTR GetBaseName(LPCSTR string) { LPCSTR result = string + strlen(string) - 1; @@ -273,13 +272,12 @@ LPCSTR GetBaseName(LPCSTR string) return result; } -} // namespace - +} // namespace winapi::ex::ansi namespace winapi::ex::wide { -bool fileExists(LPCWSTR fileName, bool *isDirectory) +bool fileExists(LPCWSTR fileName, bool* isDirectory) { DWORD attrib = GetFileAttributesW(fileName); @@ -301,41 +299,39 @@ std::wstring errorString(DWORD errorCode) DWORD currentErrorCode = GetLastError(); - errorCode = errorCode != std::numeric_limits::max() ? errorCode - : currentErrorCode; + errorCode = + errorCode != std::numeric_limits::max() ? errorCode : currentErrorCode; // TODO: the message is not english? - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM - , nullptr - , errorCode - , 0 //, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) - , (LPWSTR)&buffer - , 0 - , nullptr) == 0) { + if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + nullptr, errorCode, + 0 //, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) + , + (LPWSTR)&buffer, 0, nullptr) == 0) { finalMessage << L"(unknown error [" << errorCode << "])"; } else { if (buffer != nullptr) { size_t end = wcslen(buffer) - 1; - while ((buffer[end] == L'\n') - || (buffer[end] == L'\r')) { + while ((buffer[end] == L'\n') || (buffer[end] == L'\r')) { buffer[end--] = L'\0'; } finalMessage << L"(" << buffer << L" [" << errorCode << L"])"; - LocalFree(buffer); // allocated by FormatMessage + LocalFree(buffer); // allocated by FormatMessage } } - SetLastError(currentErrorCode); // restore error code because FormatMessage might have modified it + SetLastError(currentErrorCode); // restore error code because FormatMessage might + // have modified it return finalMessage.str(); } -std::wstring toString(const FILETIME &time) +std::wstring toString(const FILETIME& time) { SYSTEMTIME temp; FileTimeToSystemTime(&time, &temp); std::wostringstream stream; - stream << temp.wYear << "-" << temp.wMonth << "-" << temp.wDay - << temp.wHour << ":" << temp.wMinute << ":" << temp.wSecond; + stream << temp.wYear << "-" << temp.wMonth << "-" << temp.wDay << temp.wHour << ":" + << temp.wMinute << ":" << temp.wSecond; return stream.str(); } @@ -394,48 +390,40 @@ std::vector quickFindFiles(LPCWSTR directoryName, LPCWSTR pattern) static const unsigned int BUFFER_SIZE = 1024; - HANDLE hdl = CreateFileW(directoryName - , GENERIC_READ - , FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE - , nullptr - , OPEN_EXISTING - , FILE_FLAG_BACKUP_SEMANTICS - , nullptr); + HANDLE hdl = CreateFileW(directoryName, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - ON_BLOCK_EXIT([hdl] () { + ON_BLOCK_EXIT([hdl]() { CloseHandle(hdl); }); uint8_t buffer[BUFFER_SIZE]; - NTSTATUS res = STATUS_SUCCESS; // status success + NTSTATUS res = STATUS_SUCCESS; // status success while (res == STATUS_SUCCESS) { IO_STATUS_BLOCK status; - res = NtQueryDirectoryFile(hdl - , nullptr - , nullptr - , nullptr - , &status - , buffer - , BUFFER_SIZE - , FileFullDirectoryInformation - , FALSE - , static_cast(usvfs::UnicodeString(pattern)) - , FALSE); + res = NtQueryDirectoryFile( + hdl, nullptr, nullptr, nullptr, &status, buffer, BUFFER_SIZE, + FileFullDirectoryInformation, FALSE, + static_cast(usvfs::UnicodeString(pattern)), FALSE); if (res == STATUS_SUCCESS) { - FILE_FULL_DIR_INFORMATION *info = reinterpret_cast(buffer); - void *endPos = buffer + status.Information; + FILE_FULL_DIR_INFORMATION* info = + reinterpret_cast(buffer); + void* endPos = buffer + status.Information; while (info < endPos) { FileResult file; - file.fileName = std::wstring(info->FileName, info->FileNameLength / sizeof(wchar_t)); + file.fileName = + std::wstring(info->FileName, info->FileNameLength / sizeof(wchar_t)); file.attributes = info->FileAttributes; result.push_back(file); if (info->NextEntryOffset == 0) { break; } else { - info = reinterpret_cast(reinterpret_cast(info) + info->NextEntryOffset); + info = reinterpret_cast( + reinterpret_cast(info) + info->NextEntryOffset); } } } @@ -448,26 +436,33 @@ bool createPath(boost::filesystem::path path, LPSECURITY_ATTRIBUTES securityAttr { // sanity and guaranteed recursion end: if (!path.has_relative_path()) - throw usvfs::shared::windows_error("createPath() refusing to create non-existing top level path: " + path.string()); + throw usvfs::shared::windows_error( + "createPath() refusing to create non-existing top level path: " + + path.string()); DWORD attr = GetFileAttributesW(path.c_str()); - DWORD err = GetLastError(); + DWORD err = GetLastError(); if (attr != INVALID_FILE_ATTRIBUTES) { if (attr & FILE_ATTRIBUTE_DIRECTORY) - return false; // if directory already exists all is good + return false; // if directory already exists all is good else - throw usvfs::shared::windows_error("createPath() called on a file: " + path.string()); + throw usvfs::shared::windows_error("createPath() called on a file: " + + path.string()); } if (err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND) - throw usvfs::shared::windows_error("createPath() GetFileAttributesW failed on: " + path.string(), err); + throw usvfs::shared::windows_error( + "createPath() GetFileAttributesW failed on: " + path.string(), err); - if (err != ERROR_FILE_NOT_FOUND) // ERROR_FILE_NOT_FOUND means parent directory already exists - createPath(path.parent_path(), securityAttributes); // otherwise create parent directory (recursively) + if (err != ERROR_FILE_NOT_FOUND) // ERROR_FILE_NOT_FOUND means parent directory + // already exists + createPath(path.parent_path(), + securityAttributes); // otherwise create parent directory (recursively) BOOL res = CreateDirectoryW(path.c_str(), securityAttributes); if (!res) { err = GetLastError(); - throw usvfs::shared::windows_error("createPath() CreateDirectoryW failed on: " + path.string(), err); + throw usvfs::shared::windows_error( + "createPath() CreateDirectoryW failed on: " + path.string(), err); } return true; } @@ -475,12 +470,15 @@ bool createPath(boost::filesystem::path path, LPSECURITY_ATTRIBUTES securityAttr std::wstring getWindowsBuildLab(bool ex) { HKEY hKey = nullptr; - auto res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", 0, KEY_READ, &hKey); + auto res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", 0, + KEY_READ, &hKey); if (res != ERROR_SUCCESS || !hKey) return L"Opening HKLM Windows NT\\CurrentVersion failed?!"; WCHAR buf[200]; DWORD size = static_cast(sizeof(buf)); - res = RegQueryValueExW(hKey, ex ? L"BuildLabEx" : L"BuildLab", NULL, NULL, reinterpret_cast(buf), &size); + res = RegQueryValueExW(hKey, ex ? L"BuildLabEx" : L"BuildLab", NULL, NULL, + reinterpret_cast(buf), &size); if (res != ERROR_SUCCESS || size > sizeof(buf)) return ex ? L"BuildLabEx reg value not found?!" : L"BuildLab reg value not found?!"; size /= sizeof(buf[0]); @@ -489,4 +487,4 @@ std::wstring getWindowsBuildLab(bool ex) return std::wstring(buf, size); } -} // namespace +} // namespace winapi::ex::wide diff --git a/src/shared/winapi.h b/src/shared/winapi.h index 29ebcf8..f94eff6 100644 --- a/src/shared/winapi.h +++ b/src/shared/winapi.h @@ -20,32 +20,35 @@ along with usvfs. If not, see . */ #pragma once -#include "windows_sane.h" -#include #include "logging.h" #include "stringcast.h" +#include "windows_sane.h" +#include -#define ALIAS(alias, original) template \ - auto alias(Args&&... args) -> decltype(original(std::forward(args)...)) {\ - return original(std::forward(args)...);\ - } - -#define ALIAST(alias, original) template \ - auto alias(Args&&... args) -> decltype(original(std::forward(args)...)) {\ - return original(std::forward(args)...);\ - } +#define ALIAS(alias, original) \ + template \ + auto alias(Args&&... args) -> decltype(original(std::forward(args)...)) \ + { \ + return original(std::forward(args)...); \ + } +#define ALIAST(alias, original) \ + template \ + auto alias(Args && ... args) \ + -> decltype(original(std::forward(args)...)) \ + { \ + return original(std::forward(args)...); \ + } namespace winapi { struct parameter_error : public std::runtime_error { - parameter_error(const std::string &msg) : runtime_error(msg) {} + parameter_error(const std::string& msg) : runtime_error(msg) {} }; -} // namespace - +} // namespace winapi namespace winapi::process { @@ -62,7 +65,7 @@ struct Result startupInfo.cb = sizeof(STARTUPINFO); } - Result(Result &&reference) + Result(Result&& reference) : valid(reference.valid), startupInfo(reference.startupInfo), processInfo(reference.processInfo), errorCode(reference.errorCode) { @@ -81,15 +84,15 @@ struct Result } } - Result(const Result &) = delete; + Result(const Result&) = delete; - size_t readStdout(std::vector &buffer, bool &eof) + size_t readStdout(std::vector& buffer, bool& eof) { if (stdoutPipe != INVALID_HANDLE_VALUE) { DWORD read; - BOOL res = ReadFile(stdoutPipe, &buffer[0], - static_cast(buffer.size()), &read, nullptr); - eof = (res == TRUE) && (read == 0); + BOOL res = ReadFile(stdoutPipe, &buffer[0], static_cast(buffer.size()), + &read, nullptr); + eof = (res == TRUE) && (read == 0); return static_cast(read); } else { eof = true; @@ -105,18 +108,18 @@ struct Result HANDLE stdoutPipe{INVALID_HANDLE_VALUE}; }; - /** * @brief internal class to handle process creation with named parameters. */ -template class _Create +template +class _Create { public: - _Create(const std::basic_string &binaryName); - _Create(const _Create &reference) = delete; - _Create &operator=(const _Create &reference) = delete; + _Create(const std::basic_string& binaryName); + _Create(const _Create& reference) = delete; + _Create& operator=(const _Create& reference) = delete; - _Create(_Create &&reference) + _Create(_Create&& reference) : m_CurrentDirectory(std::move(reference.m_CurrentDirectory)), m_ProcessAttributes(reference.m_ProcessAttributes), m_ThreadAttributes(reference.m_ThreadAttributes), @@ -131,18 +134,21 @@ public: /// named parameter "argument". May be called repeatedly. This is /// directly appended to the command line with a separating space. No /// quoting happens - template _Create &argument(const ArgT &argin) + template + _Create& argument(const ArgT& argin) { m_CommandLine << " " << argin; return *this; } - template _Create &arg(const ArgT &argin) + template + _Create& arg(const ArgT& argin) { return this->argument(argin); } - template _Create &arguments(IterT begin, IterT end) + template + _Create& arguments(IterT begin, IterT end) { for (; begin != end; ++begin) { m_CommandLine << " " << *begin; @@ -152,23 +158,23 @@ public: } /// @brief set the working directory for the process - _Create &workingDirectory(const std::basic_string &path); + _Create& workingDirectory(const std::basic_string& path); /// @brief set process attributes - _Create &processAttributes(SECURITY_ATTRIBUTES *attributes); + _Create& processAttributes(SECURITY_ATTRIBUTES* attributes); /// @brief set thread attributes - _Create &threadAttributes(SECURITY_ATTRIBUTES *attributes); + _Create& threadAttributes(SECURITY_ATTRIBUTES* attributes); /// @brief activate inheriting handles - _Create &inheritHandles(); + _Create& inheritHandles(); /// @brief have the process start suspended - _Create &suspended(); + _Create& suspended(); /// @brief set the process up to output stout to a pipe which can be /// retrieved through the result object - _Create &stdoutPipe(); + _Create& stdoutPipe(); /// @brief end the named parameter cascade and create the process Result operator()() @@ -187,10 +193,9 @@ public: result.valid = createProcessInt(nullptr, clBuffer.get(), m_ProcessAttributes, - m_ThreadAttributes, m_InheritHandles, m_CreationFlags, - nullptr, m_CurrentDirectory.length() > 0 - ? m_CurrentDirectory.c_str() - : nullptr, + m_ThreadAttributes, m_InheritHandles, m_CreationFlags, nullptr, + m_CurrentDirectory.length() > 0 ? m_CurrentDirectory.c_str() + : nullptr, &result.startupInfo, &result.processInfo) == TRUE; if (m_Stdout != INVALID_HANDLE_VALUE) { @@ -208,22 +213,22 @@ public: private: static BOOL createProcessInt(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, - SECURITY_ATTRIBUTES *lpProcessAttributes, - SECURITY_ATTRIBUTES *lpThreadAttributes, + SECURITY_ATTRIBUTES* lpProcessAttributes, + SECURITY_ATTRIBUTES* lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { - return ::CreateProcessW( - lpApplicationName, lpCommandLine, lpProcessAttributes, - lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, - lpCurrentDirectory, lpStartupInfo, lpProcessInformation); + return ::CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, + lpThreadAttributes, bInheritHandles, dwCreationFlags, + lpEnvironment, lpCurrentDirectory, lpStartupInfo, + lpProcessInformation); } static BOOL createProcessInt(LPCSTR lpApplicationName, LPSTR lpCommandLine, - SECURITY_ATTRIBUTES *lpProcessAttributes, - SECURITY_ATTRIBUTES *lpThreadAttributes, + SECURITY_ATTRIBUTES* lpProcessAttributes, + SECURITY_ATTRIBUTES* lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, @@ -244,19 +249,19 @@ private: cwd = usvfs::shared::string_cast(lpCurrentDirectory); } - return ::CreateProcessW( - lpApplicationName != nullptr ? executable.c_str() : nullptr, - lpCommandLine != nullptr ? &cmdline[0] : nullptr, lpProcessAttributes, - lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, - lpCurrentDirectory != nullptr ? cwd.c_str() : nullptr, lpStartupInfo, - lpProcessInformation); + return ::CreateProcessW(lpApplicationName != nullptr ? executable.c_str() : nullptr, + lpCommandLine != nullptr ? &cmdline[0] : nullptr, + lpProcessAttributes, lpThreadAttributes, bInheritHandles, + dwCreationFlags, lpEnvironment, + lpCurrentDirectory != nullptr ? cwd.c_str() : nullptr, + lpStartupInfo, lpProcessInformation); } - HANDLE setupPipe(HANDLE &childHandle) + HANDLE setupPipe(HANDLE& childHandle) { SECURITY_ATTRIBUTES attr; - attr.nLength = sizeof(SECURITY_ATTRIBUTES); - attr.bInheritHandle = TRUE; + attr.nLength = sizeof(SECURITY_ATTRIBUTES); + attr.bInheritHandle = TRUE; attr.lpSecurityDescriptor = nullptr; HANDLE pipe[2]; @@ -272,8 +277,8 @@ private: private: std::basic_stringstream m_CommandLine; std::basic_string m_CurrentDirectory{}; - SECURITY_ATTRIBUTES *m_ProcessAttributes{nullptr}; - SECURITY_ATTRIBUTES *m_ThreadAttributes{nullptr}; + SECURITY_ATTRIBUTES* m_ProcessAttributes{nullptr}; + SECURITY_ATTRIBUTES* m_ThreadAttributes{nullptr}; BOOL m_InheritHandles{false}; DWORD m_CreationFlags{0UL}; bool m_Executed{false}; @@ -282,8 +287,7 @@ private: HANDLE m_Stdout{INVALID_HANDLE_VALUE}; }; -} // namespace - +} // namespace winapi::process namespace winapi::file { @@ -291,45 +295,43 @@ namespace winapi::file * @brief internal class to handle file creation (opening) with named * parameters. */ -template class _Create +template +class _Create { public: - _Create(const std::basic_string &fileName) - : m_FileName(fileName) - { - } + _Create(const std::basic_string& fileName) : m_FileName(fileName) {} - _Create &access(DWORD desiredAccess) + _Create& access(DWORD desiredAccess) { m_DesiredAccess = desiredAccess; return *this; } - _Create &share(DWORD shareMode) + _Create& share(DWORD shareMode) { m_ShareMode = shareMode; return *this; } - _Create &createAlways() + _Create& createAlways() { m_CreationDisposition = CREATE_ALWAYS; return *this; } - _Create &openAlways() + _Create& openAlways() { m_CreationDisposition = OPEN_ALWAYS; return *this; } - _Create &security(SECURITY_ATTRIBUTES *attributes) + _Create& security(SECURITY_ATTRIBUTES* attributes) { m_SecurityAttributes = attributes; return *this; } - _Create &templateFile(HANDLE templateFile) + _Create& templateFile(HANDLE templateFile) { m_Template = templateFile; return *this; @@ -364,11 +366,10 @@ private: DWORD m_CreationDisposition{DefaultDisposition}; DWORD m_Flags{FILE_ATTRIBUTE_NORMAL}; HANDLE m_Template{nullptr}; - SECURITY_ATTRIBUTES *m_SecurityAttributes{nullptr}; + SECURITY_ATTRIBUTES* m_SecurityAttributes{nullptr}; }; -} // namespace - +} // namespace winapi::file namespace winapi::ansi { @@ -380,8 +381,7 @@ typedef process::_Create createProcess; typedef file::_Create createFile; typedef file::_Create openFile; -} // namespace - +} // namespace winapi::ansi namespace winapi::wide { @@ -395,8 +395,7 @@ typedef process::_Create createProcess; typedef file::_Create createFile; typedef file::_Create openFile; -} // namespace - +} // namespace winapi::wide /** * useful convenience functions close to the api @@ -405,16 +404,17 @@ namespace winapi::ex { /** - * @brief retrieve the address range covering the code section of a module - * @param moduleHandle handle to the module - * @return start and end address of the code section - * @note the code section can only be identified if it has the standardized section name ".text" - * Otherwise the whole address range of all sections in the module is returned. - * This happens for compressed exectuables for example - */ + * @brief retrieve the address range covering the code section of a module + * @param moduleHandle handle to the module + * @return start and end address of the code section + * @note the code section can only be identified if it has the standardized section name + * ".text" Otherwise the whole address range of all sections in the module is returned. + * This happens for compressed exectuables for example + */ std::pair getSectionRange(HANDLE moduleHandle); -struct OSVersion { +struct OSVersion +{ DWORD major; DWORD minor; DWORD build; @@ -424,137 +424,140 @@ struct OSVersion { OSVersion getOSVersion(); -} // namespace - +} // namespace winapi::ex namespace winapi::ex::ansi { /** - * @brief retrieve an error string for a windows error message - * @param errorCode the error code to look up. If this is left at the default, ::GetLastError is used - * @return string representation of the error. Currently this is localized - */ + * @brief retrieve an error string for a windows error message + * @param errorCode the error code to look up. If this is left at the default, + * ::GetLastError is used + * @return string representation of the error. Currently this is localized + */ std::string errorString(DWORD errorCode = std::numeric_limits::max()); /** - * @brief convert filetime to string - * @param time time to convert - * @return a string representation (currently only supports utc and iso format with second precision) - */ -std::string toString(const FILETIME &time); + * @brief convert filetime to string + * @param time time to convert + * @return a string representation (currently only supports utc and iso format with + * second precision) + */ +std::string toString(const FILETIME& time); /** - * @brief find file name in a windows file path - * @param path the path to search in - * @return the file name of the path or an empty string if the path ends on - * a slash - * @note this function doesn't access the file system so it doesn't depend - * on whether the file actually exists. This also means it can't - * determine if a path that doesn't end on a slash refers to a file or - * directory - * @note the return value is a pointer into the same buffer, no copy is - * created - */ + * @brief find file name in a windows file path + * @param path the path to search in + * @return the file name of the path or an empty string if the path ends on + * a slash + * @note this function doesn't access the file system so it doesn't depend + * on whether the file actually exists. This also means it can't + * determine if a path that doesn't end on a slash refers to a file or + * directory + * @note the return value is a pointer into the same buffer, no copy is + * created + */ LPCSTR GetBaseName(LPCSTR string); -} // namespace - +} // namespace winapi::ex::ansi namespace winapi::ex::wide { /** - * retrieve the name of the binary section containing the specified address - * @param address the address to test - * @param process the process for which to retrieve the section. If this is - * nullptr, the current process is analized. - * @return name of the section or "unknown" if no matching section was found - */ + * retrieve the name of the binary section containing the specified address + * @param address the address to test + * @param process the process for which to retrieve the section. If this is + * nullptr, the current process is analized. + * @return name of the section or "unknown" if no matching section was found + */ std::wstring getSectionName(PVOID address, HANDLE process = nullptr); /** - * @brief test if a file exists - * @param path path to check - * @param isDirectory (optional) if this isn't null, it will be set to true if the path specifies a directory, false otherwise - * @return true if the file (or directory) exists. - */ -bool fileExists(LPCWSTR fileName, bool *isDirectory = nullptr); + * @brief test if a file exists + * @param path path to check + * @param isDirectory (optional) if this isn't null, it will be set to true if the path + * specifies a directory, false otherwise + * @return true if the file (or directory) exists. + */ +bool fileExists(LPCWSTR fileName, bool* isDirectory = nullptr); /** - * @brief retrieve an error string for a windows error message - * @param errorCode the error code to look up. If this is left at the default, ::GetLastError is used - * @return string representation of the error. Currently this is localized - */ + * @brief retrieve an error string for a windows error message + * @param errorCode the error code to look up. If this is left at the default, + * ::GetLastError is used + * @return string representation of the error. Currently this is localized + */ std::wstring errorString(DWORD errorCode = std::numeric_limits::max()); /** - * @brief convert filetime to string - * @param time time to convert - * @return a string representation (currently only supports utc and iso format with second precision) - */ -std::wstring toString(const FILETIME &time); + * @brief convert filetime to string + * @param time time to convert + * @return a string representation (currently only supports utc and iso format with + * second precision) + */ +std::wstring toString(const FILETIME& time); /** - * @brief find file name in a windows file path - * @param path the path to search in - * @return the file name of the path or an empty string if the path ends on - * a slash - * @note this function doesn't access the file system so it doesn't depend - * on whether the file actually exists. This also means it can't - * determine if a path that doesn't end on a slash refers to a file or - * directory - * @note the return value is a pointer into the same buffer, no copy is - * created - */ + * @brief find file name in a windows file path + * @param path the path to search in + * @return the file name of the path or an empty string if the path ends on + * a slash + * @note this function doesn't access the file system so it doesn't depend + * on whether the file actually exists. This also means it can't + * determine if a path that doesn't end on a slash refers to a file or + * directory + * @note the return value is a pointer into the same buffer, no copy is + * created + */ LPCWSTR GetBaseName(LPCWSTR path); /** - * @see const-variant of this function - */ + * @see const-variant of this function + */ LPWSTR GetBaseName(LPWSTR path); -struct FileResult { +struct FileResult +{ std::wstring fileName; ULONG attributes; }; /** - * @brief a quick function to find all files in a directory or files following a pattern. This uses - * NtQueryDirectoryFile api internally so it should be faster than the usual FindFirstFile/FindNextFile pattern - * @param directoryName name of the directory to search in - * @param pattern name pattern that needs to match - * @return the list of files found - */ + * @brief a quick function to find all files in a directory or files following a + * pattern. This uses NtQueryDirectoryFile api internally so it should be faster than + * the usual FindFirstFile/FindNextFile pattern + * @param directoryName name of the directory to search in + * @param pattern name pattern that needs to match + * @return the list of files found + */ std::vector quickFindFiles(LPCWSTR directoryName, LPCWSTR pattern); /** - * @brief create the specified directory including all intermediate - * directories - * @param path the path to create - * @param securityAttributes the security attributes to use for all created - * directories. if this is null (default), the standard attributes - * are used - * @return true if the directory (and possibly parent directories) were actually created - * and false if the directory already existed. Throws exceptions on failure. - */ + * @brief create the specified directory including all intermediate + * directories + * @param path the path to create + * @param securityAttributes the security attributes to use for all created + * directories. if this is null (default), the standard attributes + * are used + * @return true if the directory (and possibly parent directories) were actually created + * and false if the directory already existed. Throws exceptions on failure. + */ bool createPath(boost::filesystem::path path, LPSECURITY_ATTRIBUTES securityAttributes = nullptr); -inline bool createPath(LPCWSTR path, - LPSECURITY_ATTRIBUTES securityAttributes = nullptr) +inline bool createPath(LPCWSTR path, LPSECURITY_ATTRIBUTES securityAttributes = nullptr) { return createPath(boost::filesystem::path(path), securityAttributes); } std::wstring getWindowsBuildLab(bool ex = false); -} // namespace - +} // namespace winapi::ex::wide namespace winapi::process { template -_Create::_Create(const std::basic_string &binaryName) +_Create::_Create(const std::basic_string& binaryName) { if (binaryName.length() > MAX_PATH) { throw parameter_error("executable filename can't be longer than 260 characters"); @@ -563,39 +566,45 @@ _Create::_Create(const std::basic_string &binaryName) } template -_Create &_Create::workingDirectory(const std::basic_string &path) { +_Create& _Create::workingDirectory(const std::basic_string& path) +{ m_CurrentDirectory = path; return *this; } template -_Create &_Create::processAttributes(SECURITY_ATTRIBUTES *attributes) { +_Create& _Create::processAttributes(SECURITY_ATTRIBUTES* attributes) +{ m_ProcessAttributes = attributes; return *this; } template -_Create &_Create::threadAttributes(SECURITY_ATTRIBUTES *attributes) { +_Create& _Create::threadAttributes(SECURITY_ATTRIBUTES* attributes) +{ m_ThreadAttributes = attributes; return *this; } template -_Create &_Create::inheritHandles() { +_Create& _Create::inheritHandles() +{ m_InheritHandles = true; return *this; } template -_Create &_Create::suspended() { +_Create& _Create::suspended() +{ m_CreationFlags |= CREATE_SUSPENDED; return *this; } template -_Create &_Create::stdoutPipe() { +_Create& _Create::stdoutPipe() +{ m_StdoutPipe = true; return *this; } -} // namespace +} // namespace winapi::process diff --git a/src/shared/windows_sane.h b/src/shared/windows_sane.h index d49bf5d..7bb3726 100644 --- a/src/shared/windows_sane.h +++ b/src/shared/windows_sane.h @@ -20,9 +20,8 @@ along with usvfs. If not, see . */ #pragma once - #ifndef NOMINMAX - #define NOMINMAX +#define NOMINMAX #endif #define WIN32_LEAN_AND_MEAN diff --git a/src/thooklib/asmjit_sane.h b/src/thooklib/asmjit_sane.h index 23f637d..365622a 100644 --- a/src/thooklib/asmjit_sane.h +++ b/src/thooklib/asmjit_sane.h @@ -20,10 +20,10 @@ along with usvfs. If not, see . */ #pragma once -#pragma warning (push) +#pragma warning(push) #pragma warning(disable : 4201) #pragma warning(disable : 4244) #pragma warning(disable : 4245) #include #include -#pragma warning (pop) +#pragma warning(pop) diff --git a/src/thooklib/hooklib.cpp b/src/thooklib/hooklib.cpp index b76d92d..9dbbafa 100644 --- a/src/thooklib/hooklib.cpp +++ b/src/thooklib/hooklib.cpp @@ -18,24 +18,24 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with usvfs. If not, see . */ -#include -#include -#include #include "udis86wrapper.h" -#pragma warning (push, 3) +#include +#include +#include +#pragma warning(push, 3) #include -#pragma warning (pop) +#pragma warning(pop) #include "hooklib.h" -#include "utility.h" #include "ttrampolinepool.h" -#include +#include "utility.h" #include -#include #include +#include +#include #if BOOST_ARCH_X86_64 #pragma message("64bit build") -#define JUMP_SIZE 13 +#define JUMP_SIZE 13 #elif BOOST_ARCH_X86_32 #define JUMP_SIZE 5 #else @@ -45,35 +45,40 @@ along with usvfs. If not, see . using namespace asmjit; // from here on out I'll only test for 64 or "other" - using namespace HookLib; using namespace asmjit; using namespace usvfs; -struct THookInfo { +struct THookInfo +{ LPVOID originalFunction; LPVOID replacementFunction; - LPVOID detour; // detour to call the original function after hook was installed. - LPVOID trampoline; // code fragment that decides whether the replacement function or detour is executed (preventing endless loops) - std::vector preamble; // part of the detour that needs to be re-inserted into the original function to return it to vanilla state - bool stub; // if this is true, the trampoline calls the "replacement"-function that before the original function, not instead of it - enum { - TYPE_HOTPATCH, // official hot-patch variant as used on 32-bit windows - TYPE_WIN64PATCH, // custom patch variant used on 64-bit windows - TYPE_CHAINPATCH, // the hook is part of the hook chain (and not the first) - TYPE_OVERWRITE, // full jump overwrite used if none of the above work - TYPE_RIPINDIRECT // the function already started on a rip-relative jump so we only modified that variable + LPVOID detour; // detour to call the original function after hook was installed. + LPVOID trampoline; // code fragment that decides whether the replacement function or + // detour is executed (preventing endless loops) + std::vector + preamble; // part of the detour that needs to be re-inserted into the original + // function to return it to vanilla state + bool stub; // if this is true, the trampoline calls the "replacement"-function that + // before the original function, not instead of it + enum + { + TYPE_HOTPATCH, // official hot-patch variant as used on 32-bit windows + TYPE_WIN64PATCH, // custom patch variant used on 64-bit windows + TYPE_CHAINPATCH, // the hook is part of the hook chain (and not the first) + TYPE_OVERWRITE, // full jump overwrite used if none of the above work + TYPE_RIPINDIRECT // the function already started on a rip-relative jump so we only + // modified that variable } type; }; - -UDis86Wrapper &disasm() { +UDis86Wrapper& disasm() +{ static UDis86Wrapper instance; return instance; } - void PauseOtherThreads() { // TODO: implement me! @@ -84,7 +89,6 @@ void ResumePausedThreads() // TODO: implement me! should resume only the threads paused by PauseOtherThreads } - // not using the disassembler because this is simpler LPBYTE ShortJumpTarget(LPBYTE address) { @@ -92,7 +96,6 @@ LPBYTE ShortJumpTarget(LPBYTE address) return address + 2 + off; } - size_t GetJumpSize(LPBYTE, LPVOID) { // TODO: it would be neater to use asmjit to generate this jump and ask asmjit for @@ -110,29 +113,29 @@ void WriteLongJump(LPBYTE jumpAddr, LPVOID destination) // a working, space-optimized, relative jump to outside the generated code and // we do want to optimize this jump #if BOOST_ARCH_X86_64 - intptr_t dist = reinterpret_cast(destination) - (reinterpret_cast(jumpAddr) + 5); + intptr_t dist = reinterpret_cast(destination) - + (reinterpret_cast(jumpAddr) + 5); int32_t distShort = static_cast(dist); #else - int32_t distShort = reinterpret_cast(destination) - (reinterpret_cast(jumpAddr) + 5); + int32_t distShort = reinterpret_cast(destination) - + (reinterpret_cast(jumpAddr) + 5); #endif - *jumpAddr = 0xE9; + *jumpAddr = 0xE9; *reinterpret_cast(jumpAddr + 1) = distShort; } - - -void WriteSingleJump(THookInfo &hookInfo, HookError *error) +void WriteSingleJump(THookInfo& hookInfo, HookError* error) { DWORD oldprotect, ignore; - // Set the target function to copy on write, so we don't modify code for other processes - if (!VirtualProtect(hookInfo.originalFunction, - JUMP_SIZE, - PAGE_EXECUTE_WRITECOPY, - &oldprotect)) { + // Set the target function to copy on write, so we don't modify code for other + // processes + if (!VirtualProtect(hookInfo.originalFunction, JUMP_SIZE, PAGE_EXECUTE_WRITECOPY, + &oldprotect)) { throw std::runtime_error("failed to change virtual protection"); } - WriteLongJump(reinterpret_cast(hookInfo.originalFunction), hookInfo.trampoline); + WriteLongJump(reinterpret_cast(hookInfo.originalFunction), + hookInfo.trampoline); // restore old memory protection if (!VirtualProtect(hookInfo.originalFunction, JUMP_SIZE, oldprotect, &ignore)) { @@ -144,17 +147,16 @@ void WriteSingleJump(THookInfo &hookInfo, HookError *error) } } - void WriteShortJump(LPBYTE jumpAddr, const signed char offset) { *jumpAddr = 0xEB; *(jumpAddr + 1) = offset; } -void WriteIndirectJump(THookInfo &hookInfo, size_t jumpSize, HookError *error) +void WriteIndirectJump(THookInfo& hookInfo, size_t jumpSize, HookError* error) { DWORD oldProtect = 0; - LPBYTE jumpAddr = reinterpret_cast(hookInfo.originalFunction) - jumpSize; + LPBYTE jumpAddr = reinterpret_cast(hookInfo.originalFunction) - jumpSize; // allow write to jump address + the short jump inside the function if (!VirtualProtect(jumpAddr, jumpSize + 2, PAGE_EXECUTE_WRITECOPY, &oldProtect)) { throw std::runtime_error("failed to change virtual protection"); @@ -177,7 +179,6 @@ void WriteIndirectJump(THookInfo &hookInfo, size_t jumpSize, HookError *error) } } - /// implements function hooking using the mechanism intended for hot patching /// Explanation: the visual studio compiler offers an option to prepare functions /// for hot patching. In this case the compiler leaves room for one far jump before @@ -191,18 +192,20 @@ void WriteIndirectJump(THookInfo &hookInfo, size_t jumpSize, HookError *error) /// but they don't have the 2-byte nop so this function doesn't work /// \param hookInfo info about the hook to be installed /// \return true on success, false on error -BOOL HookHotPatch(THookInfo &hookInfo, HookError *error) +BOOL HookHotPatch(THookInfo& hookInfo, HookError* error) { LPVOID original = reinterpret_cast(hookInfo.originalFunction); if (hookInfo.stub) { - hookInfo.trampoline = TrampolinePool::instance().storeStub(hookInfo.replacementFunction, - reinterpret_cast(hookInfo.originalFunction), - shared::AddrAdd(original, 2)); + hookInfo.trampoline = TrampolinePool::instance().storeStub( + hookInfo.replacementFunction, + reinterpret_cast(hookInfo.originalFunction), + shared::AddrAdd(original, 2)); } else { - hookInfo.trampoline = TrampolinePool::instance().storeTrampoline(hookInfo.replacementFunction, - reinterpret_cast(hookInfo.originalFunction), - shared::AddrAdd(original, 2)); + hookInfo.trampoline = TrampolinePool::instance().storeTrampoline( + hookInfo.replacementFunction, + reinterpret_cast(hookInfo.originalFunction), + shared::AddrAdd(original, 2)); } WriteIndirectJump(hookInfo, JUMP_SIZE, error); @@ -213,10 +216,9 @@ BOOL HookHotPatch(THookInfo &hookInfo, HookError *error) return TRUE; } - -uintptr_t followJumps(THookInfo &hookInfo) +uintptr_t followJumps(THookInfo& hookInfo) { - LPBYTE original = reinterpret_cast(hookInfo.originalFunction); + LPBYTE original = reinterpret_cast(hookInfo.originalFunction); LPBYTE shortTarget = ShortJumpTarget(original); // disassemble the long jump @@ -234,18 +236,19 @@ uintptr_t followJumps(THookInfo &hookInfo) return static_cast(res); } - /// -/// \brief hook a call that is implemented as a short-jump to a long jump using a rip-relative address variable +/// \brief hook a call that is implemented as a short-jump to a long jump using a +/// rip-relative address variable /// \param hookInfo info about the hook to be installed -/// \param error if the return code is false and this is not null, the referred-to variable is set to an error code +/// \param error if the return code is false and this is not null, the referred-to +/// variable is set to an error code /// \return true on success, false on error /// -BOOL HookRIPIndirection(THookInfo &hookInfo, HookError *error) +BOOL HookRIPIndirection(THookInfo& hookInfo, HookError* error) { uintptr_t res = followJumps(hookInfo); - const ud_operand_t *op = ud_insn_opr(disasm(), 0); + const ud_operand_t* op = ud_insn_opr(disasm(), 0); if (op->base != UD_R_RIP) { throw std::runtime_error("expected rip-relative addressing"); @@ -253,17 +256,20 @@ BOOL HookRIPIndirection(THookInfo &hookInfo, HookError *error) auto chainNext = disasm().jumpTarget(); if (hookInfo.stub) { - hookInfo.trampoline = TrampolinePool::instance().storeStub(hookInfo.replacementFunction - , reinterpret_cast(hookInfo.originalFunction) - , reinterpret_cast(chainNext)); + hookInfo.trampoline = TrampolinePool::instance().storeStub( + hookInfo.replacementFunction, + reinterpret_cast(hookInfo.originalFunction), + reinterpret_cast(chainNext)); } else { - hookInfo.trampoline = TrampolinePool::instance().storeTrampoline(hookInfo.replacementFunction - , reinterpret_cast(hookInfo.originalFunction) - , reinterpret_cast(chainNext)); + hookInfo.trampoline = TrampolinePool::instance().storeTrampoline( + hookInfo.replacementFunction, + reinterpret_cast(hookInfo.originalFunction), + reinterpret_cast(chainNext)); } DWORD oldProtect = 0; - if (!VirtualProtect(reinterpret_cast(res), 2, PAGE_EXECUTE_WRITECOPY, &oldProtect)) { + if (!VirtualProtect(reinterpret_cast(res), 2, PAGE_EXECUTE_WRITECOPY, + &oldProtect)) { throw std::runtime_error("failed to change virtual protection"); } @@ -273,7 +279,7 @@ BOOL HookRIPIndirection(THookInfo &hookInfo, HookError *error) throw std::runtime_error("failed to change virtual protection"); } - hookInfo.type = THookInfo::TYPE_RIPINDIRECT; + hookInfo.type = THookInfo::TYPE_RIPINDIRECT; hookInfo.detour = reinterpret_cast(chainNext); if (error != nullptr) { @@ -283,7 +289,7 @@ BOOL HookRIPIndirection(THookInfo &hookInfo, HookError *error) return TRUE; } -BOOL HookChainHook(THookInfo &hookInfo, LPBYTE jumpPos, HookError *error) +BOOL HookChainHook(THookInfo& hookInfo, LPBYTE jumpPos, HookError* error) { // disassemble the long jump disasm().setInputBuffer(jumpPos, JUMP_SIZE); @@ -298,25 +304,24 @@ BOOL HookChainHook(THookInfo &hookInfo, LPBYTE jumpPos, HookError *error) size_t size = ud_insn_len(disasm()); - // save the original code for the preamble so we can restore it later + // save the original code for the preamble so we can restore it later hookInfo.preamble.resize(size); memcpy(&hookInfo.preamble[0], jumpPos, size); - spdlog::get("usvfs") - ->info("existing hook to {0:x} in {1}", chainTarget, - shared::string_cast( - winapi::ex::wide::getSectionName((void *)chainTarget))); + spdlog::get("usvfs")->info("existing hook to {0:x} in {1}", chainTarget, + shared::string_cast( + winapi::ex::wide::getSectionName((void*)chainTarget))); if (hookInfo.stub) { hookInfo.trampoline = TrampolinePool::instance().storeStub( - hookInfo.replacementFunction - , reinterpret_cast(hookInfo.originalFunction) - , reinterpret_cast(chainTarget)); + hookInfo.replacementFunction, + reinterpret_cast(hookInfo.originalFunction), + reinterpret_cast(chainTarget)); } else { hookInfo.trampoline = TrampolinePool::instance().storeTrampoline( - hookInfo.replacementFunction - , reinterpret_cast(hookInfo.originalFunction) - , reinterpret_cast(chainTarget)); + hookInfo.replacementFunction, + reinterpret_cast(hookInfo.originalFunction), + reinterpret_cast(chainTarget)); } DWORD oldProtect = 0; @@ -330,7 +335,7 @@ BOOL HookChainHook(THookInfo &hookInfo, LPBYTE jumpPos, HookError *error) throw std::runtime_error("failed to change virtual protection"); } - hookInfo.type = THookInfo::TYPE_CHAINPATCH; + hookInfo.type = THookInfo::TYPE_CHAINPATCH; hookInfo.detour = reinterpret_cast(chainTarget); if (error != nullptr) { @@ -347,11 +352,10 @@ BOOL HookChainHook(THookInfo &hookInfo, LPBYTE jumpPos, HookError *error) /// the referred-to variable is set to an error code /// \return true on success, false on error /// -BOOL HookChainHook(THookInfo &hookInfo, HookError *error) +BOOL HookChainHook(THookInfo& hookInfo, HookError* error) { - return HookChainHook(hookInfo - , reinterpret_cast(hookInfo.originalFunction) - , error); + return HookChainHook(hookInfo, reinterpret_cast(hookInfo.originalFunction), + error); } /// @@ -361,9 +365,9 @@ BOOL HookChainHook(THookInfo &hookInfo, HookError *error) /// the referred-to variable is set to an error code /// \return true on success, false on error /// -BOOL HookChainPatch(THookInfo &hookInfo, HookError *error) +BOOL HookChainPatch(THookInfo& hookInfo, HookError* error) { - LPBYTE original = reinterpret_cast(hookInfo.originalFunction); + LPBYTE original = reinterpret_cast(hookInfo.originalFunction); LPBYTE shortTarget = ShortJumpTarget(original); return HookChainHook(hookInfo, shortTarget, error); @@ -375,15 +379,17 @@ BOOL HookChainPatch(THookInfo &hookInfo, HookError *error) /// and that code needs to be called via a detour. This is a lot more complex than /// the hotpatch mechanism. /// \param hookInfo info about the hook to be installed -/// \param error if the return code is false and this is not null, the referred-to variable is set to an error code +/// \param error if the return code is false and this is not null, the referred-to +/// variable is set to an error code /// \return true on success, false on error -BOOL HookDisasm(THookInfo &hookInfo, HookError *error) +BOOL HookDisasm(THookInfo& hookInfo, HookError* error) { LPBYTE address = reinterpret_cast(hookInfo.originalFunction); ud_set_input_buffer(disasm(), address, 40); - size_t jumpSize = GetJumpSize(static_cast(hookInfo.originalFunction), - TrampolinePool::instance().currentBufferAddress(hookInfo.originalFunction)); + size_t jumpSize = GetJumpSize( + static_cast(hookInfo.originalFunction), + TrampolinePool::instance().currentBufferAddress(hookInfo.originalFunction)); // test if we have room for a jump before the function bool jumpspace = true; @@ -425,16 +431,15 @@ BOOL HookDisasm(THookInfo &hookInfo, HookError *error) // check the operands for relative addressing (not supported) for (int i = 0; i < 3; ++i) { - const ud_operand *op = ud_insn_opr(disasm(), i); + const ud_operand* op = ud_insn_opr(disasm(), i); if (op) { if ( - // rip-relative are not handled, usually relative jumps - op->base == UD_R_RIP + // rip-relative are not handled, usually relative jumps + op->base == UD_R_RIP - // rsp-relative call are not handled (there are valid rsp-relative - // instructions, e.g. sub) - || (ud_insn_mnemonic(disasm()) == UD_Icall && op->base == UD_R_RSP) - ) { + // rsp-relative call are not handled (there are valid rsp-relative + // instructions, e.g. sub) + || (ud_insn_mnemonic(disasm()) == UD_Icall && op->base == UD_R_RSP)) { if (error != nullptr) { *error = ERR_RIP; } @@ -450,17 +455,11 @@ BOOL HookDisasm(THookInfo &hookInfo, HookError *error) size_t rerouteOffset = 0; if (hookInfo.stub) { - hookInfo.trampoline = - TrampolinePool::instance().storeStub(hookInfo.replacementFunction - , hookInfo.originalFunction - , size - , &rerouteOffset); + hookInfo.trampoline = TrampolinePool::instance().storeStub( + hookInfo.replacementFunction, hookInfo.originalFunction, size, &rerouteOffset); } else { - hookInfo.trampoline = - TrampolinePool::instance().storeTrampoline(hookInfo.replacementFunction - , hookInfo.originalFunction - , size - , &rerouteOffset); + hookInfo.trampoline = TrampolinePool::instance().storeTrampoline( + hookInfo.replacementFunction, hookInfo.originalFunction, size, &rerouteOffset); } if (jumpspace) { @@ -470,14 +469,13 @@ BOOL HookDisasm(THookInfo &hookInfo, HookError *error) WriteSingleJump(hookInfo, error); hookInfo.type = THookInfo::TYPE_OVERWRITE; } - hookInfo.detour = reinterpret_cast(hookInfo.trampoline) - + rerouteOffset; + hookInfo.detour = reinterpret_cast(hookInfo.trampoline) + rerouteOffset; return TRUE; } - -enum EPreamble { +enum EPreamble +{ PRE_PATCHFREE, PRE_PATCHUSED, PRE_RIPINDIRECT, @@ -485,19 +483,17 @@ enum EPreamble { PRE_UNKNOWN }; - EPreamble DeterminePreamble(LPBYTE address) { ud_set_input_buffer(disasm(), address, JUMP_SIZE); ud_disassemble(disasm()); - if ((ud_insn_mnemonic(disasm()) == UD_Imov) - && (ud_insn_opr(disasm(), 0) == ud_insn_opr(disasm(), 1)) - && (ud_insn_opr(disasm(), 0)->type == UD_OP_REG)) { + if ((ud_insn_mnemonic(disasm()) == UD_Imov) && + (ud_insn_opr(disasm(), 0) == ud_insn_opr(disasm(), 1)) && + (ud_insn_opr(disasm(), 0)->type == UD_OP_REG)) { // mov edi, edi return PRE_PATCHFREE; - } else if ((ud_insn_mnemonic(disasm()) == UD_Ijmp) - && (ud_insn_len(disasm()) == 2)) { + } else if ((ud_insn_mnemonic(disasm()) == UD_Ijmp) && (ud_insn_len(disasm()) == 2)) { // determine target of the short jump LPBYTE shortTarget = ShortJumpTarget(address); @@ -505,7 +501,7 @@ EPreamble DeterminePreamble(LPBYTE address) ud_set_input_buffer(disasm(), shortTarget, JUMP_SIZE); ud_disassemble(disasm()); if (ud_insn_mnemonic(disasm()) == UD_Ijmp) { - const ud_operand *op = ud_insn_opr(disasm(), 0); + const ud_operand* op = ud_insn_opr(disasm(), 0); if (op->base == UD_R_RIP) { return PRE_RIPINDIRECT; } else { @@ -529,91 +525,92 @@ static HOOKHANDLE GenerateHandle() return NextHandle++; } - -HOOKHANDLE applyHook(THookInfo info, HookError *error) +HOOKHANDLE applyHook(THookInfo info, HookError* error) { // apply the correct hook function depending on how the function start looks EPreamble preamble = DeterminePreamble((LPBYTE)info.originalFunction); BOOL success = FALSE; switch (preamble) { - case PRE_PATCHUSED: { - success = HookChainPatch(info, error); - } break; - case PRE_PATCHFREE: { - success = HookHotPatch(info, error); - } break; - case PRE_RIPINDIRECT: { - success = HookRIPIndirection(info, error); - } break; - case PRE_FOREIGNHOOK: { - success = HookChainHook(info, error); - } break; - default: { - success = HookDisasm(info, error); - } break; + case PRE_PATCHUSED: { + success = HookChainPatch(info, error); + } break; + case PRE_PATCHFREE: { + success = HookHotPatch(info, error); + } break; + case PRE_RIPINDIRECT: { + success = HookRIPIndirection(info, error); + } break; + case PRE_FOREIGNHOOK: { + success = HookChainHook(info, error); + } break; + default: { + success = HookDisasm(info, error); + } break; } if (success == TRUE) { HOOKHANDLE handle = GenerateHandle(); - s_Hooks[handle] = info; + s_Hooks[handle] = info; return handle; } else { return INVALID_HOOK; } } -HOOKHANDLE HookLib::InstallStub(LPVOID functionAddress, LPVOID stubAddress, HookError *error) +HOOKHANDLE HookLib::InstallStub(LPVOID functionAddress, LPVOID stubAddress, + HookError* error) { if (functionAddress == nullptr) { - if (error != nullptr) *error = ERR_INVALIDPARAMETERS; + if (error != nullptr) + *error = ERR_INVALIDPARAMETERS; return INVALID_HOOK; } THookInfo info; - info.originalFunction = functionAddress; + info.originalFunction = functionAddress; info.replacementFunction = stubAddress; - info.stub = true; - info.detour = nullptr; - info.trampoline = nullptr; - info.type = THookInfo::TYPE_OVERWRITE; + info.stub = true; + info.detour = nullptr; + info.trampoline = nullptr; + info.type = THookInfo::TYPE_OVERWRITE; return applyHook(info, error); } - -HOOKHANDLE HookLib::InstallStub(HMODULE module, LPCSTR functionName, LPVOID stubAddress, HookError *error) +HOOKHANDLE HookLib::InstallStub(HMODULE module, LPCSTR functionName, LPVOID stubAddress, + HookError* error) { LPVOID funcAddr = MyGetProcAddress(module, functionName); return InstallStub(funcAddr, stubAddress, error); } - -HOOKHANDLE HookLib::InstallHook(LPVOID functionAddress, LPVOID hookAddress, HookError *error) +HOOKHANDLE HookLib::InstallHook(LPVOID functionAddress, LPVOID hookAddress, + HookError* error) { if (functionAddress == nullptr) { - if (error != nullptr) *error = ERR_INVALIDPARAMETERS; + if (error != nullptr) + *error = ERR_INVALIDPARAMETERS; return INVALID_HOOK; } THookInfo info; - info.originalFunction = functionAddress; + info.originalFunction = functionAddress; info.replacementFunction = hookAddress; - info.stub = false; - info.detour = nullptr; - info.trampoline = nullptr; - info.type = THookInfo::TYPE_OVERWRITE; + info.stub = false; + info.detour = nullptr; + info.trampoline = nullptr; + info.type = THookInfo::TYPE_OVERWRITE; return applyHook(info, error); } - -HOOKHANDLE HookLib::InstallHook(HMODULE module, LPCSTR functionName, LPVOID hookAddress, HookError *error) +HOOKHANDLE HookLib::InstallHook(HMODULE module, LPCSTR functionName, LPVOID hookAddress, + HookError* error) { LPVOID funcAddr = MyGetProcAddress(module, functionName); return InstallHook(funcAddr, hookAddress, error); } - void HookLib::RemoveHook(HOOKHANDLE handle) { auto iter = s_Hooks.find(handle); @@ -629,13 +626,14 @@ void HookLib::RemoveHook(HOOKHANDLE handle) if (!VirtualProtect(address, 2, PAGE_EXECUTE_WRITECOPY, &oldProtect)) { throw shared::windows_error("failed to gain write access to remove hook"); } - *address = 0x8b; + *address = 0x8b; *(address + 1) = 0xff; VirtualProtect(address, 2, oldProtect, &oldProtect); } else if ((info.type == THookInfo::TYPE_OVERWRITE) || (info.type == THookInfo::TYPE_WIN64PATCH)) { DWORD oldProtect = 0; - if (!VirtualProtect(address, info.preamble.size(), PAGE_EXECUTE_WRITECOPY, &oldProtect)) { + if (!VirtualProtect(address, info.preamble.size(), PAGE_EXECUTE_WRITECOPY, + &oldProtect)) { throw shared::windows_error("failed to gain write access to remove hook"); } // TODO: remove hook by restoring the original function. This only works if we @@ -646,8 +644,7 @@ void HookLib::RemoveHook(HOOKHANDLE handle) // we could attempt to restore the original function preamble but I'm not // sure we can reliably write the jump with same (or lower) size. // Instead overwrite our own trampoline - disasm().setInputBuffer(static_cast(info.originalFunction), - JUMP_SIZE); + disasm().setInputBuffer(static_cast(info.originalFunction), JUMP_SIZE); ud_disassemble(disasm()); if (ud_insn_mnemonic(disasm()) != UD_Ijmp) { // this shouldn't happen, we only call this if the jump was discovered before @@ -660,19 +657,21 @@ void HookLib::RemoveHook(HOOKHANDLE handle) } DWORD oldProtect = 0; - if (!VirtualProtect(jumpPos, info.preamble.size(), - PAGE_EXECUTE_WRITECOPY, &oldProtect)) { + if (!VirtualProtect(jumpPos, info.preamble.size(), PAGE_EXECUTE_WRITECOPY, + &oldProtect)) { throw shared::windows_error("failed to gain write access to remove hook"); } memcpy(jumpPos, info.preamble.data(), info.preamble.size()); VirtualProtect(jumpPos, info.preamble.size(), oldProtect, &oldProtect); } else if (info.type == THookInfo::TYPE_RIPINDIRECT) { - uintptr_t res = followJumps(info); + uintptr_t res = followJumps(info); DWORD oldProtect = 0; - if (!VirtualProtect(reinterpret_cast(res), JUMP_SIZE, PAGE_EXECUTE_WRITECOPY, &oldProtect)) { + if (!VirtualProtect(reinterpret_cast(res), JUMP_SIZE, + PAGE_EXECUTE_WRITECOPY, &oldProtect)) { throw shared::windows_error("failed to gain write access to remove hook"); } - *reinterpret_cast(res) = reinterpret_cast(info.originalFunction); + *reinterpret_cast(res) = + reinterpret_cast(info.originalFunction); VirtualProtect(reinterpret_cast(res), JUMP_SIZE, oldProtect, &oldProtect); } else { spdlog::get("usvfs")->critical("can't remove hook, unknown hook type!"); @@ -685,42 +684,51 @@ void HookLib::RemoveHook(HOOKHANDLE handle) } } - -const char *HookLib::GetErrorString(HookError err) +const char* HookLib::GetErrorString(HookError err) { switch (err) { - case ERR_NONE: return "No Error"; - case ERR_INVALIDPARAMETERS: return "Invalid parameters"; - case ERR_FUNCEND: return "Function too short"; - case ERR_JUMP: return "Function starts on a jump"; - case ERR_RIP: return "RIP-relative addressing can't be relocated."; - case ERR_RELJUMP: return "Relative Jump can't be relocated."; - default: return "Unkown error code"; + case ERR_NONE: + return "No Error"; + case ERR_INVALIDPARAMETERS: + return "Invalid parameters"; + case ERR_FUNCEND: + return "Function too short"; + case ERR_JUMP: + return "Function starts on a jump"; + case ERR_RIP: + return "RIP-relative addressing can't be relocated."; + case ERR_RELJUMP: + return "Relative Jump can't be relocated."; + default: + return "Unkown error code"; } } - -const char *HookLib::GetHookType(HOOKHANDLE handle) +const char* HookLib::GetHookType(HOOKHANDLE handle) { auto iter = s_Hooks.find(handle); if (iter != s_Hooks.end()) { THookInfo info = iter->second; switch (info.type) { - case THookInfo::TYPE_HOTPATCH: return "hot patch"; - case THookInfo::TYPE_WIN64PATCH: return "64-bit hot patch"; - case THookInfo::TYPE_CHAINPATCH: return "chained patch"; - case THookInfo::TYPE_OVERWRITE: return "overwrite"; - case THookInfo::TYPE_RIPINDIRECT: return "rip indirection modified"; - default: { - spdlog::get("usvfs")->error("invalid hook type {0}", info.type); - return "invalid hook type"; - } + case THookInfo::TYPE_HOTPATCH: + return "hot patch"; + case THookInfo::TYPE_WIN64PATCH: + return "64-bit hot patch"; + case THookInfo::TYPE_CHAINPATCH: + return "chained patch"; + case THookInfo::TYPE_OVERWRITE: + return "overwrite"; + case THookInfo::TYPE_RIPINDIRECT: + return "rip indirection modified"; + default: { + spdlog::get("usvfs")->error("invalid hook type {0}", info.type); + return "invalid hook type"; + } } } return "invalid handle"; } - LPVOID HookLib::GetDetour(HOOKHANDLE handle) { auto iter = s_Hooks.find(handle); diff --git a/src/thooklib/hooklib.h b/src/thooklib/hooklib.h index b50c5fe..a549c03 100644 --- a/src/thooklib/hooklib.h +++ b/src/thooklib/hooklib.h @@ -20,18 +20,23 @@ along with usvfs. If not, see . */ #pragma once -#include #include +#include -namespace HookLib { +namespace HookLib +{ -enum HookError { +enum HookError +{ ERR_NONE, - ERR_INVALIDPARAMETERS, // parameters are invalid - ERR_FUNCEND, // function is too short to be hooked - ERR_JUMP, // function consists only of an unconditional jump. Maybe it has already been hooked? - ERR_RIP, // segment of the function to be overwritten contains a instruction-relative operation - ERR_RELJUMP // segment of the function to be overwritten contains a relative jump we can't relocated + ERR_INVALIDPARAMETERS, // parameters are invalid + ERR_FUNCEND, // function is too short to be hooked + ERR_JUMP, // function consists only of an unconditional jump. Maybe it has already + // been hooked? + ERR_RIP, // segment of the function to be overwritten contains a instruction-relative + // operation + ERR_RELJUMP // segment of the function to be overwritten contains a relative jump we + // can't relocated }; typedef ULONG HOOKHANDLE; @@ -40,41 +45,55 @@ static const HOOKHANDLE INVALID_HOOK = (HOOKHANDLE)-1; /// /// \brief install a stub (function to be called before the target function) /// \param functionAddress address of the function to stub -/// \param stubAddress address of the stub function. This function has to have the signature of void foobar(LPVOID address). +/// \param stubAddress address of the stub function. This function has to have the +/// signature of void foobar(LPVOID address). /// address receives the address of the function. -/// \param error (optional) if set, the referenced variable will receive an error code describing the problem (if any) +/// \param error (optional) if set, the referenced variable will receive an error code +/// describing the problem (if any) /// \return a handle to reference the hook in later operations or INVALID_HOOK on error /// -HOOKHANDLE InstallStub(LPVOID functionAddress, LPVOID stubAddress, HookError *error = nullptr); +HOOKHANDLE InstallStub(LPVOID functionAddress, LPVOID stubAddress, + HookError* error = nullptr); /// /// \brief install a stub (function to be called before the target function) /// \param module the module containing the function to hook /// \param functionName name of the function to stub (as exported by the library) -/// \param stubAddress address of the stub function. This function has to have the signature of void foobar(LPVOID address). +/// \param stubAddress address of the stub function. This function has to have the +/// signature of void foobar(LPVOID address). /// address receives the address of the function. -/// \param error (optional) if set, the referenced variable will receive an error code describing the problem (if any) +/// \param error (optional) if set, the referenced variable will receive an error code +/// describing the problem (if any) /// \return a handle to reference the hook in later operations or INVALID_HOOK on error /// -HOOKHANDLE InstallStub(HMODULE module, LPCSTR functionName, LPVOID stubAddress, HookError *error = nullptr); +HOOKHANDLE InstallStub(HMODULE module, LPCSTR functionName, LPVOID stubAddress, + HookError* error = nullptr); /// -/// \brief install a hook (function replacing the existing functionality of the function) +/// \brief install a hook (function replacing the existing functionality of the +/// function) /// \param functionAddress address of the function to hook -/// \param hookAddress address of the replacement function. This function has to have the exact same signature as the replaced function -/// \param error (optional) if set, the referenced variable will receive an error code describing the problem (if any) +/// \param hookAddress address of the replacement function. This function has to have +/// the exact same signature as the replaced function +/// \param error (optional) if set, the referenced variable will receive an error code +/// describing the problem (if any) /// \return a handle to reference the hook in later operations or INVALID_HOOK on error /// -HOOKHANDLE InstallHook(LPVOID functionAddress, LPVOID hookAddress, HookError *error = nullptr); +HOOKHANDLE InstallHook(LPVOID functionAddress, LPVOID hookAddress, + HookError* error = nullptr); /// -/// \brief install a hook (function replacing the existing functionality of the function) +/// \brief install a hook (function replacing the existing functionality of the +/// function) /// \param functionName name of the function to hook (as exported by the library) -/// \param hookAddress address of the replacement function. This function has to have the exact same signature as the replaced function -/// \param error (optional) if set, the referenced variable will receive an error code describing the problem (if any) +/// \param hookAddress address of the replacement function. This function has to have +/// the exact same signature as the replaced function +/// \param error (optional) if set, the referenced variable will receive an error code +/// describing the problem (if any) /// \return a handle to reference the hook in later operations or INVALID_HOOK on error /// -HOOKHANDLE InstallHook(HMODULE module, LPCSTR functionName, LPVOID hookAddress, HookError *error = nullptr); +HOOKHANDLE InstallHook(HMODULE module, LPCSTR functionName, LPVOID hookAddress, + HookError* error = nullptr); /// /// \brief remove a hook @@ -87,7 +106,7 @@ void RemoveHook(HOOKHANDLE handle); /// \param handle the handle to look up /// \return a string describing the used hooking mechanism /// -const char *GetHookType(HOOKHANDLE handle); +const char* GetHookType(HOOKHANDLE handle); /// /// \brief retrieve the address that can be used to directly call a detour @@ -101,6 +120,6 @@ LPVOID GetDetour(HOOKHANDLE handle); /// \param err the error code to resolve /// \return the error string /// -const char *GetErrorString(HookError err); +const char* GetErrorString(HookError err); -} +} // namespace HookLib diff --git a/src/thooklib/ttrampolinepool.cpp b/src/thooklib/ttrampolinepool.cpp index c77a466..3b6a51f 100644 --- a/src/thooklib/ttrampolinepool.cpp +++ b/src/thooklib/ttrampolinepool.cpp @@ -21,10 +21,9 @@ along with usvfs. If not, see . #include "ttrampolinepool.h" #include #include -//#include +// #include #include "udis86wrapper.h" - using namespace asmjit; #if BOOST_ARCH_X86_64 using namespace x86; @@ -34,15 +33,12 @@ using namespace asmjit::x86; using namespace usvfs::shared; +namespace HookLib +{ -namespace HookLib { +TrampolinePool* TrampolinePool::s_Instance = nullptr; - -TrampolinePool *TrampolinePool::s_Instance = nullptr; - - -TrampolinePool::TrampolinePool() - : m_MaxTrampolineSize(sizeof(LPVOID)) +TrampolinePool::TrampolinePool() : m_MaxTrampolineSize(sizeof(LPVOID)) { m_BarrierAddr = &TrampolinePool::barrier; m_ReleaseAddr = &TrampolinePool::release; @@ -56,21 +52,22 @@ TrampolinePool::TrampolinePool() // => all jumps between xxxxxxxxxx000000 and xxxxxxxxxxffffff will use the same buffer // for trampolines which is guaranteed to be in that range // TODO it should be valid to use 2 ^ 32 as the search range to increase our chances - // of finding a memory block we can reserve but then there is a problem with converting - // negative jump distances to 32 bit I didn't understand. - // Everything up to 2 ^ 31 seems to be fine though + // of finding a memory block we can reserve but then there is a problem with + // converting negative jump distances to 32 bit I didn't understand. Everything + // up to 2 ^ 31 seems to be fine though m_SearchRange = static_cast(pow(2, 30)) - 1; m_AddressMask = std::numeric_limits::max() - m_SearchRange; } -//static +// static void TrampolinePool::initialize() { if (!s_Instance) s_Instance = new TrampolinePool(); } -void TrampolinePool::setBlock(bool block) { +void TrampolinePool::setBlock(bool block) +{ m_FullBlock = block; if (m_ThreadGuards.get() == nullptr) { m_ThreadGuards.reset(new TThreadMap()); @@ -79,7 +76,7 @@ void TrampolinePool::setBlock(bool block) { #if BOOST_ARCH_X86_64 // push all registers (except rax) and flags to the stack -static void pushAll(X86Assembler &assembler) +static void pushAll(X86Assembler& assembler) { assembler.pushf(); assembler.push(rcx); @@ -99,7 +96,7 @@ static void pushAll(X86Assembler &assembler) } // pop all registers (except rax) and flags from stack -static void popAll(X86Assembler &assembler) +static void popAll(X86Assembler& assembler) { assembler.pop(r15); assembler.pop(r14); @@ -117,34 +114,37 @@ static void popAll(X86Assembler &assembler) assembler.pop(rcx); assembler.popf(); } -#endif // BOOST_ARCH_X86_64 +#endif // BOOST_ARCH_X86_64 - -void TrampolinePool::addBarrier(LPVOID rerouteAddr, LPVOID original, X86Assembler &assembler) +void TrampolinePool::addBarrier(LPVOID rerouteAddr, LPVOID original, + X86Assembler& assembler) { Label skipLabel = assembler.newLabel(); #if BOOST_ARCH_X86_64 pushAll(assembler); - assembler.mov(rcx, imm(reinterpret_cast(original))); // set call parameter for call to barrier function + assembler.mov(rcx, + imm(reinterpret_cast( + original))); // set call parameter for call to barrier function assembler.mov(rax, imm((intptr_t)(void*)barrier)); assembler.sub(rsp, 32); assembler.call(rax); assembler.add(rsp, 32); popAll(assembler); // test barrier - assembler.cmp(rax, 0); // test if the barrier is locked - assembler.jz(skipLabel); // skip if barrier was locked + assembler.cmp(rax, 0); // test if the barrier is locked + assembler.jz(skipLabel); // skip if barrier was locked // call replacement function // for this call no registers are saved. the called function is a compiled function so // it should correctly save non-volatile registers, and the caller can't expect the // volatile ones to remain valid assembler.pop(r10); - assembler.mov(dword_ptr(rax), r10); // store that return address to the variable supplied by the barrier function + assembler.mov(dword_ptr(rax), r10); // store that return address to the variable + // supplied by the barrier function assembler.mov(rax, imm((intptr_t)(LPVOID)rerouteAddr)); assembler.call(rax); - assembler.push(rax); // save away result + assembler.push(rax); // save away result // open the barrier again pushAll(assembler); @@ -154,62 +154,62 @@ void TrampolinePool::addBarrier(LPVOID rerouteAddr, LPVOID original, X86Assemble assembler.call(rax); assembler.add(rsp, 32); popAll(assembler); - assembler.pop(r10); // get the result from the replacement function to a register - assembler.push(rax); // push the original return address back on the stack - assembler.mov(rax, r10); // move result of actual call to rax - assembler.ret(); // return, using the original return address -#else // BOOST_ARCH_X86_64 - assembler.push(imm(void_ptr_cast(original))); // push original function, as parameter to barrier - assembler.mov(ecx, (Ptr)static_cast(TrampolinePool::barrier)); - assembler.call(ecx); // call barrier function + assembler.pop(r10); // get the result from the replacement function to a register + assembler.push(rax); // push the original return address back on the stack + assembler.mov(rax, r10); // move result of actual call to rax + assembler.ret(); // return, using the original return address +#else // BOOST_ARCH_X86_64 + assembler.push(imm(void_ptr_cast( + original))); // push original function, as parameter to barrier + assembler.mov(ecx, (Ptr) static_cast(TrampolinePool::barrier)); + assembler.call(ecx); // call barrier function assembler.cmp(eax, 0); - assembler.jz(skipLabel); // if barrier is locked, jump to end of function + assembler.jz(skipLabel); // if barrier is locked, jump to end of function // case a: we got through the barrier - assembler.pop(ecx); // pop the return address into ecx - assembler.mov(dword_ptr(eax), ecx); // store that return address in the variable supplied by the barrier function + assembler.pop(ecx); // pop the return address into ecx + assembler.mov(dword_ptr(eax), ecx); // store that return address in the variable + // supplied by the barrier function - assembler.mov(eax, (Ptr)static_cast(rerouteAddr)); - assembler.call(eax); // call replacement function (pointer was stored in front of the trampoline) - // (this function gets the parameters that were on the stack already and cleans - // them up itself (stdcall convention)) - assembler.push(eax); // save away result - assembler.push(imm(void_ptr_cast(original))); // open the barrier again - assembler.mov(eax, (Ptr)static_cast(TrampolinePool::release)); + assembler.mov(eax, (Ptr) static_cast(rerouteAddr)); + assembler.call(eax); // call replacement function (pointer was stored in front of the + // trampoline) (this function gets the parameters that were on + // the stack already and cleans + // them up itself (stdcall convention)) + assembler.push(eax); // save away result + assembler.push(imm(void_ptr_cast(original))); // open the barrier again + assembler.mov(eax, (Ptr) static_cast(TrampolinePool::release)); assembler.call(eax); - assembler.pop(ecx); // pop the result from the actual call to ecx - assembler.push(eax); // push the original return address (returned by TTrampolinePool::release) - // back on the stack - assembler.mov(eax, ecx); // move result of actual call to eax - assembler.ret(); // return, using the original return address -#endif // BOOST_ARCH_X86_64 + assembler.pop(ecx); // pop the result from the actual call to ecx + assembler.push(eax); // push the original return address (returned by + // TTrampolinePool::release) back on the stack + assembler.mov(eax, ecx); // move result of actual call to eax + assembler.ret(); // return, using the original return address +#endif // BOOST_ARCH_X86_64 assembler.bind(skipLabel); } - LPVOID TrampolinePool::roundAddress(LPVOID address) const { return reinterpret_cast(reinterpret_cast(address) & m_AddressMask); } - -TrampolinePool::BufferList &TrampolinePool::getBufferList(LPVOID address) +TrampolinePool::BufferList& TrampolinePool::getBufferList(LPVOID address) { LPVOID rounded = roundAddress(address); - auto iter = m_Buffers.find(rounded); + auto iter = m_Buffers.find(rounded); if (iter == m_Buffers.end()) { - BufferList newBufList = { 0, std::vector() }; - m_Buffers[rounded] = newBufList; - iter = allocateBuffer(address); + BufferList newBufList = {0, std::vector()}; + m_Buffers[rounded] = newBufList; + iter = allocateBuffer(address); } return iter->second; } - LPVOID TrampolinePool::storeStub(LPVOID reroute, LPVOID original, LPVOID returnAddress) { - BufferList &bufferList = getBufferList(original); + BufferList& bufferList = getBufferList(original); // first test to increase likelyhood we don't have to reallocate later if (bufferList.offset + m_MaxTrampolineSize > m_BufferSize) { allocateBuffer(original); @@ -234,8 +234,8 @@ LPVOID TrampolinePool::storeStub(LPVOID reroute, LPVOID original, LPVOID returnA size_t codeSize = assembler.getCodeSize(); - m_MaxTrampolineSize = std::max(m_MaxTrampolineSize, - static_cast(codeSize + sizeof(LPVOID))); + m_MaxTrampolineSize = + std::max(m_MaxTrampolineSize, static_cast(codeSize + sizeof(LPVOID))); // final test to see if we can store the trampoline in the buffer if ((bufferList.offset + codeSize) > m_BufferSize) { @@ -248,7 +248,7 @@ LPVOID TrampolinePool::storeStub(LPVOID reroute, LPVOID original, LPVOID returnA // adjust relative jumps for move to buffer codeSize = assembler.relocCode(spot); - uint8_t *code = assembler.getBuffer(); + uint8_t* code = assembler.getBuffer(); memcpy(spot, code, codeSize); bufferList.offset += codeSize; @@ -256,10 +256,10 @@ LPVOID TrampolinePool::storeStub(LPVOID reroute, LPVOID original, LPVOID returnA return spot; } - -LPVOID TrampolinePool::storeTrampoline(LPVOID reroute, LPVOID original, LPVOID returnAddress) +LPVOID TrampolinePool::storeTrampoline(LPVOID reroute, LPVOID original, + LPVOID returnAddress) { - BufferList &bufferList = getBufferList(original); + BufferList& bufferList = getBufferList(original); // first test to increase likelyhood we don't have to reallocate later if (bufferList.offset + m_MaxTrampolineSize > m_BufferSize) { allocateBuffer(original); @@ -284,8 +284,8 @@ LPVOID TrampolinePool::storeTrampoline(LPVOID reroute, LPVOID original, LPVOID r #endif size_t codeSize = assembler.getCodeSize(); - m_MaxTrampolineSize = std::max(m_MaxTrampolineSize, - static_cast(codeSize + sizeof(LPVOID))); + m_MaxTrampolineSize = + std::max(m_MaxTrampolineSize, static_cast(codeSize + sizeof(LPVOID))); // final test to see if we can store the trampoline in the buffer if ((bufferList.offset + codeSize) > m_BufferSize) { @@ -299,16 +299,15 @@ LPVOID TrampolinePool::storeTrampoline(LPVOID reroute, LPVOID original, LPVOID r codeSize = assembler.relocCode(spot); // copy code to buffer - uint8_t *code = assembler.getBuffer(); + uint8_t* code = assembler.getBuffer(); memcpy(spot, code, codeSize); bufferList.offset += codeSize; return spot; } - #if BOOST_ARCH_X86_64 -void TrampolinePool::copyCode(X86Assembler &assembler, LPVOID source, size_t numBytes) +void TrampolinePool::copyCode(X86Assembler& assembler, LPVOID source, size_t numBytes) { static UDis86Wrapper disasm; @@ -322,20 +321,21 @@ void TrampolinePool::copyCode(X86Assembler &assembler, LPVOID source, size_t num offset += ud_insn_len(disasm); // WARNING: doesn't support conditional jumps - if ((ud_insn_mnemonic(disasm) == UD_Ijmp) && (ud_insn_opr(disasm, 0)->type == UD_OP_JIMM)) { + if ((ud_insn_mnemonic(disasm) == UD_Ijmp) && + (ud_insn_opr(disasm, 0)->type == UD_OP_JIMM)) { uintptr_t dest = disasm.jumpTarget(); assembler.mov(rax, imm(static_cast(dest))); assembler.jmp(rax); } else { assembler.embed(ud_insn_ptr(&disasm.obj()), ud_insn_len(&disasm.obj())); -// assembler.data(); + // assembler.data(); } } } #endif - -void TrampolinePool::addCallToStub(X86Assembler &assembler, LPVOID original, LPVOID reroute) +void TrampolinePool::addCallToStub(X86Assembler& assembler, LPVOID original, + LPVOID reroute) { #if BOOST_ARCH_X86_64 pushAll(assembler); @@ -345,16 +345,15 @@ void TrampolinePool::addCallToStub(X86Assembler &assembler, LPVOID original, LPV assembler.call(rax); assembler.add(rsp, 32); popAll(assembler); -#else // BOOST_ARCH_X86_64 +#else // BOOST_ARCH_X86_64 assembler.push(reinterpret_cast(original)); assembler.mov(ecx, imm((intptr_t)(LPVOID)reroute)); assembler.call(ecx); - assembler.pop(ecx); // remove argument from stack -#endif // BOOST_ARCH_X86_64 + assembler.pop(ecx); // remove argument from stack +#endif // BOOST_ARCH_X86_64 } - -void TrampolinePool::addAbsoluteJump(X86Assembler &assembler, uint64_t destination) +void TrampolinePool::addAbsoluteJump(X86Assembler& assembler, uint64_t destination) { #if BOOST_ARCH_X86_64 assembler.push(rax); @@ -363,15 +362,16 @@ void TrampolinePool::addAbsoluteJump(X86Assembler &assembler, uint64_t destinati assembler.mov(ptr(rsp, 8), rax); assembler.pop(rax); assembler.ret(); -#else // BOOST_ARCH_X86_64 +#else // BOOST_ARCH_X86_64 assembler.push(imm(destination)); assembler.ret(); -#endif // BOOST_ARCH_X86_64 +#endif // BOOST_ARCH_X86_64 } -LPVOID TrampolinePool::storeStub(LPVOID reroute, LPVOID original, size_t preambleSize, size_t *rerouteOffset) +LPVOID TrampolinePool::storeStub(LPVOID reroute, LPVOID original, size_t preambleSize, + size_t* rerouteOffset) { - BufferList &bufferList = getBufferList(original); + BufferList& bufferList = getBufferList(original); // first test to increase likelyhood we don't have to reallocate later if (bufferList.offset + m_MaxTrampolineSize > m_BufferSize) { allocateBuffer(original); @@ -391,16 +391,16 @@ LPVOID TrampolinePool::storeStub(LPVOID reroute, LPVOID original, size_t preambl // insert backup code *rerouteOffset = assembler.getCodeSize(); copyCode(assembler, original, preambleSize); -#else // BOOST_ARCH_X86_64 +#else // BOOST_ARCH_X86_64 assembler.embed(original, preambleSize); -#endif // BOOST_ARCH_X86_64 +#endif // BOOST_ARCH_X86_64 addAbsoluteJump(assembler, reinterpret_cast(original) + preambleSize); // adjust relative jumps for move to buffer size_t codeSize = assembler.getCodeSize(); - m_MaxTrampolineSize = std::max(m_MaxTrampolineSize, - static_cast(codeSize + sizeof(LPVOID))); + m_MaxTrampolineSize = + std::max(m_MaxTrampolineSize, static_cast(codeSize + sizeof(LPVOID))); // final test to see if we can store the trampoline in the buffer if ((bufferList.offset + codeSize) > m_BufferSize) { @@ -417,10 +417,10 @@ LPVOID TrampolinePool::storeStub(LPVOID reroute, LPVOID original, size_t preambl return spot; } - -LPVOID TrampolinePool::storeTrampoline(LPVOID reroute, LPVOID original, size_t preambleSize, size_t *rerouteOffset) +LPVOID TrampolinePool::storeTrampoline(LPVOID reroute, LPVOID original, + size_t preambleSize, size_t* rerouteOffset) { - BufferList &bufferList = getBufferList(original); + BufferList& bufferList = getBufferList(original); // first test to increase likelyhood we don't have to reallocate later if (bufferList.offset + m_MaxTrampolineSize > m_BufferSize) { allocateBuffer(original); @@ -444,12 +444,13 @@ LPVOID TrampolinePool::storeTrampoline(LPVOID reroute, LPVOID original, size_t p // adjust relative jumps for move to buffer size_t codeSize = assembler.getCodeSize(); - m_MaxTrampolineSize = std::max(m_MaxTrampolineSize, - static_cast(codeSize + sizeof(LPVOID))); + m_MaxTrampolineSize = + std::max(m_MaxTrampolineSize, static_cast(codeSize + sizeof(LPVOID))); - // TODO this does not take into account that the code size may technically change after relocation - // in which case the following test may determine the code fits into the buffer when it really - // doesnt't. asmjit doesn't seem to provide a way to adjust jumps without actually moving the code though + // TODO this does not take into account that the code size may technically change + // after relocation in which case the following test may determine the code fits into + // the buffer when it really doesnt't. asmjit doesn't seem to provide a way to adjust + // jumps without actually moving the code though // final test to see if we can store the trampoline in the buffer if ((bufferList.offset + codeSize) > m_BufferSize) { @@ -469,7 +470,7 @@ LPVOID TrampolinePool::storeTrampoline(LPVOID reroute, LPVOID original, size_t p LPVOID TrampolinePool::currentBufferAddress(LPVOID addressNear) { - LPVOID rounded = roundAddress(addressNear); + LPVOID rounded = roundAddress(addressNear); auto lookupAddress = m_Buffers.find(rounded); if (lookupAddress == m_Buffers.end()) { @@ -489,7 +490,7 @@ void TrampolinePool::forceUnlockBarrier() for (auto funcId : *m_ThreadGuards) { (*m_ThreadGuards)[funcId.first] = nullptr; } - } // else no barriers to unlock + } // else no barriers to unlock } TrampolinePool::BufferMap::iterator TrampolinePool::allocateBuffer(LPVOID addressNear) @@ -504,16 +505,16 @@ TrampolinePool::BufferMap::iterator TrampolinePool::allocateBuffer(LPVOID addres uintptr_t lowerEnd = reinterpret_cast(rounded); if (iter->second.buffers.size() > 0) { // start searching were we last found a buffer - lowerEnd = reinterpret_cast(*iter->second.buffers.rbegin()) - + sysInfo.dwPageSize; + lowerEnd = reinterpret_cast(*iter->second.buffers.rbegin()) + + sysInfo.dwPageSize; } - uintptr_t start = std::max( - std::max(lowerEnd, MIN_ALLOC_ADDR), - reinterpret_cast(sysInfo.lpMinimumApplicationAddress)); + uintptr_t start = + std::max(std::max(lowerEnd, MIN_ALLOC_ADDR), + reinterpret_cast(sysInfo.lpMinimumApplicationAddress)); uintptr_t upperEnd = reinterpret_cast(rounded) + m_SearchRange; - uintptr_t end = std::min(upperEnd, reinterpret_cast( - sysInfo.lpMaximumApplicationAddress)); + uintptr_t end = std::min( + upperEnd, reinterpret_cast(sysInfo.lpMaximumApplicationAddress)); LPVOID buffer = nullptr; for (uintptr_t cur = start; cur < end; cur += sysInfo.dwPageSize) { @@ -535,16 +536,15 @@ TrampolinePool::BufferMap::iterator TrampolinePool::allocateBuffer(LPVOID addres iter->second.buffers.push_back(buffer); spdlog::get("usvfs")->debug( "allocated trampoline buffer for jumps between {0:p} and {1:x} at {2:p}" - "(size {3})", - rounded, - (reinterpret_cast(rounded) + m_SearchRange), - buffer, m_BufferSize); + "(size {3})", + rounded, (reinterpret_cast(rounded) + m_SearchRange), buffer, + m_BufferSize); return iter; } LPVOID TrampolinePool::barrier(LPVOID function) { - DWORD err = GetLastError(); + DWORD err = GetLastError(); LPVOID res = instance().barrierInt(function); SetLastError(err); return res; @@ -552,7 +552,7 @@ LPVOID TrampolinePool::barrier(LPVOID function) LPVOID TrampolinePool::release(LPVOID function) { - DWORD err = GetLastError(); + DWORD err = GetLastError(); LPVOID res = instance().releaseInt(function); SetLastError(err); return res; @@ -591,11 +591,11 @@ LPVOID TrampolinePool::releaseInt(LPVOID func) return nullptr; } - LPVOID res = (*m_ThreadGuards)[func]; + LPVOID res = (*m_ThreadGuards)[func]; (*m_ThreadGuards)[func] = nullptr; ::SetLastError(lastError); return res; } -} // namespace HookLib +} // namespace HookLib diff --git a/src/thooklib/ttrampolinepool.h b/src/thooklib/ttrampolinepool.h index 85653ff..5b44c51 100644 --- a/src/thooklib/ttrampolinepool.h +++ b/src/thooklib/ttrampolinepool.h @@ -20,11 +20,11 @@ along with usvfs. If not, see . */ #pragma once -#include -#include -#include -#include #include "asmjit_sane.h" +#include +#include +#include +#include #ifdef _MSC_VER #pragma warning(disable : 4714) @@ -36,9 +36,10 @@ along with usvfs. If not, see . #include #include -//#include +// #include -namespace HookLib { +namespace HookLib +{ /// /// trampolines are runtime-generated mini-functions that are used to call the @@ -47,13 +48,13 @@ namespace HookLib { class TrampolinePool { public: - /// Call initialize before you use the TrampolinePool static void initialize(); - static TrampolinePool &instance() { - // This is a very very sensitive place so we want to keep this function as simple as possible - // and having it inlined probably cann't hurt + static TrampolinePool& instance() + { + // This is a very very sensitive place so we want to keep this function as simple as + // possible and having it inlined probably cann't hurt return *s_Instance; } @@ -61,46 +62,58 @@ public: /// /// store a stub without moving code from the original function. This is used in cases - /// where the hook can be placed without overwriting logic (i.e. hot-patchable functions and - /// when chaining hooks) - /// \param reroute the stub function to call before the regular function (on x86 this needs to be cdecl calling convention!) + /// where the hook can be placed without overwriting logic (i.e. hot-patchable + /// functions and when chaining hooks) + /// \param reroute the stub function to call before the regular function (on x86 this + /// needs to be cdecl calling convention!) /// \param original the original function - /// \param returnAddress address under which the original functionality can be reached. - /// for the first hook this should be (original + 2), otherwise the address of the next hook in the chain + /// \param returnAddress address under which the original functionality can be + /// reached. + /// for the first hook this should be (original + 2), otherwise + /// the address of the next hook in the chain /// \return address of the created trampoline function /// LPVOID storeStub(LPVOID reroute, LPVOID original, LPVOID returnAddress); /// /// store a stub, moving part of the original function to the trampoline - /// \param reroute the stub function to call before the regular function (on x86 this needs to be cdecl calling convention!) + /// \param reroute the stub function to call before the regular function (on x86 this + /// needs to be cdecl calling convention!) /// \param original the original function - /// \param preambleSize number of bytes from the original function to backup. Needs to correspond to complete instructions - /// \param rerouteOffset offset in bytes from the created trampoline to the preamble that leads back to the original code + /// \param preambleSize number of bytes from the original function to backup. Needs to + /// correspond to complete instructions + /// \param rerouteOffset offset in bytes from the created trampoline to the preamble + /// that leads back to the original code /// \return address of the created trampoline function /// - LPVOID storeStub(LPVOID reroute, LPVOID original, size_t preambleSize, size_t *rerouteOffset); + LPVOID storeStub(LPVOID reroute, LPVOID original, size_t preambleSize, + size_t* rerouteOffset); /// /// store a trampoline for hot-patchable functions, where the original function /// is unharmed. /// \param reroute the reroute function /// \param original original function - /// \param returnAddress address under which the original functionality can be reached. + /// \param returnAddress address under which the original functionality can be + /// reached. /// \return address of the trampoline function /// LPVOID storeTrampoline(LPVOID reroute, LPVOID original, LPVOID returnAddress); /// - /// store a trampoline, copying a part of the original function to the trampoline. This - /// is used for the case where the hooking mechanism needs to overwrite part of the function + /// store a trampoline, copying a part of the original function to the trampoline. + /// This is used for the case where the hooking mechanism needs to overwrite part of + /// the function /// \param reroute the reroute function /// \param original original function - /// \param preambleSize number of bytes from the original function to backup. Needs to correspond to complete instructions - /// \param rerouteOffset offset in bytes from the created trampoline to the preamble that leads us back to the original code + /// \param preambleSize number of bytes from the original function to backup. Needs to + /// correspond to complete instructions + /// \param rerouteOffset offset in bytes from the created trampoline to the preamble + /// that leads us back to the original code /// \return address of the trampoline function /// - LPVOID storeTrampoline(LPVOID reroute, LPVOID original, size_t preambleSize, size_t *rerouteOffset); + LPVOID storeTrampoline(LPVOID reroute, LPVOID original, size_t preambleSize, + size_t* rerouteOffset); /// /// \param addressNear used to find a trampoline buffer near the jump instruction @@ -114,20 +127,21 @@ public: void forceUnlockBarrier(); private: - - struct BufferList { + struct BufferList + { size_t offset; std::vector buffers; }; typedef std::map BufferMap; - static const intptr_t ADDRESS_MASK = 0xFFFFFFFFFF000000LL; // mask to "round" addresses to consolidate near trampolines + static const intptr_t ADDRESS_MASK = + 0xFFFFFFFFFF000000LL; // mask to "round" addresses to consolidate near + // trampolines private: - TrampolinePool(); - TrampolinePool &operator=(const TrampolinePool &reference); // not implemented + TrampolinePool& operator=(const TrampolinePool& reference); // not implemented /** * @brief allocates a buffer with read, write and execute rights near the @@ -138,40 +152,38 @@ private: */ BufferMap::iterator allocateBuffer(LPVOID addressNear); - void addBarrier(LPVOID rerouteAddr, LPVOID original, asmjit::X86Assembler &assembler); + void addBarrier(LPVOID rerouteAddr, LPVOID original, asmjit::X86Assembler& assembler); #if BOOST_ARCH_X86_64 - void copyCode(asmjit::X86Assembler &assembler, LPVOID source, size_t numBytes); -#endif // BOOST_ARCH_X86_64 + void copyCode(asmjit::X86Assembler& assembler, LPVOID source, size_t numBytes); +#endif // BOOST_ARCH_X86_64 - BufferList &getBufferList(LPVOID address); + BufferList& getBufferList(LPVOID address); LPVOID roundAddress(LPVOID address) const; public: - static LPVOID __stdcall barrier(LPVOID function); static LPVOID __stdcall release(LPVOID function); LPVOID barrierInt(LPVOID function); LPVOID releaseInt(LPVOID function); - void addCallToStub(asmjit::X86Assembler &assembler, LPVOID original, LPVOID reroute); + void addCallToStub(asmjit::X86Assembler& assembler, LPVOID original, LPVOID reroute); private: - /// - /// \brief add a jump to an address outside the custom generated asm code (without modifying registers) + /// \brief add a jump to an address outside the custom generated asm code (without + /// modifying registers) /// \param assembler the assembler generator to write to /// \param destination destination address /// \note this currently generates a lot code on x64, may be overly complicated /// - void addAbsoluteJump(asmjit::X86Assembler &assembler, uint64_t destination); + void addAbsoluteJump(asmjit::X86Assembler& assembler, uint64_t destination); DWORD determinePageSize(); private: - #if BOOST_ARCH_X86_64 static const int SIZE_OF_JUMP = 13; #elif BOOST_ARCH_X86_32 @@ -188,9 +200,9 @@ private: // static constexpr uintptr_t MIN_ALLOC_ADDR = 0x40000000 + 0x200000; - static TrampolinePool *s_Instance; + static TrampolinePool* s_Instance; - bool m_FullBlock {false}; + bool m_FullBlock{false}; BufferMap m_Buffers; @@ -200,12 +212,11 @@ private: LPVOID m_BarrierAddr; LPVOID m_ReleaseAddr; - DWORD m_BufferSize = { 1024 }; + DWORD m_BufferSize = {1024}; size_t m_SearchRange; uint64_t m_AddressMask; int m_MaxTrampolineSize; - }; -} // namespace HookLib +} // namespace HookLib diff --git a/src/thooklib/udis86wrapper.cpp b/src/thooklib/udis86wrapper.cpp index 69fa950..1ac7332 100644 --- a/src/thooklib/udis86wrapper.cpp +++ b/src/thooklib/udis86wrapper.cpp @@ -18,17 +18,17 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with usvfs. If not, see . */ -#include "pch.h" #include "udis86wrapper.h" +#include "pch.h" #include -#include #include +#include +namespace HookLib +{ -namespace HookLib { - - -UDis86Wrapper::UDis86Wrapper() { +UDis86Wrapper::UDis86Wrapper() +{ ud_init(&m_Obj); ud_set_syntax(&m_Obj, UD_SYN_INTEL); #if BOOST_ARCH_X86_64 @@ -38,14 +38,14 @@ UDis86Wrapper::UDis86Wrapper() { #endif } -void UDis86Wrapper::setInputBuffer(const uint8_t *buffer, size_t size) +void UDis86Wrapper::setInputBuffer(const uint8_t* buffer, size_t size) { m_Buffer = buffer; ud_set_input_buffer(&m_Obj, buffer, size); ud_set_pc(&m_Obj, reinterpret_cast(m_Buffer)); } -ud_t &UDis86Wrapper::obj() +ud_t& UDis86Wrapper::obj() { return m_Obj; } @@ -53,48 +53,37 @@ ud_t &UDis86Wrapper::obj() bool UDis86Wrapper::isRelativeJump() { ud_mnemonic_code code = ud_insn_mnemonic(&m_Obj); - // all conditional jumps and loops are relative, as are unconditional jumps with an offset - // operand - return (code == UD_Ijo) || - (code == UD_Ijno) || - (code == UD_Ijb) || - (code == UD_Ijae) || - (code == UD_Ijz) || - (code == UD_Ijnz) || - (code == UD_Ijbe) || - (code == UD_Ija) || - (code == UD_Ijs) || - (code == UD_Ijns) || - (code == UD_Ijp) || - (code == UD_Ijnp) || - (code == UD_Ijl) || - (code == UD_Ijge) || - (code == UD_Ijle) || - (code == UD_Ijg) || - (code == UD_Ijcxz) || - (code == UD_Ijecxz) || - (code == UD_Ijrcxz) || - (code == UD_Iloop) || - (code == UD_Iloope) || - (code == UD_Iloopne) || - ((code == UD_Icall) && (ud_insn_opr(&m_Obj, 0)->type == UD_OP_JIMM)) || - ((code == UD_Ijmp) && (ud_insn_opr(&m_Obj, 0)->type == UD_OP_JIMM)); + // all conditional jumps and loops are relative, as are unconditional jumps with an + // offset operand + return (code == UD_Ijo) || (code == UD_Ijno) || (code == UD_Ijb) || + (code == UD_Ijae) || (code == UD_Ijz) || (code == UD_Ijnz) || + (code == UD_Ijbe) || (code == UD_Ija) || (code == UD_Ijs) || + (code == UD_Ijns) || (code == UD_Ijp) || (code == UD_Ijnp) || + (code == UD_Ijl) || (code == UD_Ijge) || (code == UD_Ijle) || + (code == UD_Ijg) || (code == UD_Ijcxz) || (code == UD_Ijecxz) || + (code == UD_Ijrcxz) || (code == UD_Iloop) || (code == UD_Iloope) || + (code == UD_Iloopne) || + ((code == UD_Icall) && (ud_insn_opr(&m_Obj, 0)->type == UD_OP_JIMM)) || + ((code == UD_Ijmp) && (ud_insn_opr(&m_Obj, 0)->type == UD_OP_JIMM)); } - intptr_t UDis86Wrapper::jumpOffset() { - const ud_operand_t *op = ud_insn_opr(&m_Obj, 0); + const ud_operand_t* op = ud_insn_opr(&m_Obj, 0); switch (op->size) { - case 8: return static_cast(op->lval.sbyte); - case 16: return static_cast(op->lval.sword); - case 32: return static_cast(op->lval.sdword); - case 64: return static_cast(op->lval.sqword); - default: throw std::runtime_error("unsupported jump size"); + case 8: + return static_cast(op->lval.sbyte); + case 16: + return static_cast(op->lval.sword); + case 32: + return static_cast(op->lval.sdword); + case 64: + return static_cast(op->lval.sqword); + default: + throw std::runtime_error("unsupported jump size"); } } - uint64_t UDis86Wrapper::jumpTarget() { // TODO: assert we're actually on a jump @@ -110,4 +99,4 @@ uint64_t UDis86Wrapper::jumpTarget() return res; } -} // namespace HookLib +} // namespace HookLib diff --git a/src/thooklib/udis86wrapper.h b/src/thooklib/udis86wrapper.h index 68a36d6..48d8a42 100644 --- a/src/thooklib/udis86wrapper.h +++ b/src/thooklib/udis86wrapper.h @@ -21,19 +21,21 @@ along with usvfs. If not, see . #pragma once #include -#undef inline // libudis86/types.h defines inline to __inline which is no longer legal since vs2012 +#undef inline // libudis86/types.h defines inline to __inline which is no longer legal + // since vs2012 -namespace HookLib { +namespace HookLib +{ -class UDis86Wrapper { +class UDis86Wrapper +{ public: - UDis86Wrapper(); - void setInputBuffer(const uint8_t *buffer, size_t size); + void setInputBuffer(const uint8_t* buffer, size_t size); - ud_t &obj(); + ud_t& obj(); operator ud_t*() { return &m_Obj; } @@ -42,21 +44,19 @@ public: intptr_t jumpOffset(); /// - /// determines the absolute jump target at the current instruction, taking into account - /// relative instructions of all sizes and RIP-relative addressing. + /// determines the absolute jump target at the current instruction, taking into + /// account relative instructions of all sizes and RIP-relative addressing. /// \return absolute address of the jump at the current disassembler instruction - /// \note this works correctly ONLY if the input buffer has been set with setInputBuffer or + /// \note this works correctly ONLY if the input buffer has been set with + /// setInputBuffer or /// if ud_set_pc has been called /// uint64_t jumpTarget(); private: - private: - ud_t m_Obj; - const uint8_t *m_Buffer { nullptr }; - + const uint8_t* m_Buffer{nullptr}; }; -} // namespace HookLib +} // namespace HookLib diff --git a/src/thooklib/utility.cpp b/src/thooklib/utility.cpp index e383507..124141f 100644 --- a/src/thooklib/utility.cpp +++ b/src/thooklib/utility.cpp @@ -22,8 +22,8 @@ along with usvfs. If not, see . #include "exceptionex.h" #include - -namespace HookLib { +namespace HookLib +{ FARPROC MyGetProcAddress(HMODULE module, LPCSTR functionName) { @@ -33,7 +33,8 @@ FARPROC MyGetProcAddress(HMODULE module, LPCSTR functionName) return nullptr; } - PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(((LPBYTE)dosHeader) + dosHeader->e_lfanew); + PIMAGE_NT_HEADERS ntHeaders = + (PIMAGE_NT_HEADERS)(((LPBYTE)dosHeader) + dosHeader->e_lfanew); if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) { return nullptr; } @@ -42,29 +43,33 @@ FARPROC MyGetProcAddress(HMODULE module, LPCSTR functionName) if (optionalHeader->NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_EXPORT) { return nullptr; } - PIMAGE_DATA_DIRECTORY dataDirectory = &optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; - PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)dosHeader + dataDirectory->VirtualAddress); + PIMAGE_DATA_DIRECTORY dataDirectory = + &optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + PIMAGE_EXPORT_DIRECTORY exportDirectory = + (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)dosHeader + dataDirectory->VirtualAddress); - ULONG *addressOfNames = (ULONG*)((LPBYTE) module + exportDirectory->AddressOfNames); - ULONG *funcAddr = (ULONG*)((LPBYTE) module + exportDirectory->AddressOfFunctions); + ULONG* addressOfNames = (ULONG*)((LPBYTE)module + exportDirectory->AddressOfNames); + ULONG* funcAddr = (ULONG*)((LPBYTE)module + exportDirectory->AddressOfFunctions); // search exports for the specified name for (DWORD i = 0; i < exportDirectory->NumberOfNames; ++i) { - char *curFunctionName = (char*)((LPBYTE) module + addressOfNames[i]); - USHORT *nameOrdinals = (USHORT*)((LPBYTE) module + exportDirectory->AddressOfNameOrdinals); + char* curFunctionName = (char*)((LPBYTE)module + addressOfNames[i]); + USHORT* nameOrdinals = + (USHORT*)((LPBYTE)module + exportDirectory->AddressOfNameOrdinals); if (strcmp(functionName, curFunctionName) == 0) { if (funcAddr[nameOrdinals[i]] >= dataDirectory->VirtualAddress && - funcAddr[nameOrdinals[i]] < dataDirectory->VirtualAddress + dataDirectory->Size) { - char *forwardLibName = _strdup((LPSTR)module + funcAddr[nameOrdinals[i]]); - ON_BLOCK_EXIT([forwardLibName] () { + funcAddr[nameOrdinals[i]] < + dataDirectory->VirtualAddress + dataDirectory->Size) { + char* forwardLibName = _strdup((LPSTR)module + funcAddr[nameOrdinals[i]]); + ON_BLOCK_EXIT([forwardLibName]() { free(forwardLibName); }); - char *forwardFunctionName = strchr(forwardLibName, '.'); - *forwardFunctionName = 0; + char* forwardFunctionName = strchr(forwardLibName, '.'); + *forwardFunctionName = 0; ++forwardFunctionName; HMODULE forwardLib = LoadLibraryA(forwardLibName); - FARPROC forward = nullptr; + FARPROC forward = nullptr; if (forwardLib != nullptr) { forward = MyGetProcAddress(forwardLib, forwardFunctionName); FreeLibrary(forwardLib); @@ -78,4 +83,4 @@ FARPROC MyGetProcAddress(HMODULE module, LPCSTR functionName) return nullptr; } -} // namespace HookLib +} // namespace HookLib diff --git a/src/thooklib/utility.h b/src/thooklib/utility.h index 03c05c8..e0be9f7 100644 --- a/src/thooklib/utility.h +++ b/src/thooklib/utility.h @@ -22,12 +22,14 @@ along with usvfs. If not, see . #include -namespace HookLib { +namespace HookLib +{ -/// \brief reimplementation of GetProcAddress to circumvent foreign hooks of GetProcAddress like AcLayer +/// \brief reimplementation of GetProcAddress to circumvent foreign hooks of +/// GetProcAddress like AcLayer /// \param module handle to the module that contains the function or variable /// \param functionName function to retrieve the address of /// \return address of the exported function FARPROC MyGetProcAddress(HMODULE module, LPCSTR functionName); -} +} // namespace HookLib diff --git a/src/tinjectlib/asmjit_sane.h b/src/tinjectlib/asmjit_sane.h index 10d0521..70ee117 100644 --- a/src/tinjectlib/asmjit_sane.h +++ b/src/tinjectlib/asmjit_sane.h @@ -20,13 +20,13 @@ along with usvfs. If not, see . */ #pragma once -#pragma warning (push, 3) +#pragma warning(push, 3) #pragma warning(disable : 4201) #pragma warning(disable : 4244) #pragma warning(disable : 4245) -//#ifndef ASMJIT_API -//#define ASMJIT_API -//#endif // ASMJIT_API +// #ifndef ASMJIT_API +// #define ASMJIT_API +// #endif // ASMJIT_API #include #include -#pragma warning (pop) +#pragma warning(pop) diff --git a/src/tinjectlib/injectlib.cpp b/src/tinjectlib/injectlib.cpp index 7e1875b..2c7362a 100644 --- a/src/tinjectlib/injectlib.cpp +++ b/src/tinjectlib/injectlib.cpp @@ -18,24 +18,24 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with usvfs. If not, see . */ -#include #include +#include -#include #include +#include #include #include namespace fs = boost::filesystem; #include "injectlib.h" -#include -#include -#include #include +#include +#include +#include // local version of asmjit with warning suppression #include "asmjit_sane.h" -#include #include +#include using namespace asmjit; using namespace usvfs::shared; @@ -50,16 +50,16 @@ using namespace asmjit::x86; #error "unsupported architecture" #endif +typedef HMODULE(WINAPI* TLoadLibraryType)(LPCWSTR); +typedef FARPROC(WINAPI* TGetProcAddressType)(HMODULE, LPCSTR); +typedef DWORD(WINAPI* TGetLastErrorType)(); -typedef HMODULE (WINAPI *TLoadLibraryType)(LPCWSTR); -typedef FARPROC (WINAPI *TGetProcAddressType)(HMODULE, LPCSTR); -typedef DWORD (WINAPI *TGetLastErrorType)(); - -typedef BOOL (WINAPI *TSetXStateFeaturesMaskType)(PCONTEXT, DWORD64); +typedef BOOL(WINAPI* TSetXStateFeaturesMaskType)(PCONTEXT, DWORD64); static const size_t MAX_FUNCTIONAME = 20; -struct TDataRemote { +struct TDataRemote +{ TLoadLibraryType loadLibrary; TGetProcAddressType getProcAddress; TGetLastErrorType getLastError; @@ -69,9 +69,8 @@ struct TDataRemote { WCHAR dllName[MAX_PATH]; }; - #if BOOST_ARCH_X86_64 -void pushAll(X86Assembler &assembler) +void pushAll(X86Assembler& assembler) { assembler.pushf(); assembler.push(rax); @@ -91,7 +90,7 @@ void pushAll(X86Assembler &assembler) assembler.push(r15); } -void popAll(X86Assembler &assembler) +void popAll(X86Assembler& assembler) { assembler.pop(r15); assembler.pop(r14); @@ -110,10 +109,10 @@ void popAll(X86Assembler &assembler) assembler.pop(rax); assembler.popf(); } -#endif // BOOST_ARCH_X86_64 +#endif // BOOST_ARCH_X86_64 -void addStub(size_t userDataSize, X86Assembler &assembler, bool skipInit, - TDataRemote *localData, TDataRemote *remoteData, LPCSTR initFunction) +void addStub(size_t userDataSize, X86Assembler& assembler, bool skipInit, + TDataRemote* localData, TDataRemote* remoteData, LPCSTR initFunction) { Label Label_DLLLoaded = assembler.newLabel(); @@ -130,12 +129,12 @@ void addStub(size_t userDataSize, X86Assembler &assembler, bool skipInit, // TODO: would be great to report this error. But how? assembler.test(rax, rax); assembler.jnz(Label_DLLLoaded); -/* this commented out code may seem pointless but it is a simple way to get at the error code when debugging. - assembler.mov(rax, imm((intptr_t)(void*)localData->getLastError)); - assembler.sub(rsp, 32); - assembler.call(rax); - assembler.add(rsp, 32); - assembler.int3();*/ + /* this commented out code may seem pointless but it is a simple way to get at the + error code when debugging. assembler.mov(rax, + imm((intptr_t)(void*)localData->getLastError)); assembler.sub(rsp, 32); + assembler.call(rax); + assembler.add(rsp, 32); + assembler.int3();*/ popAll(assembler); assembler.ret(); assembler.bind(Label_DLLLoaded); @@ -143,8 +142,9 @@ void addStub(size_t userDataSize, X86Assembler &assembler, bool skipInit, // determine address of the init function if (initFunction != nullptr) { Label Label_SkipInit = assembler.newLabel(); - assembler.mov(rcx, rax); // handle of the dll - assembler.mov(rdx, imm(reinterpret_cast(remoteData->initFunction))); // name of init function + assembler.mov(rcx, rax); // handle of the dll + assembler.mov(rdx, imm(reinterpret_cast( + remoteData->initFunction))); // name of init function assembler.mov(rax, imm((intptr_t)(void*)localData->getProcAddress)); assembler.sub(rsp, 32); assembler.call(rax); @@ -156,7 +156,8 @@ void addStub(size_t userDataSize, X86Assembler &assembler, bool skipInit, } // call the init function with user data - assembler.mov(rcx, imm(reinterpret_cast(remoteData) + sizeof(TDataRemote))); + assembler.mov(rcx, + imm(reinterpret_cast(remoteData) + sizeof(TDataRemote))); assembler.mov(rdx, imm(static_cast(userDataSize))); assembler.sub(rsp, 32); assembler.call(rax); @@ -174,16 +175,16 @@ void addStub(size_t userDataSize, X86Assembler &assembler, bool skipInit, // call load library for the actual injection assembler.push(imm(void_ptr_cast(remoteData->dllName))); -// assembler.call(ptr_abs(static_cast(remoteData->loadLibrary))); + // assembler.call(ptr_abs(static_cast(remoteData->loadLibrary))); assembler.mov(eax, imm(void_ptr_cast(localData->loadLibrary))); assembler.call(eax); assembler.test(eax, eax); assembler.jnz(Label_DLLLoaded); -/* this commented out code may seem pointless but it is a simple way to get at the error code when debugging. - assembler.mov(eax, imm((intptr_t)(void*)localData->getLastError)); - assembler.call(eax); - assembler.int3();*/ + /* this commented out code may seem pointless but it is a simple way to get at the + error code when debugging. assembler.mov(eax, + imm((intptr_t)(void*)localData->getLastError)); assembler.call(eax); + assembler.int3();*/ assembler.popf(); assembler.pop(eax); assembler.ret(); @@ -192,8 +193,9 @@ void addStub(size_t userDataSize, X86Assembler &assembler, bool skipInit, // determine address of the init function if (initFunction != nullptr) { Label Label_SkipInit = assembler.newLabel(); - assembler.push(imm(void_ptr_cast(remoteData->initFunction))); // name of init function - assembler.push(eax); // handle of the dll + assembler.push(imm( + void_ptr_cast(remoteData->initFunction))); // name of init function + assembler.push(eax); // handle of the dll assembler.mov(eax, imm(void_ptr_cast(localData->getProcAddress))); assembler.call(eax); if (skipInit) { @@ -228,25 +230,22 @@ void addStub(size_t userDataSize, X86Assembler &assembler, bool skipInit, #endif } - -REGWORD WriteInjectionStub(HANDLE processHandle - , LPCWSTR dllName - , LPCSTR initFunction - , LPCVOID userData - , size_t userDataSize - , bool skipInit - , REGWORD returnAddress) +REGWORD WriteInjectionStub(HANDLE processHandle, LPCWSTR dllName, LPCSTR initFunction, + LPCVOID userData, size_t userDataSize, bool skipInit, + REGWORD returnAddress) { - HMODULE k32mod = ::LoadLibrary(__TEXT("kernel32.dll")); - TDataRemote data = { 0 }; + HMODULE k32mod = ::LoadLibrary(__TEXT("kernel32.dll")); + TDataRemote data = {0}; if (k32mod != nullptr) { - data.loadLibrary = reinterpret_cast( GetProcAddress(k32mod, "LoadLibraryW")); - data.getProcAddress = reinterpret_cast(GetProcAddress(k32mod, "GetProcAddress")); - data.getLastError = reinterpret_cast( GetProcAddress(k32mod, "GetLastError")); - if ( (data.loadLibrary == nullptr) - || (data.getProcAddress == nullptr) - || (data.getLastError == nullptr)) { + data.loadLibrary = + reinterpret_cast(GetProcAddress(k32mod, "LoadLibraryW")); + data.getProcAddress = + reinterpret_cast(GetProcAddress(k32mod, "GetProcAddress")); + data.getLastError = + reinterpret_cast(GetProcAddress(k32mod, "GetLastError")); + if ((data.loadLibrary == nullptr) || (data.getProcAddress == nullptr) || + (data.getLastError == nullptr)) { throw windows_error("failed to determine address for required functions"); } } else { @@ -269,14 +268,15 @@ REGWORD WriteInjectionStub(HANDLE processHandle // allocate memory in the target process and write the data-block there LPVOID remoteMem = VirtualAllocEx(processHandle, nullptr, totalSize, - MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (remoteMem == nullptr) { throw windows_error("failed to allocate memory in target process"); } SIZE_T written; - if (!WriteProcessMemory(processHandle, remoteMem, &data, sizeof(TDataRemote), &written)) { + if (!WriteProcessMemory(processHandle, remoteMem, &data, sizeof(TDataRemote), + &written)) { throw windows_error("failed to write control data to target process"); } if (written != sizeof(TDataRemote)) { @@ -286,7 +286,7 @@ REGWORD WriteInjectionStub(HANDLE processHandle // write user data to remote memory if necessary if (userData != nullptr) { if (!WriteProcessMemory(processHandle, AddrAdd(remoteMem, sizeof(TDataRemote)), - userData, userDataSize, &written)) { + userData, userDataSize, &written)) { throw windows_error("failed to write user data to target process"); } if (written != userDataSize) { @@ -294,9 +294,10 @@ REGWORD WriteInjectionStub(HANDLE processHandle } } - TDataRemote *remoteData = reinterpret_cast(remoteMem); + TDataRemote* remoteData = reinterpret_cast(remoteMem); - // now for the interesting part: write a stub into the target process that is run before any code of the original binary. + // now for the interesting part: write a stub into the target process that is run + // before any code of the original binary. JitRuntime runtime; #if BOOST_ARCH_X86_64 @@ -306,7 +307,8 @@ REGWORD WriteInjectionStub(HANDLE processHandle // (this damages rax which hopefully doesn't matter) assembler.mov(rax, imm((intptr_t)(void*)data.returnAddress)); assembler.push(rax); - } // otherwise no return address was specified here. It better be on the stack already + } // otherwise no return address was specified here. It better be on the stack + // already #else X86Assembler assembler(&runtime); if (returnAddress != 0) { @@ -320,16 +322,16 @@ REGWORD WriteInjectionStub(HANDLE processHandle size_t stubSize = assembler.getCodeSize(); // reserve memory for the stub - PBYTE stubRemote = reinterpret_cast(VirtualAllocEx(processHandle, nullptr, - stubSize, - MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)); + PBYTE stubRemote = reinterpret_cast( + VirtualAllocEx(processHandle, nullptr, stubSize, MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE)); if (stubRemote == nullptr) { throw windows_error("failed to allocate memory for stub"); } // almost there. copy stub to target process - if (!WriteProcessMemory(processHandle, stubRemote, assembler.getBuffer(), - stubSize, &written) || + if (!WriteProcessMemory(processHandle, stubRemote, assembler.getBuffer(), stubSize, + &written) || (written != stubSize)) { throw windows_error("failed to write stub to target process"); } @@ -337,17 +339,13 @@ REGWORD WriteInjectionStub(HANDLE processHandle return reinterpret_cast(stubRemote); } - -void InjectDLLEIP(HANDLE processHandle - , HANDLE threadHandle - , LPCWSTR dllName - , LPCSTR initFunction - , LPCVOID userData - , size_t userDataSize - , bool skipInit) +void InjectDLLEIP(HANDLE processHandle, HANDLE threadHandle, LPCWSTR dllName, + LPCSTR initFunction, LPCVOID userData, size_t userDataSize, + bool skipInit) { - threadHandle = OpenThread((THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME), - FALSE, GetThreadId(threadHandle)); + threadHandle = + OpenThread((THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME), + FALSE, GetThreadId(threadHandle)); if (threadHandle == nullptr) { throw windows_error("failed to open thread"); @@ -359,10 +357,10 @@ void InjectDLLEIP(HANDLE processHandle // documentation says starting with Win7 SP1 you HAVE to call SetXStateFeaturesMask HMODULE k32mod = ::LoadLibrary(__TEXT("kernel32.dll")); if (k32mod == nullptr) { - throw windows_error("failed to load kernel32.dll"); + throw windows_error("failed to load kernel32.dll"); } - TSetXStateFeaturesMaskType sxsfm = - reinterpret_cast(GetProcAddress(k32mod, "SetXStateFeaturesMask")); + TSetXStateFeaturesMaskType sxsfm = reinterpret_cast( + GetProcAddress(k32mod, "SetXStateFeaturesMask")); if (sxsfm != nullptr) { sxsfm(&threadContext, 0); } @@ -378,13 +376,9 @@ void InjectDLLEIP(HANDLE processHandle REGWORD returnAddress = threadContext.Eip; #endif - REGWORD stubAddress = WriteInjectionStub(processHandle - , dllName - , initFunction - , userData - , userDataSize - , skipInit - , returnAddress); + REGWORD stubAddress = + WriteInjectionStub(processHandle, dllName, initFunction, userData, userDataSize, + skipInit, returnAddress); // make the stub the new next thing for the thread to execute #if BOOST_ARCH_X86_64 @@ -398,59 +392,48 @@ void InjectDLLEIP(HANDLE processHandle } } - -void InjectDLLRemoteThread(HANDLE processHandle - , LPCWSTR dllName - , LPCSTR initFunction - , LPCVOID userData - , size_t userDataSize - , bool skipInit) +void InjectDLLRemoteThread(HANDLE processHandle, LPCWSTR dllName, LPCSTR initFunction, + LPCVOID userData, size_t userDataSize, bool skipInit) { - REGWORD stubAddress = WriteInjectionStub(processHandle - , dllName - , initFunction - , userData - , userDataSize - , skipInit - , 0); + REGWORD stubAddress = WriteInjectionStub(processHandle, dllName, initFunction, + userData, userDataSize, skipInit, 0); - DWORD threadId = 0UL; - HANDLE threadHandle = CreateRemoteThread(processHandle, nullptr, 0, - reinterpret_cast(stubAddress), - nullptr, 0, &threadId); + DWORD threadId = 0UL; + HANDLE threadHandle = CreateRemoteThread( + processHandle, nullptr, 0, reinterpret_cast(stubAddress), + nullptr, 0, &threadId); if (threadHandle == nullptr) { throw windows_error("failed to start remote thread"); } ResumeThread(threadHandle); - spdlog::get("usvfs")->info("waiting for {0:x} to complete", GetThreadId(threadHandle)); + spdlog::get("usvfs")->info("waiting for {0:x} to complete", + GetThreadId(threadHandle)); ::WaitForSingleObject(threadHandle, 100); ::CloseHandle(threadHandle); } -void InjectLib::InjectDLL(HANDLE processHandle - , HANDLE threadHandle - , LPCWSTR dllName - , LPCSTR initFunction - , LPCVOID userData - , size_t userDataSize - , bool skipInit) +void InjectLib::InjectDLL(HANDLE processHandle, HANDLE threadHandle, LPCWSTR dllName, + LPCSTR initFunction, LPCVOID userData, size_t userDataSize, + bool skipInit) { namespace bfs = boost::filesystem; if (!exists(bfs::path(dllName))) { - USVFS_THROW_EXCEPTION(file_not_found_error() << ex_msg(string_cast(dllName))); + USVFS_THROW_EXCEPTION(file_not_found_error() + << ex_msg(string_cast(dllName))); } if (threadHandle == INVALID_HANDLE_VALUE) { -#pragma message ("doesn't seem to work as usvfs causes an exception in the first static initialization or pretty much on any function call. Because process is in different session? CRT related?") +#pragma message( \ + "doesn't seem to work as usvfs causes an exception in the first static initialization or pretty much on any function call. Because process is in different session? CRT related?") /* InjectDLLRemoteThread(processHandle, dllName, initFunction, userData, userDataSize, skipInit); */ - DWORD pid = GetProcessId(processHandle); + DWORD pid = GetProcessId(processHandle); HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); - THREADENTRY32 threadInfo; + THREADENTRY32 threadInfo; threadInfo.dwSize = sizeof(THREADENTRY32); - BOOL moreThreads = Thread32First(snapshot, &threadInfo); + BOOL moreThreads = Thread32First(snapshot, &threadInfo); std::vector threadHandles; HANDLE injectThread = INVALID_HANDLE_VALUE; FILETIME injectThreadTime; @@ -460,27 +443,28 @@ void InjectLib::InjectDLL(HANDLE processHandle HANDLE thread = ::OpenThread(THREAD_ALL_ACCESS, FALSE, threadInfo.th32ThreadID); if (thread != nullptr) { - DWORD suspCount = SuspendThread(thread); - if (suspCount == 0) { - FILETIME creationTime, exitTime, kernelTime, userTime; - ::GetThreadTimes(thread, &creationTime, &exitTime, &kernelTime, &userTime); + DWORD suspCount = SuspendThread(thread); + if (suspCount == 0) { + FILETIME creationTime, exitTime, kernelTime, userTime; + ::GetThreadTimes(thread, &creationTime, &exitTime, &kernelTime, &userTime); - if ((injectThread == INVALID_HANDLE_VALUE) - || (CompareFileTime(&creationTime, &injectThreadTime) < 0)) { - spdlog::get("usvfs")->info("candidate for oldest thread: {0}", threadInfo.th32ThreadID); - injectThread = thread; - injectThreadTime = creationTime; - } + if ((injectThread == INVALID_HANDLE_VALUE) || + (CompareFileTime(&creationTime, &injectThreadTime) < 0)) { + spdlog::get("usvfs")->info("candidate for oldest thread: {0}", + threadInfo.th32ThreadID); + injectThread = thread; + injectThreadTime = creationTime; } - threadHandles.push_back(thread); + } + threadHandles.push_back(thread); } } moreThreads = Thread32Next(snapshot, &threadInfo); } if (injectThread != INVALID_HANDLE_VALUE) { spdlog::get("usvfs")->debug("going to inject dll"); - InjectDLLEIP(processHandle, injectThread, dllName, - initFunction, userData, userDataSize, skipInit); + InjectDLLEIP(processHandle, injectThread, dllName, initFunction, userData, + userDataSize, skipInit); } else { spdlog::get("usvfs")->critical("found no thread to use for injecting"); } @@ -492,7 +476,7 @@ void InjectLib::InjectDLL(HANDLE processHandle } CloseHandle(snapshot); } else { - InjectDLLEIP(processHandle, threadHandle, dllName, - initFunction, userData, userDataSize, skipInit); + InjectDLLEIP(processHandle, threadHandle, dllName, initFunction, userData, + userDataSize, skipInit); } } diff --git a/src/tinjectlib/injectlib.h b/src/tinjectlib/injectlib.h index fc267c8..f165667 100644 --- a/src/tinjectlib/injectlib.h +++ b/src/tinjectlib/injectlib.h @@ -22,33 +22,29 @@ along with usvfs. If not, see . #include - -namespace InjectLib { +namespace InjectLib +{ /** * @brief inject a dll into the target process * @param processHandle handle of the process to inject to * @param threadHandle handle of the main thread in the process - * @param dllname name/path of the dll to inject. The path can't be longer than MAX_PATH characters - * @param initFunction name of the initialization function. Can't be longer than 20 characters. - * If this is null, no function is called. - * Important: the init function has to exist, be exported, take the two userdata parameters - * and must be __cdecl calling convention on 32bit windows! - * Failing any of these the target process will crash or the dll isn't loaded - * Why __cdecl? Because otherwise we would need .def files to export the init function - * with a GetProcAddress-able function name. + * @param dllname name/path of the dll to inject. The path can't be longer than MAX_PATH + * characters + * @param initFunction name of the initialization function. Can't be longer than 20 + * characters. If this is null, no function is called. Important: the init function has + * to exist, be exported, take the two userdata parameters and must be __cdecl calling + * convention on 32bit windows! Failing any of these the target process will crash or + * the dll isn't loaded Why __cdecl? Because otherwise we would need .def files to + * export the init function with a GetProcAddress-able function name. * @param userData data passed to the init function * @param userDataSize size of the data to be passed - * @param skipInit skip the call to the init function if the named function wasn't found in the - * dll. If false, the target process will crash if the function isn't exported - * in the dll + * @param skipInit skip the call to the init function if the named function wasn't found + * in the dll. If false, the target process will crash if the function isn't exported in + * the dll */ -void InjectDLL(HANDLE processHandle - , HANDLE threadHandle - , LPCWSTR dllName - , LPCSTR initFunction = nullptr - , LPCVOID userData = nullptr - , size_t userDataSize = 0 - , bool skipInit = false); +void InjectDLL(HANDLE processHandle, HANDLE threadHandle, LPCWSTR dllName, + LPCSTR initFunction = nullptr, LPCVOID userData = nullptr, + size_t userDataSize = 0, bool skipInit = false); -} +} // namespace InjectLib diff --git a/src/usvfs_dll/hookcallcontext.cpp b/src/usvfs_dll/hookcallcontext.cpp index 950f01d..32510c9 100644 --- a/src/usvfs_dll/hookcallcontext.cpp +++ b/src/usvfs_dll/hookcallcontext.cpp @@ -19,15 +19,17 @@ You should have received a copy of the GNU General Public License along with usvfs. If not, see . */ #include "hookcallcontext.h" -#include #include "hookcontext.h" +#include namespace usvfs { -class HookStack { +class HookStack +{ public: - static HookStack &instance() { + static HookStack& instance() + { PreserveGetLastError boostChangesGetLastError; if (s_Instance.get() == nullptr) { s_Instance.reset(new HookStack()); @@ -35,9 +37,10 @@ public: return *s_Instance.get(); } - bool setGroup(MutExHookGroup group) { - if (m_ActiveGroups.test(static_cast(group)) - || m_ActiveGroups.test(static_cast(MutExHookGroup::ALL_GROUPS))) { + bool setGroup(MutExHookGroup group) + { + if (m_ActiveGroups.test(static_cast(group)) || + m_ActiveGroups.test(static_cast(MutExHookGroup::ALL_GROUPS))) { return false; } else { m_ActiveGroups.set(static_cast(group), true); @@ -45,15 +48,13 @@ public: } } - void unsetGroup(MutExHookGroup group) { + void unsetGroup(MutExHookGroup group) + { m_ActiveGroups.set(static_cast(group), false); } private: - - HookStack() { - - } + HookStack() {} private: static boost::thread_specific_ptr s_Instance; @@ -62,22 +63,17 @@ private: boost::thread_specific_ptr HookStack::s_Instance; - -HookCallContext::HookCallContext() - : m_Active(true) - , m_Group(MutExHookGroup::NO_GROUP) +HookCallContext::HookCallContext() : m_Active(true), m_Group(MutExHookGroup::NO_GROUP) { updateLastError(); } HookCallContext::HookCallContext(MutExHookGroup group) - : m_Active(HookStack::instance().setGroup(group)) - , m_Group(group) + : m_Active(HookStack::instance().setGroup(group)), m_Group(group) { updateLastError(); } - HookCallContext::~HookCallContext() { if (m_Active && (m_Group != MutExHookGroup::NO_GROUP)) { @@ -96,22 +92,21 @@ void HookCallContext::updateLastError(DWORD lastError) m_LastError = lastError; } - bool HookCallContext::active() const { return m_Active; } -FunctionGroupLock::FunctionGroupLock(MutExHookGroup group) - : m_Group(group) +FunctionGroupLock::FunctionGroupLock(MutExHookGroup group) : m_Group(group) { m_Active = HookStack::instance().setGroup(m_Group); } -FunctionGroupLock::~FunctionGroupLock() { +FunctionGroupLock::~FunctionGroupLock() +{ if (m_Active) { HookStack::instance().unsetGroup(m_Group); } } -} // namespace usvfs +} // namespace usvfs diff --git a/src/usvfs_dll/hookcallcontext.h b/src/usvfs_dll/hookcallcontext.h index faedda5..ebb3bf9 100644 --- a/src/usvfs_dll/hookcallcontext.h +++ b/src/usvfs_dll/hookcallcontext.h @@ -24,39 +24,40 @@ namespace usvfs { /** - * @brief groups of hooks which may be used to implement each other, so only the first call should be - * to one should be manipulated + * @brief groups of hooks which may be used to implement each other, so only the first + * call should be to one should be manipulated */ -enum class MutExHookGroup : int { - ALL_GROUPS = 0, // An ALL_GROUPS-hook prevents all other hooks from becoming active BUT - // hooks from other groups don't prevent the ALL_GROUPS-hook from becoming activated - OPEN_FILE = 1, - CREATE_PROCESS = 2, - FILE_ATTRIBUTES = 3, - FIND_FILES = 4, - LOAD_LIBRARY = 5, - FULL_PATHNAME = 6, - SHELL_FILEOP = 7, - DELETE_FILE = 8, - GET_FILE_VERSION = 9, +enum class MutExHookGroup : int +{ + ALL_GROUPS = 0, // An ALL_GROUPS-hook prevents all other hooks from becoming active + // BUT hooks from other groups don't prevent the ALL_GROUPS-hook from + // becoming activated + OPEN_FILE = 1, + CREATE_PROCESS = 2, + FILE_ATTRIBUTES = 3, + FIND_FILES = 4, + LOAD_LIBRARY = 5, + FULL_PATHNAME = 6, + SHELL_FILEOP = 7, + DELETE_FILE = 8, + GET_FILE_VERSION = 9, GET_MODULE_HANDLE = 10, - SEARCH_FILES = 11, + SEARCH_FILES = 11, NO_GROUP = 12, - LAST = NO_GROUP, + LAST = NO_GROUP, }; - -class HookCallContext { +class HookCallContext +{ public: - HookCallContext(); HookCallContext(MutExHookGroup group); ~HookCallContext(); - HookCallContext(const HookCallContext &reference) = delete; - HookCallContext &operator=(const HookCallContext &reference) = delete; + HookCallContext(const HookCallContext& reference) = delete; + HookCallContext& operator=(const HookCallContext& reference) = delete; void restoreLastError(); @@ -67,20 +68,20 @@ public: bool active() const; private: - DWORD m_LastError; bool m_Active; MutExHookGroup m_Group; - }; -class FunctionGroupLock { +class FunctionGroupLock +{ public: FunctionGroupLock(MutExHookGroup group); ~FunctionGroupLock(); + private: MutExHookGroup m_Group; bool m_Active; }; -} // namespace usvfs +} // namespace usvfs diff --git a/src/usvfs_dll/hookcontext.cpp b/src/usvfs_dll/hookcontext.cpp index 0a75faa..eba1d36 100644 --- a/src/usvfs_dll/hookcontext.cpp +++ b/src/usvfs_dll/hookcontext.cpp @@ -20,13 +20,13 @@ along with usvfs. If not, see . */ #include "hookcontext.h" #include "exceptionex.h" -#include "usvfs.h" #include "hookcallcontext.h" -#include +#include "loghelpers.h" +#include "usvfs.h" +#include #include #include -#include -#include "loghelpers.h" +#include namespace bi = boost::interprocess; using usvfs::shared::SharedMemoryT; @@ -35,10 +35,9 @@ using usvfs::shared::VoidAllocatorT; using namespace usvfs; namespace ush = usvfs::shared; -HookContext *HookContext::s_Instance = nullptr; +HookContext* HookContext::s_Instance = nullptr; - -void printBuffer(const char *buffer, size_t size) +void printBuffer(const char* buffer, size_t size) { static const int bufferSize = 16 * 3; char temp[bufferSize + 1]; @@ -55,15 +54,18 @@ void printBuffer(const char *buffer, size_t size) spdlog::get("hooks")->info(temp); } - - HookContext::HookContext(const usvfsParameters& params, HMODULE module) - : m_ConfigurationSHM(bi::open_or_create, params.instanceName, 64 * 1024) - , m_Parameters(retrieveParameters(params)) - , m_Tree(m_Parameters->currentSHMName(), 4 * 1024 * 1024) // 4 MiB empirically covers most small setups without need to resize - , m_InverseTree(m_Parameters->currentInverseSHMName(), 128 * 1024) // 128 KiB should cover reverse tree for even larger setups - , m_DebugMode(params.debugMode) - , m_DLLModule(module) + : m_ConfigurationSHM(bi::open_or_create, params.instanceName, 64 * 1024), + m_Parameters(retrieveParameters(params)), + m_Tree(m_Parameters->currentSHMName(), + 4 * 1024 * 1024) // 4 MiB empirically covers most small setups without + // need to resize + , + m_InverseTree( + m_Parameters->currentInverseSHMName(), + 128 * 1024) // 128 KiB should cover reverse tree for even larger setups + , + m_DebugMode(params.debugMode), m_DLLModule(module) { if (s_Instance != nullptr) { throw std::runtime_error("singleton duplicate instantiation (HookContext)"); @@ -71,19 +73,18 @@ HookContext::HookContext(const usvfsParameters& params, HMODULE module) const auto userCount = m_Parameters->userConnected(); - spdlog::get("usvfs")->debug( - "context current shm: {0} (now {1} connections)", - m_Parameters->currentSHMName(), userCount); + spdlog::get("usvfs")->debug("context current shm: {0} (now {1} connections)", + m_Parameters->currentSHMName(), userCount); s_Instance = this; if (m_Tree.get() == nullptr) { - USVFS_THROW_EXCEPTION(usage_error() << ex_msg("shm not found") - << ex_msg(params.instanceName)); + USVFS_THROW_EXCEPTION(usage_error() + << ex_msg("shm not found") << ex_msg(params.instanceName)); } } -void HookContext::remove(const char *instanceName) +void HookContext::remove(const char* instanceName) { bi::shared_memory_object::remove(instanceName); } @@ -92,7 +93,7 @@ HookContext::~HookContext() { spdlog::get("usvfs")->info("releasing hook context"); - s_Instance = nullptr; + s_Instance = nullptr; const auto userCount = m_Parameters->userDisconnected(); if (userCount == 0) { @@ -103,10 +104,10 @@ HookContext::~HookContext() } } -SharedParameters *HookContext::retrieveParameters(const usvfsParameters& params) +SharedParameters* HookContext::retrieveParameters(const usvfsParameters& params) { - std::pair res - = m_ConfigurationSHM.find("parameters"); + std::pair res = + m_ConfigurationSHM.find("parameters"); if (res.first == nullptr) { // not configured yet @@ -119,12 +120,10 @@ SharedParameters *HookContext::retrieveParameters(const usvfsParameters& params) USVFS_THROW_EXCEPTION(bi::bad_alloc()); } } else { - spdlog::get("usvfs")->info( - "access existing config in {}", ::GetCurrentProcessId()); + spdlog::get("usvfs")->info("access existing config in {}", ::GetCurrentProcessId()); } - spdlog::get("usvfs")->info( - "{} processes", res.first->registeredProcessCount()); + spdlog::get("usvfs")->info("{} processes", res.first->registeredProcessCount()); return res.first; } @@ -146,10 +145,9 @@ HookContext::Ptr HookContext::writeAccess(const char*) return Ptr(s_Instance, unlock); } - -void HookContext::setDebugParameters( - LogLevel level, CrashDumpsType dumpType, const std::string& dumpPath, - std::chrono::milliseconds delayProcess) +void HookContext::setDebugParameters(LogLevel level, CrashDumpsType dumpType, + const std::string& dumpPath, + std::chrono::milliseconds delayProcess) { m_Parameters->setDebugParameters(level, dumpType, dumpPath, delayProcess); } @@ -188,8 +186,7 @@ std::vector HookContext::registeredProcesses() const void HookContext::blacklistExecutable(const std::wstring& wexe) { - const auto exe = shared::string_cast( - wexe, shared::CodePage::UTF8); + const auto exe = shared::string_cast(wexe, shared::CodePage::UTF8); spdlog::get("usvfs")->debug("blacklisting '{}'", exe); m_Parameters->blacklistExecutable(exe); @@ -216,9 +213,10 @@ BOOL HookContext::executableBlacklisted(LPCWSTR wapp, LPCWSTR wcmd) const return m_Parameters->executableBlacklisted(app, cmd); } -void usvfs::HookContext::addSkipFileSuffix(const std::wstring& fileSuffix) +void usvfs::HookContext::addSkipFileSuffix(const std::wstring& fileSuffix) { - const auto fsuffix = shared::string_cast(fileSuffix, shared::CodePage::UTF8); + const auto fsuffix = + shared::string_cast(fileSuffix, shared::CodePage::UTF8); if (fsuffix.empty()) { return; @@ -228,7 +226,7 @@ void usvfs::HookContext::addSkipFileSuffix(const std::wstring& fileSuffix) m_Parameters->addSkipFileSuffix(fsuffix); } -void usvfs::HookContext::clearSkipFileSuffixes() +void usvfs::HookContext::clearSkipFileSuffixes() { spdlog::get("usvfs")->debug("clearing skip file suffixes"); m_Parameters->clearSkipFileSuffixes(); @@ -239,7 +237,7 @@ std::vector usvfs::HookContext::skipFileSuffixes() const return m_Parameters->skipFileSuffixes(); } -void usvfs::HookContext::addSkipDirectory(const std::wstring& directory) +void usvfs::HookContext::addSkipDirectory(const std::wstring& directory) { const auto dir = shared::string_cast(directory, shared::CodePage::UTF8); @@ -251,7 +249,7 @@ void usvfs::HookContext::addSkipDirectory(const std::wstring& directory) m_Parameters->addSkipDirectory(dir); } -void usvfs::HookContext::clearSkipDirectories() +void usvfs::HookContext::clearSkipDirectories() { spdlog::get("usvfs")->debug("clearing skip directories"); m_Parameters->clearSkipDirectories(); @@ -262,17 +260,16 @@ std::vector usvfs::HookContext::skipDirectories() const return m_Parameters->skipDirectories(); } -void HookContext::forceLoadLibrary( - const std::wstring& wprocess, const std::wstring& wpath) +void HookContext::forceLoadLibrary(const std::wstring& wprocess, + const std::wstring& wpath) { - const auto process = shared::string_cast( - wprocess, shared::CodePage::UTF8); + const auto process = + shared::string_cast(wprocess, shared::CodePage::UTF8); - const auto path = shared::string_cast( - wpath, shared::CodePage::UTF8); + const auto path = shared::string_cast(wpath, shared::CodePage::UTF8); - spdlog::get("usvfs")->debug( - "adding forced library '{}' for process '{}'", path, process); + spdlog::get("usvfs")->debug("adding forced library '{}' for process '{}'", path, + process); m_Parameters->addForcedLibrary(process, path); } @@ -283,10 +280,11 @@ void HookContext::clearLibraryForceLoads() m_Parameters->clearForcedLibraries(); } -std::vector HookContext::librariesToForceLoad(const std::wstring &processName) +std::vector +HookContext::librariesToForceLoad(const std::wstring& processName) { const auto v = m_Parameters->forcedLibraries( - shared::string_cast(processName, shared::CodePage::UTF8)); + shared::string_cast(processName, shared::CodePage::UTF8)); std::vector wv; for (const auto& s : v) { @@ -301,33 +299,32 @@ void HookContext::registerDelayed(std::future delayed) m_Futures.push_back(std::move(delayed)); } -std::vector> &HookContext::delayed() +std::vector>& HookContext::delayed() { return m_Futures; } -void HookContext::unlock(HookContext *instance) +void HookContext::unlock(HookContext* instance) { instance->m_Mutex.signal(); } -void HookContext::unlockShared(const HookContext *instance) +void HookContext::unlockShared(const HookContext* instance) { instance->m_Mutex.signal(); } - // deprecated // -extern "C" DLLEXPORT HookContext *__cdecl CreateHookContext( - const USVFSParameters &oldParams, HMODULE module) +extern "C" DLLEXPORT HookContext* __cdecl CreateHookContext( + const USVFSParameters& oldParams, HMODULE module) { const usvfsParameters p(oldParams); return usvfsCreateHookContext(p, module); } -extern "C" DLLEXPORT usvfs::HookContext* WINAPI usvfsCreateHookContext( - const usvfsParameters& params, HMODULE module) +extern "C" DLLEXPORT usvfs::HookContext* WINAPI +usvfsCreateHookContext(const usvfsParameters& params, HMODULE module) { return new HookContext(params, module); } diff --git a/src/usvfs_dll/hookcontext.h b/src/usvfs_dll/hookcontext.h index b04af95..d3dac89 100644 --- a/src/usvfs_dll/hookcontext.h +++ b/src/usvfs_dll/hookcontext.h @@ -20,14 +20,14 @@ along with usvfs. If not, see . */ #pragma once -#include "redirectiontree.h" -#include "tree_container.h" #include "dllimport.h" +#include "redirectiontree.h" #include "semaphore.h" -#include -#include +#include "tree_container.h" #include #include +#include +#include #include namespace usvfs @@ -43,61 +43,48 @@ class HookContext { public: - typedef std::unique_ptr - ConstPtr; - typedef std::unique_ptr Ptr; + typedef std::unique_ptr ConstPtr; + typedef std::unique_ptr Ptr; typedef unsigned int DataIDT; public: HookContext(const usvfsParameters& params, HMODULE module); - HookContext(const HookContext &reference) = delete; + HookContext(const HookContext& reference) = delete; DLLEXPORT ~HookContext(); - HookContext &operator=(const HookContext &reference) = delete; + HookContext& operator=(const HookContext& reference) = delete; - static void remove(const char *instance); + static void remove(const char* instance); /** * @brief get read access to the context. * @return smart ptr to the context. mutex will automatically be released when * this leaves scope */ - static ConstPtr readAccess(const char *source); + static ConstPtr readAccess(const char* source); /** * @brief get write access to the context. * @return smart ptr to the context. mutex will automatically be released when * this leaves scope */ - static Ptr writeAccess(const char *source); + static Ptr writeAccess(const char* source); /** * @return table containing file redirection information */ - RedirectionTreeContainer &redirectionTable() - { - return m_Tree; - } + RedirectionTreeContainer& redirectionTable() { return m_Tree; } /** * @return table containing file redirection information */ - const RedirectionTreeContainer &redirectionTable() const - { - return m_Tree; - } + const RedirectionTreeContainer& redirectionTable() const { return m_Tree; } - RedirectionTreeContainer &inverseTable() - { - return m_InverseTree; - } + RedirectionTreeContainer& inverseTable() { return m_InverseTree; } - const RedirectionTreeContainer &inverseTable() const - { - return m_InverseTree; - } + const RedirectionTreeContainer& inverseTable() const { return m_InverseTree; } /** * @return the parameters passed in on dll initialisation @@ -107,10 +94,7 @@ public: /** * @return true if usvfs is running in debug mode */ - bool debugMode() const - { - return m_DebugMode; - } + bool debugMode() const { return m_DebugMode; } /** * @return path to the calling library itself @@ -123,7 +107,8 @@ public: * the context * as a whole. The caller himself has to ensure thread safety */ - template T &customData(DataIDT id) const + template + T& customData(DataIDT id) const { auto iter = m_CustomData.find(id); if (iter == m_CustomData.end()) { @@ -132,7 +117,7 @@ public: // std::map is supposed to not invalidate any iterators when elements are // added // so it should be safe to return a pointer here - T *res = boost::any_cast(&iter->second); + T* res = boost::any_cast(&iter->second); return *res; } @@ -140,7 +125,7 @@ public: void unregisterCurrentProcess(); std::vector registeredProcesses() const; - void blacklistExecutable(const std::wstring &executableName); + void blacklistExecutable(const std::wstring& executableName); void clearExecutableBlacklist(); BOOL executableBlacklisted(LPCWSTR lpApplicationName, LPCWSTR lpCommandLine) const; @@ -150,33 +135,34 @@ public: void addSkipDirectory(const std::wstring& directory); void clearSkipDirectories(); - std::vector skipDirectories () const; + std::vector skipDirectories() const; - void forceLoadLibrary(const std::wstring &processName, const std::wstring &libraryPath); + void forceLoadLibrary(const std::wstring& processName, + const std::wstring& libraryPath); void clearLibraryForceLoads(); - std::vector librariesToForceLoad(const std::wstring &processName); + std::vector librariesToForceLoad(const std::wstring& processName); - void setDebugParameters( - LogLevel level, CrashDumpsType dumpType, const std::string& dumpPath, - std::chrono::milliseconds delayProcess); + void setDebugParameters(LogLevel level, CrashDumpsType dumpType, + const std::string& dumpPath, + std::chrono::milliseconds delayProcess); void updateParameters() const; void registerDelayed(std::future delayed); - std::vector> &delayed(); + std::vector>& delayed(); private: - static void unlock(HookContext *instance); - static void unlockShared(const HookContext *instance); + static void unlock(HookContext* instance); + static void unlockShared(const HookContext* instance); SharedParameters* retrieveParameters(const usvfsParameters& params); private: - static HookContext *s_Instance; + static HookContext* s_Instance; shared::SharedMemoryT m_ConfigurationSHM; - SharedParameters *m_Parameters{nullptr}; + SharedParameters* m_Parameters{nullptr}; RedirectionTreeContainer m_Tree; RedirectionTreeContainer m_InverseTree; @@ -192,25 +178,23 @@ private: mutable RecursiveBenaphore m_Mutex; }; -} // namespace - - -extern "C" DLLEXPORT usvfs::HookContext* WINAPI usvfsCreateHookContext( - const usvfsParameters& params, HMODULE module); +} // namespace usvfs +extern "C" DLLEXPORT usvfs::HookContext* WINAPI +usvfsCreateHookContext(const usvfsParameters& params, HMODULE module); class PreserveGetLastError { public: PreserveGetLastError() : m_err(GetLastError()) {} ~PreserveGetLastError() { SetLastError(m_err); } + private: DWORD m_err; }; // declare an identifier that is guaranteed to be unique across the application -#define DATA_ID(name) \ - static const usvfs::HookContext::DataIDT name = __COUNTER__ +#define DATA_ID(name) static const usvfs::HookContext::DataIDT name = __COUNTER__ // set of macros. These ensure a call context is created but most of all these // ensure exceptions are caught. @@ -218,30 +202,29 @@ private: #define READ_CONTEXT() HookContext::readAccess(__MYFUNC__) #define WRITE_CONTEXT() HookContext::writeAccess(__MYFUNC__) -#define HOOK_START_GROUP(group) \ - try { \ +#define HOOK_START_GROUP(group) \ + try { \ HookCallContext callContext(group); -#define HOOK_START \ - try { \ +#define HOOK_START \ + try { \ HookCallContext callContext; -#define HOOK_END \ - } \ - catch (const std::exception &e) \ - { \ - spdlog::get("usvfs") \ - ->error("exception in {0}: {1}", __MYFUNC__, e.what()); \ - logExtInfo(e); \ +#define HOOK_END \ + } \ + catch (const std::exception& e) \ + { \ + spdlog::get("usvfs")->error("exception in {0}: {1}", __MYFUNC__, e.what()); \ + logExtInfo(e); \ } -#define HOOK_ENDP(param) \ - } \ - catch (const std::exception &e) \ - { \ - spdlog::get("usvfs") \ - ->error("exception in {0} ({1}): {2}", __MYFUNC__, param, e.what()); \ - logExtInfo(e); \ +#define HOOK_ENDP(param) \ + } \ + catch (const std::exception& e) \ + { \ + spdlog::get("usvfs")->error("exception in {0} ({1}): {2}", __MYFUNC__, param, \ + e.what()); \ + logExtInfo(e); \ } #define PRE_REALCALL callContext.restoreLastError(); diff --git a/src/usvfs_dll/hookmanager.cpp b/src/usvfs_dll/hookmanager.cpp index 4083fb4..b0e2902 100644 --- a/src/usvfs_dll/hookmanager.cpp +++ b/src/usvfs_dll/hookmanager.cpp @@ -19,18 +19,18 @@ You should have received a copy of the GNU General Public License along with usvfs. If not, see . */ #include "hookmanager.h" -#include "hooks/ntdll.h" -#include "hooks/kernel32.h" -#include "exceptionex.h" -#include "usvfs.h" -#include "../thooklib/utility.h" #include "../thooklib/ttrampolinepool.h" -#include -#include +#include "../thooklib/utility.h" +#include "exceptionex.h" +#include "hooks/kernel32.h" +#include "hooks/ntdll.h" +#include "usvfs.h" +#include #include +#include +#include #include #include -#include using namespace HookLib; namespace bf = boost::filesystem; @@ -38,11 +38,10 @@ namespace bf = boost::filesystem; namespace usvfs { -HookManager *HookManager::s_Instance = nullptr; - +HookManager* HookManager::s_Instance = nullptr; HookManager::HookManager(const usvfsParameters& params, HMODULE module) - : m_Context(params, module) + : m_Context(params, module) { if (s_Instance != nullptr) { throw std::runtime_error("singleton duplicate instantiation (HookManager)"); @@ -51,12 +50,15 @@ HookManager::HookManager(const usvfsParameters& params, HMODULE module) s_Instance = this; m_Context.registerProcess(::GetCurrentProcessId()); - spdlog::get("usvfs")->info("Process registered in shared process list : {}",::GetCurrentProcessId()); + spdlog::get("usvfs")->info("Process registered in shared process list : {}", + ::GetCurrentProcessId()); winapi::ex::OSVersion version = winapi::ex::getOSVersion(); - spdlog::get("usvfs")->info("Windows version {}.{}.{} sp {} platform {} ({})", - version.major, version.minor, version.build, version.servicpack, version.platformid, - shared::string_cast(winapi::ex::wide::getWindowsBuildLab(true)).c_str()); + spdlog::get("usvfs")->info( + "Windows version {}.{}.{} sp {} platform {} ({})", version.major, version.minor, + version.build, version.servicpack, version.platformid, + shared::string_cast(winapi::ex::wide::getWindowsBuildLab(true)) + .c_str()); initHooks(); @@ -72,7 +74,7 @@ HookManager::~HookManager() m_Context.unregisterCurrentProcess(); } -HookManager &HookManager::instance() +HookManager& HookManager::instance() { if (s_Instance == nullptr) { throw std::runtime_error("singleton not instantiated"); @@ -81,7 +83,7 @@ HookManager &HookManager::instance() return *s_Instance; } -LPVOID HookManager::detour(const char *functionName) +LPVOID HookManager::detour(const char* functionName) { auto iter = m_Hooks.find(functionName); if (iter != m_Hooks.end()) { @@ -91,7 +93,7 @@ LPVOID HookManager::detour(const char *functionName) } } -void HookManager::removeHook(const std::string &functionName) +void HookManager::removeHook(const std::string& functionName) { auto iter = m_Hooks.find(functionName); if (iter != m_Hooks.end()) { @@ -99,9 +101,9 @@ void HookManager::removeHook(const std::string &functionName) RemoveHook(iter->second); m_Hooks.erase(iter); spdlog::get("usvfs")->info("removed hook for {}", functionName); - } catch (const std::exception &e) { - spdlog::get("usvfs")->critical("failed to remove hook of {}: {}", - functionName, e.what()); + } catch (const std::exception& e) { + spdlog::get("usvfs")->critical("failed to remove hook of {}: {}", functionName, + e.what()); } } else { spdlog::get("usvfs")->info("{} wasn't hooked", functionName); @@ -121,17 +123,20 @@ void HookManager::logStub(LPVOID address) { try { instance().logStubInt(address); - } catch (const std::exception &e) { - spdlog::get("hooks")->debug("function at {0} called after shutdown: {1}", address, e.what()); + } catch (const std::exception& e) { + spdlog::get("hooks")->debug("function at {0} called after shutdown: {1}", address, + e.what()); } } -void HookManager::installHook(HMODULE module1, HMODULE module2, const std::string &functionName, LPVOID hook, LPVOID* fillFuncAddr = nullptr) +void HookManager::installHook(HMODULE module1, HMODULE module2, + const std::string& functionName, LPVOID hook, + LPVOID* fillFuncAddr = nullptr) { BOOST_ASSERT(hook != nullptr); - HOOKHANDLE handle = INVALID_HOOK; - HookError err = ERR_NONE; - LPVOID funcAddr = nullptr; + HOOKHANDLE handle = INVALID_HOOK; + HookError err = ERR_NONE; + LPVOID funcAddr = nullptr; HMODULE usedModule = nullptr; // both module1 and module2 are allowed to be null if (module1 != nullptr) { @@ -139,7 +144,8 @@ void HookManager::installHook(HMODULE module1, HMODULE module2, const std::strin if (funcAddr != nullptr) { handle = InstallHook(funcAddr, hook, &err); } - if (handle != INVALID_HOOK) usedModule = module1; + if (handle != INVALID_HOOK) + usedModule = module1; } if ((handle == INVALID_HOOK) && (module2 != nullptr)) { @@ -147,29 +153,31 @@ void HookManager::installHook(HMODULE module1, HMODULE module2, const std::strin if (funcAddr != nullptr) { handle = InstallHook(funcAddr, hook, &err); } - if (handle != INVALID_HOOK) usedModule = module2; + if (handle != INVALID_HOOK) + usedModule = module2; } if (fillFuncAddr) *fillFuncAddr = funcAddr; if (handle == INVALID_HOOK) { - spdlog::get("usvfs")->error("failed to hook {0}: {1}", - functionName, GetErrorString(err)); + spdlog::get("usvfs")->error("failed to hook {0}: {1}", functionName, + GetErrorString(err)); } else { m_Stubs.insert(make_pair(funcAddr, functionName)); m_Hooks.insert(make_pair(std::string(functionName), handle)); - spdlog::get("usvfs")->info( - "hooked {0} ({1}) in {2} type {3}", functionName, funcAddr, - winapi::ansi::getModuleFileName(usedModule), GetHookType(handle)); + spdlog::get("usvfs")->info("hooked {0} ({1}) in {2} type {3}", functionName, + funcAddr, winapi::ansi::getModuleFileName(usedModule), + GetHookType(handle)); } } -void HookManager::installStub(HMODULE module1, HMODULE module2, const std::string &functionName) +void HookManager::installStub(HMODULE module1, HMODULE module2, + const std::string& functionName) { - HOOKHANDLE handle = INVALID_HOOK; - HookError err = ERR_NONE; - LPVOID funcAddr = nullptr; + HOOKHANDLE handle = INVALID_HOOK; + HookError err = ERR_NONE; + LPVOID funcAddr = nullptr; HMODULE usedModule = nullptr; // both module1 and module2 are allowed to be null if (module1 != nullptr) { @@ -181,7 +189,8 @@ void HookManager::installStub(HMODULE module1, HMODULE module2, const std::strin winapi::ansi::getModuleFileName(module1), functionName); } - if (handle != INVALID_HOOK) usedModule = module1; + if (handle != INVALID_HOOK) + usedModule = module1; } if ((handle == INVALID_HOOK) && (module2 != nullptr)) { @@ -193,21 +202,22 @@ void HookManager::installStub(HMODULE module1, HMODULE module2, const std::strin winapi::ansi::getModuleFileName(module2), functionName); } - if (handle != INVALID_HOOK) usedModule = module2; + if (handle != INVALID_HOOK) + usedModule = module2; } if (handle == INVALID_HOOK) { - spdlog::get("usvfs")->error("failed to stub {0}: {1}", functionName, GetErrorString(err)); + spdlog::get("usvfs")->error("failed to stub {0}: {1}", functionName, + GetErrorString(err)); } else { m_Stubs.insert(make_pair(funcAddr, functionName)); m_Hooks.insert(make_pair(std::string(functionName), handle)); - spdlog::get("usvfs")->info( - "stubbed {0} ({1}) in {2} type {3}", functionName, funcAddr, - winapi::ansi::getModuleFileName(usedModule), GetHookType(handle)); + spdlog::get("usvfs")->info("stubbed {0} ({1}) in {2} type {3}", functionName, + funcAddr, winapi::ansi::getModuleFileName(usedModule), + GetHookType(handle)); } } - void HookManager::initHooks() { TrampolinePool::initialize(); @@ -215,12 +225,14 @@ void HookManager::initHooks() HookLib::TrampolinePool::instance().setBlock(true); HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); - spdlog::get("usvfs")->debug("kernel32.dll at {0:x}", reinterpret_cast(k32Mod)); + spdlog::get("usvfs")->debug("kernel32.dll at {0:x}", + reinterpret_cast(k32Mod)); // kernelbase.dll contains the actual implementation for functions formerly in // kernel32.dll and advapi32.dll, starting with Windows 7 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd371752(v=vs.85).aspx HMODULE kbaseMod = GetModuleHandleA("kernelbase.dll"); - spdlog::get("usvfs")->debug("kernelbase.dll at {0:x}", reinterpret_cast(kbaseMod)); + spdlog::get("usvfs")->debug("kernelbase.dll at {0:x}", + reinterpret_cast(kbaseMod)); installHook(kbaseMod, k32Mod, "GetFileAttributesExA", hook_GetFileAttributesExA); installHook(kbaseMod, k32Mod, "GetFileAttributesA", hook_GetFileAttributesA); @@ -238,7 +250,8 @@ void HookManager::initHooks() installHook(kbaseMod, k32Mod, "ExitProcess", hook_ExitProcess); - installHook(kbaseMod, k32Mod, "CreateProcessInternalW", hook_CreateProcessInternalW, reinterpret_cast(&CreateProcessInternalW)); + installHook(kbaseMod, k32Mod, "CreateProcessInternalW", hook_CreateProcessInternalW, + reinterpret_cast(&CreateProcessInternalW)); installHook(kbaseMod, k32Mod, "MoveFileA", hook_MoveFileA); installHook(kbaseMod, k32Mod, "MoveFileW", hook_MoveFileW); @@ -249,14 +262,21 @@ void HookManager::initHooks() installHook(kbaseMod, k32Mod, "CopyFileExW", hook_CopyFileExW); if (IsWindows8OrGreater()) - installHook(kbaseMod, k32Mod, "CopyFile2", hook_CopyFile2, reinterpret_cast(&CopyFile2)); + installHook(kbaseMod, k32Mod, "CopyFile2", hook_CopyFile2, + reinterpret_cast(&CopyFile2)); - installHook(kbaseMod, k32Mod, "GetPrivateProfileStringA", hook_GetPrivateProfileStringA); - installHook(kbaseMod, k32Mod, "GetPrivateProfileStringW", hook_GetPrivateProfileStringW); - installHook(kbaseMod, k32Mod, "GetPrivateProfileSectionA", hook_GetPrivateProfileSectionA); - installHook(kbaseMod, k32Mod, "GetPrivateProfileSectionW", hook_GetPrivateProfileSectionW); - installHook(kbaseMod, k32Mod, "WritePrivateProfileStringA", hook_WritePrivateProfileStringA); - installHook(kbaseMod, k32Mod, "WritePrivateProfileStringW", hook_WritePrivateProfileStringW); + installHook(kbaseMod, k32Mod, "GetPrivateProfileStringA", + hook_GetPrivateProfileStringA); + installHook(kbaseMod, k32Mod, "GetPrivateProfileStringW", + hook_GetPrivateProfileStringW); + installHook(kbaseMod, k32Mod, "GetPrivateProfileSectionA", + hook_GetPrivateProfileSectionA); + installHook(kbaseMod, k32Mod, "GetPrivateProfileSectionW", + hook_GetPrivateProfileSectionW); + installHook(kbaseMod, k32Mod, "WritePrivateProfileStringA", + hook_WritePrivateProfileStringA); + installHook(kbaseMod, k32Mod, "WritePrivateProfileStringW", + hook_WritePrivateProfileStringW); installHook(kbaseMod, k32Mod, "GetFullPathNameA", hook_GetFullPathNameA); installHook(kbaseMod, k32Mod, "GetFullPathNameW", hook_GetFullPathNameW); @@ -264,14 +284,17 @@ void HookManager::initHooks() installHook(kbaseMod, k32Mod, "FindFirstFileExW", hook_FindFirstFileExW); HMODULE ntdllMod = GetModuleHandleA("ntdll.dll"); - spdlog::get("usvfs")->debug("ntdll.dll at {0:x}", reinterpret_cast(ntdllMod)); - installHook(ntdllMod, nullptr, "NtQueryFullAttributesFile", hook_NtQueryFullAttributesFile); + spdlog::get("usvfs")->debug("ntdll.dll at {0:x}", + reinterpret_cast(ntdllMod)); + installHook(ntdllMod, nullptr, "NtQueryFullAttributesFile", + hook_NtQueryFullAttributesFile); installHook(ntdllMod, nullptr, "NtQueryAttributesFile", hook_NtQueryAttributesFile); installHook(ntdllMod, nullptr, "NtQueryDirectoryFile", hook_NtQueryDirectoryFile); installHook(ntdllMod, nullptr, "NtQueryDirectoryFileEx", hook_NtQueryDirectoryFileEx); installHook(ntdllMod, nullptr, "NtQueryObject", hook_NtQueryObject); installHook(ntdllMod, nullptr, "NtQueryInformationFile", hook_NtQueryInformationFile); - installHook(ntdllMod, nullptr, "NtQueryInformationByName", hook_NtQueryInformationByName); + installHook(ntdllMod, nullptr, "NtQueryInformationByName", + hook_NtQueryInformationByName); installHook(ntdllMod, nullptr, "NtOpenFile", hook_NtOpenFile); installHook(ntdllMod, nullptr, "NtCreateFile", hook_NtCreateFile); installHook(ntdllMod, nullptr, "NtClose", hook_NtClose); @@ -288,7 +311,6 @@ void HookManager::initHooks() HookLib::TrampolinePool::instance().setBlock(false); } - void HookManager::removeHooks() { while (m_Hooks.size() > 0) { @@ -296,7 +318,7 @@ void HookManager::removeHooks() try { RemoveHook(iter->second); spdlog::get("usvfs")->debug("removed hook {}", iter->first); - } catch (const std::exception &e) { + } catch (const std::exception& e) { spdlog::get("usvfs")->critical("failed to remove hook: {}", e.what()); } @@ -305,4 +327,4 @@ void HookManager::removeHooks() } } -} // namespace usvfs +} // namespace usvfs diff --git a/src/usvfs_dll/hookmanager.h b/src/usvfs_dll/hookmanager.h index cd46086..636a29c 100644 --- a/src/usvfs_dll/hookmanager.h +++ b/src/usvfs_dll/hookmanager.h @@ -21,66 +21,61 @@ along with usvfs. If not, see . #pragma once #include "hookcontext.h" -#include #include +#include - -namespace usvfs { +namespace usvfs +{ class HookManager { public: - HookManager(const usvfsParameters& params, HMODULE module); ~HookManager(); - HookManager(const HookManager &reference) = delete; + HookManager(const HookManager& reference) = delete; - HookManager &operator=(const HookManager &reference) = delete; + HookManager& operator=(const HookManager& reference) = delete; + static HookManager& instance(); - static HookManager &instance(); - - - HookContext *context() { return &m_Context; } + HookContext* context() { return &m_Context; } /// /// \brief retrieve address of the detour of a function /// \param functionName name of the function to look up /// \return function address that can be used to directly execute the original code /// - LPVOID detour(const char *functionName); + LPVOID detour(const char* functionName); /// /// \brief remove the hook on the specified function. /// \param functionName name of the function to unhook - /// \note This function is only exposed to allow a workaround for ExitProcess and may be - /// removed if a better solution is found there. If you have another legit use case, - /// please let me know! + /// \note This function is only exposed to allow a workaround for ExitProcess and may + /// be + /// removed if a better solution is found there. If you have another legit use + /// case, please let me know! /// - void removeHook(const std::string &functionName); + void removeHook(const std::string& functionName); private: - void logStubInt(LPVOID address); static void logStub(LPVOID address); - void installHook(HMODULE module1, HMODULE module2, const std::string &functionName, LPVOID hook, LPVOID* fillFuncAddr); - void installStub(HMODULE module1, HMODULE module2, const std::string &functionName); + void installHook(HMODULE module1, HMODULE module2, const std::string& functionName, + LPVOID hook, LPVOID* fillFuncAddr); + void installStub(HMODULE module1, HMODULE module2, const std::string& functionName); void initHooks(); void removeHooks(); private: - - static HookManager *s_Instance; + static HookManager* s_Instance; std::map m_Hooks; std::map m_Stubs; HookContext m_Context; - }; -} // namespace usvfs - +} // namespace usvfs diff --git a/src/usvfs_dll/hooks/kernel32.cpp b/src/usvfs_dll/hooks/kernel32.cpp index 8fc4d14..6599eb0 100644 --- a/src/usvfs_dll/hooks/kernel32.cpp +++ b/src/usvfs_dll/hooks/kernel32.cpp @@ -1,18 +1,18 @@ #include "kernel32.h" #include "sharedids.h" -#include -#include "../hookmanager.h" -#include "../hookcontext.h" #include "../hookcallcontext.h" +#include "../hookcontext.h" +#include "../hookmanager.h" #include "../maptracker.h" -#include +#include #include +#include +#include +#include +#include #include #include -#include -#include -#include namespace ush = usvfs::shared; using ush::CodePage; @@ -20,39 +20,42 @@ using ush::string_cast; namespace usvfs { - MapTracker k32DeleteTracker; - MapTracker k32FakeDirTracker; -} // namespace usvfs +MapTracker k32DeleteTracker; +MapTracker k32FakeDirTracker; +} // namespace usvfs class CurrentDirectoryTracker { public: using wstring = std::wstring; - bool get(wstring ¤tDir, const wchar_t *forRelativePath = nullptr) + bool get(wstring& currentDir, const wchar_t* forRelativePath = nullptr) { int index = m_currentDrive; if (forRelativePath && *forRelativePath && forRelativePath[1] == ':') if (!getDriveIndex(forRelativePath, index)) - spdlog::get("usvfs")->warn("CurrentDirectoryTracker::get() invalid drive letter: {}, will use current drive {}", - string_cast(forRelativePath), static_cast('A' + index)); // prints '@' for m_currentDrive == -1 + spdlog::get("usvfs")->warn( + "CurrentDirectoryTracker::get() invalid drive letter: {}, will use current " + "drive {}", + string_cast(forRelativePath), + static_cast('A' + index)); // prints '@' for m_currentDrive == -1 if (index < 0) return false; std::shared_lock lock(m_mutex); if (m_perDrive[index].empty()) return false; - else - { + else { currentDir = m_perDrive[index]; return true; } } - bool set(const wstring ¤tDir) + bool set(const wstring& currentDir) { int index = -1; - bool good = !currentDir.empty() && getDriveIndex(currentDir.c_str(), index) && currentDir[1] == ':'; + bool good = !currentDir.empty() && getDriveIndex(currentDir.c_str(), index) && + currentDir[1] == ':'; std::unique_lock lock(m_mutex); m_currentDrive = good ? index : -1; if (good) @@ -61,7 +64,7 @@ public: } private: - static bool getDriveIndex(const wchar_t *path, int &index) + static bool getDriveIndex(const wchar_t* path, int& index) { if (*path >= 'a' && *path <= 'z') index = *path - 'a'; @@ -83,7 +86,10 @@ CurrentDirectoryTracker k32CurrentDirectoryTracker; static inline DWORD copyFileDirect(LPCWSTR source, LPCWSTR destination, bool overwrite) { usvfs::FunctionGroupLock lock(usvfs::MutExHookGroup::SHELL_FILEOP); - return CopyFileExW(source, destination, NULL, NULL, NULL, overwrite ? 0 : COPY_FILE_FAIL_IF_EXISTS) ? ERROR_SUCCESS : GetLastError(); + return CopyFileExW(source, destination, NULL, NULL, NULL, + overwrite ? 0 : COPY_FILE_FAIL_IF_EXISTS) + ? ERROR_SUCCESS + : GetLastError(); } static inline WCHAR pathNameDriveLetter(LPCWSTR path) @@ -94,15 +100,15 @@ static inline WCHAR pathNameDriveLetter(LPCWSTR path) return path[0]; // if path is not ?: or \* then we need to get absolute path: std::wstring buf; - if (path[0] != '\\') - { - buf = winapi::wide::getFullPathName(path).first; + if (path[0] != '\\') { + buf = winapi::wide::getFullPathName(path).first; path = buf.c_str(); if (!path[0] || path[1] == ':') return path[0]; } // check for \??\C: - if (path[1] && path[2] && path[3] && path[4] && path[0] == '\\' && path[3] == '\\' && path[5] == ':') + if (path[1] && path[2] && path[3] && path[4] && path[0] == '\\' && path[3] == '\\' && + path[5] == ':') return path[4]; // give up return 0; @@ -145,9 +151,12 @@ HMODULE WINAPI usvfs::hook_LoadLibraryExW(LPCWSTR lpFileName, HANDLE hFile, res = ::LoadLibraryExW(reroute.fileName(), hFile, dwFlags); POST_REALCALL - if (reroute.wasRerouted()) - { - LOG_CALL().PARAM(lpFileName).PARAM(reroute.fileName()).PARAM(res).PARAM(callContext.lastError()); + if (reroute.wasRerouted()) { + LOG_CALL() + .PARAM(lpFileName) + .PARAM(reroute.fileName()) + .PARAM(res) + .PARAM(callContext.lastError()); } HOOK_END @@ -158,18 +167,14 @@ HMODULE WINAPI usvfs::hook_LoadLibraryExW(LPCWSTR lpFileName, HANDLE hFile, /// determine name of the binary to run based on parameters for createprocess std::wstring getBinaryName(LPCWSTR applicationName, LPCWSTR lpCommandLine) { - if (applicationName != nullptr) - { - std::pair fullPath = winapi::wide::getFullPathName(applicationName); + if (applicationName != nullptr) { + std::pair fullPath = + winapi::wide::getFullPathName(applicationName); return fullPath.second; - } - else - { - if (lpCommandLine[0] == '"') - { - const wchar_t *endQuote = wcschr(lpCommandLine, '"'); - if (endQuote != nullptr) - { + } else { + if (lpCommandLine[0] == '"') { + const wchar_t* endQuote = wcschr(lpCommandLine, '"'); + if (endQuote != nullptr) { return std::wstring(lpCommandLine + 1, endQuote - 1); } } @@ -181,16 +186,13 @@ std::wstring getBinaryName(LPCWSTR applicationName, LPCWSTR lpCommandLine) // c:\program files\sub dir\program.exe name // c:\program files\sub dir\program name.exe LPCWSTR space = wcschr(lpCommandLine, L' '); - while (space != nullptr) - { + while (space != nullptr) { std::wstring subString(lpCommandLine, space); bool isDirectory = true; - if (winapi::ex::wide::fileExists(subString.c_str(), &isDirectory) && !isDirectory) - { + if (winapi::ex::wide::fileExists(subString.c_str(), &isDirectory) && + !isDirectory) { return subString; - } - else - { + } else { space = wcschr(space + 1, L' '); } } @@ -198,28 +200,28 @@ std::wstring getBinaryName(LPCWSTR applicationName, LPCWSTR lpCommandLine) } } -BOOL(WINAPI *usvfs::CreateProcessInternalW)(LPVOID token, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation, LPVOID newToken); +BOOL(WINAPI* usvfs::CreateProcessInternalW)( + LPVOID token, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation, LPVOID newToken); BOOL WINAPI usvfs::hook_CreateProcessInternalW( - LPVOID token, - LPCWSTR lpApplicationName, LPWSTR lpCommandLine, - LPSECURITY_ATTRIBUTES lpProcessAttributes, - LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, - DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, - LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation, - LPVOID newToken) + LPVOID token, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation, LPVOID newToken) { BOOL res = FALSE; HOOK_START_GROUP(MutExHookGroup::CREATE_PROCESS) - if (!callContext.active()) - { + if (!callContext.active()) { res = CreateProcessInternalW( - token, - lpApplicationName, lpCommandLine, lpProcessAttributes, + token, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, - lpCurrentDirectory, lpStartupInfo, lpProcessInformation, - newToken); + lpCurrentDirectory, lpStartupInfo, lpProcessInformation, newToken); callContext.updateLastError(); return res; } @@ -236,18 +238,16 @@ BOOL WINAPI usvfs::hook_CreateProcessInternalW( std::wstring dllPath; usvfsParameters callParameters; - { // scope for context lock + { // scope for context lock auto context = READ_CONTEXT(); - if (RerouteW::interestingPath(lpCommandLine)) - { - // First "argument" in the commandline is the command, we need to identify it and reroute it: - if (*lpCommandLine == '"') - { + if (RerouteW::interestingPath(lpCommandLine)) { + // First "argument" in the commandline is the command, we need to identify it and + // reroute it: + if (*lpCommandLine == '"') { // If the first argument is quoted we trust its is quoted correctly for (cend = lpCommandLine; *cend && *cend != ' '; ++cend) - if (*cend == '"') - { + if (*cend == '"') { int escaped = 0; for (++cend; *cend && (*cend != '"' || escaped % 2 != 0); ++cend) escaped = *cend == '\\' ? escaped + 1 : 0; @@ -256,35 +256,32 @@ BOOL WINAPI usvfs::hook_CreateProcessInternalW( if (*(cend - 1) == '"') --cend; auto old_cend = *cend; - *cend = 0; - cmdReroute = RerouteW::create(context, callContext, lpCommandLine + 1); - *cend = old_cend; + *cend = 0; + cmdReroute = RerouteW::create(context, callContext, lpCommandLine + 1); + *cend = old_cend; if (old_cend == '"') ++cend; - } - else - { - // If the first argument we have no choice but to test all the options to quote the command as the - // real CreateProcess will do this: + } else { + // If the first argument we have no choice but to test all the options to quote + // the command as the real CreateProcess will do this: cend = lpCommandLine; - while (true) - { + while (true) { while (*cend && *cend != ' ') ++cend; auto old_cend = *cend; - *cend = 0; - cmdReroute = RerouteW::create(context, callContext, lpCommandLine); - *cend = old_cend; + *cend = 0; + cmdReroute = RerouteW::create(context, callContext, lpCommandLine); + *cend = old_cend; if (cmdReroute.wasRerouted() || pathIsFile(cmdReroute.fileName())) break; while (*cend == ' ') ++cend; - if (!*cend) - { - // if we reached the end of the string we'll just use the whole commandline as is: + if (!*cend) { + // if we reached the end of the string we'll just use the whole commandline + // as is: cend = nullptr; break; } @@ -294,13 +291,12 @@ BOOL WINAPI usvfs::hook_CreateProcessInternalW( applicationReroute = RerouteW::create(context, callContext, lpApplicationName); - dllPath = context->dllPath(); + dllPath = context->dllPath(); callParameters = context->callParameters(); } std::wstring cmdline; - if (cend && cmdReroute.fileName()) - { + if (cend && cmdReroute.fileName()) { auto fileName = cmdReroute.fileName(); cmdline.reserve(wcslen(fileName) + wcslen(cend) + 2); if (*fileName != '"') @@ -312,45 +308,35 @@ BOOL WINAPI usvfs::hook_CreateProcessInternalW( } PRE_REALCALL - res = CreateProcessInternalW( - token, - applicationReroute.fileName(), - cmdline.empty() ? lpCommandLine : &cmdline[0], lpProcessAttributes, - lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, - lpCurrentDirectory, lpStartupInfo, lpProcessInformation, - newToken); + res = CreateProcessInternalW(token, applicationReroute.fileName(), + cmdline.empty() ? lpCommandLine : &cmdline[0], + lpProcessAttributes, lpThreadAttributes, bInheritHandles, + dwCreationFlags, lpEnvironment, lpCurrentDirectory, + lpStartupInfo, lpProcessInformation, newToken); POST_REALCALL BOOL blacklisted = FALSE; - { // limit scope of context + { // limit scope of context auto context = READ_CONTEXT(); - blacklisted = context->executableBlacklisted( - applicationReroute.fileName(), - cmdReroute.fileName()); + blacklisted = context->executableBlacklisted(applicationReroute.fileName(), + cmdReroute.fileName()); } - if (res) - { - if (!blacklisted) - { - try - { + if (res) { + if (!blacklisted) { + try { injectProcess(dllPath, callParameters, *lpProcessInformation); - } - catch (const std::exception &e) - { - spdlog::get("hooks") - ->error("failed to inject into {0}: {1}", - lpApplicationName != nullptr - ? applicationReroute.fileName() - : static_cast(lpCommandLine), - e.what()); + } catch (const std::exception& e) { + spdlog::get("hooks")->error("failed to inject into {0}: {1}", + lpApplicationName != nullptr + ? applicationReroute.fileName() + : static_cast(lpCommandLine), + e.what()); } } // resume unless process is supposed to start suspended - if (!susp && (ResumeThread(lpProcessInformation->hThread) == (DWORD)-1)) - { + if (!susp && (ResumeThread(lpProcessInformation->hThread) == (DWORD)-1)) { spdlog::get("hooks")->error("failed to inject into spawned process"); res = FALSE; } @@ -368,15 +354,14 @@ BOOL WINAPI usvfs::hook_CreateProcessInternalW( return res; } -BOOL WINAPI usvfs::hook_GetFileAttributesExA( - LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, - LPVOID lpFileInformation) +BOOL WINAPI usvfs::hook_GetFileAttributesExA(LPCSTR lpFileName, + GET_FILEEX_INFO_LEVELS fInfoLevelId, + LPVOID lpFileInformation) { BOOL res = FALSE; HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES) - if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) - { + if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) { res = GetFileAttributesExA(lpFileName, fInfoLevelId, lpFileInformation); callContext.updateLastError(); return res; @@ -394,15 +379,14 @@ BOOL WINAPI usvfs::hook_GetFileAttributesExA( return res; } -BOOL WINAPI usvfs::hook_GetFileAttributesExW( - LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, - LPVOID lpFileInformation) +BOOL WINAPI usvfs::hook_GetFileAttributesExW(LPCWSTR lpFileName, + GET_FILEEX_INFO_LEVELS fInfoLevelId, + LPVOID lpFileInformation) { BOOL res = FALSE; HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES) - if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) - { + if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) { res = GetFileAttributesExW(lpFileName, fInfoLevelId, lpFileInformation); callContext.updateLastError(); return res; @@ -410,43 +394,49 @@ BOOL WINAPI usvfs::hook_GetFileAttributesExW( fs::path canonicalFile = RerouteW::canonizePath(RerouteW::absolutePath(lpFileName)); - RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, canonicalFile.c_str()); + RerouteW reroute = + RerouteW::create(READ_CONTEXT(), callContext, canonicalFile.c_str()); PRE_REALCALL - res = ::GetFileAttributesExW(reroute.fileName(), fInfoLevelId, - lpFileInformation); + res = ::GetFileAttributesExW(reroute.fileName(), fInfoLevelId, lpFileInformation); POST_REALCALL DWORD originalError = callContext.lastError(); - DWORD fixedError = originalError; + DWORD fixedError = originalError; // In case the target does not exist the error value varies to differentiate if the // parent folder exists (ERROR_FILE_NOT_FOUND) or not (ERROR_PATH_NOT_FOUND). // If the original target's parent folder doesn't actually exist it may exist in the // the virtualized sense, or if we rerouted the query the parent of the original path // might exist while the parent of the rerouted path might not: - if (!res && fixedError == ERROR_PATH_NOT_FOUND) - { + if (!res && fixedError == ERROR_PATH_NOT_FOUND) { // first query original file parent (if we rerouted it): fs::path originalParent = canonicalFile.parent_path(); WIN32_FILE_ATTRIBUTE_DATA parentAttr; - if (reroute.wasRerouted() && ::GetFileAttributesExW(originalParent.c_str(), GetFileExInfoStandard, &parentAttr) && (parentAttr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + if (reroute.wasRerouted() && + ::GetFileAttributesExW(originalParent.c_str(), GetFileExInfoStandard, + &parentAttr) && + (parentAttr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) fixedError = ERROR_FILE_NOT_FOUND; - else - { - // now query the rerouted path for parent (which can be different from the parent of the rerouted path) - RerouteW rerouteParent = RerouteW::create(READ_CONTEXT(), callContext, originalParent.c_str()); - if (rerouteParent.wasRerouted() && ::GetFileAttributesExW(rerouteParent.fileName(), GetFileExInfoStandard, &parentAttr) && (parentAttr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + else { + // now query the rerouted path for parent (which can be different from the parent + // of the rerouted path) + RerouteW rerouteParent = + RerouteW::create(READ_CONTEXT(), callContext, originalParent.c_str()); + if (rerouteParent.wasRerouted() && + ::GetFileAttributesExW(rerouteParent.fileName(), GetFileExInfoStandard, + &parentAttr) && + (parentAttr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) fixedError = ERROR_FILE_NOT_FOUND; } } if (fixedError != originalError) callContext.updateLastError(fixedError); - if (reroute.wasRerouted() || fixedError != originalError) - { + if (reroute.wasRerouted() || fixedError != originalError) { DWORD resAttrib; if (res && fInfoLevelId == GetFileExInfoStandard && lpFileInformation) - resAttrib = reinterpret_cast(lpFileInformation)->dwFileAttributes; + resAttrib = reinterpret_cast(lpFileInformation) + ->dwFileAttributes; else resAttrib = (DWORD)-1; LOG_CALL() @@ -469,8 +459,7 @@ DWORD WINAPI usvfs::hook_GetFileAttributesA(LPCSTR lpFileName) BOOL res = FALSE; HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES) - if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) - { + if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) { res = GetFileAttributesA(lpFileName); callContext.updateLastError(); return res; @@ -493,8 +482,7 @@ DWORD WINAPI usvfs::hook_GetFileAttributesW(LPCWSTR lpFileName) DWORD res = 0UL; HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES) - if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) - { + if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) { res = GetFileAttributesW(lpFileName); callContext.updateLastError(); return res; @@ -502,7 +490,8 @@ DWORD WINAPI usvfs::hook_GetFileAttributesW(LPCWSTR lpFileName) fs::path canonicalFile = RerouteW::canonizePath(RerouteW::absolutePath(lpFileName)); - RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, canonicalFile.c_str()); + RerouteW reroute = + RerouteW::create(READ_CONTEXT(), callContext, canonicalFile.c_str()); if (reroute.wasRerouted()) PRE_REALCALL @@ -510,32 +499,37 @@ DWORD WINAPI usvfs::hook_GetFileAttributesW(LPCWSTR lpFileName) POST_REALCALL DWORD originalError = callContext.lastError(); - DWORD fixedError = originalError; + DWORD fixedError = originalError; // In case the target does not exist the error value varies to differentiate if the // parent folder exists (ERROR_FILE_NOT_FOUND) or not (ERROR_PATH_NOT_FOUND). // If the original target's parent folder doesn't actually exist it may exist in the // the virtualized sense, or if we rerouted the query the parent of the original path // might exist while the parent of the rerouted path might not: - if (res == INVALID_FILE_ATTRIBUTES && fixedError == ERROR_PATH_NOT_FOUND) - { + if (res == INVALID_FILE_ATTRIBUTES && fixedError == ERROR_PATH_NOT_FOUND) { // first query original file parent (if we rerouted it): fs::path originalParent = canonicalFile.parent_path(); DWORD attr; - if (reroute.wasRerouted() && (attr = ::GetFileAttributesW(originalParent.c_str())) != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY)) + if (reroute.wasRerouted() && + (attr = ::GetFileAttributesW(originalParent.c_str())) != + INVALID_FILE_ATTRIBUTES && + (attr & FILE_ATTRIBUTE_DIRECTORY)) fixedError = ERROR_FILE_NOT_FOUND; - else - { - // now query the rerouted path for parent (which can be different from the parent of the rerouted path) - RerouteW rerouteParent = RerouteW::create(READ_CONTEXT(), callContext, originalParent.c_str()); - if (rerouteParent.wasRerouted() && (attr = ::GetFileAttributesW(rerouteParent.fileName())) != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY)) + else { + // now query the rerouted path for parent (which can be different from the parent + // of the rerouted path) + RerouteW rerouteParent = + RerouteW::create(READ_CONTEXT(), callContext, originalParent.c_str()); + if (rerouteParent.wasRerouted() && + (attr = ::GetFileAttributesW(rerouteParent.fileName())) != + INVALID_FILE_ATTRIBUTES && + (attr & FILE_ATTRIBUTE_DIRECTORY)) fixedError = ERROR_FILE_NOT_FOUND; } } if (fixedError != originalError) callContext.updateLastError(fixedError); - if (reroute.wasRerouted() || fixedError != originalError) - { + if (reroute.wasRerouted() || fixedError != originalError) { LOG_CALL() .PARAM(lpFileName) .PARAM(reroute.fileName()) @@ -549,8 +543,7 @@ DWORD WINAPI usvfs::hook_GetFileAttributesW(LPCWSTR lpFileName) return res; } -DWORD WINAPI usvfs::hook_SetFileAttributesW( - LPCWSTR lpFileName, DWORD dwFileAttributes) +DWORD WINAPI usvfs::hook_SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes) { DWORD res = 0UL; @@ -562,8 +555,7 @@ DWORD WINAPI usvfs::hook_SetFileAttributesW( res = ::SetFileAttributesW(reroute.fileName(), dwFileAttributes); POST_REALCALL - if (reroute.wasRerouted()) - { + if (reroute.wasRerouted()) { LOG_CALL().PARAM(reroute.fileName()).PARAM(res).PARAM(callContext.lastError()); } @@ -579,28 +571,29 @@ BOOL WINAPI usvfs::hook_DeleteFileW(LPCWSTR lpFileName) HOOK_START_GROUP(MutExHookGroup::DELETE_FILE) // Why is the usual if (!callContext.active()... check missing? - const std::wstring path = RerouteW::canonizePath(RerouteW::absolutePath(lpFileName)).wstring(); + const std::wstring path = + RerouteW::canonizePath(RerouteW::absolutePath(lpFileName)).wstring(); RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, path.c_str()); PRE_REALCALL - if (reroute.wasRerouted()) - { + if (reroute.wasRerouted()) { res = ::DeleteFileW(reroute.fileName()); - } - else - { + } else { res = ::DeleteFileW(path.c_str()); } POST_REALCALL - if (res) - { + if (res) { reroute.removeMapping(READ_CONTEXT()); } if (reroute.wasRerouted()) - LOG_CALL().PARAM(lpFileName).PARAM(reroute.fileName()).PARAM(res).PARAM(callContext.lastError()); + LOG_CALL() + .PARAM(lpFileName) + .PARAM(reroute.fileName()) + .PARAM(res) + .PARAM(callContext.lastError()); HOOK_END @@ -608,20 +601,21 @@ BOOL WINAPI usvfs::hook_DeleteFileW(LPCWSTR lpFileName) } BOOL rewriteChangedDrives(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, - const usvfs::RerouteW &readReroute, const usvfs::CreateRerouter &writeReroute) + const usvfs::RerouteW& readReroute, + const usvfs::CreateRerouter& writeReroute) { - return ((readReroute.wasRerouted() || writeReroute.wasRerouted()) && pathsOnDifferentDrives(readReroute.fileName(), writeReroute.fileName()) && !pathsOnDifferentDrives(lpExistingFileName, lpNewFileName)); + return ((readReroute.wasRerouted() || writeReroute.wasRerouted()) && + pathsOnDifferentDrives(readReroute.fileName(), writeReroute.fileName()) && + !pathsOnDifferentDrives(lpExistingFileName, lpNewFileName)); } -BOOL WINAPI usvfs::hook_MoveFileA(LPCSTR lpExistingFileName, - LPCSTR lpNewFileName) +BOOL WINAPI usvfs::hook_MoveFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName) { BOOL res = FALSE; HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP) - if (!callContext.active()) - { + if (!callContext.active()) { res = MoveFileA(lpExistingFileName, lpNewFileName); callContext.updateLastError(); return res; @@ -630,8 +624,8 @@ BOOL WINAPI usvfs::hook_MoveFileA(LPCSTR lpExistingFileName, HOOK_END HOOK_START - const auto &existingFileName = ush::string_cast(lpExistingFileName); - const auto &newFileName = ush::string_cast(lpNewFileName); + const auto& existingFileName = ush::string_cast(lpExistingFileName); + const auto& newFileName = ush::string_cast(lpNewFileName); PRE_REALCALL res = MoveFileW(existingFileName.c_str(), newFileName.c_str()); @@ -642,14 +636,12 @@ BOOL WINAPI usvfs::hook_MoveFileA(LPCSTR lpExistingFileName, return res; } -BOOL WINAPI usvfs::hook_MoveFileW(LPCWSTR lpExistingFileName, - LPCWSTR lpNewFileName) +BOOL WINAPI usvfs::hook_MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName) { BOOL res = FALSE; HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP) - if (!callContext.active()) - { + if (!callContext.active()) { res = MoveFileW(lpExistingFileName, lpNewFileName); callContext.updateLastError(); return res; @@ -658,34 +650,33 @@ BOOL WINAPI usvfs::hook_MoveFileW(LPCWSTR lpExistingFileName, RerouteW readReroute; CreateRerouter writeReroute; bool callOriginal = true; - DWORD newFlags = 0; + DWORD newFlags = 0; { auto context = READ_CONTEXT(); - readReroute = RerouteW::create(context, callContext, lpExistingFileName); - callOriginal = writeReroute.rerouteNew(context, callContext, lpNewFileName, false, "hook_MoveFileW"); + readReroute = RerouteW::create(context, callContext, lpExistingFileName); + callOriginal = writeReroute.rerouteNew(context, callContext, lpNewFileName, false, + "hook_MoveFileW"); } - if (callOriginal) - { - bool movedDrives = rewriteChangedDrives(lpExistingFileName, lpNewFileName, readReroute, writeReroute); + if (callOriginal) { + bool movedDrives = rewriteChangedDrives(lpExistingFileName, lpNewFileName, + readReroute, writeReroute); if (movedDrives) newFlags |= MOVEFILE_COPY_ALLOWED; bool isDirectory = pathIsDirectory(readReroute.fileName()); PRE_REALCALL - if (isDirectory && movedDrives) - { + if (isDirectory && movedDrives) { SHFILEOPSTRUCTW sf = {0}; - sf.wFunc = FO_MOVE; - sf.hwnd = 0; - sf.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI; - sf.pFrom = readReroute.fileName(); - sf.pTo = writeReroute.fileName(); - int shRes = ::SHFileOperationW(&sf); - switch (shRes) - { + sf.wFunc = FO_MOVE; + sf.hwnd = 0; + sf.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI; + sf.pFrom = readReroute.fileName(); + sf.pTo = writeReroute.fileName(); + int shRes = ::SHFileOperationW(&sf); + switch (shRes) { case 0x78: callContext.updateLastError(ERROR_ACCESS_DENIED); break; @@ -700,8 +691,7 @@ BOOL WINAPI usvfs::hook_MoveFileW(LPCWSTR lpExistingFileName, callContext.updateLastError(shRes); } res = shRes == 0; - } - else if (newFlags) + } else if (newFlags) res = ::MoveFileExW(readReroute.fileName(), writeReroute.fileName(), newFlags); else res = ::MoveFileW(readReroute.fileName(), writeReroute.fileName()); @@ -712,20 +702,22 @@ BOOL WINAPI usvfs::hook_MoveFileW(LPCWSTR lpExistingFileName, writeReroute.updateResult(callContext, res); - if (res) - { - readReroute.removeMapping(READ_CONTEXT(), isDirectory); // Updating the rerouteCreate to check deleted file entries should make this okay + if (res) { + readReroute.removeMapping( + READ_CONTEXT(), isDirectory); // Updating the rerouteCreate to check deleted + // file entries should make this okay - if (writeReroute.newReroute()) - { + if (writeReroute.newReroute()) { if (isDirectory) - RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName), fs::path(writeReroute.fileName())); + RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName), + fs::path(writeReroute.fileName())); else writeReroute.insertMapping(WRITE_CONTEXT()); } } - if (readReroute.wasRerouted() || writeReroute.wasRerouted() || writeReroute.changedError()) + if (readReroute.wasRerouted() || writeReroute.wasRerouted() || + writeReroute.changedError()) LOG_CALL() .PARAM(readReroute.fileName()) .PARAM(writeReroute.fileName()) @@ -740,15 +732,14 @@ BOOL WINAPI usvfs::hook_MoveFileW(LPCWSTR lpExistingFileName, return res; } -BOOL WINAPI usvfs::hook_MoveFileExA(LPCSTR lpExistingFileName, - LPCSTR lpNewFileName, DWORD dwFlags) +BOOL WINAPI usvfs::hook_MoveFileExA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, + DWORD dwFlags) { BOOL res = FALSE; HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP) - if (!callContext.active()) - { + if (!callContext.active()) { res = MoveFileExA(lpExistingFileName, lpNewFileName, dwFlags); callContext.updateLastError(); return res; @@ -757,18 +748,18 @@ BOOL WINAPI usvfs::hook_MoveFileExA(LPCSTR lpExistingFileName, HOOK_END HOOK_START - const std::wstring existingFileName = ush::string_cast(lpExistingFileName); + const std::wstring existingFileName = + ush::string_cast(lpExistingFileName); // careful: lpNewFileName can be null if dwFlags is // MOVEFILE_DELAY_UNTIL_REBOOT, so don't blindly cast the string and make sure // the null pointer is forwarded correctly std::wstring newFileNameWstring; - const wchar_t *newFileName = nullptr; + const wchar_t* newFileName = nullptr; - if (lpNewFileName) - { + if (lpNewFileName) { newFileNameWstring = ush::string_cast(lpNewFileName); - newFileName = newFileNameWstring.c_str(); + newFileName = newFileNameWstring.c_str(); } PRE_REALCALL @@ -780,14 +771,13 @@ BOOL WINAPI usvfs::hook_MoveFileExA(LPCSTR lpExistingFileName, return res; } -BOOL WINAPI usvfs::hook_MoveFileExW(LPCWSTR lpExistingFileName, - LPCWSTR lpNewFileName, DWORD dwFlags) +BOOL WINAPI usvfs::hook_MoveFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, + DWORD dwFlags) { BOOL res = FALSE; HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP) - if (!callContext.active()) - { + if (!callContext.active()) { res = MoveFileExW(lpExistingFileName, lpNewFileName, dwFlags); callContext.updateLastError(); return res; @@ -796,33 +786,32 @@ BOOL WINAPI usvfs::hook_MoveFileExW(LPCWSTR lpExistingFileName, RerouteW readReroute; CreateRerouter writeReroute; bool callOriginal = true; - DWORD newFlags = dwFlags; + DWORD newFlags = dwFlags; { auto context = READ_CONTEXT(); - readReroute = RerouteW::create(context, callContext, lpExistingFileName); + readReroute = RerouteW::create(context, callContext, lpExistingFileName); callOriginal = writeReroute.rerouteNew(context, callContext, lpNewFileName, - newFlags & MOVEFILE_REPLACE_EXISTING, "hook_MoveFileExW"); + newFlags & MOVEFILE_REPLACE_EXISTING, + "hook_MoveFileExW"); } - if (callOriginal) - { - bool movedDrives = rewriteChangedDrives(lpExistingFileName, lpNewFileName, readReroute, writeReroute); + if (callOriginal) { + bool movedDrives = rewriteChangedDrives(lpExistingFileName, lpNewFileName, + readReroute, writeReroute); bool isDirectory = pathIsDirectory(readReroute.fileName()); PRE_REALCALL - if (isDirectory && movedDrives) - { + if (isDirectory && movedDrives) { SHFILEOPSTRUCTW sf = {0}; - sf.wFunc = FO_MOVE; - sf.hwnd = 0; - sf.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI; - sf.pFrom = readReroute.fileName(); - sf.pTo = writeReroute.fileName(); - int shRes = ::SHFileOperationW(&sf); - switch (shRes) - { + sf.wFunc = FO_MOVE; + sf.hwnd = 0; + sf.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI; + sf.pFrom = readReroute.fileName(); + sf.pTo = writeReroute.fileName(); + int shRes = ::SHFileOperationW(&sf); + switch (shRes) { case 0x78: callContext.updateLastError(ERROR_ACCESS_DENIED); break; @@ -837,8 +826,7 @@ BOOL WINAPI usvfs::hook_MoveFileExW(LPCWSTR lpExistingFileName, callContext.updateLastError(shRes); } res = shRes == 0; - } - else + } else res = ::MoveFileExW(readReroute.fileName(), writeReroute.fileName(), newFlags); POST_REALCALL @@ -847,20 +835,22 @@ BOOL WINAPI usvfs::hook_MoveFileExW(LPCWSTR lpExistingFileName, writeReroute.updateResult(callContext, res); - if (res) - { - readReroute.removeMapping(READ_CONTEXT(), isDirectory); // Updating the rerouteCreate to check deleted file entries should make this okay + if (res) { + readReroute.removeMapping( + READ_CONTEXT(), isDirectory); // Updating the rerouteCreate to check deleted + // file entries should make this okay - if (writeReroute.newReroute()) - { + if (writeReroute.newReroute()) { if (isDirectory) - RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName), fs::path(writeReroute.fileName())); + RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName), + fs::path(writeReroute.fileName())); else writeReroute.insertMapping(WRITE_CONTEXT()); } } - if (readReroute.wasRerouted() || writeReroute.wasRerouted() || writeReroute.changedError()) + if (readReroute.wasRerouted() || writeReroute.wasRerouted() || + writeReroute.changedError()) LOG_CALL() .PARAM(readReroute.fileName()) .PARAM(writeReroute.fileName()) @@ -876,15 +866,18 @@ BOOL WINAPI usvfs::hook_MoveFileExW(LPCWSTR lpExistingFileName, return res; } -BOOL WINAPI usvfs::hook_MoveFileWithProgressA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags) +BOOL WINAPI usvfs::hook_MoveFileWithProgressA(LPCSTR lpExistingFileName, + LPCSTR lpNewFileName, + LPPROGRESS_ROUTINE lpProgressRoutine, + LPVOID lpData, DWORD dwFlags) { BOOL res = FALSE; HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP) - if (!callContext.active()) - { - res = MoveFileWithProgressA(lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, dwFlags); + if (!callContext.active()) { + res = MoveFileWithProgressA(lpExistingFileName, lpNewFileName, lpProgressRoutine, + lpData, dwFlags); callContext.updateLastError(); return res; } @@ -892,22 +885,22 @@ BOOL WINAPI usvfs::hook_MoveFileWithProgressA(LPCSTR lpExistingFileName, LPCSTR HOOK_END HOOK_START - const auto &existingFileName = ush::string_cast(lpExistingFileName); + const auto& existingFileName = ush::string_cast(lpExistingFileName); // careful: lpNewFileName can be null if dwFlags is // MOVEFILE_DELAY_UNTIL_REBOOT, so don't blindly cast the string and make sure // the null pointer is forwarded correctly std::wstring newFileNameWstring; - const wchar_t *newFileName = nullptr; + const wchar_t* newFileName = nullptr; - if (lpNewFileName) - { + if (lpNewFileName) { newFileNameWstring = ush::string_cast(lpNewFileName); - newFileName = newFileNameWstring.c_str(); + newFileName = newFileNameWstring.c_str(); } PRE_REALCALL - res = MoveFileWithProgressW(existingFileName.c_str(), newFileName, lpProgressRoutine, lpData, dwFlags); + res = MoveFileWithProgressW(existingFileName.c_str(), newFileName, lpProgressRoutine, + lpData, dwFlags); POST_REALCALL HOOK_END @@ -915,17 +908,21 @@ BOOL WINAPI usvfs::hook_MoveFileWithProgressA(LPCSTR lpExistingFileName, LPCSTR return res; } -BOOL WINAPI usvfs::hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags) +BOOL WINAPI usvfs::hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, + LPCWSTR lpNewFileName, + LPPROGRESS_ROUTINE lpProgressRoutine, + LPVOID lpData, DWORD dwFlags) { // TODO: Remove all redundant hooks to moveFile alternatives. - // it would appear that all other moveFile functions end up calling this one with no additional code. + // it would appear that all other moveFile functions end up calling this one with no + // additional code. BOOL res = FALSE; HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP) - if (!callContext.active()) - { - res = MoveFileWithProgressW(lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, dwFlags); + if (!callContext.active()) { + res = MoveFileWithProgressW(lpExistingFileName, lpNewFileName, lpProgressRoutine, + lpData, dwFlags); callContext.updateLastError(); return res; } @@ -933,35 +930,34 @@ BOOL WINAPI usvfs::hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, LPCWST RerouteW readReroute; usvfs::CreateRerouter writeReroute; bool callOriginal = true; - DWORD newFlags = dwFlags; + DWORD newFlags = dwFlags; { auto context = READ_CONTEXT(); - readReroute = RerouteW::create(context, callContext, lpExistingFileName); + readReroute = RerouteW::create(context, callContext, lpExistingFileName); callOriginal = writeReroute.rerouteNew(context, callContext, lpNewFileName, - newFlags & MOVEFILE_REPLACE_EXISTING, "hook_MoveFileWithProgressW"); + newFlags & MOVEFILE_REPLACE_EXISTING, + "hook_MoveFileWithProgressW"); } - if (callOriginal) - { - bool movedDrives = rewriteChangedDrives(lpExistingFileName, lpNewFileName, readReroute, writeReroute); + if (callOriginal) { + bool movedDrives = rewriteChangedDrives(lpExistingFileName, lpNewFileName, + readReroute, writeReroute); if (movedDrives) newFlags |= MOVEFILE_COPY_ALLOWED; bool isDirectory = pathIsDirectory(readReroute.fileName()); PRE_REALCALL - if (isDirectory && movedDrives) - { + if (isDirectory && movedDrives) { SHFILEOPSTRUCTW sf = {0}; - sf.wFunc = FO_MOVE; - sf.hwnd = 0; - sf.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI; - sf.pFrom = readReroute.fileName(); - sf.pTo = writeReroute.fileName(); - int shRes = ::SHFileOperationW(&sf); - switch (shRes) - { + sf.wFunc = FO_MOVE; + sf.hwnd = 0; + sf.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI; + sf.pFrom = readReroute.fileName(); + sf.pTo = writeReroute.fileName(); + int shRes = ::SHFileOperationW(&sf); + switch (shRes) { case 0x78: callContext.updateLastError(ERROR_ACCESS_DENIED); break; @@ -976,9 +972,9 @@ BOOL WINAPI usvfs::hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, LPCWST callContext.updateLastError(shRes); } res = shRes == 0; - } - else - res = ::MoveFileWithProgressW(readReroute.fileName(), writeReroute.fileName(), lpProgressRoutine, lpData, newFlags); + } else + res = ::MoveFileWithProgressW(readReroute.fileName(), writeReroute.fileName(), + lpProgressRoutine, lpData, newFlags); POST_REALCALL if (res) @@ -986,22 +982,27 @@ BOOL WINAPI usvfs::hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, LPCWST writeReroute.updateResult(callContext, res); - if (res) - { - // TODO: this call causes the node to be removed twice in case of MOVEFILE_COPY_ALLOWED as the deleteFile hook lower level already takes care of it, - // but deleteFile can't be disabled since we are relying on it in case of MOVEFILE_REPLACE_EXISTING for the destination file. - readReroute.removeMapping(READ_CONTEXT(), isDirectory); // Updating the rerouteCreate to check deleted file entries should make this okay (not related to comments above) + if (res) { + // TODO: this call causes the node to be removed twice in case of + // MOVEFILE_COPY_ALLOWED as the deleteFile hook lower level already takes care of + // it, but deleteFile can't be disabled since we are relying on it in case of + // MOVEFILE_REPLACE_EXISTING for the destination file. + readReroute.removeMapping( + READ_CONTEXT(), + isDirectory); // Updating the rerouteCreate to check deleted file entries + // should make this okay (not related to comments above) - if (writeReroute.newReroute()) - { + if (writeReroute.newReroute()) { if (isDirectory) - RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName), fs::path(writeReroute.fileName())); + RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName), + fs::path(writeReroute.fileName())); else writeReroute.insertMapping(WRITE_CONTEXT()); } } - if (readReroute.wasRerouted() || writeReroute.wasRerouted() || writeReroute.changedError()) + if (readReroute.wasRerouted() || writeReroute.wasRerouted() || + writeReroute.changedError()) LOG_CALL() .PARAM(readReroute.fileName()) .PARAM(writeReroute.fileName()) @@ -1017,18 +1018,16 @@ BOOL WINAPI usvfs::hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, LPCWST return res; } -BOOL WINAPI usvfs::hook_CopyFileExW(LPCWSTR lpExistingFileName, - LPCWSTR lpNewFileName, - LPPROGRESS_ROUTINE lpProgressRoutine, - LPVOID lpData, LPBOOL pbCancel, - DWORD dwCopyFlags) +BOOL WINAPI usvfs::hook_CopyFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, + LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, + LPBOOL pbCancel, DWORD dwCopyFlags) { BOOL res = FALSE; HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP) - if (!callContext.active()) - { - res = CopyFileExW(lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags); + if (!callContext.active()) { + res = CopyFileExW(lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, + pbCancel, dwCopyFlags); callContext.updateLastError(); return res; } @@ -1039,13 +1038,13 @@ BOOL WINAPI usvfs::hook_CopyFileExW(LPCWSTR lpExistingFileName, { auto context = READ_CONTEXT(); - readReroute = RerouteW::create(context, callContext, lpExistingFileName); - callOriginal = writeReroute.rerouteNew(context, callContext, lpNewFileName, - (dwCopyFlags & COPY_FILE_FAIL_IF_EXISTS) == 0, "hook_CopyFileExW"); + readReroute = RerouteW::create(context, callContext, lpExistingFileName); + callOriginal = writeReroute.rerouteNew( + context, callContext, lpNewFileName, + (dwCopyFlags & COPY_FILE_FAIL_IF_EXISTS) == 0, "hook_CopyFileExW"); } - if (callOriginal) - { + if (callOriginal) { PRE_REALCALL res = ::CopyFileExW(readReroute.fileName(), writeReroute.fileName(), lpProgressRoutine, lpData, pbCancel, dwCopyFlags); @@ -1055,7 +1054,8 @@ BOOL WINAPI usvfs::hook_CopyFileExW(LPCWSTR lpExistingFileName, if (res && writeReroute.newReroute()) writeReroute.insertMapping(WRITE_CONTEXT()); - if (readReroute.wasRerouted() || writeReroute.wasRerouted() || writeReroute.changedError()) + if (readReroute.wasRerouted() || writeReroute.wasRerouted() || + writeReroute.changedError()) LOG_CALL() .PARAM(readReroute.fileName()) .PARAM(writeReroute.fileName()) @@ -1069,8 +1069,7 @@ BOOL WINAPI usvfs::hook_CopyFileExW(LPCWSTR lpExistingFileName, return res; } -DWORD WINAPI usvfs::hook_GetCurrentDirectoryA(DWORD nBufferLength, - LPSTR lpBuffer) +DWORD WINAPI usvfs::hook_GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer) { DWORD res = 0; @@ -1083,10 +1082,9 @@ DWORD WINAPI usvfs::hook_GetCurrentDirectoryA(DWORD nBufferLength, res = GetCurrentDirectoryW(nBufferLength, &buffer[0]); POST_REALCALL - if (res > 0) - { - res = WideCharToMultiByte(CP_ACP, 0, buffer.c_str(), res + 1, - lpBuffer, nBufferLength, nullptr, nullptr); + if (res > 0) { + res = WideCharToMultiByte(CP_ACP, 0, buffer.c_str(), res + 1, lpBuffer, + nBufferLength, nullptr, nullptr); } HOOK_END @@ -1094,8 +1092,7 @@ DWORD WINAPI usvfs::hook_GetCurrentDirectoryA(DWORD nBufferLength, return res; } -DWORD WINAPI usvfs::hook_GetCurrentDirectoryW(DWORD nBufferLength, - LPWSTR lpBuffer) +DWORD WINAPI usvfs::hook_GetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer) { DWORD res = FALSE; @@ -1103,25 +1100,18 @@ DWORD WINAPI usvfs::hook_GetCurrentDirectoryW(DWORD nBufferLength, std::wstring actualCWD; - if (!k32CurrentDirectoryTracker.get(actualCWD)) - { + if (!k32CurrentDirectoryTracker.get(actualCWD)) { PRE_REALCALL res = ::GetCurrentDirectoryW(nBufferLength, lpBuffer); POST_REALCALL - } - else - { - ush::wcsncpy_sz( - lpBuffer, &actualCWD[0], - std::min(static_cast(nBufferLength), actualCWD.size() + 1)); + } else { + ush::wcsncpy_sz(lpBuffer, &actualCWD[0], + std::min(static_cast(nBufferLength), actualCWD.size() + 1)); // yupp, that's how GetCurrentDirectory actually works... - if (actualCWD.size() < nBufferLength) - { + if (actualCWD.size() < nBufferLength) { res = static_cast(actualCWD.size()); - } - else - { + } else { res = static_cast(actualCWD.size() + 1); } } @@ -1141,8 +1131,7 @@ DWORD WINAPI usvfs::hook_GetCurrentDirectoryW(DWORD nBufferLength, BOOL WINAPI usvfs::hook_SetCurrentDirectoryA(LPCSTR lpPathName) { - return SetCurrentDirectoryW( - ush::string_cast(lpPathName).c_str()); + return SetCurrentDirectoryW(ush::string_cast(lpPathName).c_str()); } BOOL WINAPI usvfs::hook_SetCurrentDirectoryW(LPCWSTR lpPathName) @@ -1151,37 +1140,35 @@ BOOL WINAPI usvfs::hook_SetCurrentDirectoryW(LPCWSTR lpPathName) HOOK_START - const fs::path &realPath = RerouteW::canonizePath(RerouteW::absolutePath(lpPathName)); - const std::wstring &realPathStr = realPath.wstring(); + const fs::path& realPath = RerouteW::canonizePath(RerouteW::absolutePath(lpPathName)); + const std::wstring& realPathStr = realPath.wstring(); std::wstring finalRoute; BOOL found = FALSE; if (fs::exists(realPath)) finalRoute = realPathStr; - else - { + else { WCHAR processDir[MAX_PATH]; - if (::GetModuleFileNameW(NULL, processDir, MAX_PATH) != 0 && ::PathRemoveFileSpecW(processDir)) - { + if (::GetModuleFileNameW(NULL, processDir, MAX_PATH) != 0 && + ::PathRemoveFileSpecW(processDir)) { WCHAR processName[MAX_PATH]; ::GetModuleFileNameW(NULL, processName, MAX_PATH); fs::path routedName = realPath / processName; - RerouteW rerouteTest = RerouteW::create(READ_CONTEXT(), callContext, routedName.wstring().c_str()); - if (rerouteTest.wasRerouted()) - { + RerouteW rerouteTest = + RerouteW::create(READ_CONTEXT(), callContext, routedName.wstring().c_str()); + if (rerouteTest.wasRerouted()) { std::wstring reroutedPath = rerouteTest.fileName(); - if (routedName.wstring().find(processDir) != std::string::npos) - { + if (routedName.wstring().find(processDir) != std::string::npos) { fs::path finalPath(reroutedPath); finalRoute = finalPath.parent_path().wstring(); - found = TRUE; + found = TRUE; } } } - if (!found) - { - RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, realPathStr.c_str()); + if (!found) { + RerouteW reroute = + RerouteW::create(READ_CONTEXT(), callContext, realPathStr.c_str()); finalRoute = reroute.fileName(); } } @@ -1192,7 +1179,8 @@ BOOL WINAPI usvfs::hook_SetCurrentDirectoryW(LPCWSTR lpPathName) if (res) if (!k32CurrentDirectoryTracker.set(realPathStr)) - spdlog::get("usvfs")->warn("Updating actual current directory failed: {} ?!", string_cast(realPathStr)); + spdlog::get("usvfs")->warn("Updating actual current directory failed: {} ?!", + string_cast(realPathStr)); LOG_CALL() .PARAM(lpPathName) @@ -1222,15 +1210,18 @@ DLLEXPORT BOOL WINAPI usvfs::hook_CreateDirectoryW( reroute.insertMapping(WRITE_CONTEXT(), true); if (reroute.wasRerouted()) - LOG_CALL().PARAM(lpPathName).PARAM(reroute.fileName()).PARAM(res).PARAM(callContext.lastError()); + LOG_CALL() + .PARAM(lpPathName) + .PARAM(reroute.fileName()) + .PARAM(res) + .PARAM(callContext.lastError()); HOOK_END return res; } -DLLEXPORT BOOL WINAPI usvfs::hook_RemoveDirectoryW( - LPCWSTR lpPathName) +DLLEXPORT BOOL WINAPI usvfs::hook_RemoveDirectoryW(LPCWSTR lpPathName) { BOOL res = FALSE; @@ -1241,36 +1232,36 @@ DLLEXPORT BOOL WINAPI usvfs::hook_RemoveDirectoryW( RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, lpPathName); PRE_REALCALL - if (reroute.wasRerouted()) - { + if (reroute.wasRerouted()) { res = ::RemoveDirectoryW(reroute.fileName()); - } - else - { + } else { res = ::RemoveDirectoryW(lpPathName); } POST_REALCALL - if (res) - { + if (res) { reroute.removeMapping(READ_CONTEXT(), true); } if (reroute.wasRerouted()) - LOG_CALL().PARAM(lpPathName).PARAM(reroute.fileName()).PARAM(res).PARAM(callContext.lastError()); + LOG_CALL() + .PARAM(lpPathName) + .PARAM(reroute.fileName()) + .PARAM(res) + .PARAM(callContext.lastError()); HOOK_END return res; } -DWORD WINAPI usvfs::hook_GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR *lpFilePart) +DWORD WINAPI usvfs::hook_GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, + LPSTR lpBuffer, LPSTR* lpFilePart) { DWORD res = 0UL; HOOK_START_GROUP(MutExHookGroup::FULL_PATHNAME) - if (!callContext.active()) - { + if (!callContext.active()) { res = GetFullPathNameA(lpFileName, nBufferLength, lpBuffer, lpFilePart); callContext.updateLastError(); return res; @@ -1280,16 +1271,16 @@ DWORD WINAPI usvfs::hook_GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength std::wstring actualCWD; fs::path filePath = ush::string_cast(lpFileName, CodePage::UTF8); - if (k32CurrentDirectoryTracker.get(actualCWD, filePath.wstring().c_str())) - { + if (k32CurrentDirectoryTracker.get(actualCWD, filePath.wstring().c_str())) { if (!filePath.is_absolute()) - resolvedWithCMD = - ush::string_cast((actualCWD / filePath.relative_path()).wstring()); + resolvedWithCMD = ush::string_cast( + (actualCWD / filePath.relative_path()).wstring()); } PRE_REALCALL - res = ::GetFullPathNameA( - resolvedWithCMD.empty() ? lpFileName : resolvedWithCMD.c_str(), nBufferLength, lpBuffer, lpFilePart); + res = + ::GetFullPathNameA(resolvedWithCMD.empty() ? lpFileName : resolvedWithCMD.c_str(), + nBufferLength, lpBuffer, lpFilePart); POST_REALCALL if (false && nBufferLength) @@ -1306,15 +1297,13 @@ DWORD WINAPI usvfs::hook_GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength return res; } -DWORD WINAPI usvfs::hook_GetFullPathNameW(LPCWSTR lpFileName, - DWORD nBufferLength, - LPWSTR lpBuffer, LPWSTR *lpFilePart) +DWORD WINAPI usvfs::hook_GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, + LPWSTR lpBuffer, LPWSTR* lpFilePart) { DWORD res = 0UL; HOOK_START_GROUP(MutExHookGroup::FULL_PATHNAME) - if (!callContext.active()) - { + if (!callContext.active()) { res = GetFullPathNameW(lpFileName, nBufferLength, lpBuffer, lpFilePart); callContext.updateLastError(); return res; @@ -1323,16 +1312,16 @@ DWORD WINAPI usvfs::hook_GetFullPathNameW(LPCWSTR lpFileName, std::wstring resolvedWithCMD; std::wstring actualCWD; - if (k32CurrentDirectoryTracker.get(actualCWD, lpFileName)) - { + if (k32CurrentDirectoryTracker.get(actualCWD, lpFileName)) { fs::path filePath = lpFileName; if (!filePath.is_absolute()) resolvedWithCMD = (actualCWD / filePath.relative_path()).wstring(); } PRE_REALCALL - res = ::GetFullPathNameW( - resolvedWithCMD.empty() ? lpFileName : resolvedWithCMD.c_str(), nBufferLength, lpBuffer, lpFilePart); + res = + ::GetFullPathNameW(resolvedWithCMD.empty() ? lpFileName : resolvedWithCMD.c_str(), + nBufferLength, lpBuffer, lpFilePart); POST_REALCALL if (false && nBufferLength) @@ -1359,8 +1348,7 @@ DWORD WINAPI usvfs::hook_GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, PRE_REALCALL res = ::GetModuleFileNameA(hModule, lpFilename, nSize); POST_REALCALL - if ((res != 0) && callContext.active()) - { + if ((res != 0) && callContext.active()) { std::vector buf; // If GetModuleFileNameA failed because the buffer is not large enough this // complicates matters because we are dealing with incomplete information @@ -1368,29 +1356,27 @@ DWORD WINAPI usvfs::hook_GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, // be routed to a short virtual so the call should actually succeed in such // a case). To solve this we simply use our own buffer to find the complete // module path: - DWORD full_res = res; + DWORD full_res = res; size_t buf_size = nSize; - while (full_res == buf_size) - { + while (full_res == buf_size) { buf_size = std::max(static_cast(MAX_PATH), buf_size * 2); buf.resize(buf_size); full_res = ::GetModuleFileNameA(hModule, buf.data(), buf_size); } - RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, ush::string_cast(buf.empty() ? lpFilename : buf.data()).c_str(), true); - if (reroute.wasRerouted()) - { + RerouteW reroute = RerouteW::create( + READ_CONTEXT(), callContext, + ush::string_cast(buf.empty() ? lpFilename : buf.data()).c_str(), + true); + if (reroute.wasRerouted()) { DWORD reroutedSize = static_cast(wcslen(reroute.fileName())); - if (reroutedSize >= nSize) - { + if (reroutedSize >= nSize) { reroutedSize = nSize - 1; callContext.updateLastError(ERROR_INSUFFICIENT_BUFFER); res = nSize; - } - else + } else res = reroutedSize; - memcpy(lpFilename, - ush::string_cast(reroute.fileName()).c_str(), + memcpy(lpFilename, ush::string_cast(reroute.fileName()).c_str(), reroutedSize * sizeof(lpFilename[0])); lpFilename[reroutedSize] = 0; @@ -1407,8 +1393,8 @@ DWORD WINAPI usvfs::hook_GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, return res; } -DWORD WINAPI usvfs::hook_GetModuleFileNameW(HMODULE hModule, - LPWSTR lpFilename, DWORD nSize) +DWORD WINAPI usvfs::hook_GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, + DWORD nSize) { DWORD res = 0UL; @@ -1417,34 +1403,30 @@ DWORD WINAPI usvfs::hook_GetModuleFileNameW(HMODULE hModule, PRE_REALCALL res = ::GetModuleFileNameW(hModule, lpFilename, nSize); POST_REALCALL - if ((res != 0) && callContext.active()) - { + if ((res != 0) && callContext.active()) { std::vector buf; - // If GetModuleFileNameW failed because the buffer is not large enough this complicates matters - // because we are dealing with incomplete information (consider for example the case that we - // have a long real path which will be routed to a short virtual so the call should actually - // succeed in such a case). - // To solve this we simply use our own buffer to find the complete module path: - DWORD full_res = res; + // If GetModuleFileNameW failed because the buffer is not large enough this + // complicates matters because we are dealing with incomplete information (consider + // for example the case that we have a long real path which will be routed to a + // short virtual so the call should actually succeed in such a case). To solve this + // we simply use our own buffer to find the complete module path: + DWORD full_res = res; size_t buf_size = nSize; - while (full_res == buf_size) - { + while (full_res == buf_size) { buf_size = std::max(static_cast(MAX_PATH), buf_size * 2); buf.resize(buf_size); full_res = ::GetModuleFileNameW(hModule, buf.data(), buf_size); } - RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, buf.empty() ? lpFilename : buf.data(), true); - if (reroute.wasRerouted()) - { + RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, + buf.empty() ? lpFilename : buf.data(), true); + if (reroute.wasRerouted()) { DWORD reroutedSize = static_cast(wcslen(reroute.fileName())); - if (reroutedSize >= nSize) - { + if (reroutedSize >= nSize) { reroutedSize = nSize - 1; callContext.updateLastError(ERROR_INSUFFICIENT_BUFFER); res = nSize; - } - else + } else res = reroutedSize; memcpy(lpFilename, reroute.fileName(), reroutedSize * sizeof(lpFilename[0])); lpFilename[reroutedSize] = 0; @@ -1462,27 +1444,28 @@ DWORD WINAPI usvfs::hook_GetModuleFileNameW(HMODULE hModule, return res; } -HANDLE WINAPI usvfs::hook_FindFirstFileExW(LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags) +HANDLE WINAPI usvfs::hook_FindFirstFileExW( + LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, + FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags) { HANDLE res = INVALID_HANDLE_VALUE; HOOK_START_GROUP(MutExHookGroup::SEARCH_FILES) - if (!callContext.active()) - { - res = FindFirstFileExW(lpFileName, fInfoLevelId, lpFindFileData, fSearchOp, lpSearchFilter, dwAdditionalFlags); + if (!callContext.active()) { + res = FindFirstFileExW(lpFileName, fInfoLevelId, lpFindFileData, fSearchOp, + lpSearchFilter, dwAdditionalFlags); callContext.updateLastError(); return res; } // FindFirstFileEx() must fail early if the path ends with a slash - if (lpFileName) - { + if (lpFileName) { const auto len = wcslen(lpFileName); - if (len > 0) - { - if (lpFileName[len - 1] == L'\\' || lpFileName[len - 1] == L'/') - { - spdlog::get("usvfs")->warn("hook_FindFirstFileExW(): path '{}' ends with slash, always fails", fs::path(lpFileName).string()); + if (len > 0) { + if (lpFileName[len - 1] == L'\\' || lpFileName[len - 1] == L'/') { + spdlog::get("usvfs")->warn( + "hook_FindFirstFileExW(): path '{}' ends with slash, always fails", + fs::path(lpFileName).string()); return INVALID_HANDLE_VALUE; } } @@ -1494,65 +1477,73 @@ HANDLE WINAPI usvfs::hook_FindFirstFileExW(LPCWSTR lpFileName, FINDEX_INFO_LEVEL bool usedRewrite = false; - // We need to do some trickery here, since we only want to use the hooked NtQueryDirectoryFile for rerouted locations we need to check if the Directory path has been routed instead of the full path. + // We need to do some trickery here, since we only want to use the hooked + // NtQueryDirectoryFile for rerouted locations we need to check if the Directory path + // has been routed instead of the full path. originalPath = RerouteW::canonizePath(RerouteW::absolutePath(lpFileName)); PRE_REALCALL - res = ::FindFirstFileExW(originalPath.c_str(), fInfoLevelId, lpFindFileData, fSearchOp, lpSearchFilter, dwAdditionalFlags); + res = ::FindFirstFileExW(originalPath.c_str(), fInfoLevelId, lpFindFileData, + fSearchOp, lpSearchFilter, dwAdditionalFlags); POST_REALCALL - if (res == INVALID_HANDLE_VALUE) - { - fs::path searchPath = originalPath.filename(); - fs::path parentPath = originalPath.parent_path(); + if (res == INVALID_HANDLE_VALUE) { + fs::path searchPath = originalPath.filename(); + fs::path parentPath = originalPath.parent_path(); std::wstring findPath = parentPath.wstring(); - while (findPath.find(L"*?<>\"", 0, 1) != std::wstring::npos) - { + while (findPath.find(L"*?<>\"", 0, 1) != std::wstring::npos) { searchPath = parentPath.filename() / searchPath; parentPath = parentPath.parent_path(); - findPath = parentPath.wstring(); + findPath = parentPath.wstring(); } reroute = RerouteW::create(READ_CONTEXT(), callContext, parentPath.c_str()); - if (reroute.wasRerouted()) - { + if (reroute.wasRerouted()) { finalPath = reroute.fileName(); finalPath /= searchPath.wstring(); } - if (!finalPath.empty()) - { + if (!finalPath.empty()) { PRE_REALCALL usedRewrite = true; - res = ::FindFirstFileExW(finalPath.c_str(), fInfoLevelId, lpFindFileData, fSearchOp, lpSearchFilter, dwAdditionalFlags); + res = ::FindFirstFileExW(finalPath.c_str(), fInfoLevelId, lpFindFileData, + fSearchOp, lpSearchFilter, dwAdditionalFlags); POST_REALCALL } } - if (res != INVALID_HANDLE_VALUE) - { + if (res != INVALID_HANDLE_VALUE) { // store the original search path for use during iteration - WRITE_CONTEXT() - ->customData(SearchHandles)[res] = lpFileName; + WRITE_CONTEXT()->customData(SearchHandles)[res] = lpFileName; } - LOG_CALL().PARAM(lpFileName).PARAM(originalPath.c_str()).PARAM(res).PARAM(callContext.lastError()); + LOG_CALL() + .PARAM(lpFileName) + .PARAM(originalPath.c_str()) + .PARAM(res) + .PARAM(callContext.lastError()); if (usedRewrite) - LOG_CALL().PARAM(lpFileName).PARAM(finalPath.c_str()).PARAM(res).PARAM(callContext.lastError()); + LOG_CALL() + .PARAM(lpFileName) + .PARAM(finalPath.c_str()) + .PARAM(res) + .PARAM(callContext.lastError()); HOOK_END return res; } -HRESULT(WINAPI *usvfs::CopyFile2)(PCWSTR pwszExistingFileName, PCWSTR pwszNewFileName, COPYFILE2_EXTENDED_PARAMETERS *pExtendedParameters); +HRESULT(WINAPI* usvfs::CopyFile2)(PCWSTR pwszExistingFileName, PCWSTR pwszNewFileName, + COPYFILE2_EXTENDED_PARAMETERS* pExtendedParameters); -HRESULT WINAPI usvfs::hook_CopyFile2(PCWSTR pwszExistingFileName, PCWSTR pwszNewFileName, COPYFILE2_EXTENDED_PARAMETERS *pExtendedParameters) +HRESULT WINAPI usvfs::hook_CopyFile2(PCWSTR pwszExistingFileName, + PCWSTR pwszNewFileName, + COPYFILE2_EXTENDED_PARAMETERS* pExtendedParameters) { HRESULT res = E_FAIL; - typedef HRESULT(WINAPI * CopyFile2_t)(PCWSTR, PCWSTR, COPYFILE2_EXTENDED_PARAMETERS *); + typedef HRESULT(WINAPI * CopyFile2_t)(PCWSTR, PCWSTR, COPYFILE2_EXTENDED_PARAMETERS*); HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP) - if (!callContext.active()) - { + if (!callContext.active()) { res = CopyFile2(pwszExistingFileName, pwszNewFileName, pExtendedParameters); callContext.updateLastError(); return res; @@ -1564,22 +1555,26 @@ HRESULT WINAPI usvfs::hook_CopyFile2(PCWSTR pwszExistingFileName, PCWSTR pwszNew { auto context = READ_CONTEXT(); - readReroute = RerouteW::create(context, callContext, pwszExistingFileName); - callOriginal = writeReroute.rerouteNew(context, callContext, pwszNewFileName, - pExtendedParameters && (pExtendedParameters->dwCopyFlags & COPY_FILE_FAIL_IF_EXISTS) == 0, "hook_CopyFile2"); + readReroute = RerouteW::create(context, callContext, pwszExistingFileName); + callOriginal = writeReroute.rerouteNew( + context, callContext, pwszNewFileName, + pExtendedParameters && + (pExtendedParameters->dwCopyFlags & COPY_FILE_FAIL_IF_EXISTS) == 0, + "hook_CopyFile2"); } - if (callOriginal) - { + if (callOriginal) { PRE_REALCALL - res = CopyFile2(readReroute.fileName(), writeReroute.fileName(), pExtendedParameters); + res = + CopyFile2(readReroute.fileName(), writeReroute.fileName(), pExtendedParameters); POST_REALCALL writeReroute.updateResult(callContext, SUCCEEDED(res)); if (SUCCEEDED(res) && writeReroute.newReroute()) writeReroute.insertMapping(WRITE_CONTEXT()); - if (readReroute.wasRerouted() || writeReroute.wasRerouted() || writeReroute.changedError()) + if (readReroute.wasRerouted() || writeReroute.wasRerouted() || + writeReroute.changedError()) LOG_CALL() .PARAM(readReroute.fileName()) .PARAM(writeReroute.fileName()) @@ -1593,28 +1588,32 @@ HRESULT WINAPI usvfs::hook_CopyFile2(PCWSTR pwszExistingFileName, PCWSTR pwszNew return res; } -DWORD WINAPI usvfs::hook_GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName) +DWORD WINAPI usvfs::hook_GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, + LPCSTR lpDefault, + LPSTR lpReturnedString, DWORD nSize, + LPCSTR lpFileName) { DWORD res = 0; HOOK_START_GROUP(MutExHookGroup::OPEN_FILE) - if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) - { - res = ::GetPrivateProfileStringA(lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, lpFileName); + if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) { + res = ::GetPrivateProfileStringA(lpAppName, lpKeyName, lpDefault, lpReturnedString, + nSize, lpFileName); callContext.updateLastError(); return res; } - RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, ush::string_cast(lpFileName).c_str()); + RerouteW reroute = RerouteW::create( + READ_CONTEXT(), callContext, ush::string_cast(lpFileName).c_str()); PRE_REALCALL - res = - ::GetPrivateProfileStringA(lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, ush::string_cast(reroute.fileName()).c_str()); + res = ::GetPrivateProfileStringA( + lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, + ush::string_cast(reroute.fileName()).c_str()); POST_REALCALL - if (reroute.wasRerouted()) - { + if (reroute.wasRerouted()) { LOG_CALL() .PARAM(lpAppName) .PARAM(lpKeyName) @@ -1629,15 +1628,18 @@ DWORD WINAPI usvfs::hook_GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKey return res; } -DWORD WINAPI usvfs::hook_GetPrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName) +DWORD WINAPI usvfs::hook_GetPrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpKeyName, + LPCWSTR lpDefault, + LPWSTR lpReturnedString, DWORD nSize, + LPCWSTR lpFileName) { DWORD res = 0; HOOK_START_GROUP(MutExHookGroup::OPEN_FILE) - if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) - { - res = ::GetPrivateProfileStringW(lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, lpFileName); + if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) { + res = ::GetPrivateProfileStringW(lpAppName, lpKeyName, lpDefault, lpReturnedString, + nSize, lpFileName); callContext.updateLastError(); return res; } @@ -1645,12 +1647,11 @@ DWORD WINAPI usvfs::hook_GetPrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpK RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, lpFileName); PRE_REALCALL - res = - ::GetPrivateProfileStringW(lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, reroute.fileName()); + res = ::GetPrivateProfileStringW(lpAppName, lpKeyName, lpDefault, lpReturnedString, + nSize, reroute.fileName()); POST_REALCALL - if (reroute.wasRerouted()) - { + if (reroute.wasRerouted()) { LOG_CALL() .PARAM(lpAppName) .PARAM(lpKeyName) @@ -1665,28 +1666,30 @@ DWORD WINAPI usvfs::hook_GetPrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpK return res; } -DWORD WINAPI usvfs::hook_GetPrivateProfileSectionA(LPCSTR lpAppName, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName) +DWORD WINAPI usvfs::hook_GetPrivateProfileSectionA(LPCSTR lpAppName, + LPSTR lpReturnedString, DWORD nSize, + LPCSTR lpFileName) { DWORD res = 0; HOOK_START_GROUP(MutExHookGroup::OPEN_FILE) - if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) - { + if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) { res = ::GetPrivateProfileSectionA(lpAppName, lpReturnedString, nSize, lpFileName); callContext.updateLastError(); return res; } - RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, ush::string_cast(lpFileName).c_str()); + RerouteW reroute = RerouteW::create( + READ_CONTEXT(), callContext, ush::string_cast(lpFileName).c_str()); PRE_REALCALL - res = - ::GetPrivateProfileSectionA(lpAppName, lpReturnedString, nSize, ush::string_cast(reroute.fileName()).c_str()); + res = ::GetPrivateProfileSectionA( + lpAppName, lpReturnedString, nSize, + ush::string_cast(reroute.fileName()).c_str()); POST_REALCALL - if (reroute.wasRerouted()) - { + if (reroute.wasRerouted()) { LOG_CALL() .PARAM(lpAppName) .PARAM(lpFileName) @@ -1700,14 +1703,15 @@ DWORD WINAPI usvfs::hook_GetPrivateProfileSectionA(LPCSTR lpAppName, LPSTR lpRet return res; } -DWORD WINAPI usvfs::hook_GetPrivateProfileSectionW(LPCWSTR lpAppName, LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName) +DWORD WINAPI usvfs::hook_GetPrivateProfileSectionW(LPCWSTR lpAppName, + LPWSTR lpReturnedString, DWORD nSize, + LPCWSTR lpFileName) { DWORD res = 0; HOOK_START_GROUP(MutExHookGroup::OPEN_FILE) - if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) - { + if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) { res = ::GetPrivateProfileSectionW(lpAppName, lpReturnedString, nSize, lpFileName); callContext.updateLastError(); return res; @@ -1716,12 +1720,11 @@ DWORD WINAPI usvfs::hook_GetPrivateProfileSectionW(LPCWSTR lpAppName, LPWSTR lpR RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, lpFileName); PRE_REALCALL - res = - ::GetPrivateProfileSectionW(lpAppName, lpReturnedString, nSize, reroute.fileName()); + res = ::GetPrivateProfileSectionW(lpAppName, lpReturnedString, nSize, + reroute.fileName()); POST_REALCALL - if (reroute.wasRerouted()) - { + if (reroute.wasRerouted()) { LOG_CALL() .PARAM(lpAppName) .PARAM(lpFileName) @@ -1735,27 +1738,29 @@ DWORD WINAPI usvfs::hook_GetPrivateProfileSectionW(LPCWSTR lpAppName, LPWSTR lpR return res; } -BOOL WINAPI usvfs::hook_WritePrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpString, LPCSTR lpFileName) +BOOL WINAPI usvfs::hook_WritePrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, + LPCSTR lpString, LPCSTR lpFileName) { BOOL res = false; HOOK_START_GROUP(MutExHookGroup::OPEN_FILE) - if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) - { + if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) { res = ::WritePrivateProfileStringA(lpAppName, lpKeyName, lpString, lpFileName); callContext.updateLastError(); return res; } CreateRerouter reroute; - bool callOriginal = reroute.rerouteNew(READ_CONTEXT(), callContext, - ush::string_cast(lpFileName).c_str(), true, "hook_WritePrivateProfileStringA"); + bool callOriginal = reroute.rerouteNew( + READ_CONTEXT(), callContext, ush::string_cast(lpFileName).c_str(), + true, "hook_WritePrivateProfileStringA"); - if (callOriginal) - { + if (callOriginal) { PRE_REALCALL - res = ::WritePrivateProfileStringA(lpAppName, lpKeyName, lpString, ush::string_cast(reroute.fileName()).c_str()); + res = ::WritePrivateProfileStringA( + lpAppName, lpKeyName, lpString, + ush::string_cast(reroute.fileName()).c_str()); POST_REALCALL reroute.updateResult(callContext, res); @@ -1778,27 +1783,27 @@ BOOL WINAPI usvfs::hook_WritePrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKe return res; } -BOOL WINAPI usvfs::hook_WritePrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpString, LPCWSTR lpFileName) +BOOL WINAPI usvfs::hook_WritePrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpKeyName, + LPCWSTR lpString, LPCWSTR lpFileName) { BOOL res = false; HOOK_START_GROUP(MutExHookGroup::OPEN_FILE) - if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) - { + if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) { res = ::WritePrivateProfileStringW(lpAppName, lpKeyName, lpString, lpFileName); callContext.updateLastError(); return res; } CreateRerouter reroute; - bool callOriginal = reroute.rerouteNew(READ_CONTEXT(), callContext, - lpFileName, true, "hook_WritePrivateProfileStringW"); + bool callOriginal = reroute.rerouteNew(READ_CONTEXT(), callContext, lpFileName, true, + "hook_WritePrivateProfileStringW"); - if (callOriginal) - { + if (callOriginal) { PRE_REALCALL - res = ::WritePrivateProfileStringW(lpAppName, lpKeyName, lpString, reroute.fileName()); + res = ::WritePrivateProfileStringW(lpAppName, lpKeyName, lpString, + reroute.fileName()); POST_REALCALL reroute.updateResult(callContext, res); @@ -1828,13 +1833,11 @@ VOID WINAPI usvfs::hook_ExitProcess(UINT exitCode) { HookContext::Ptr context = WRITE_CONTEXT(); - std::vector> &delayed = context->delayed(); + std::vector>& delayed = context->delayed(); - if (!delayed.empty()) - { + if (!delayed.empty()) { // ensure all delayed tasks are completed before we exit the process - for (std::future &delayedOp : delayed) - { + for (std::future& delayedOp : delayed) { delayedOp.get(); } delayed.clear(); diff --git a/src/usvfs_dll/hooks/kernel32.h b/src/usvfs_dll/hooks/kernel32.h index c59f432..7087b2e 100644 --- a/src/usvfs_dll/hooks/kernel32.h +++ b/src/usvfs_dll/hooks/kernel32.h @@ -3,57 +3,114 @@ #include "ntdll_declarations.h" #include -namespace usvfs { +namespace usvfs +{ -DLLEXPORT BOOL WINAPI hook_GetFileAttributesExA(LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation); -DLLEXPORT BOOL WINAPI hook_GetFileAttributesExW(LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation); +DLLEXPORT BOOL WINAPI hook_GetFileAttributesExA(LPCSTR lpFileName, + GET_FILEEX_INFO_LEVELS fInfoLevelId, + LPVOID lpFileInformation); +DLLEXPORT BOOL WINAPI hook_GetFileAttributesExW(LPCWSTR lpFileName, + GET_FILEEX_INFO_LEVELS fInfoLevelId, + LPVOID lpFileInformation); DLLEXPORT DWORD WINAPI hook_GetFileAttributesA(LPCSTR lpFileName); DLLEXPORT DWORD WINAPI hook_GetFileAttributesW(LPCWSTR lpFileName); -DLLEXPORT DWORD WINAPI hook_SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes); +DLLEXPORT DWORD WINAPI hook_SetFileAttributesW(LPCWSTR lpFileName, + DWORD dwFileAttributes); DLLEXPORT DWORD WINAPI hook_GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer); DLLEXPORT DWORD WINAPI hook_GetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer); DLLEXPORT BOOL WINAPI hook_SetCurrentDirectoryA(LPCSTR lpPathName); DLLEXPORT BOOL WINAPI hook_SetCurrentDirectoryW(LPCWSTR lpPathName); -DLLEXPORT DWORD WINAPI hook_GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR *lpFilePart); -DLLEXPORT DWORD WINAPI hook_GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart); +DLLEXPORT DWORD WINAPI hook_GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, + LPSTR lpBuffer, LPSTR* lpFilePart); +DLLEXPORT DWORD WINAPI hook_GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, + LPWSTR lpBuffer, LPWSTR* lpFilePart); -DLLEXPORT BOOL WINAPI hook_CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); +DLLEXPORT BOOL WINAPI hook_CreateDirectoryW(LPCWSTR lpPathName, + LPSECURITY_ATTRIBUTES lpSecurityAttributes); DLLEXPORT BOOL WINAPI hook_RemoveDirectoryW(LPCWSTR lpPathName); DLLEXPORT BOOL WINAPI hook_DeleteFileW(LPCWSTR lpFileName); DLLEXPORT BOOL WINAPI hook_MoveFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName); DLLEXPORT BOOL WINAPI hook_MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName); -DLLEXPORT BOOL WINAPI hook_MoveFileExA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags); -DLLEXPORT BOOL WINAPI hook_MoveFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, DWORD dwFlags); -DLLEXPORT BOOL WINAPI hook_MoveFileWithProgressA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags); -DLLEXPORT BOOL WINAPI hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags);; +DLLEXPORT BOOL WINAPI hook_MoveFileExA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, + DWORD dwFlags); +DLLEXPORT BOOL WINAPI hook_MoveFileExW(LPCWSTR lpExistingFileName, + LPCWSTR lpNewFileName, DWORD dwFlags); +DLLEXPORT BOOL WINAPI hook_MoveFileWithProgressA(LPCSTR lpExistingFileName, + LPCSTR lpNewFileName, + LPPROGRESS_ROUTINE lpProgressRoutine, + LPVOID lpData, DWORD dwFlags); +DLLEXPORT BOOL WINAPI hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, + LPCWSTR lpNewFileName, + LPPROGRESS_ROUTINE lpProgressRoutine, + LPVOID lpData, DWORD dwFlags); +; -DLLEXPORT BOOL WINAPI hook_CopyFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, LPBOOL pbCancel, DWORD dwCopyFlags); +DLLEXPORT BOOL WINAPI hook_CopyFileExW(LPCWSTR lpExistingFileName, + LPCWSTR lpNewFileName, + LPPROGRESS_ROUTINE lpProgressRoutine, + LPVOID lpData, LPBOOL pbCancel, + DWORD dwCopyFlags); -extern HRESULT (WINAPI *CopyFile2)(PCWSTR pwszExistingFileName, PCWSTR pwszNewFileName, COPYFILE2_EXTENDED_PARAMETERS *pExtendedParameters); -DLLEXPORT HRESULT WINAPI hook_CopyFile2(PCWSTR pwszExistingFileName, PCWSTR pwszNewFileName, COPYFILE2_EXTENDED_PARAMETERS *pExtendedParameters); +extern HRESULT(WINAPI* CopyFile2)(PCWSTR pwszExistingFileName, PCWSTR pwszNewFileName, + COPYFILE2_EXTENDED_PARAMETERS* pExtendedParameters); +DLLEXPORT HRESULT WINAPI +hook_CopyFile2(PCWSTR pwszExistingFileName, PCWSTR pwszNewFileName, + COPYFILE2_EXTENDED_PARAMETERS* pExtendedParameters); -DLLEXPORT HMODULE WINAPI hook_LoadLibraryExA(LPCSTR lpFileName, HANDLE hFile, DWORD dwFlags); -DLLEXPORT HMODULE WINAPI hook_LoadLibraryExW(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags); +DLLEXPORT HMODULE WINAPI hook_LoadLibraryExA(LPCSTR lpFileName, HANDLE hFile, + DWORD dwFlags); +DLLEXPORT HMODULE WINAPI hook_LoadLibraryExW(LPCWSTR lpFileName, HANDLE hFile, + DWORD dwFlags); -extern BOOL (WINAPI *CreateProcessInternalW)(LPVOID token, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation, LPVOID newToken); -DLLEXPORT BOOL WINAPI hook_CreateProcessInternalW(LPVOID token, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation, LPVOID newToken); +extern BOOL(WINAPI* CreateProcessInternalW)( + LPVOID token, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation, LPVOID newToken); +DLLEXPORT BOOL WINAPI hook_CreateProcessInternalW( + LPVOID token, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation, LPVOID newToken); -DLLEXPORT DWORD WINAPI hook_GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize); -DLLEXPORT DWORD WINAPI hook_GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize); +DLLEXPORT DWORD WINAPI hook_GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, + DWORD nSize); +DLLEXPORT DWORD WINAPI hook_GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, + DWORD nSize); -DLLEXPORT HANDLE WINAPI hook_FindFirstFileExW(LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags); +DLLEXPORT HANDLE WINAPI hook_FindFirstFileExW( + LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, + FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags); -DLLEXPORT DWORD WINAPI hook_GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName); -DLLEXPORT DWORD WINAPI hook_GetPrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName); -DLLEXPORT DWORD WINAPI hook_GetPrivateProfileSectionA(LPCSTR lpAppName, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName); -DLLEXPORT DWORD WINAPI hook_GetPrivateProfileSectionW(LPCWSTR lpAppName, LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName); -DLLEXPORT BOOL WINAPI hook_WritePrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpString, LPCSTR lpFileName); -DLLEXPORT BOOL WINAPI hook_WritePrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpString, LPCWSTR lpFileName); +DLLEXPORT DWORD WINAPI hook_GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, + LPCSTR lpDefault, + LPSTR lpReturnedString, + DWORD nSize, LPCSTR lpFileName); +DLLEXPORT DWORD WINAPI hook_GetPrivateProfileStringW(LPCWSTR lpAppName, + LPCWSTR lpKeyName, + LPCWSTR lpDefault, + LPWSTR lpReturnedString, + DWORD nSize, LPCWSTR lpFileName); +DLLEXPORT DWORD WINAPI hook_GetPrivateProfileSectionA(LPCSTR lpAppName, + LPSTR lpReturnedString, + DWORD nSize, LPCSTR lpFileName); +DLLEXPORT DWORD WINAPI hook_GetPrivateProfileSectionW(LPCWSTR lpAppName, + LPWSTR lpReturnedString, + DWORD nSize, LPCWSTR lpFileName); +DLLEXPORT BOOL WINAPI hook_WritePrivateProfileStringA(LPCSTR lpAppName, + LPCSTR lpKeyName, LPCSTR lpString, + LPCSTR lpFileName); +DLLEXPORT BOOL WINAPI hook_WritePrivateProfileStringW(LPCWSTR lpAppName, + LPCWSTR lpKeyName, + LPCWSTR lpString, + LPCWSTR lpFileName); DLLEXPORT VOID WINAPI hook_ExitProcess(UINT exitCode); -} +} // namespace usvfs diff --git a/src/usvfs_dll/hooks/ntdll.cpp b/src/usvfs_dll/hooks/ntdll.cpp index 94107e4..3c96859 100644 --- a/src/usvfs_dll/hooks/ntdll.cpp +++ b/src/usvfs_dll/hooks/ntdll.cpp @@ -1,16 +1,16 @@ #include "ntdll.h" -#include "sharedids.h" -#include -#include "../hookcontext.h" #include "../hookcallcontext.h" +#include "../hookcontext.h" #include "../maptracker.h" #include "../stringcast_boost.h" -#include -#include -#include +#include "sharedids.h" #include -#include +#include #include +#include +#include +#include +#include namespace ulog = usvfs::log; namespace ush = usvfs::shared; @@ -28,30 +28,31 @@ using usvfs::UnicodeString; #define FILE_MAXIMUM_DISPOSITION 0x00000005 template -using unique_ptr_deleter = std::unique_ptr; +using unique_ptr_deleter = std::unique_ptr; -class RedirectionInfo { +class RedirectionInfo +{ public: UnicodeString path; bool redirected; RedirectionInfo() {} RedirectionInfo(UnicodeString path, bool redirected) - : path(path) - , redirected(redirected) + : path(path), redirected(redirected) {} }; -class HandleTracker { +class HandleTracker +{ public: using handle_type = HANDLE; - using info_type = UnicodeString; + using info_type = UnicodeString; HandleTracker() { insert_current_directory(); } - info_type lookup(handle_type handle) const { - if (valid_handle(handle)) - { + info_type lookup(handle_type handle) const + { + if (valid_handle(handle)) { std::shared_lock lock(m_mutex); auto find = m_map.find(handle); if (find != m_map.end()) @@ -60,7 +61,8 @@ public: return info_type(); } - void insert(handle_type handle, const info_type& info) { + void insert(handle_type handle, const info_type& info) + { if (!valid_handle(handle)) return; std::unique_lock lock(m_mutex); @@ -76,19 +78,22 @@ public: } private: - static bool valid_handle(handle_type handle) { return handle && handle != INVALID_HANDLE_VALUE; } + static bool valid_handle(handle_type handle) + { + return handle && handle != INVALID_HANDLE_VALUE; + } void insert_current_directory() { ntdll_declarations_init(); - UNICODE_STRING p{ 0 }; - RTL_RELATIVE_NAME r{ 0 }; - NTSTATUS status = RtlDosPathNameToRelativeNtPathName_U_WithStatus(L"x", &p, nullptr, &r); + UNICODE_STRING p{0}; + RTL_RELATIVE_NAME r{0}; + NTSTATUS status = + RtlDosPathNameToRelativeNtPathName_U_WithStatus(L"x", &p, nullptr, &r); if (status >= 0) { - if (r.ContainingDirectory && p.Buffer) - { - size_t len = p.Length / sizeof(WCHAR); + if (r.ContainingDirectory && p.Buffer) { + size_t len = p.Length / sizeof(WCHAR); size_t trim = strlen("\\x") + (p.Buffer[len - 1] ? 0 : 1); if (len > trim) insert(r.ContainingDirectory, info_type(p.Buffer, len - trim)); @@ -105,8 +110,7 @@ private: HandleTracker ntdllHandleTracker; - -UnicodeString CreateUnicodeString(const OBJECT_ATTRIBUTES *objectAttributes) +UnicodeString CreateUnicodeString(const OBJECT_ATTRIBUTES* objectAttributes) { UnicodeString result = ntdllHandleTracker.lookup(objectAttributes->RootDirectory); if (objectAttributes->ObjectName != nullptr) { @@ -115,7 +119,7 @@ UnicodeString CreateUnicodeString(const OBJECT_ATTRIBUTES *objectAttributes) return result; } -std::ostream &operator<<(std::ostream &os, const _UNICODE_STRING &str) +std::ostream& operator<<(std::ostream& os, const _UNICODE_STRING& str) { try { // TODO this does not correctly support surrogate pairs @@ -126,25 +130,24 @@ std::ostream &operator<<(std::ostream &os, const _UNICODE_STRING &str) // the string os << ush::string_cast(str.Buffer, ush::CodePage::UTF8, str.Length / sizeof(WCHAR)); - } catch (const std::exception &e) { + } catch (const std::exception& e) { os << e.what(); } return os; } -std::ostream &operator<<(std::ostream &os, POBJECT_ATTRIBUTES attr) +std::ostream& operator<<(std::ostream& os, POBJECT_ATTRIBUTES attr) { return operator<<(os, *attr->ObjectName); } -RedirectionInfo -applyReroute(const usvfs::HookContext::ConstPtr &context, - const usvfs::HookCallContext &callContext, - const UnicodeString &inPath) +RedirectionInfo applyReroute(const usvfs::HookContext::ConstPtr& context, + const usvfs::HookCallContext& callContext, + const UnicodeString& inPath) { RedirectionInfo result; - result.path = inPath; + result.path = inPath; result.redirected = false; if (callContext.active()) { @@ -153,19 +156,16 @@ applyReroute(const usvfs::HookContext::ConstPtr &context, static_cast(result.path) + 4, ush::CodePage::UTF8); auto node = context->redirectionTable()->findNode(lookupPath.c_str()); // if so, replace the file name with the path to the mapped file - if ((node.get() != nullptr) && (!node->data().linkTarget.empty() || node->isDirectory())) { + if ((node.get() != nullptr) && + (!node->data().linkTarget.empty() || node->isDirectory())) { std::wstring reroutePath; - if (node->data().linkTarget.length() > 0) - { - reroutePath = ush::string_cast( - node->data().linkTarget.c_str(), ush::CodePage::UTF8); - } - else - { - reroutePath = ush::string_cast( - node->path().c_str(), - ush::CodePage::UTF8); + if (node->data().linkTarget.length() > 0) { + reroutePath = ush::string_cast(node->data().linkTarget.c_str(), + ush::CodePage::UTF8); + } else { + reroutePath = + ush::string_cast(node->path().c_str(), ush::CodePage::UTF8); } if ((*reroutePath.rbegin() == L'\\') && (*lookupPath.rbegin() != '\\')) { reroutePath.resize(reroutePath.size() - 1); @@ -173,35 +173,33 @@ applyReroute(const usvfs::HookContext::ConstPtr &context, std::replace(reroutePath.begin(), reroutePath.end(), L'/', L'\\'); if (reroutePath[1] == L'\\') reroutePath[1] = L'?'; - result.path = LR"(\??\)" + reroutePath; + result.path = LR"(\??\)" + reroutePath; result.redirected = true; } } return result; } -RedirectionInfo -applyReroute(const usvfs::CreateRerouter &rerouter) +RedirectionInfo applyReroute(const usvfs::CreateRerouter& rerouter) { RedirectionInfo result; - result.path = rerouter.fileName(); + result.path = rerouter.fileName(); result.redirected = rerouter.wasRerouted(); std::wstring reroutePath(static_cast(result.path)); std::replace(reroutePath.begin(), reroutePath.end(), L'/', L'\\'); if (reroutePath[1] == L'\\') reroutePath[1] = L'?'; - if (!((reroutePath[0] == L'\\') && - (reroutePath[1] == L'?') && - (reroutePath[2] == L'?') && - (reroutePath[3] == L'\\'))) { + if (!((reroutePath[0] == L'\\') && (reroutePath[1] == L'?') && + (reroutePath[2] == L'?') && (reroutePath[3] == L'\\'))) { result.path = LR"(\??\)" + reroutePath; } return result; } -struct FindCreateTarget { +struct FindCreateTarget +{ usvfs::RedirectionTree::NodePtrT target; void operator()(usvfs::RedirectionTree::NodePtrT node) { @@ -212,8 +210,8 @@ struct FindCreateTarget { }; std::pair -findCreateTarget(const usvfs::HookContext::ConstPtr &context, - const UnicodeString &inPath) +findCreateTarget(const usvfs::HookContext::ConstPtr& context, + const UnicodeString& inPath) { std::pair result; result.first = inPath; @@ -223,11 +221,13 @@ findCreateTarget(const usvfs::HookContext::ConstPtr &context, static_cast(result.first) + 4, ush::CodePage::UTF8); FindCreateTarget visitor; usvfs::RedirectionTree::VisitorFunction visitorWrapper = - [&](const usvfs::RedirectionTree::NodePtrT &node) { visitor(node); }; + [&](const usvfs::RedirectionTree::NodePtrT& node) { + visitor(node); + }; context->redirectionTable()->visitPath(lookupPath, visitorWrapper); if (visitor.target.get() != nullptr) { - bfs::path relativePath - = ush::make_relative(visitor.target->path(), bfs::path(lookupPath)); + bfs::path relativePath = + ush::make_relative(visitor.target->path(), bfs::path(lookupPath)); bfs::path target(visitor.target->data().linkTarget.c_str()); target /= relativePath; @@ -238,10 +238,9 @@ findCreateTarget(const usvfs::HookContext::ConstPtr &context, return result; } -RedirectionInfo -applyReroute(const usvfs::HookContext::ConstPtr &context, - const usvfs::HookCallContext &callContext, - POBJECT_ATTRIBUTES inAttributes) +RedirectionInfo applyReroute(const usvfs::HookContext::ConstPtr& context, + const usvfs::HookCallContext& callContext, + POBJECT_ATTRIBUTES inAttributes) { return applyReroute(context, callContext, CreateUnicodeString(inAttributes)); } @@ -249,87 +248,81 @@ applyReroute(const usvfs::HookContext::ConstPtr &context, ULONG StructMinSize(FILE_INFORMATION_CLASS infoClass) { switch (infoClass) { - case FileBothDirectoryInformation: - return sizeof(FILE_BOTH_DIR_INFORMATION); - case FileDirectoryInformation: - return sizeof(FILE_DIRECTORY_INFORMATION); - case FileFullDirectoryInformation: - return sizeof(FILE_FULL_DIR_INFORMATION); - case FileIdBothDirectoryInformation: - return sizeof(FILE_ID_BOTH_DIR_INFORMATION); - case FileIdFullDirectoryInformation: - return sizeof(FILE_ID_FULL_DIR_INFORMATION); - case FileNamesInformation: - return sizeof(FILE_NAMES_INFORMATION); - case FileObjectIdInformation: - return sizeof(FILE_OBJECTID_INFORMATION); - case FileReparsePointInformation: - return sizeof(FILE_REPARSE_POINT_INFORMATION); - default: - return 0; + case FileBothDirectoryInformation: + return sizeof(FILE_BOTH_DIR_INFORMATION); + case FileDirectoryInformation: + return sizeof(FILE_DIRECTORY_INFORMATION); + case FileFullDirectoryInformation: + return sizeof(FILE_FULL_DIR_INFORMATION); + case FileIdBothDirectoryInformation: + return sizeof(FILE_ID_BOTH_DIR_INFORMATION); + case FileIdFullDirectoryInformation: + return sizeof(FILE_ID_FULL_DIR_INFORMATION); + case FileNamesInformation: + return sizeof(FILE_NAMES_INFORMATION); + case FileObjectIdInformation: + return sizeof(FILE_OBJECTID_INFORMATION); + case FileReparsePointInformation: + return sizeof(FILE_REPARSE_POINT_INFORMATION); + default: + return 0; } } -void GetInfoData(LPCVOID address, FILE_INFORMATION_CLASS infoClass, - ULONG &offset, std::wstring &fileName) +void GetInfoData(LPCVOID address, FILE_INFORMATION_CLASS infoClass, ULONG& offset, + std::wstring& fileName) { switch (infoClass) { - case FileBothDirectoryInformation: { - const FILE_BOTH_DIR_INFORMATION *info - = reinterpret_cast(address); - offset = info->NextEntryOffset; - fileName - = std::wstring(info->FileName, info->FileNameLength / sizeof(WCHAR)); - } break; - case FileDirectoryInformation: { - const FILE_DIRECTORY_INFORMATION *info - = reinterpret_cast(address); - offset = info->NextEntryOffset; - fileName - = std::wstring(info->FileName, info->FileNameLength / sizeof(WCHAR)); - } break; - case FileNamesInformation: { - const FILE_NAMES_INFORMATION *info - = reinterpret_cast(address); - offset = info->NextEntryOffset; - fileName - = std::wstring(info->FileName, info->FileNameLength / sizeof(WCHAR)); - } break; - case FileIdFullDirectoryInformation: { - const FILE_ID_FULL_DIR_INFORMATION *info - = reinterpret_cast(address); - offset = info->NextEntryOffset; - fileName - = std::wstring(info->FileName, info->FileNameLength / sizeof(WCHAR)); - } break; - case FileFullDirectoryInformation: { - const FILE_FULL_DIR_INFORMATION *info - = reinterpret_cast(address); - offset = info->NextEntryOffset; - fileName - = std::wstring(info->FileName, info->FileNameLength / sizeof(WCHAR)); - } break; - case FileIdBothDirectoryInformation: { - const FILE_ID_BOTH_DIR_INFORMATION *info - = reinterpret_cast(address); - offset = info->NextEntryOffset; - fileName - = std::wstring(info->FileName, info->FileNameLength / sizeof(WCHAR)); - } break; - case FileObjectIdInformation: { - offset = sizeof(FILE_OBJECTID_INFORMATION); - } break; - case FileReparsePointInformation: { - offset = sizeof(FILE_REPARSE_POINT_INFORMATION); - } break; - default: { - offset = ULONG_MAX; - } break; + case FileBothDirectoryInformation: { + const FILE_BOTH_DIR_INFORMATION* info = + reinterpret_cast(address); + offset = info->NextEntryOffset; + fileName = std::wstring(info->FileName, info->FileNameLength / sizeof(WCHAR)); + } break; + case FileDirectoryInformation: { + const FILE_DIRECTORY_INFORMATION* info = + reinterpret_cast(address); + offset = info->NextEntryOffset; + fileName = std::wstring(info->FileName, info->FileNameLength / sizeof(WCHAR)); + } break; + case FileNamesInformation: { + const FILE_NAMES_INFORMATION* info = + reinterpret_cast(address); + offset = info->NextEntryOffset; + fileName = std::wstring(info->FileName, info->FileNameLength / sizeof(WCHAR)); + } break; + case FileIdFullDirectoryInformation: { + const FILE_ID_FULL_DIR_INFORMATION* info = + reinterpret_cast(address); + offset = info->NextEntryOffset; + fileName = std::wstring(info->FileName, info->FileNameLength / sizeof(WCHAR)); + } break; + case FileFullDirectoryInformation: { + const FILE_FULL_DIR_INFORMATION* info = + reinterpret_cast(address); + offset = info->NextEntryOffset; + fileName = std::wstring(info->FileName, info->FileNameLength / sizeof(WCHAR)); + } break; + case FileIdBothDirectoryInformation: { + const FILE_ID_BOTH_DIR_INFORMATION* info = + reinterpret_cast(address); + offset = info->NextEntryOffset; + fileName = std::wstring(info->FileName, info->FileNameLength / sizeof(WCHAR)); + } break; + case FileObjectIdInformation: { + offset = sizeof(FILE_OBJECTID_INFORMATION); + } break; + case FileReparsePointInformation: { + offset = sizeof(FILE_REPARSE_POINT_INFORMATION); + } break; + default: { + offset = ULONG_MAX; + } break; } } template -void SetInfoFilenameImpl(T *info, const std::wstring &fileName) +void SetInfoFilenameImpl(T* info, const std::wstring& fileName) { info->FileNameLength = static_cast(fileName.length() * sizeof(WCHAR)); memcpy(info->FileName, fileName.c_str(), info->FileNameLength + 1); @@ -338,8 +331,7 @@ void SetInfoFilenameImpl(T *info, const std::wstring &fileName) // like wcsrchr except that the position to start searching can be specified and // the string doesn't // need to be 0-terminated -const wchar_t *wcsrevsearch(const wchar_t *cur, const wchar_t *start, - wchar_t ch) +const wchar_t* wcsrevsearch(const wchar_t* cur, const wchar_t* start, wchar_t ch) { for (; cur > start; --cur) { if (*cur == ch) { @@ -350,104 +342,93 @@ const wchar_t *wcsrevsearch(const wchar_t *cur, const wchar_t *start, } template -void SetInfoFilenameImplSN(T *info, const std::wstring &fileName) +void SetInfoFilenameImplSN(T* info, const std::wstring& fileName) { memset(info->FileName, L'\0', info->FileNameLength); info->FileNameLength = static_cast(fileName.length() * sizeof(WCHAR)); memcpy(info->FileName, fileName.c_str(), - info->FileNameLength); // doesn't need to be 0-terminated + info->FileNameLength); // doesn't need to be 0-terminated if (info->ShortNameLength > 0) { - info->ShortNameLength = static_cast( - GetShortPathNameW(fileName.c_str(), info->ShortName, 8)); + info->ShortNameLength = + static_cast(GetShortPathNameW(fileName.c_str(), info->ShortName, 8)); } } void SetInfoFilename(LPVOID address, FILE_INFORMATION_CLASS infoClass, - const std::wstring &fileName) + const std::wstring& fileName) { switch (infoClass) { - case FileAllInformation: { - SetInfoFilenameImpl( + case FileAllInformation: { + SetInfoFilenameImpl( &reinterpret_cast(address)->NameInformation, fileName); - } break; - case FileBothDirectoryInformation: { - SetInfoFilenameImplSN( - reinterpret_cast(address), fileName); - } break; - case FileDirectoryInformation: { - SetInfoFilenameImpl( - reinterpret_cast(address), fileName); - } break; - case FileNameInformation: { - SetInfoFilenameImpl( - reinterpret_cast(address), fileName); - } break; - case FileNamesInformation: { - SetInfoFilenameImpl( - reinterpret_cast(address), fileName); - } break; - case FileNormalizedNameInformation: { - SetInfoFilenameImpl( - reinterpret_cast(address), fileName); - } break; - case FileIdFullDirectoryInformation: { - SetInfoFilenameImpl( - reinterpret_cast(address), fileName); - } break; - case FileFullDirectoryInformation: { - SetInfoFilenameImpl( - reinterpret_cast(address), fileName); - } break; - case FileIdBothDirectoryInformation: { - SetInfoFilenameImplSN( - reinterpret_cast(address), fileName); - } break; - default: { - // NOP - } break; + } break; + case FileBothDirectoryInformation: { + SetInfoFilenameImplSN(reinterpret_cast(address), + fileName); + } break; + case FileDirectoryInformation: { + SetInfoFilenameImpl(reinterpret_cast(address), + fileName); + } break; + case FileNameInformation: { + SetInfoFilenameImpl(reinterpret_cast(address), fileName); + } break; + case FileNamesInformation: { + SetInfoFilenameImpl(reinterpret_cast(address), fileName); + } break; + case FileNormalizedNameInformation: { + SetInfoFilenameImpl(reinterpret_cast(address), fileName); + } break; + case FileIdFullDirectoryInformation: { + SetInfoFilenameImpl(reinterpret_cast(address), + fileName); + } break; + case FileFullDirectoryInformation: { + SetInfoFilenameImpl(reinterpret_cast(address), + fileName); + } break; + case FileIdBothDirectoryInformation: { + SetInfoFilenameImplSN(reinterpret_cast(address), + fileName); + } break; + default: { + // NOP + } break; } } -void SetInfoOffset(LPVOID address, FILE_INFORMATION_CLASS infoClass, - ULONG offset) +void SetInfoOffset(LPVOID address, FILE_INFORMATION_CLASS infoClass, ULONG offset) { switch (infoClass) { - case FileBothDirectoryInformation: { - reinterpret_cast(address)->NextEntryOffset - = offset; - } break; - case FileDirectoryInformation: { - reinterpret_cast(address)->NextEntryOffset - = offset; - } break; - case FileNamesInformation: { - reinterpret_cast(address)->NextEntryOffset - = offset; - } break; - case FileIdFullDirectoryInformation: { - reinterpret_cast(address)->NextEntryOffset - = offset; - } break; - case FileFullDirectoryInformation: { - reinterpret_cast(address)->NextEntryOffset - = offset; - } break; - case FileIdBothDirectoryInformation: { - reinterpret_cast(address)->NextEntryOffset - = offset; - } break; - default: { - // NOP - } break; + case FileBothDirectoryInformation: { + reinterpret_cast(address)->NextEntryOffset = offset; + } break; + case FileDirectoryInformation: { + reinterpret_cast(address)->NextEntryOffset = offset; + } break; + case FileNamesInformation: { + reinterpret_cast(address)->NextEntryOffset = offset; + } break; + case FileIdFullDirectoryInformation: { + reinterpret_cast(address)->NextEntryOffset = offset; + } break; + case FileFullDirectoryInformation: { + reinterpret_cast(address)->NextEntryOffset = offset; + } break; + case FileIdBothDirectoryInformation: { + reinterpret_cast(address)->NextEntryOffset = offset; + } break; + default: { + // NOP + } break; } } int NextDividableBy(int number, int divider) { return static_cast( - ceilf(static_cast(number) / static_cast(divider)) - * divider); + ceilf(static_cast(number) / static_cast(divider)) * divider); } // Something is trying to create a variety of files starting with "\Device\", @@ -482,29 +463,27 @@ bool isDeviceFile(std::wstring_view name) } } - NTSTATUS addNtSearchData(HANDLE hdl, PUNICODE_STRING FileName, - const std::wstring &fakeName, - FILE_INFORMATION_CLASS FileInformationClass, - PVOID &buffer, ULONG &bufferSize, - std::set &foundFiles, HANDLE event, - PIO_APC_ROUTINE apcRoutine, PVOID apcContext, + const std::wstring& fakeName, + FILE_INFORMATION_CLASS FileInformationClass, PVOID& buffer, + ULONG& bufferSize, std::set& foundFiles, + HANDLE event, PIO_APC_ROUTINE apcRoutine, PVOID apcContext, BOOLEAN returnSingleEntry) { NTSTATUS res = STATUS_NO_SUCH_FILE; if (hdl != INVALID_HANDLE_VALUE) { PVOID lastValidRecord = nullptr; - PVOID bufferInit = buffer; + PVOID bufferInit = buffer; IO_STATUS_BLOCK status; - res = NtQueryDirectoryFile(hdl, event, apcRoutine, apcContext, &status, - buffer, bufferSize, FileInformationClass, - returnSingleEntry, FileName, FALSE); + res = NtQueryDirectoryFile(hdl, event, apcRoutine, apcContext, &status, buffer, + bufferSize, FileInformationClass, returnSingleEntry, + FileName, FALSE); if ((res != STATUS_SUCCESS) || (status.Information <= 0)) { bufferSize = 0UL; } else { - ULONG totalOffset = 0; - PVOID lastSkipPos = nullptr; + ULONG totalOffset = 0; + PVOID lastSkipPos = nullptr; while (totalOffset < status.Information) { ULONG offset; @@ -516,9 +495,9 @@ NTSTATUS addNtSearchData(HANDLE hdl, PUNICODE_STRING FileName, if ((totalOffset == 0) && (offset == 0) && (fakeName.length() > 0)) { // if the fake name is larger than what is in the buffer and there is // not enough room, that's a buffer overflow - if ((fakeName.length() > fileName.length()) - && ((fakeName.length() - fileName.length()) - > (bufferSize - status.Information))) { + if ((fakeName.length() > fileName.length()) && + ((fakeName.length() - fileName.length()) > + (bufferSize - status.Information))) { res = STATUS_BUFFER_OVERFLOW; break; } @@ -530,7 +509,7 @@ NTSTATUS addNtSearchData(HANDLE hdl, PUNICODE_STRING FileName, bool add = true; if (fileName.length() > 0) { auto insertRes = foundFiles.insert(ush::to_upper(fileName)); - add = insertRes.second; // add only if we didn't find this file before + add = insertRes.second; // add only if we didn't find this file before } if (!add) { if (lastSkipPos == nullptr) { @@ -542,7 +521,7 @@ NTSTATUS addNtSearchData(HANDLE hdl, PUNICODE_STRING FileName, ULONG delta = static_cast(ush::AddrDiff(buffer, lastSkipPos)); totalOffset -= delta; - buffer = lastSkipPos; + buffer = lastSkipPos; lastSkipPos = nullptr; } lastValidRecord = buffer; @@ -556,7 +535,7 @@ NTSTATUS addNtSearchData(HANDLE hdl, PUNICODE_STRING FileName, } if (lastSkipPos != nullptr) { - buffer = lastSkipPos; + buffer = lastSkipPos; bufferSize = static_cast(ush::AddrDiff(buffer, bufferInit)); // null out the unused rest if there is some memset(lastSkipPos, 0, status.Information - bufferSize); @@ -573,9 +552,12 @@ NTSTATUS addNtSearchData(HANDLE hdl, PUNICODE_STRING FileName, DATA_ID(SearchInfo); -struct Searches { - struct Info { - struct VirtualMatch { +struct Searches +{ + struct Info + { + struct VirtualMatch + { // full path to where the file/directory actually is std::wstring realPath; // virtual filename (only filename since it has to be within the searched @@ -585,9 +567,7 @@ struct Searches { std::wstring virtualName; }; - Info() : currentSearchHandle(INVALID_HANDLE_VALUE) - { - } + Info() : currentSearchHandle(INVALID_HANDLE_VALUE) {} std::set foundFiles; HANDLE currentSearchHandle; std::queue virtualMatches; @@ -599,53 +579,50 @@ struct Searches { // must provide a special copy constructor because boost::mutex is // non-copyable - Searches(const Searches &reference) : info(reference.info) - { - } + Searches(const Searches& reference) : info(reference.info) {} - Searches &operator=(const Searches &) = delete; + Searches& operator=(const Searches&) = delete; std::recursive_mutex queryMutex; std::map info; }; -void gatherVirtualEntries(const UnicodeString &dirName, - const usvfs::RedirectionTreeContainer &redir, - PUNICODE_STRING FileName, Searches::Info &info) +void gatherVirtualEntries(const UnicodeString& dirName, + const usvfs::RedirectionTreeContainer& redir, + PUNICODE_STRING FileName, Searches::Info& info) { LPCWSTR dirNameW = static_cast(dirName); // fix directory name. I'd love to know why microsoft sometimes uses "\??\" vs // "\\?\" - if ((wcsncmp(dirNameW, LR"(\\?\)", 4) == 0) - || (wcsncmp(dirNameW, LR"(\??\)", 4) == 0)) { + if ((wcsncmp(dirNameW, LR"(\\?\)", 4) == 0) || + (wcsncmp(dirNameW, LR"(\??\)", 4) == 0)) { dirNameW += 4; } auto node = redir->findNode(boost::filesystem::path(dirNameW)); if (node.get() != nullptr) { - std::string searchPattern = FileName != nullptr - ? ush::string_cast( - FileName->Buffer, ush::CodePage::UTF8) - : "*.*"; + std::string searchPattern = + FileName != nullptr + ? ush::string_cast(FileName->Buffer, ush::CodePage::UTF8) + : "*.*"; boost::replace_all(searchPattern, "\"", "."); - for (const auto &subNode : node->find(searchPattern)) { - if (((subNode->data().linkTarget.length() > 0) || subNode->isDirectory()) - && !subNode->hasFlag(usvfs::shared::FLAG_DUMMY)) { - std::wstring vName = ush::string_cast( - subNode->name(), ush::CodePage::UTF8); + for (const auto& subNode : node->find(searchPattern)) { + if (((subNode->data().linkTarget.length() > 0) || subNode->isDirectory()) && + !subNode->hasFlag(usvfs::shared::FLAG_DUMMY)) { + std::wstring vName = + ush::string_cast(subNode->name(), ush::CodePage::UTF8); Searches::Info::VirtualMatch m; - if (subNode->data().linkTarget.length() > 0) - { - m = { ush::string_cast(subNode->data().linkTarget.c_str(), - ush::CodePage::UTF8), vName }; - } - else - { - m = { ush::string_cast(subNode->path().c_str(), - ush::CodePage::UTF8), vName }; + if (subNode->data().linkTarget.length() > 0) { + m = {ush::string_cast(subNode->data().linkTarget.c_str(), + ush::CodePage::UTF8), + vName}; + } else { + m = {ush::string_cast(subNode->path().c_str(), + ush::CodePage::UTF8), + vName}; } info.virtualMatches.push(m); @@ -668,11 +645,11 @@ void gatherVirtualEntries(const UnicodeString &dirName, * @return true if a virtual result was added, false if the search handle in the * info object yields no more results */ -bool addVirtualSearchResult(PVOID &FileInformation, +bool addVirtualSearchResult(PVOID& FileInformation, FILE_INFORMATION_CLASS FileInformationClass, - Searches::Info &info, const std::wstring &realPath, - const std::wstring &virtualName, - BOOLEAN ReturnSingleEntry, ULONG &dataRead) + Searches::Info& info, const std::wstring& realPath, + const std::wstring& virtualName, BOOLEAN ReturnSingleEntry, + ULONG& dataRead) { // this opens a search in the real location, then copies the information about // files we care about (the ones being mapped) to the result we intend to @@ -682,22 +659,21 @@ bool addVirtualSearchResult(PVOID &FileInformation, fullPath = fullPath.parent_path(); } if (info.currentSearchHandle == INVALID_HANDLE_VALUE) { - std::wstring dirName = fullPath.parent_path().wstring(); + std::wstring dirName = fullPath.parent_path().wstring(); if (dirName.length() >= MAX_PATH && !ush::startswith(dirName.c_str(), LR"(\\?\)")) dirName = LR"(\\?\)" + dirName; - info.currentSearchHandle = CreateFileW( - dirName.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, - nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + info.currentSearchHandle = + CreateFileW(dirName.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); } - std::wstring fileName = ush::string_cast( - fullPath.filename().string(), ush::CodePage::UTF8); + std::wstring fileName = + ush::string_cast(fullPath.filename().string(), ush::CodePage::UTF8); NTSTATUS subRes = addNtSearchData( info.currentSearchHandle, - (fileName != L".") - ? static_cast(UnicodeString(fileName.c_str())) - : nullptr, - virtualName, FileInformationClass, FileInformation, dataRead, - info.foundFiles, nullptr, nullptr, nullptr, ReturnSingleEntry); + (fileName != L".") ? static_cast(UnicodeString(fileName.c_str())) + : nullptr, + virtualName, FileInformationClass, FileInformation, dataRead, info.foundFiles, + nullptr, nullptr, nullptr, ReturnSingleEntry); if (subRes == STATUS_SUCCESS) { return true; } else { @@ -706,18 +682,17 @@ bool addVirtualSearchResult(PVOID &FileInformation, // resume in the next mapped directory if (subRes != STATUS_NO_MORE_FILES) { spdlog::get("hooks")->warn("error reported listing files in {0}: {1:x}", - fullPath.string(), - static_cast(subRes)); + fullPath.string(), static_cast(subRes)); } return false; } } NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFile( - HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, - PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, - ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, - BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan) + HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, + PUNICODE_STRING FileName, BOOLEAN RestartScan) { PreserveGetLastError ntFunctionsDoNotChangeGetLastError; @@ -733,20 +708,19 @@ NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFile( NTSTATUS res = STATUS_NO_MORE_FILES; HOOK_START_GROUP(MutExHookGroup::FIND_FILES) if (!callContext.active()) { - return ::NtQueryDirectoryFile(FileHandle, Event, ApcRoutine, ApcContext, - IoStatusBlock, FileInformation, Length, - FileInformationClass, ReturnSingleEntry, - FileName, RestartScan); + return ::NtQueryDirectoryFile( + FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, FileInformation, + Length, FileInformationClass, ReturnSingleEntry, FileName, RestartScan); } -// std::unique_lock queryLock; + // std::unique_lock queryLock; std::map::iterator infoIter; bool firstSearch = false; - { // scope to limit context lifetime + { // scope to limit context lifetime HookContext::ConstPtr context = READ_CONTEXT(); - Searches &activeSearches = context->customData(SearchInfo); -// queryLock = std::unique_lock(activeSearches.queryMutex); + Searches& activeSearches = context->customData(SearchInfo); + // queryLock = std::unique_lock(activeSearches.queryMutex); if (RestartScan) { auto iter = activeSearches.info.find(FileHandle); @@ -756,34 +730,31 @@ NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFile( } // see if we already have a running search - infoIter = activeSearches.info.find(FileHandle); + infoIter = activeSearches.info.find(FileHandle); firstSearch = (infoIter == activeSearches.info.end()); } if (firstSearch) { HookContext::Ptr context = WRITE_CONTEXT(); - Searches &activeSearches = context->customData(SearchInfo); + Searches& activeSearches = context->customData(SearchInfo); // tradeoff time: we store this search status even if no virtual results // were found. This causes a little extra cost here and in NtClose every // time a non-virtual dir is being searched. However if we don't, // whenever NtQueryDirectoryFile is called another time on the same handle, // this (expensive) block would be run again. - infoIter = activeSearches.info.insert(std::make_pair(FileHandle, - Searches::Info())) - .first; + infoIter = + activeSearches.info.insert(std::make_pair(FileHandle, Searches::Info())).first; infoIter->second.searchPattern.appendPath(FileName); - SearchHandleMap &searchMap - = context->customData(SearchHandles); + SearchHandleMap& searchMap = context->customData(SearchHandles); SearchHandleMap::iterator iter = searchMap.find(FileHandle); UnicodeString searchPath; if (iter != searchMap.end()) { - searchPath = UnicodeString(iter->second.c_str()); - infoIter->second.currentSearchHandle = - CreateFileW(iter->second.c_str(), GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + searchPath = UnicodeString(iter->second.c_str()); + infoIter->second.currentSearchHandle = CreateFileW( + iter->second.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); } else { searchPath = ntdllHandleTracker.lookup(FileHandle); } @@ -791,7 +762,7 @@ NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFile( infoIter->second); } - ULONG dataRead = Length; + ULONG dataRead = Length; PVOID FileInformationCurrent = FileInformation; // add regular search results, skipping those files we have in a virtual @@ -799,16 +770,15 @@ NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFile( bool moreRegular = !infoIter->second.regularComplete; bool dataReturned = false; while (moreRegular && !dataReturned) { - dataRead = Length; + dataRead = Length; HANDLE handle = infoIter->second.currentSearchHandle; if (handle == INVALID_HANDLE_VALUE) { handle = FileHandle; } NTSTATUS subRes = addNtSearchData( - handle, FileName, L"", FileInformationClass, FileInformationCurrent, - dataRead, infoIter->second.foundFiles, Event, ApcRoutine, ApcContext, - ReturnSingleEntry); + handle, FileName, L"", FileInformationClass, FileInformationCurrent, dataRead, + infoIter->second.foundFiles, Event, ApcRoutine, ApcContext, ReturnSingleEntry); moreRegular = subRes == STATUS_SUCCESS; if (moreRegular) { dataReturned = dataRead != 0; @@ -828,9 +798,8 @@ NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFile( if (match.realPath.size() != 0) { dataRead = Length; if (addVirtualSearchResult(FileInformationCurrent, FileInformationClass, - infoIter->second, match.realPath, - match.virtualName, ReturnSingleEntry, - dataRead)) { + infoIter->second, match.realPath, match.virtualName, + ReturnSingleEntry, dataRead)) { // a positive result here means the call returned data and there may // be further objects to be retrieved by repeating the call dataReturned = true; @@ -875,15 +844,9 @@ NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFile( } NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFileEx( - HANDLE FileHandle, - HANDLE Event, - PIO_APC_ROUTINE ApcRoutine, - PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass, - ULONG QueryFlags, + HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass, ULONG QueryFlags, PUNICODE_STRING FileName) { PreserveGetLastError ntFunctionsDoNotChangeGetLastError; @@ -901,17 +864,17 @@ NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFileEx( HOOK_START_GROUP(MutExHookGroup::FIND_FILES) if (!callContext.active()) { return ::NtQueryDirectoryFileEx(FileHandle, Event, ApcRoutine, ApcContext, - IoStatusBlock, FileInformation, Length, - FileInformationClass, QueryFlags, FileName); + IoStatusBlock, FileInformation, Length, + FileInformationClass, QueryFlags, FileName); } // std::unique_lock queryLock; std::map::iterator infoIter; bool firstSearch = false; - { // scope to limit context lifetime + { // scope to limit context lifetime HookContext::ConstPtr context = READ_CONTEXT(); - Searches &activeSearches = context->customData(SearchInfo); + Searches& activeSearches = context->customData(SearchInfo); // queryLock = std::unique_lock(activeSearches.queryMutex); if (QueryFlags & SL_RESTART_SCAN) { @@ -922,48 +885,44 @@ NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFileEx( } // see if we already have a running search - infoIter = activeSearches.info.find(FileHandle); + infoIter = activeSearches.info.find(FileHandle); firstSearch = (infoIter == activeSearches.info.end()); } if (firstSearch) { HookContext::Ptr context = WRITE_CONTEXT(); - Searches &activeSearches = context->customData(SearchInfo); + Searches& activeSearches = context->customData(SearchInfo); // tradeoff time: we store this search status even if no virtual results // were found. This causes a little extra cost here and in NtClose every // time a non-virtual dir is being searched. However if we don't, // whenever NtQueryDirectoryFile is called another time on the same handle, // this (expensive) block would be run again. - infoIter = activeSearches.info.insert(std::make_pair(FileHandle, - Searches::Info())) - .first; + infoIter = + activeSearches.info.insert(std::make_pair(FileHandle, Searches::Info())).first; infoIter->second.searchPattern.appendPath(FileName); - SearchHandleMap &searchMap - = context->customData(SearchHandles); + SearchHandleMap& searchMap = context->customData(SearchHandles); SearchHandleMap::iterator iter = searchMap.find(FileHandle); UnicodeString searchPath; if (iter != searchMap.end()) { - searchPath = UnicodeString(iter->second.c_str()); - infoIter->second.currentSearchHandle = - CreateFileW(iter->second.c_str(), GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - } - else { + searchPath = UnicodeString(iter->second.c_str()); + infoIter->second.currentSearchHandle = CreateFileW( + iter->second.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + } else { searchPath = ntdllHandleTracker.lookup(FileHandle); } gatherVirtualEntries(searchPath, context->redirectionTable(), FileName, - infoIter->second); + infoIter->second); } - ULONG dataRead = Length; + ULONG dataRead = Length; PVOID FileInformationCurrent = FileInformation; // add regular search results, skipping those files we have in a virtual // location - bool moreRegular = !infoIter->second.regularComplete; + bool moreRegular = !infoIter->second.regularComplete; bool dataReturned = false; while (moreRegular && !dataReturned) { dataRead = Length; @@ -972,15 +931,14 @@ NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFileEx( if (handle == INVALID_HANDLE_VALUE) { handle = FileHandle; } - NTSTATUS subRes = addNtSearchData( - handle, FileName, L"", FileInformationClass, FileInformationCurrent, - dataRead, infoIter->second.foundFiles, Event, ApcRoutine, ApcContext, - QueryFlags & SL_RETURN_SINGLE_ENTRY); - moreRegular = subRes == STATUS_SUCCESS; + NTSTATUS subRes = addNtSearchData(handle, FileName, L"", FileInformationClass, + FileInformationCurrent, dataRead, + infoIter->second.foundFiles, Event, ApcRoutine, + ApcContext, QueryFlags & SL_RETURN_SINGLE_ENTRY); + moreRegular = subRes == STATUS_SUCCESS; if (moreRegular) { dataReturned = dataRead != 0; - } - else { + } else { infoIter->second.regularComplete = true; infoIter->second.foundFiles.clear(); if (infoIter->second.currentSearchHandle != INVALID_HANDLE_VALUE) { @@ -996,14 +954,12 @@ NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFileEx( if (match.realPath.size() != 0) { dataRead = Length; if (addVirtualSearchResult(FileInformationCurrent, FileInformationClass, - infoIter->second, match.realPath, - match.virtualName, QueryFlags & SL_RETURN_SINGLE_ENTRY, - dataRead)) { + infoIter->second, match.realPath, match.virtualName, + QueryFlags & SL_RETURN_SINGLE_ENTRY, dataRead)) { // a positive result here means the call returned data and there may // be further objects to be retrieved by repeating the call dataReturned = true; - } - else { + } else { // proceed to next search handle // TODO: doesn't append search results from more than one redirection @@ -1020,26 +976,24 @@ NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFileEx( if (!dataReturned) { if (firstSearch) { res = STATUS_NO_SUCH_FILE; - } - else { + } else { res = STATUS_NO_MORE_FILES; } - } - else { + } else { res = STATUS_SUCCESS; } - IoStatusBlock->Status = res; + IoStatusBlock->Status = res; IoStatusBlock->Information = dataRead; size_t numVirtualFiles = infoIter->second.virtualMatches.size(); if ((numVirtualFiles > 0)) { LOG_CALL() - .addParam("path", ntdllHandleTracker.lookup(FileHandle)) - .PARAM(FileInformationClass) - .PARAM(FileName) - .PARAM(QueryFlags) - .PARAM(numVirtualFiles) - .PARAMWRAP(res); + .addParam("path", ntdllHandleTracker.lookup(FileHandle)) + .PARAM(FileInformationClass) + .PARAM(FileName) + .PARAM(QueryFlags) + .PARAM(numVirtualFiles) + .PARAMWRAP(res); } HOOK_END @@ -1047,15 +1001,15 @@ NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFileEx( } DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryObject( - HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, - PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength) + HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, + PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength) { NTSTATUS res = STATUS_SUCCESS; HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES) if (!callContext.active()) { return ::NtQueryObject(Handle, ObjectInformationClass, ObjectInformation, - ObjectInformationLength, ReturnLength); + ObjectInformationLength, ReturnLength); } PRE_REALCALL @@ -1067,23 +1021,22 @@ DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryObject( // smaller than the original one // // we only handle STATUS_INFO_LENGTH_MISMATCH if ReturnLength is not NULL since - // this is only returned if the length is too small to hold the structure itself + // this is only returned if the length is too small to hold the structure itself // (regardless of the name), in which case, we need to compute our own ReturnLength - // - if ((res == STATUS_SUCCESS - || res == STATUS_BUFFER_OVERFLOW - || (res == STATUS_INFO_LENGTH_MISMATCH && ReturnLength)) - && (ObjectInformationClass == ObjectNameInformation)) { + // + if ((res == STATUS_SUCCESS || res == STATUS_BUFFER_OVERFLOW || + (res == STATUS_INFO_LENGTH_MISMATCH && ReturnLength)) && + (ObjectInformationClass == ObjectNameInformation)) { const auto trackerInfo = ntdllHandleTracker.lookup(Handle); const auto redir = applyReroute(READ_CONTEXT(), callContext, trackerInfo); OBJECT_NAME_INFORMATION* info = reinterpret_cast(ObjectInformation); - + if (redir.redirected) { // https://learn.microsoft.com/en-us/windows/win32/fileio/displaying-volume-paths - // - + // + // TODO: is that always true? // path should start with \??\X: - we need to replace this by device name // @@ -1091,17 +1044,19 @@ DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryObject( std::wstring buffer(static_cast(trackerInfo)); buffer[6] = L'\0'; - QueryDosDeviceW(buffer.data() + 4, deviceName, ARRAYSIZE(deviceName)); + QueryDosDeviceW(buffer.data() + 4, deviceName, ARRAYSIZE(deviceName)); - buffer = - std::wstring(deviceName) + L'\\' + std::wstring(buffer.data() + 7, buffer.size() - 7); + buffer = std::wstring(deviceName) + L'\\' + + std::wstring(buffer.data() + 7, buffer.size() - 7); - // the name is put in the buffer AFTER the struct, so the required size if - // sizeof(OBJECT_NAME_INFORMATION) + the number of bytes for the name + 2 bytes for a wide null character - const auto requiredLength = sizeof(OBJECT_NAME_INFORMATION) + buffer.size() * 2 + 2; + // the name is put in the buffer AFTER the struct, so the required size if + // sizeof(OBJECT_NAME_INFORMATION) + the number of bytes for the name + 2 bytes + // for a wide null character + const auto requiredLength = + sizeof(OBJECT_NAME_INFORMATION) + buffer.size() * 2 + 2; if (ObjectInformationLength < requiredLength) { - // if the status was info length mismatch, we keep it, we are just going to update - // *ReturnLength + // if the status was info length mismatch, we keep it, we are just going to + // update *ReturnLength if (res != STATUS_INFO_LENGTH_MISMATCH) { res = STATUS_BUFFER_OVERFLOW; } @@ -1112,10 +1067,11 @@ DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryObject( } else { // put the unicode buffer at the end of the object const USHORT unicodeBufferLength = static_cast(std::min( - static_cast(std::numeric_limits::max()), - static_cast(ObjectInformationLength - sizeof(OBJECT_NAME_INFORMATION)))); - LPWSTR unicodeBuffer = reinterpret_cast( - static_cast(ObjectInformation) + sizeof(OBJECT_NAME_INFORMATION)); + static_cast(std::numeric_limits::max()), + static_cast(ObjectInformationLength - + sizeof(OBJECT_NAME_INFORMATION)))); + LPWSTR unicodeBuffer = reinterpret_cast( + static_cast(ObjectInformation) + sizeof(OBJECT_NAME_INFORMATION)); // copy the path into the buffer wmemcpy_s(unicodeBuffer, unicodeBufferLength, buffer.data(), buffer.size()); @@ -1128,23 +1084,22 @@ DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryObject( info->Name.Length = static_cast(buffer.size() * 2); info->Name.MaximumLength = unicodeBufferLength; - res = STATUS_SUCCESS; + res = STATUS_SUCCESS; } } auto logger = LOG_CALL() - .PARAMWRAP(res) - .PARAM(ObjectInformationLength) - .addParam("return_length", ReturnLength ? *ReturnLength : -1) - .addParam("tracker_path", trackerInfo) - .PARAM(ObjectInformationClass) - .PARAM(redir.redirected) - .PARAM(redir.path); + .PARAMWRAP(res) + .PARAM(ObjectInformationLength) + .addParam("return_length", ReturnLength ? *ReturnLength : -1) + .addParam("tracker_path", trackerInfo) + .PARAM(ObjectInformationClass) + .PARAM(redir.redirected) + .PARAM(redir.path); if (res == STATUS_SUCCESS) { logger.addParam("name_info", info->Name); - } - else { + } else { logger.addParam("name_info", ""); } } @@ -1154,15 +1109,15 @@ DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryObject( } DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryInformationFile( - HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, - ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) + HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, + ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) { NTSTATUS res = STATUS_SUCCESS; HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES) if (!callContext.active()) { - return ::NtQueryInformationFile(FileHandle, IoStatusBlock, FileInformation, - Length, FileInformationClass); + return ::NtQueryInformationFile(FileHandle, IoStatusBlock, FileInformation, Length, + FileInformationClass); } PRE_REALCALL @@ -1175,40 +1130,40 @@ DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryInformationFile( // // we do not handle STATUS_INFO_LENGTH_MISMATCH because this is only returned if // the length is too small to old the structure itself (regardless of the name) - // + // // TODO: currently, this does not handle STATUS_BUFFER_OVERLOW for ALL information // because most of the structures would need to be manually filled, which is very // complicated - this should not pose huge issue - // + // if (((res == STATUS_SUCCESS || res == STATUS_BUFFER_OVERFLOW) && - (FileInformationClass == FileNameInformation || - FileInformationClass == FileNormalizedNameInformation)) || + (FileInformationClass == FileNameInformation || + FileInformationClass == FileNormalizedNameInformation)) || (res == STATUS_SUCCESS && FileInformationClass == FileAllInformation)) { const auto trackerInfo = ntdllHandleTracker.lookup(FileHandle); - const auto redir = applyReroute(READ_CONTEXT(), callContext, trackerInfo); + const auto redir = applyReroute(READ_CONTEXT(), callContext, trackerInfo); // TODO: difference between FileNameInformation and FileNormalizedNameInformation // maximum length in bytes - the required length is // - for ALL, 100 + the number of bytes in the name (not account for null character) - // - for NAME, 4 + the number of bytes in the name (not accounting for null character) + // - for NAME, 4 + the number of bytes in the name (not accounting for null + // character) // - // it is close to the sizeof the structure + the number of bytes in the name, except + // it is close to the sizeof the structure + the number of bytes in the name, except // for the alignment that gives us a bit more space // ULONG prefixStructLength; - FILE_NAME_INFORMATION *info; + FILE_NAME_INFORMATION* info; if (FileInformationClass == FileAllInformation) { info = &reinterpret_cast(FileInformation)->NameInformation; prefixStructLength = sizeof(FILE_ALL_INFORMATION) - 4; } else { - info = reinterpret_cast(FileInformation); + info = reinterpret_cast(FileInformation); prefixStructLength = sizeof(FILE_NAME_INFORMATION) - 4; } - if (redir.redirected) - { + if (redir.redirected) { auto requiredLength = prefixStructLength + 2 * (trackerInfo.size() - 6); if (Length < requiredLength) { res = STATUS_BUFFER_OVERFLOW; @@ -1216,7 +1171,7 @@ DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryInformationFile( // strip the \??\X: prefix (X being the drive name) LPCWSTR filenameFixed = static_cast(trackerInfo) + 6; - // not using SetInfoFilename because the length is not set and we do not need to + // not using SetInfoFilename because the length is not set and we do not need to // 0-out the memory here info->FileNameLength = static_cast((trackerInfo.size() - 6) * 2); wmemcpy(info->FileName, filenameFixed, trackerInfo.size() - 6); @@ -1224,21 +1179,21 @@ DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryInformationFile( // update status block, Information is the number of bytes written, basically // the required length - IoStatusBlock->Status = STATUS_SUCCESS; + IoStatusBlock->Status = STATUS_SUCCESS; IoStatusBlock->Information = static_cast(requiredLength); } } LOG_CALL() - .PARAMWRAP(res) - .addParam("tracker_path", trackerInfo) - .PARAM(FileInformationClass) - .PARAM(redir.redirected) - .PARAM(redir.path) - .addParam("name_info", res == STATUS_SUCCESS ? std::wstring{info->FileName, + .PARAMWRAP(res) + .addParam("tracker_path", trackerInfo) + .PARAM(FileInformationClass) + .PARAM(redir.redirected) + .PARAM(redir.path) + .addParam("name_info", res == STATUS_SUCCESS + ? std::wstring{info->FileName, info->FileNameLength / sizeof(WCHAR)} : std::wstring{}); - } HOOK_END @@ -1246,59 +1201,58 @@ DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryInformationFile( } unique_ptr_deleter -makeObjectAttributes(RedirectionInfo& redirInfo, - POBJECT_ATTRIBUTES attributeTemplate) +makeObjectAttributes(RedirectionInfo& redirInfo, POBJECT_ATTRIBUTES attributeTemplate) { if (redirInfo.redirected) { - unique_ptr_deleter result( - new OBJECT_ATTRIBUTES, [](OBJECT_ATTRIBUTES* ptr) { delete ptr; }); + unique_ptr_deleter result(new OBJECT_ATTRIBUTES, + [](OBJECT_ATTRIBUTES* ptr) { + delete ptr; + }); memcpy(result.get(), attributeTemplate, sizeof(OBJECT_ATTRIBUTES)); result->RootDirectory = nullptr; - result->ObjectName = static_cast(redirInfo.path); + result->ObjectName = static_cast(redirInfo.path); return result; - } - else { + } else { // just reuse the template with a dummy deleter return unique_ptr_deleter(attributeTemplate, - [](OBJECT_ATTRIBUTES*) {}); + [](OBJECT_ATTRIBUTES*) {}); } } DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryInformationByName( - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass -) + POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) { NTSTATUS res = STATUS_SUCCESS; HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES) if (!callContext.active()) { - res = ::NtQueryInformationByName(ObjectAttributes, IoStatusBlock, FileInformation, Length, FileInformationClass); + res = ::NtQueryInformationByName(ObjectAttributes, IoStatusBlock, FileInformation, + Length, FileInformationClass); callContext.updateLastError(); return res; } - RedirectionInfo redir = applyReroute(READ_CONTEXT(), callContext, CreateUnicodeString(ObjectAttributes)); + RedirectionInfo redir = + applyReroute(READ_CONTEXT(), callContext, CreateUnicodeString(ObjectAttributes)); if (redir.redirected) { auto newObjectAttributes = makeObjectAttributes(redir, ObjectAttributes); PRE_REALCALL - res = ::NtQueryInformationByName(newObjectAttributes.get(), IoStatusBlock, FileInformation, Length, FileInformationClass); + res = ::NtQueryInformationByName(newObjectAttributes.get(), IoStatusBlock, + FileInformation, Length, FileInformationClass); POST_REALCALL LOG_CALL() - .PARAMWRAP(res) - .addParam("input_path", *ObjectAttributes->ObjectName) - .addParam("reroute_path", redir.path); - } - else { + .PARAMWRAP(res) + .addParam("input_path", *ObjectAttributes->ObjectName) + .addParam("reroute_path", redir.path); + } else { PRE_REALCALL - res = ::NtQueryInformationByName(ObjectAttributes, IoStatusBlock, FileInformation, Length, FileInformationClass); + res = ::NtQueryInformationByName(ObjectAttributes, IoStatusBlock, FileInformation, + Length, FileInformationClass); POST_REALCALL } @@ -1306,11 +1260,10 @@ DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryInformationByName( return res; } -NTSTATUS ntdll_mess_NtOpenFile(PHANDLE FileHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - ULONG ShareAccess, ULONG OpenOptions) +NTSTATUS ntdll_mess_NtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, + ULONG OpenOptions) { using namespace usvfs; @@ -1322,44 +1275,44 @@ NTSTATUS ntdll_mess_NtOpenFile(PHANDLE FileHandle, // Why is the usual if (!callContext.active()... check missing? bool storePath = false; - if (((OpenOptions & FILE_DIRECTORY_FILE) != 0UL) - && ((OpenOptions & FILE_OPEN_FOR_BACKUP_INTENT) != 0UL)) { + if (((OpenOptions & FILE_DIRECTORY_FILE) != 0UL) && + ((OpenOptions & FILE_OPEN_FOR_BACKUP_INTENT) != 0UL)) { // this may be an attempt to open a directory handle for iterating. // If so we need to treat it a little bit differently -/* usvfs::FunctionGroupLock lock(usvfs::MutExHookGroup::FILE_ATTRIBUTES); - FILE_BASIC_INFORMATION dummy; - storePath = FAILED(NtQueryAttributesFile(ObjectAttributes, &dummy));*/ + /* usvfs::FunctionGroupLock lock(usvfs::MutExHookGroup::FILE_ATTRIBUTES); + FILE_BASIC_INFORMATION dummy; + storePath = FAILED(NtQueryAttributesFile(ObjectAttributes, &dummy));*/ storePath = true; } UnicodeString fullName = CreateUnicodeString(ObjectAttributes); if (isDeviceFile(static_cast(fullName))) { - return ::NtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, - IoStatusBlock, ShareAccess, OpenOptions); + return ::NtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, + ShareAccess, OpenOptions); } UnicodeString Path = ntdllHandleTracker.lookup(ObjectAttributes->RootDirectory); - std::wstring checkpath = ush::string_cast( - static_cast(Path), ush::CodePage::UTF8); + std::wstring checkpath = + ush::string_cast(static_cast(Path), ush::CodePage::UTF8); - if ((fullName.size() == 0) - || (GetFileSize(ObjectAttributes->RootDirectory, nullptr) - != INVALID_FILE_SIZE)) { - // //relative paths that we don't have permission over will fail here due that we can't get the filesize of the root directory - // //We should try again to see if it is a directory using another method - if ((fullName.size() == 0) || (GetFileAttributesW((LPCWSTR)checkpath.c_str()) == INVALID_FILE_ATTRIBUTES)) { - return ::NtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, - IoStatusBlock, ShareAccess, OpenOptions); - } + if ((fullName.size() == 0) || + (GetFileSize(ObjectAttributes->RootDirectory, nullptr) != INVALID_FILE_SIZE)) { + // //relative paths that we don't have permission over will fail here due that we + // can't get the filesize of the root directory + // //We should try again to see if it is a directory using another method + if ((fullName.size() == 0) || + (GetFileAttributesW((LPCWSTR)checkpath.c_str()) == INVALID_FILE_ATTRIBUTES)) { + return ::NtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, + ShareAccess, OpenOptions); + } } try { - RedirectionInfo redir - = applyReroute(READ_CONTEXT(), callContext, fullName); - unique_ptr_deleter adjustedAttributes - = makeObjectAttributes(redir, ObjectAttributes); + RedirectionInfo redir = applyReroute(READ_CONTEXT(), callContext, fullName); + unique_ptr_deleter adjustedAttributes = + makeObjectAttributes(redir, ObjectAttributes); PRE_REALCALL res = ::NtOpenFile(FileHandle, DesiredAccess, adjustedAttributes.get(), @@ -1367,9 +1320,8 @@ NTSTATUS ntdll_mess_NtOpenFile(PHANDLE FileHandle, POST_REALCALL if (SUCCEEDED(res) && storePath) { // store the original search path for use during iteration - READ_CONTEXT() - ->customData(SearchHandles)[*FileHandle] - = static_cast(fullName); + READ_CONTEXT()->customData(SearchHandles)[*FileHandle] = + static_cast(fullName); #pragma message("need to clean up this handle in CloseHandle call") } @@ -1383,8 +1335,8 @@ NTSTATUS ntdll_mess_NtOpenFile(PHANDLE FileHandle, } } catch (const std::exception&) { PRE_REALCALL - res = ::NtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, - IoStatusBlock, ShareAccess, OpenOptions); + res = ::NtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, + ShareAccess, OpenOptions); POST_REALCALL } HOOK_END @@ -1392,24 +1344,25 @@ NTSTATUS ntdll_mess_NtOpenFile(PHANDLE FileHandle, return res; } -NTSTATUS WINAPI usvfs::hook_NtOpenFile(PHANDLE FileHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - ULONG ShareAccess, ULONG OpenOptions) +NTSTATUS WINAPI usvfs::hook_NtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG ShareAccess, ULONG OpenOptions) { - NTSTATUS res = ntdll_mess_NtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, ShareAccess, OpenOptions); - if (res >= 0 && ObjectAttributes && FileHandle && GetFileType(*FileHandle) == FILE_TYPE_DISK) + NTSTATUS res = ntdll_mess_NtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, + IoStatusBlock, ShareAccess, OpenOptions); + if (res >= 0 && ObjectAttributes && FileHandle && + GetFileType(*FileHandle) == FILE_TYPE_DISK) ntdllHandleTracker.insert(*FileHandle, CreateUnicodeString(ObjectAttributes)); return res; } -NTSTATUS ntdll_mess_NtCreateFile( - PHANDLE FileHandle, ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, - PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, - ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, - ULONG EaLength) +NTSTATUS ntdll_mess_NtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, + PLARGE_INTEGER AllocationSize, ULONG FileAttributes, + ULONG ShareAccess, ULONG CreateDisposition, + ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength) { using namespace usvfs; @@ -1419,71 +1372,97 @@ NTSTATUS ntdll_mess_NtCreateFile( HOOK_START_GROUP(MutExHookGroup::OPEN_FILE) if (!callContext.active()) { - return ::NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, - IoStatusBlock, AllocationSize, FileAttributes, - ShareAccess, CreateDisposition, CreateOptions, - EaBuffer, EaLength); + return ::NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, + AllocationSize, FileAttributes, ShareAccess, + CreateDisposition, CreateOptions, EaBuffer, EaLength); } UnicodeString inPath = CreateUnicodeString(ObjectAttributes); - LPCWSTR inPathW = static_cast(inPath); + LPCWSTR inPathW = static_cast(inPath); if (inPath.size() == 0) { spdlog::get("hooks")->info( "failed to set from handle: {0}", ush::string_cast(ObjectAttributes->ObjectName->Buffer)); - return ::NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, - IoStatusBlock, AllocationSize, FileAttributes, - ShareAccess, CreateDisposition, CreateOptions, - EaBuffer, EaLength); + return ::NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, + AllocationSize, FileAttributes, ShareAccess, + CreateDisposition, CreateOptions, EaBuffer, EaLength); } if (isDeviceFile(inPathW)) { - return ::NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, - IoStatusBlock, AllocationSize, FileAttributes, - ShareAccess, CreateDisposition, CreateOptions, - EaBuffer, EaLength); + return ::NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, + AllocationSize, FileAttributes, ShareAccess, + CreateDisposition, CreateOptions, EaBuffer, EaLength); } DWORD convertedDisposition = OPEN_EXISTING; - switch(CreateDisposition) { - case FILE_SUPERSEDE: convertedDisposition = CREATE_ALWAYS; break; - case FILE_OPEN: convertedDisposition = OPEN_EXISTING; break; - case FILE_CREATE: convertedDisposition = CREATE_NEW; break; - case FILE_OPEN_IF: convertedDisposition = OPEN_ALWAYS; break; - case FILE_OVERWRITE: convertedDisposition = TRUNCATE_EXISTING; break; - case FILE_OVERWRITE_IF: convertedDisposition = CREATE_ALWAYS; break; - default: spdlog::get("hooks")->error("invalid disposition: {0}", CreateDisposition); break; + switch (CreateDisposition) { + case FILE_SUPERSEDE: + convertedDisposition = CREATE_ALWAYS; + break; + case FILE_OPEN: + convertedDisposition = OPEN_EXISTING; + break; + case FILE_CREATE: + convertedDisposition = CREATE_NEW; + break; + case FILE_OPEN_IF: + convertedDisposition = OPEN_ALWAYS; + break; + case FILE_OVERWRITE: + convertedDisposition = TRUNCATE_EXISTING; + break; + case FILE_OVERWRITE_IF: + convertedDisposition = CREATE_ALWAYS; + break; + default: + spdlog::get("hooks")->error("invalid disposition: {0}", CreateDisposition); + break; } DWORD convertedAccess = 0; - if ((DesiredAccess & FILE_GENERIC_READ) == FILE_GENERIC_READ) convertedAccess |= GENERIC_READ; - if ((DesiredAccess & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE) convertedAccess |= GENERIC_WRITE; - if ((DesiredAccess & FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE) convertedAccess |= GENERIC_EXECUTE; - if ((DesiredAccess & FILE_ALL_ACCESS) == FILE_ALL_ACCESS) convertedAccess |= GENERIC_ALL; + if ((DesiredAccess & FILE_GENERIC_READ) == FILE_GENERIC_READ) + convertedAccess |= GENERIC_READ; + if ((DesiredAccess & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE) + convertedAccess |= GENERIC_WRITE; + if ((DesiredAccess & FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE) + convertedAccess |= GENERIC_EXECUTE; + if ((DesiredAccess & FILE_ALL_ACCESS) == FILE_ALL_ACCESS) + convertedAccess |= GENERIC_ALL; ULONG originalDisposition = CreateDisposition; CreateRerouter rerouter; - if (rerouter.rerouteCreate(READ_CONTEXT(), callContext, inPathW, convertedDisposition, - convertedAccess, (LPSECURITY_ATTRIBUTES)ObjectAttributes->SecurityDescriptor)) { - switch(convertedDisposition) { - case CREATE_NEW: CreateDisposition = FILE_CREATE; break; - case CREATE_ALWAYS: if (CreateDisposition != FILE_SUPERSEDE) CreateDisposition = FILE_OVERWRITE_IF; break; - case OPEN_EXISTING: CreateDisposition = FILE_OPEN; break; - case OPEN_ALWAYS: CreateDisposition = FILE_OPEN_IF; break; - case TRUNCATE_EXISTING: CreateDisposition = FILE_OVERWRITE; break; + if (rerouter.rerouteCreate( + READ_CONTEXT(), callContext, inPathW, convertedDisposition, convertedAccess, + (LPSECURITY_ATTRIBUTES)ObjectAttributes->SecurityDescriptor)) { + switch (convertedDisposition) { + case CREATE_NEW: + CreateDisposition = FILE_CREATE; + break; + case CREATE_ALWAYS: + if (CreateDisposition != FILE_SUPERSEDE) + CreateDisposition = FILE_OVERWRITE_IF; + break; + case OPEN_EXISTING: + CreateDisposition = FILE_OPEN; + break; + case OPEN_ALWAYS: + CreateDisposition = FILE_OPEN_IF; + break; + case TRUNCATE_EXISTING: + CreateDisposition = FILE_OVERWRITE; + break; } RedirectionInfo redir = applyReroute(rerouter); - unique_ptr_deleter adjustedAttributes - = makeObjectAttributes(redir, ObjectAttributes); + unique_ptr_deleter adjustedAttributes = + makeObjectAttributes(redir, ObjectAttributes); PRE_REALCALL - res = ::NtCreateFile(FileHandle, DesiredAccess, adjustedAttributes.get(), - IoStatusBlock, AllocationSize, FileAttributes, - ShareAccess, CreateDisposition, CreateOptions, EaBuffer, - EaLength); + res = ::NtCreateFile(FileHandle, DesiredAccess, adjustedAttributes.get(), + IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, + CreateDisposition, CreateOptions, EaBuffer, EaLength); POST_REALCALL rerouter.updateResult(callContext, res == STATUS_SUCCESS); @@ -1491,33 +1470,35 @@ NTSTATUS ntdll_mess_NtCreateFile( if (rerouter.newReroute()) rerouter.insertMapping(WRITE_CONTEXT()); - if (rerouter.isDir() && rerouter.wasRerouted() && ((FileAttributes & FILE_OPEN_FOR_BACKUP_INTENT) == FILE_OPEN_FOR_BACKUP_INTENT)) { + if (rerouter.isDir() && rerouter.wasRerouted() && + ((FileAttributes & FILE_OPEN_FOR_BACKUP_INTENT) == + FILE_OPEN_FOR_BACKUP_INTENT)) { // store the original search path for use during iteration - WRITE_CONTEXT() - ->customData(SearchHandles)[*FileHandle] = inPathW; + WRITE_CONTEXT()->customData(SearchHandles)[*FileHandle] = + inPathW; } } - if (rerouter.wasRerouted() || rerouter.changedError() || originalDisposition != CreateDisposition) { + if (rerouter.wasRerouted() || rerouter.changedError() || + originalDisposition != CreateDisposition) { LOG_CALL() - .PARAM(inPathW) - .PARAM(rerouter.fileName()) - .PARAMHEX(DesiredAccess) - .PARAMHEX(originalDisposition) - .PARAMHEX(CreateDisposition) - .PARAMHEX(FileAttributes) - .PARAMHEX(res) - .PARAMHEX(*FileHandle) - .PARAM(rerouter.originalError()) - .PARAM(rerouter.error()); + .PARAM(inPathW) + .PARAM(rerouter.fileName()) + .PARAMHEX(DesiredAccess) + .PARAMHEX(originalDisposition) + .PARAMHEX(CreateDisposition) + .PARAMHEX(FileAttributes) + .PARAMHEX(res) + .PARAMHEX(*FileHandle) + .PARAM(rerouter.originalError()) + .PARAM(rerouter.error()); } } else { // make the original call to set up the proper errors and return statuses PRE_REALCALL - res = ::NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, - IoStatusBlock, AllocationSize, FileAttributes, - ShareAccess, CreateDisposition, CreateOptions, EaBuffer, - EaLength); + res = ::NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, + AllocationSize, FileAttributes, ShareAccess, CreateDisposition, + CreateOptions, EaBuffer, EaLength); POST_REALCALL } @@ -1526,15 +1507,20 @@ NTSTATUS ntdll_mess_NtCreateFile( return res; } -NTSTATUS WINAPI usvfs::hook_NtCreateFile( - PHANDLE FileHandle, ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, - PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, - ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, - ULONG EaLength) +NTSTATUS WINAPI usvfs::hook_NtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, + PLARGE_INTEGER AllocationSize, + ULONG FileAttributes, ULONG ShareAccess, + ULONG CreateDisposition, ULONG CreateOptions, + PVOID EaBuffer, ULONG EaLength) { - NTSTATUS res = ntdll_mess_NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength); - if (res >= 0 && ObjectAttributes && FileHandle && GetFileType(*FileHandle) == FILE_TYPE_DISK) + NTSTATUS res = ntdll_mess_NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, + IoStatusBlock, AllocationSize, FileAttributes, + ShareAccess, CreateDisposition, CreateOptions, + EaBuffer, EaLength); + if (res >= 0 && ObjectAttributes && FileHandle && + GetFileType(*FileHandle) == FILE_TYPE_DISK) ntdllHandleTracker.insert(*FileHandle, CreateUnicodeString(ObjectAttributes)); return res; } @@ -1551,9 +1537,9 @@ NTSTATUS WINAPI usvfs::hook_NtClose(HANDLE Handle) if ((::GetFileType(Handle) == FILE_TYPE_DISK)) { HookContext::Ptr context = WRITE_CONTEXT(); - { // clean up search data associated with this handle part 1 - Searches &activeSearches = context->customData(SearchInfo); -// std::lock_guard lock(activeSearches.queryMutex); + { // clean up search data associated with this handle part 1 + Searches& activeSearches = context->customData(SearchInfo); + // std::lock_guard lock(activeSearches.queryMutex); auto iter = activeSearches.info.find(Handle); if (iter != activeSearches.info.end()) { if (iter->second.currentSearchHandle != INVALID_HANDLE_VALUE) { @@ -1566,8 +1552,8 @@ NTSTATUS WINAPI usvfs::hook_NtClose(HANDLE Handle) } { - SearchHandleMap &searchHandles - = context->customData(SearchHandles); + SearchHandleMap& searchHandles = + context->customData(SearchHandles); auto iter = searchHandles.find(Handle); if (iter != searchHandles.end()) { searchHandles.erase(iter); @@ -1593,8 +1579,7 @@ NTSTATUS WINAPI usvfs::hook_NtClose(HANDLE Handle) } NTSTATUS WINAPI usvfs::hook_NtQueryAttributesFile( - POBJECT_ATTRIBUTES ObjectAttributes, - PFILE_BASIC_INFORMATION FileInformation) + POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation) { PreserveGetLastError ntFunctionsDoNotChangeGetLastError; @@ -1605,10 +1590,9 @@ NTSTATUS WINAPI usvfs::hook_NtQueryAttributesFile( UnicodeString inPath = CreateUnicodeString(ObjectAttributes); - RedirectionInfo redir - = applyReroute(READ_CONTEXT(), callContext, inPath); - unique_ptr_deleter adjustedAttributes - = makeObjectAttributes(redir, ObjectAttributes); + RedirectionInfo redir = applyReroute(READ_CONTEXT(), callContext, inPath); + unique_ptr_deleter adjustedAttributes = + makeObjectAttributes(redir, ObjectAttributes); PRE_REALCALL res = ::NtQueryAttributesFile(adjustedAttributes.get(), FileInformation); @@ -1627,8 +1611,7 @@ NTSTATUS WINAPI usvfs::hook_NtQueryAttributesFile( } NTSTATUS WINAPI usvfs::hook_NtQueryFullAttributesFile( - POBJECT_ATTRIBUTES ObjectAttributes, - PFILE_NETWORK_OPEN_INFORMATION FileInformation) + POBJECT_ATTRIBUTES ObjectAttributes, PFILE_NETWORK_OPEN_INFORMATION FileInformation) { PreserveGetLastError ntFunctionsDoNotChangeGetLastError; @@ -1643,14 +1626,13 @@ NTSTATUS WINAPI usvfs::hook_NtQueryFullAttributesFile( UnicodeString inPath; try { inPath = CreateUnicodeString(ObjectAttributes); - } catch (const std::exception &) { + } catch (const std::exception&) { return ::NtQueryFullAttributesFile(ObjectAttributes, FileInformation); } - RedirectionInfo redir - = applyReroute(READ_CONTEXT(), callContext, inPath); - unique_ptr_deleter adjustedAttributes - = makeObjectAttributes(redir, ObjectAttributes); + RedirectionInfo redir = applyReroute(READ_CONTEXT(), callContext, inPath); + unique_ptr_deleter adjustedAttributes = + makeObjectAttributes(redir, ObjectAttributes); PRE_REALCALL res = ::NtQueryFullAttributesFile(adjustedAttributes.get(), FileInformation); @@ -1668,9 +1650,8 @@ NTSTATUS WINAPI usvfs::hook_NtQueryFullAttributesFile( return res; } -NTSTATUS WINAPI usvfs::hook_NtTerminateProcess( - HANDLE ProcessHandle, - NTSTATUS ExitStatus) +NTSTATUS WINAPI usvfs::hook_NtTerminateProcess(HANDLE ProcessHandle, + NTSTATUS ExitStatus) { // this hook is normally called when terminating another process, in which // case there's nothing to do @@ -1695,10 +1676,8 @@ NTSTATUS WINAPI usvfs::hook_NtTerminateProcess( HOOK_START - const bool isCurrentProcess = - ProcessHandle == (HANDLE)-1 || - ProcessHandle == 0 || - GetProcessId(ProcessHandle) == GetCurrentProcessId(); + const bool isCurrentProcess = ProcessHandle == (HANDLE)-1 || ProcessHandle == 0 || + GetProcessId(ProcessHandle) == GetCurrentProcessId(); if (isCurrentProcess) { usvfsDisconnectVFS(); diff --git a/src/usvfs_dll/hooks/ntdll.h b/src/usvfs_dll/hooks/ntdll.h index a87b00c..f3db4a6 100644 --- a/src/usvfs_dll/hooks/ntdll.h +++ b/src/usvfs_dll/hooks/ntdll.h @@ -1,91 +1,57 @@ #pragma once -#include #include #include +#include namespace usvfs { DLLEXPORT NTSTATUS WINAPI hook_NtQueryFullAttributesFile(POBJECT_ATTRIBUTES ObjectAttributes, - PFILE_NETWORK_OPEN_INFORMATION FileInformation); + PFILE_NETWORK_OPEN_INFORMATION FileInformation); -DLLEXPORT NTSTATUS WINAPI -hook_NtQueryAttributesFile(POBJECT_ATTRIBUTES ObjectAttributes, - PFILE_BASIC_INFORMATION FileInformation); +DLLEXPORT NTSTATUS WINAPI hook_NtQueryAttributesFile( + POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation); -DLLEXPORT NTSTATUS WINAPI -hook_NtQueryDirectoryFile(HANDLE FileHandle, - HANDLE Event, - PIO_APC_ROUTINE ApcRoutine, - PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass, - BOOLEAN ReturnSingleEntry, - PUNICODE_STRING FileName, - BOOLEAN RestartScan); +DLLEXPORT NTSTATUS WINAPI hook_NtQueryDirectoryFile( + HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, + PUNICODE_STRING FileName, BOOLEAN RestartScan); -DLLEXPORT NTSTATUS WINAPI -hook_NtQueryDirectoryFileEx(HANDLE FileHandle, - HANDLE Event, - PIO_APC_ROUTINE ApcRoutine, - PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass, - ULONG QueryFlags, - PUNICODE_STRING FileName); +DLLEXPORT NTSTATUS WINAPI hook_NtQueryDirectoryFileEx( + HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass, ULONG QueryFlags, + PUNICODE_STRING FileName); -DLLEXPORT NTSTATUS WINAPI -hook_NtQueryObject( - HANDLE Handle, - OBJECT_INFORMATION_CLASS ObjectInformationClass, - PVOID ObjectInformation, - ULONG ObjectInformationLength, - PULONG ReturnLength); +DLLEXPORT NTSTATUS WINAPI hook_NtQueryObject( + HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, + PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); -DLLEXPORT NTSTATUS WINAPI -hook_NtQueryInformationFile( - HANDLE FileHandle, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass); +DLLEXPORT NTSTATUS WINAPI hook_NtQueryInformationFile( + HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, + ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); -DLLEXPORT NTSTATUS WINAPI -hook_NtQueryInformationByName( - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass -); +DLLEXPORT NTSTATUS WINAPI hook_NtQueryInformationByName( + POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); -DLLEXPORT NTSTATUS WINAPI hook_NtOpenFile(PHANDLE FileHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - ULONG ShareAccess, - ULONG OpenOptions); +DLLEXPORT NTSTATUS WINAPI hook_NtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG ShareAccess, ULONG OpenOptions); -DLLEXPORT NTSTATUS WINAPI hook_NtCreateFile(PHANDLE FileHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - PLARGE_INTEGER AllocationSize, - ULONG FileAttributes, - ULONG ShareAccess, - ULONG CreateDisposition, - ULONG CreateOptions, - PVOID EaBuffer, - ULONG EaLength); +DLLEXPORT NTSTATUS WINAPI hook_NtCreateFile( + PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, + ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, + ULONG EaLength); DLLEXPORT NTSTATUS WINAPI hook_NtClose(HANDLE Handle); -DLLEXPORT NTSTATUS WINAPI hook_NtTerminateProcess(HANDLE ProcessHandle, NTSTATUS ExitStatus); +DLLEXPORT NTSTATUS WINAPI hook_NtTerminateProcess(HANDLE ProcessHandle, + NTSTATUS ExitStatus); -} // namespace usvfs +} // namespace usvfs diff --git a/src/usvfs_dll/maptracker.h b/src/usvfs_dll/maptracker.h index 2d7078c..6ddf471 100644 --- a/src/usvfs_dll/maptracker.h +++ b/src/usvfs_dll/maptracker.h @@ -1,10 +1,11 @@ #pragma once -#include "hookcontext.h" #include "hookcallcontext.h" +#include "hookcontext.h" #include "stringcast.h" -namespace usvfs { +namespace usvfs +{ // returns true iff the path exists (checks only real paths) static inline bool pathExists(LPCWSTR fileName) @@ -30,7 +31,8 @@ static inline bool pathIsDirectory(LPCWSTR fileName) return attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY); } -// returns true iff the path does not exist but it parent directory does (checks only real paths) +// returns true iff the path does not exist but it parent directory does (checks only +// real paths) static inline bool pathDirectlyAvailable(LPCWSTR pathName) { FunctionGroupLock lock(MutExHookGroup::FILE_ATTRIBUTES); @@ -38,11 +40,12 @@ static inline bool pathDirectlyAvailable(LPCWSTR pathName) return attrib == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; } -class MapTracker { +class MapTracker +{ public: - std::wstring lookup(const std::wstring& fromPath) const { - if (!fromPath.empty()) - { + std::wstring lookup(const std::wstring& fromPath) const + { + if (!fromPath.empty()) { std::shared_lock lock(m_mutex); auto find = m_map.find(fromPath); if (find != m_map.end()) @@ -51,9 +54,9 @@ public: return std::wstring(); } - bool contains(const std::wstring& fromPath) const { - if (!fromPath.empty()) - { + bool contains(const std::wstring& fromPath) const + { + if (!fromPath.empty()) { std::shared_lock lock(m_mutex); auto find = m_map.find(fromPath); if (find != m_map.end()) @@ -62,7 +65,8 @@ public: return false; } - void insert(const std::wstring& fromPath, const std::wstring& toPath) { + void insert(const std::wstring& fromPath, const std::wstring& toPath) + { if (fromPath.empty()) return; std::unique_lock lock(m_mutex); @@ -99,92 +103,81 @@ class RerouteW public: RerouteW() = default; - RerouteW(RerouteW &&reference) - : m_Buffer(std::move(reference.m_Buffer)) - , m_RealPath(std::move(reference.m_RealPath)) - , m_Rerouted(reference.m_Rerouted) - , m_PathCreated(reference.m_PathCreated) - , m_NewReroute(reference.m_NewReroute) - , m_FileNode(std::move(reference.m_FileNode)) + RerouteW(RerouteW&& reference) + : m_Buffer(std::move(reference.m_Buffer)), + m_RealPath(std::move(reference.m_RealPath)), m_Rerouted(reference.m_Rerouted), + m_PathCreated(reference.m_PathCreated), m_NewReroute(reference.m_NewReroute), + m_FileNode(std::move(reference.m_FileNode)) { - m_FileName = reference.m_FileName != nullptr ? m_Buffer.c_str() : nullptr; + m_FileName = reference.m_FileName != nullptr ? m_Buffer.c_str() : nullptr; reference.m_FileName = nullptr; } - RerouteW &operator=(RerouteW &&reference) + RerouteW& operator=(RerouteW&& reference) { - m_Buffer = std::move(reference.m_Buffer); - m_RealPath = std::move(reference.m_RealPath); - m_Rerouted = reference.m_Rerouted; + m_Buffer = std::move(reference.m_Buffer); + m_RealPath = std::move(reference.m_RealPath); + m_Rerouted = reference.m_Rerouted; m_PathCreated = reference.m_PathCreated; - m_NewReroute = reference.m_NewReroute; - m_FileName = reference.m_FileName != nullptr ? m_Buffer.c_str() : nullptr; - m_FileNode = std::move(reference.m_FileNode); + m_NewReroute = reference.m_NewReroute; + m_FileName = reference.m_FileName != nullptr ? m_Buffer.c_str() : nullptr; + m_FileNode = std::move(reference.m_FileNode); return *this; } - RerouteW(const RerouteW &reference) = delete; - RerouteW &operator=(const RerouteW &) = delete; + RerouteW(const RerouteW& reference) = delete; + RerouteW& operator=(const RerouteW&) = delete; - LPCWSTR fileName() const - { - return m_FileName; - } + LPCWSTR fileName() const { return m_FileName; } - const std::wstring &buffer() const - { - return m_Buffer; - } + const std::wstring& buffer() const { return m_Buffer; } - bool wasRerouted() const - { - return m_Rerouted; - } + bool wasRerouted() const { return m_Rerouted; } - bool newReroute() const - { - return m_NewReroute; - } + bool newReroute() const { return m_NewReroute; } - void insertMapping(const HookContext::Ptr &context, bool directory = false) + void insertMapping(const HookContext::Ptr& context, bool directory = false) { - if (directory) - { + if (directory) { addDirectoryMapping(context, m_RealPath, m_FileName); - // In case we have just created a "fake" directory, it is no longer fake and need to remove it and all its - // parent folders from the fake map: + // In case we have just created a "fake" directory, it is no longer fake and need + // to remove it and all its parent folders from the fake map: std::wstring dir = m_FileName; while (k32FakeDirTracker.erase(dir)) dir = fs::path(dir).parent_path().wstring(); - } - else - { - //if (m_PathCreated) - //addDirectoryMapping(context, fs::path(m_RealPath).parent_path(), fs::path(m_FileName).parent_path()); + } else { + // if (m_PathCreated) + // addDirectoryMapping(context, fs::path(m_RealPath).parent_path(), + // fs::path(m_FileName).parent_path()); - spdlog::get("hooks")->info("mapping file in vfs: {}, {}", - shared::string_cast(m_RealPath, shared::CodePage::UTF8), - shared::string_cast(m_FileName, shared::CodePage::UTF8)); - m_FileNode = - context->redirectionTable().addFile(m_RealPath, RedirectionDataLocal(shared::string_cast(m_FileName, shared::CodePage::UTF8))); + spdlog::get("hooks")->info( + "mapping file in vfs: {}, {}", + shared::string_cast(m_RealPath, shared::CodePage::UTF8), + shared::string_cast(m_FileName, shared::CodePage::UTF8)); + m_FileNode = context->redirectionTable().addFile( + m_RealPath, RedirectionDataLocal(shared::string_cast( + m_FileName, shared::CodePage::UTF8))); k32DeleteTracker.erase(m_RealPath); } } - void removeMapping(const HookContext::ConstPtr &readContext, bool directory = false) + void removeMapping(const HookContext::ConstPtr& readContext, bool directory = false) { - bool addToDelete = false; + bool addToDelete = false; bool dontAddToDelete = false; - // We need to track deleted files even if they were not rerouted (i.e. files deleted from the real folder which there is - // a virtualized mapped folder on top of it). Since we don't want to add, *every* file which is deleted we check this: + // We need to track deleted files even if they were not rerouted (i.e. files deleted + // from the real folder which there is a virtualized mapped folder on top of it). + // Since we don't want to add, *every* file which is deleted we check this: bool found = wasRerouted(); if (!found) { FindCreateTarget visitor; RedirectionTree::VisitorFunction visitorWrapper = - [&](const RedirectionTree::NodePtrT &node) { visitor(node); }; + [&](const RedirectionTree::NodePtrT& node) { + visitor(node); + }; readContext->redirectionTable()->visitPath(m_RealPath, visitorWrapper); if (visitor.target.get()) found = true; @@ -196,30 +189,29 @@ public: if (m_FileNode.get()) m_FileNode->removeFromTree(); else - spdlog::get("usvfs")->warn("Node not removed: {}", shared::string_cast(m_FileName)); + spdlog::get("usvfs")->warn("Node not removed: {}", + shared::string_cast(m_FileName)); - if (!directory) - { + if (!directory) { // check if this file was the last file inside a "fake" directory then remove it // and possibly also its fake empty parent folders: std::wstring parent = m_FileName; - while (true) - { + while (true) { parent = fs::path(parent).parent_path().wstring(); - if (k32FakeDirTracker.contains(parent)) - { + if (k32FakeDirTracker.contains(parent)) { dontAddToDelete = true; if (RemoveDirectoryW(parent.c_str())) { k32FakeDirTracker.erase(parent); - spdlog::get("usvfs")->info("removed empty fake directory: {}", shared::string_cast(parent)); - } - else if (GetLastError() != ERROR_DIR_NOT_EMPTY) { + spdlog::get("usvfs")->info("removed empty fake directory: {}", + shared::string_cast(parent)); + } else if (GetLastError() != ERROR_DIR_NOT_EMPTY) { auto error = GetLastError(); - spdlog::get("usvfs")->warn("removing fake directory failed: {}, error={}", shared::string_cast(parent), error); + spdlog::get("usvfs")->warn("removing fake directory failed: {}, error={}", + shared::string_cast(parent), + error); break; } - } - else + } else break; } } @@ -233,78 +225,105 @@ public: { // sanity and guaranteed recursion end: if (!path.has_relative_path()) - throw shared::windows_error("createFakePath() refusing to create non-existing top level path: " + path.string()); + throw shared::windows_error( + "createFakePath() refusing to create non-existing top level path: " + + path.string()); DWORD attr = GetFileAttributesW(path.c_str()); - DWORD err = GetLastError(); + DWORD err = GetLastError(); if (attr != INVALID_FILE_ATTRIBUTES) { if (attr & FILE_ATTRIBUTE_DIRECTORY) - return false; // if directory already exists all is good + return false; // if directory already exists all is good else - throw shared::windows_error("createFakePath() called on a file: " + path.string()); + throw shared::windows_error("createFakePath() called on a file: " + + path.string()); } if (err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND) - throw shared::windows_error("createFakePath() GetFileAttributesW failed on: " + path.string(), err); + throw shared::windows_error( + "createFakePath() GetFileAttributesW failed on: " + path.string(), err); - if (err != ERROR_FILE_NOT_FOUND) // ERROR_FILE_NOT_FOUND means parent directory already exists - createFakePath(path.parent_path(), securityAttributes); // otherwise create parent directory (recursively) + if (err != ERROR_FILE_NOT_FOUND) // ERROR_FILE_NOT_FOUND means parent directory + // already exists + createFakePath( + path.parent_path(), + securityAttributes); // otherwise create parent directory (recursively) BOOL res = CreateDirectoryW(path.c_str(), securityAttributes); if (res) k32FakeDirTracker.insert(path.wstring(), std::wstring()); else { err = GetLastError(); - throw shared::windows_error("createFakePath() CreateDirectoryW failed on: " + path.string(), err); + throw shared::windows_error( + "createFakePath() CreateDirectoryW failed on: " + path.string(), err); } return true; } - static bool addDirectoryMapping(const HookContext::Ptr &context, const fs::path& originalPath, const fs::path& reroutedPath) + static bool addDirectoryMapping(const HookContext::Ptr& context, + const fs::path& originalPath, + const fs::path& reroutedPath) { if (originalPath.empty() || reroutedPath.empty()) { spdlog::get("hooks")->error("RerouteW::addDirectoryMapping failed: {}, {}", - shared::string_cast(originalPath.wstring(), shared::CodePage::UTF8).c_str(), - shared::string_cast(reroutedPath.wstring(), shared::CodePage::UTF8).c_str()); + shared::string_cast( + originalPath.wstring(), shared::CodePage::UTF8) + .c_str(), + shared::string_cast( + reroutedPath.wstring(), shared::CodePage::UTF8) + .c_str()); return false; } - auto lookupParent = context->redirectionTable()->findNode(originalPath.parent_path()); + auto lookupParent = + context->redirectionTable()->findNode(originalPath.parent_path()); if (!lookupParent.get() || lookupParent->data().linkTarget.empty()) { - if (!addDirectoryMapping(context, originalPath.parent_path(), reroutedPath.parent_path())) - { + if (!addDirectoryMapping(context, originalPath.parent_path(), + reroutedPath.parent_path())) { spdlog::get("hooks")->error("RerouteW::addDirectoryMapping failed: {}, {}", - shared::string_cast(originalPath.wstring(), shared::CodePage::UTF8).c_str(), - shared::string_cast(reroutedPath.wstring(), shared::CodePage::UTF8).c_str()); + shared::string_cast( + originalPath.wstring(), shared::CodePage::UTF8) + .c_str(), + shared::string_cast( + reroutedPath.wstring(), shared::CodePage::UTF8) + .c_str()); return false; } } - std::string reroutedU8 - = shared::string_cast(reroutedPath.wstring(), shared::CodePage::UTF8); + std::string reroutedU8 = shared::string_cast(reroutedPath.wstring(), + shared::CodePage::UTF8); if (reroutedU8.empty() || reroutedU8[reroutedU8.size() - 1] != '\\') reroutedU8 += "\\"; spdlog::get("hooks")->info("mapping directory in vfs: {}, {}", - shared::string_cast(originalPath.wstring(), shared::CodePage::UTF8), reroutedU8.c_str()); + shared::string_cast(originalPath.wstring(), + shared::CodePage::UTF8), + reroutedU8.c_str()); context->redirectionTable().addDirectory( - originalPath, RedirectionDataLocal(reroutedU8), - shared::FLAG_DIRECTORY|shared::FLAG_CREATETARGET); + originalPath, RedirectionDataLocal(reroutedU8), + shared::FLAG_DIRECTORY | shared::FLAG_CREATETARGET); fs::directory_iterator end_itr; // cycle through the directory - for (fs::directory_iterator itr(reroutedPath); itr != end_itr; ++itr) - { + for (fs::directory_iterator itr(reroutedPath); itr != end_itr; ++itr) { // If it's not a directory, add it to the VFS, if it is recurse into it if (is_regular_file(itr->path())) { - std::string fileReroutedU8 = shared::string_cast(itr->path().wstring(), shared::CodePage::UTF8); - spdlog::get("hooks")->info("mapping file in vfs: {}, {}", - shared::string_cast((originalPath / itr->path().filename()).wstring(), shared::CodePage::UTF8), - fileReroutedU8.c_str()); - context->redirectionTable().addFile(fs::path(originalPath / itr->path().filename()), RedirectionDataLocal(fileReroutedU8)); + std::string fileReroutedU8 = shared::string_cast( + itr->path().wstring(), shared::CodePage::UTF8); + spdlog::get("hooks")->info( + "mapping file in vfs: {}, {}", + shared::string_cast( + (originalPath / itr->path().filename()).wstring(), + shared::CodePage::UTF8), + fileReroutedU8.c_str()); + context->redirectionTable().addFile( + fs::path(originalPath / itr->path().filename()), + RedirectionDataLocal(fileReroutedU8)); } else { - addDirectoryMapping(context, originalPath / itr->path().filename(), reroutedPath / itr->path().filename()); + addDirectoryMapping(context, originalPath / itr->path().filename(), + reroutedPath / itr->path().filename()); } } @@ -312,49 +331,55 @@ public: } template - static bool interestingPathImpl(const char_t *inPath) + static bool interestingPathImpl(const char_t* inPath) { if (!inPath || !inPath[0]) return false; // ignore \\.\ unless its a \\.\?: - if (inPath[0] == '\\' && inPath[1] == '\\' && inPath[2] == '.' && inPath[3] == '\\' && (!inPath[4] || inPath[5] != ':')) + if (inPath[0] == '\\' && inPath[1] == '\\' && inPath[2] == '.' && + inPath[3] == '\\' && (!inPath[4] || inPath[5] != ':')) return false; // ignore L"hid#": - if ((inPath[0] == 'h' || inPath[0] == 'H') - && ((inPath[1] == 'i' || inPath[1] == 'I')) - && ((inPath[2] == 'd' || inPath[2] == 'D')) - && inPath[3] == '#') + if ((inPath[0] == 'h' || inPath[0] == 'H') && + ((inPath[1] == 'i' || inPath[1] == 'I')) && + ((inPath[2] == 'd' || inPath[2] == 'D')) && inPath[3] == '#') return false; return true; } - static bool interestingPath(const char* inPath) { return interestingPathImpl(inPath); } - static bool interestingPath(const wchar_t* inPath) { return interestingPathImpl(inPath); } - - static fs::path absolutePath(const wchar_t *inPath) + static bool interestingPath(const char* inPath) { - if (shared::startswith(inPath, LR"(\\?\)") || shared::startswith(inPath, LR"(\??\)")) { + return interestingPathImpl(inPath); + } + static bool interestingPath(const wchar_t* inPath) + { + return interestingPathImpl(inPath); + } + + static fs::path absolutePath(const wchar_t* inPath) + { + if (shared::startswith(inPath, LR"(\\?\)") || + shared::startswith(inPath, LR"(\??\)")) { inPath += 4; return inPath; - } - else if ((shared::startswith(inPath, LR"(\\localhost\)") || shared::startswith(inPath, LR"(\\127.0.0.1\)")) && inPath[13] == L'$') { + } else if ((shared::startswith(inPath, LR"(\\localhost\)") || + shared::startswith(inPath, LR"(\\127.0.0.1\)")) && + inPath[13] == L'$') { std::wstring newPath; newPath += towupper(inPath[12]); newPath += L':'; newPath += &inPath[14]; return newPath; - } - else if (inPath[0] == L'\0' || inPath[1] == L':') { + } else if (inPath[0] == L'\0' || inPath[1] == L':') { return inPath; - } - else if (inPath[0] == L'\\' || inPath[0] == L'/') { + } else if (inPath[0] == L'\\' || inPath[0] == L'/') { return fs::path(winapi::wide::getFullPathName(inPath).first); } WCHAR currentDirectory[MAX_PATH]; ::GetCurrentDirectoryW(MAX_PATH, currentDirectory); fs::path finalPath = fs::path(currentDirectory) / inPath; return finalPath; - //winapi::wide::getFullPathName(inPath).first; + // winapi::wide::getFullPathName(inPath).first; } static fs::path canonizePath(const fs::path& inPath) @@ -365,37 +390,34 @@ public: return p.make_preferred(); } - static RerouteW create(const HookContext::ConstPtr &context, - const HookCallContext &callContext, - const wchar_t *inPath, bool inverse = false) + static RerouteW create(const HookContext::ConstPtr& context, + const HookCallContext& callContext, const wchar_t* inPath, + bool inverse = false) { RerouteW result; - if (interestingPath(inPath) && callContext.active()) - { + if (interestingPath(inPath) && callContext.active()) { const auto& lookupPath = canonizePath(absolutePath(inPath)); - result.m_RealPath = lookupPath.wstring(); + result.m_RealPath = lookupPath.wstring(); result.m_Buffer = k32DeleteTracker.lookup(result.m_RealPath); - bool found = !result.m_Buffer.empty(); + bool found = !result.m_Buffer.empty(); if (found) { - spdlog::get("hooks")->info("Rerouting file open to location of deleted file: {}", - shared::string_cast(result.m_Buffer)); + spdlog::get("hooks")->info( + "Rerouting file open to location of deleted file: {}", + shared::string_cast(result.m_Buffer)); result.m_NewReroute = true; } else { - const RedirectionTreeContainer &table - = inverse ? context->inverseTable() : context->redirectionTable(); + const RedirectionTreeContainer& table = + inverse ? context->inverseTable() : context->redirectionTable(); result.m_FileNode = table->findNode(lookupPath); - if (result.m_FileNode.get() - && (!result.m_FileNode->data().linkTarget.empty() || result.m_FileNode->isDirectory())) - { + if (result.m_FileNode.get() && (!result.m_FileNode->data().linkTarget.empty() || + result.m_FileNode->isDirectory())) { if (!result.m_FileNode->data().linkTarget.empty()) { result.m_Buffer = shared::string_cast( - result.m_FileNode->data().linkTarget.c_str(), shared::CodePage::UTF8); - } - else - { + result.m_FileNode->data().linkTarget.c_str(), shared::CodePage::UTF8); + } else { result.m_Buffer = result.m_FileNode->path().wstring(); } found = true; @@ -404,16 +426,14 @@ public: if (found) { result.m_Rerouted = true; - wchar_t inIt = inPath[wcslen(inPath) - 1]; + wchar_t inIt = inPath[wcslen(inPath) - 1]; std::wstring::iterator outIt = result.m_Buffer.end() - 1; if ((*outIt == L'\\' || *outIt == L'/') && !(inIt == L'\\' || inIt == L'/')) result.m_Buffer.erase(outIt); std::replace(result.m_Buffer.begin(), result.m_Buffer.end(), L'/', L'\\'); - } - else + } else result.m_Buffer = inPath; - } - else if (inPath) + } else if (inPath) result.m_Buffer = inPath; if (inPath) @@ -421,66 +441,65 @@ public: return result; } - static RerouteW createNew(const HookContext::ConstPtr &context, - const HookCallContext &callContext, - LPCWSTR inPath, bool createPath = true, - LPSECURITY_ATTRIBUTES securityAttributes = nullptr) + static RerouteW createNew(const HookContext::ConstPtr& context, + const HookCallContext& callContext, LPCWSTR inPath, + bool createPath = true, + LPSECURITY_ATTRIBUTES securityAttributes = nullptr) { RerouteW result; - if (interestingPath(inPath) && callContext.active()) - { + if (interestingPath(inPath) && callContext.active()) { const auto& lookupPath = canonizePath(absolutePath(inPath)); - result.m_RealPath = lookupPath.wstring(); + result.m_RealPath = lookupPath.wstring(); result.m_Buffer = k32DeleteTracker.lookup(result.m_RealPath); - bool found = !result.m_Buffer.empty(); + bool found = !result.m_Buffer.empty(); if (found) - spdlog::get("hooks")->info("Rerouting file creation to original location of deleted file: {}", - shared::string_cast(result.m_Buffer)); - else - { + spdlog::get("hooks")->info( + "Rerouting file creation to original location of deleted file: {}", + shared::string_cast(result.m_Buffer)); + else { FindCreateTarget visitor; RedirectionTree::VisitorFunction visitorWrapper = - [&](const RedirectionTree::NodePtrT &node) { visitor(node); }; + [&](const RedirectionTree::NodePtrT& node) { + visitor(node); + }; context->redirectionTable()->visitPath(lookupPath, visitorWrapper); if (visitor.target.get()) { // the visitor has found the last (deepest in the directory hierarchy) // create-target - fs::path relativePath - = shared::make_relative(visitor.target->path(), lookupPath); + fs::path relativePath = + shared::make_relative(visitor.target->path(), lookupPath); result.m_Buffer = - (fs::path(visitor.target->data().linkTarget.c_str()) / relativePath).wstring(); + (fs::path(visitor.target->data().linkTarget.c_str()) / relativePath) + .wstring(); found = true; } } - if (found) - { + if (found) { if (createPath) { try { FunctionGroupLock lock(MutExHookGroup::ALL_GROUPS); - result.m_PathCreated = - createFakePath(fs::path(result.m_Buffer).parent_path(), securityAttributes); - } - catch (const std::exception &e) { - spdlog::get("hooks")->error("failed to create {}: {}", - shared::string_cast(result.m_Buffer), e.what()); + result.m_PathCreated = createFakePath( + fs::path(result.m_Buffer).parent_path(), securityAttributes); + } catch (const std::exception& e) { + spdlog::get("hooks")->error( + "failed to create {}: {}", + shared::string_cast(result.m_Buffer), e.what()); } } - wchar_t inIt = inPath[wcslen(inPath) - 1]; + wchar_t inIt = inPath[wcslen(inPath) - 1]; std::wstring::iterator outIt = result.m_Buffer.end() - 1; if ((*outIt == L'\\' || *outIt == L'/') && !(inIt == L'\\' || inIt == L'/')) result.m_Buffer.erase(outIt); std::replace(result.m_Buffer.begin(), result.m_Buffer.end(), L'/', L'\\'); - result.m_Rerouted = true; + result.m_Rerouted = true; result.m_NewReroute = true; - } - else + } else result.m_Buffer = inPath; - } - else if (inPath) + } else if (inPath) result.m_Buffer = inPath; if (inPath) @@ -488,12 +507,15 @@ public: return result; } - static RerouteW createOrNew(const HookContext::ConstPtr &context, const HookCallContext &callContext, - LPCWSTR inPath, bool createPath = true, LPSECURITY_ATTRIBUTES securityAttributes = nullptr) + static RerouteW createOrNew(const HookContext::ConstPtr& context, + const HookCallContext& callContext, LPCWSTR inPath, + bool createPath = true, + LPSECURITY_ATTRIBUTES securityAttributes = nullptr) { { auto res = create(context, callContext, inPath); - if (res.wasRerouted() || !interestingPath(inPath) || !callContext.active() || pathExists(inPath)) + if (res.wasRerouted() || !interestingPath(inPath) || !callContext.active() || + pathExists(inPath)) return std::move(res); } return createNew(context, callContext, inPath, createPath, securityAttributes); @@ -511,7 +533,8 @@ public: } private: - struct FindCreateTarget { + struct FindCreateTarget + { RedirectionTree::NodePtrT target; void operator()(RedirectionTree::NodePtrT node) { @@ -522,18 +545,29 @@ private: }; }; -class CreateRerouter { +class CreateRerouter +{ public: - bool rerouteCreate(const HookContext::ConstPtr &context, const HookCallContext &callContext, - LPCWSTR lpFileName, DWORD& dwCreationDisposition, DWORD dwDesiredAccess, LPSECURITY_ATTRIBUTES lpSecurityAttributes) + bool rerouteCreate(const HookContext::ConstPtr& context, + const HookCallContext& callContext, LPCWSTR lpFileName, + DWORD& dwCreationDisposition, DWORD dwDesiredAccess, + LPSECURITY_ATTRIBUTES lpSecurityAttributes) { - enum class Open { existing, create, empty }; + enum class Open + { + existing, + create, + empty + }; Open open = Open::existing; - // Notice since we are calling our patched GetFileAttributesW here this will also check virtualized paths + // Notice since we are calling our patched GetFileAttributesW here this will also + // check virtualized paths DWORD virtAttr = GetFileAttributesW(lpFileName); - bool isFile = virtAttr != INVALID_FILE_ATTRIBUTES && (virtAttr & FILE_ATTRIBUTE_DIRECTORY) == 0; - m_isDir = virtAttr != INVALID_FILE_ATTRIBUTES && (virtAttr & FILE_ATTRIBUTE_DIRECTORY); + bool isFile = virtAttr != INVALID_FILE_ATTRIBUTES && + (virtAttr & FILE_ATTRIBUTE_DIRECTORY) == 0; + m_isDir = + virtAttr != INVALID_FILE_ATTRIBUTES && (virtAttr & FILE_ATTRIBUTE_DIRECTORY); switch (dwCreationDisposition) { case CREATE_ALWAYS: @@ -575,30 +609,41 @@ public: else m_reroute = RerouteW::create(context, callContext, lpFileName); - if (m_reroute.wasRerouted() && open == Open::create && pathIsDirectory(m_reroute.fileName())) - m_reroute = RerouteW::createNew(context, callContext, lpFileName, true, lpSecurityAttributes); + if (m_reroute.wasRerouted() && open == Open::create && + pathIsDirectory(m_reroute.fileName())) + m_reroute = RerouteW::createNew(context, callContext, lpFileName, true, + lpSecurityAttributes); - if (!m_isDir && !isFile && !m_reroute.wasRerouted() && (open == Open::create || open == Open::empty)) - { - m_reroute = RerouteW::createNew(context, callContext, lpFileName, true, lpSecurityAttributes); + if (!m_isDir && !isFile && !m_reroute.wasRerouted() && + (open == Open::create || open == Open::empty)) { + m_reroute = RerouteW::createNew(context, callContext, lpFileName, true, + lpSecurityAttributes); - bool newFile = !m_reroute.wasRerouted() && pathDirectlyAvailable(m_reroute.fileName()); + bool newFile = + !m_reroute.wasRerouted() && pathDirectlyAvailable(m_reroute.fileName()); if (newFile && open == Open::empty) - // TRUNCATE_EXISTING will fail since the new file doesn't exist, so change disposition: + // TRUNCATE_EXISTING will fail since the new file doesn't exist, so change + // disposition: dwCreationDisposition = CREATE_ALWAYS; } return true; } - // rerouteNew is used for rerouting the destination of copy/move operations. Assumes that the call will be skipped if false is returned. - bool rerouteNew(const HookContext::ConstPtr &context, HookCallContext &callContext, LPCWSTR lpFileName, bool replaceExisting, const char* hookName) + // rerouteNew is used for rerouting the destination of copy/move operations. Assumes + // that the call will be skipped if false is returned. + bool rerouteNew(const HookContext::ConstPtr& context, HookCallContext& callContext, + LPCWSTR lpFileName, bool replaceExisting, const char* hookName) { DWORD disposition = replaceExisting ? CREATE_ALWAYS : CREATE_NEW; - if (!rerouteCreate(context, callContext, lpFileName, disposition, GENERIC_WRITE, nullptr)) { + if (!rerouteCreate(context, callContext, lpFileName, disposition, GENERIC_WRITE, + nullptr)) { spdlog::get("hooks")->info( - "{} guaranteed failure, skipping original call: {}, replaceExisting={}, error={}", - hookName, shared::string_cast(lpFileName, shared::CodePage::UTF8), replaceExisting ? "true" : "false", error()); + "{} guaranteed failure, skipping original call: {}, replaceExisting={}, " + "error={}", + hookName, + shared::string_cast(lpFileName, shared::CodePage::UTF8), + replaceExisting ? "true" : "false", error()); callContext.updateLastError(error()); return false; @@ -606,15 +651,14 @@ public: return true; } - void updateResult(HookCallContext &callContext, bool success) + void updateResult(HookCallContext& callContext, bool success) { m_originalError = callContext.lastError(); if (success) { // m_error != ERROR_SUCCESS means we are overriding the error on success if (m_error == ERROR_SUCCESS) m_error = m_originalError; - } - else if (m_originalError == ERROR_PATH_NOT_FOUND && m_directlyAvailable) + } else if (m_originalError == ERROR_PATH_NOT_FOUND && m_directlyAvailable) m_error = ERROR_FILE_NOT_FOUND; else m_error = m_originalError; @@ -631,14 +675,17 @@ public: bool wasRerouted() const { return m_reroute.wasRerouted(); } LPCWSTR fileName() const { return m_reroute.fileName(); } - void insertMapping(const HookContext::Ptr &context, bool directory = false) { m_reroute.insertMapping(context, directory); } + void insertMapping(const HookContext::Ptr& context, bool directory = false) + { + m_reroute.insertMapping(context, directory); + } private: - DWORD m_error = ERROR_SUCCESS; - DWORD m_originalError = ERROR_SUCCESS; + DWORD m_error = ERROR_SUCCESS; + DWORD m_originalError = ERROR_SUCCESS; bool m_directlyAvailable = false; - bool m_isDir = false; + bool m_isDir = false; RerouteW m_reroute; }; -} // namespace usvfs +} // namespace usvfs diff --git a/src/usvfs_dll/redirectiontree.cpp b/src/usvfs_dll/redirectiontree.cpp index feb7793..e521365 100644 --- a/src/usvfs_dll/redirectiontree.cpp +++ b/src/usvfs_dll/redirectiontree.cpp @@ -20,7 +20,7 @@ along with usvfs. If not, see . */ #include "redirectiontree.h" -std::ostream &usvfs::operator<<(std::ostream &stream, const RedirectionData &data) +std::ostream& usvfs::operator<<(std::ostream& stream, const RedirectionData& data) { stream << data.linkTarget; return stream; diff --git a/src/usvfs_dll/redirectiontree.h b/src/usvfs_dll/redirectiontree.h index ec94ea1..7ccd1fa 100644 --- a/src/usvfs_dll/redirectiontree.h +++ b/src/usvfs_dll/redirectiontree.h @@ -22,72 +22,78 @@ along with usvfs. If not, see . #include -namespace usvfs { +namespace usvfs +{ -//typedef boost::interprocess::basic_string, shared::CharAllocatorT> StringT; +// typedef boost::interprocess::basic_string, +// shared::CharAllocatorT> StringT; -namespace shared { +namespace shared +{ static const TreeFlags FLAG_CREATETARGET = FLAG_FIRSTUSERFLAG + 0x00; } +struct RedirectionDataLocal +{ -struct RedirectionDataLocal { + RedirectionDataLocal(const char* target) : linkTarget(target) {} - RedirectionDataLocal(const char *target) - : linkTarget(target) - {} - - RedirectionDataLocal(const std::string &target) - : linkTarget(target) - {} + RedirectionDataLocal(const std::string& target) : linkTarget(target) {} std::string linkTarget; }; +struct RedirectionData +{ -struct RedirectionData { - - RedirectionData(const RedirectionData &reference, const shared::VoidAllocatorT &allocator) - : linkTarget(reference.linkTarget.c_str(), allocator) + RedirectionData(const RedirectionData& reference, + const shared::VoidAllocatorT& allocator) + : linkTarget(reference.linkTarget.c_str(), allocator) {} - RedirectionData(const RedirectionDataLocal &reference, const shared::VoidAllocatorT &allocator) - : linkTarget(reference.linkTarget.c_str(), allocator) + RedirectionData(const RedirectionDataLocal& reference, + const shared::VoidAllocatorT& allocator) + : linkTarget(reference.linkTarget.c_str(), allocator) {} - RedirectionData(const char *target, const shared::VoidAllocatorT &allocator) - : linkTarget(target, allocator) + RedirectionData(const char* target, const shared::VoidAllocatorT& allocator) + : linkTarget(target, allocator) {} shared::StringT linkTarget; - }; +std::ostream& operator<<(std::ostream& stream, const RedirectionData& data); -std::ostream &operator<<(std::ostream &stream, const RedirectionData &data); - - -template <> inline void shared::dataAssign(RedirectionData &destination, const RedirectionData &source) +template <> +inline void shared::dataAssign(RedirectionData& destination, + const RedirectionData& source) { destination.linkTarget.assign(source.linkTarget.c_str()); } -template <> inline RedirectionData shared::createDataEmpty(const VoidAllocatorT &allocator) +template <> +inline RedirectionData +shared::createDataEmpty(const VoidAllocatorT& allocator) { return RedirectionData("", allocator); } - template -struct shared::SHMDataCreator { - static RedirectionData create(T source, const VoidAllocatorT &allocator) { +struct shared::SHMDataCreator +{ + static RedirectionData create(T source, const VoidAllocatorT& allocator) + { return RedirectionData(source, allocator); } }; template <> -struct shared::SHMDataCreator { - static RedirectionData create(const RedirectionData &source, const VoidAllocatorT &allocator) { +struct shared::SHMDataCreator +{ + static RedirectionData create(const RedirectionData& source, + const VoidAllocatorT& allocator) + { return RedirectionData(source, allocator); } }; @@ -95,5 +101,4 @@ struct shared::SHMDataCreator { typedef shared::DirectoryTree RedirectionTree; typedef shared::TreeContainer RedirectionTreeContainer; - -} +} // namespace usvfs diff --git a/src/usvfs_dll/semaphore.cpp b/src/usvfs_dll/semaphore.cpp index f689271..609b2f5 100644 --- a/src/usvfs_dll/semaphore.cpp +++ b/src/usvfs_dll/semaphore.cpp @@ -1,10 +1,7 @@ #include "semaphore.h" #include "exceptionex.h" -RecursiveBenaphore::RecursiveBenaphore() - : m_Counter(0) - , m_OwnerId(0UL) - , m_Recursion(0) +RecursiveBenaphore::RecursiveBenaphore() : m_Counter(0), m_OwnerId(0UL), m_Recursion(0) { m_Semaphore = ::CreateSemaphore(nullptr, 1, 1, nullptr); } @@ -23,13 +20,13 @@ void RecursiveBenaphore::wait(DWORD timeout) int tries = 3; while (::WaitForSingleObject(m_Semaphore, timeout) != WAIT_OBJECT_0) { HANDLE owner = ::OpenThread(SYNCHRONIZE, FALSE, m_OwnerId); - ON_BLOCK_EXIT([owner] () { ::CloseHandle(owner); }); - if ((tries <= 0) - || (::WaitForSingleObject(owner, 0) == WAIT_OBJECT_0)) { + ON_BLOCK_EXIT([owner]() { + ::CloseHandle(owner); + }); + if ((tries <= 0) || (::WaitForSingleObject(owner, 0) == WAIT_OBJECT_0)) { // owner has quit without releasing the semaphore! m_Recursion = 0; - spdlog::get("usvfs") - ->error("thread {} never released the mutex", m_OwnerId); + spdlog::get("usvfs")->error("thread {} never released the mutex", m_OwnerId); break; } else { --tries; diff --git a/src/usvfs_dll/semaphore.h b/src/usvfs_dll/semaphore.h index 4b533b6..1048c47 100644 --- a/src/usvfs_dll/semaphore.h +++ b/src/usvfs_dll/semaphore.h @@ -6,7 +6,6 @@ // undefined behaviour over deadlock. It's utterly broken // and needs to be replaced in time. - class RecursiveBenaphore { @@ -21,10 +20,8 @@ public: void signal(); private: - LONG m_Counter; DWORD m_OwnerId; int m_Recursion; HANDLE m_Semaphore; - }; diff --git a/src/usvfs_dll/sharedparameters.cpp b/src/usvfs_dll/sharedparameters.cpp index 78f8e3f..95cd0b2 100644 --- a/src/usvfs_dll/sharedparameters.cpp +++ b/src/usvfs_dll/sharedparameters.cpp @@ -1,17 +1,15 @@ +#include #include #include -#include namespace usvfs { -ForcedLibrary::ForcedLibrary( - const std::string& process, const std::string& path, - const shared::VoidAllocatorT& alloc) : - m_processName(process.begin(), process.end(), alloc), - m_libraryPath(path.begin(), path.end(), alloc) -{ -} +ForcedLibrary::ForcedLibrary(const std::string& process, const std::string& path, + const shared::VoidAllocatorT& alloc) + : m_processName(process.begin(), process.end(), alloc), + m_libraryPath(path.begin(), path.end(), alloc) +{} std::string ForcedLibrary::processName() const { @@ -23,37 +21,28 @@ std::string ForcedLibrary::libraryPath() const return {m_libraryPath.begin(), m_libraryPath.end()}; } - SharedParameters::SharedParameters(const usvfsParameters& reference, - const shared::VoidAllocatorT &allocator) - : m_instanceName(reference.instanceName, allocator) - , m_currentSHMName(reference.currentSHMName, allocator) - , m_currentInverseSHMName(reference.currentInverseSHMName, allocator) - , m_debugMode(reference.debugMode) - , m_logLevel(reference.logLevel) - , m_crashDumpsType(reference.crashDumpsType) - , m_crashDumpsPath(reference.crashDumpsPath, allocator) - , m_delayProcess(reference.delayProcessMs) - , m_userCount(1) - , m_processBlacklist(allocator) - , m_processList(allocator) - , m_fileSuffixSkipList(allocator) - , m_directorySkipList(allocator) - , m_forcedLibraries(allocator) -{ -} + const shared::VoidAllocatorT& allocator) + : m_instanceName(reference.instanceName, allocator), + m_currentSHMName(reference.currentSHMName, allocator), + m_currentInverseSHMName(reference.currentInverseSHMName, allocator), + m_debugMode(reference.debugMode), m_logLevel(reference.logLevel), + m_crashDumpsType(reference.crashDumpsType), + m_crashDumpsPath(reference.crashDumpsPath, allocator), + m_delayProcess(reference.delayProcessMs), m_userCount(1), + m_processBlacklist(allocator), m_processList(allocator), + m_fileSuffixSkipList(allocator), m_directorySkipList(allocator), + m_forcedLibraries(allocator) +{} usvfsParameters SharedParameters::makeLocal() const { bi::scoped_lock lock(m_mutex); - return usvfsParameters( - m_instanceName.c_str(), - m_currentSHMName.c_str(), - m_currentInverseSHMName.c_str(), - m_debugMode, m_logLevel, m_crashDumpsType, - m_crashDumpsPath.c_str(), - m_delayProcess.count()); + return usvfsParameters(m_instanceName.c_str(), m_currentSHMName.c_str(), + m_currentInverseSHMName.c_str(), m_debugMode, m_logLevel, + m_crashDumpsType, m_crashDumpsPath.c_str(), + m_delayProcess.count()); } std::string SharedParameters::instanceName() const @@ -74,8 +63,8 @@ std::string SharedParameters::currentInverseSHMName() const return {m_currentInverseSHMName.begin(), m_currentInverseSHMName.end()}; } -void SharedParameters::setSHMNames( - const std::string& current, const std::string& inverse) +void SharedParameters::setSHMNames(const std::string& current, + const std::string& inverse) { bi::scoped_lock lock(m_mutex); @@ -83,13 +72,13 @@ void SharedParameters::setSHMNames( m_currentInverseSHMName.assign(inverse.begin(), inverse.end()); } -void SharedParameters::setDebugParameters( - LogLevel level, CrashDumpsType dumpType, const std::string& dumpPath, - std::chrono::milliseconds delayProcess) +void SharedParameters::setDebugParameters(LogLevel level, CrashDumpsType dumpType, + const std::string& dumpPath, + std::chrono::milliseconds delayProcess) { bi::scoped_lock lock(m_mutex); - m_logLevel = level; + m_logLevel = level; m_crashDumpsType = dumpType; m_crashDumpsPath.assign(dumpPath.begin(), dumpPath.end()); m_delayProcess = delayProcess; @@ -144,16 +133,15 @@ void SharedParameters::unregisterProcess(DWORD pid) } } - spdlog::get("usvfs")->error( - "cannot unregister process {}, not in list", pid); + spdlog::get("usvfs")->error("cannot unregister process {}, not in list", pid); } void SharedParameters::blacklistExecutable(const std::string& name) { bi::scoped_lock lock(m_mutex); - m_processBlacklist.insert(shared::StringT( - name.begin(), name.end(), m_processBlacklist.get_allocator())); + m_processBlacklist.insert( + shared::StringT(name.begin(), name.end(), m_processBlacklist.get_allocator())); } void SharedParameters::clearExecutableBlacklist() @@ -162,8 +150,8 @@ void SharedParameters::clearExecutableBlacklist() m_processBlacklist.clear(); } -bool SharedParameters::executableBlacklisted( - const std::string& appName, const std::string& cmdLine) const +bool SharedParameters::executableBlacklisted(const std::string& appName, + const std::string& cmdLine) const { bool blacklisted = false; std::string log; @@ -177,7 +165,7 @@ bool SharedParameters::executableBlacklisted( if (!appName.empty()) { if (boost::algorithm::iends_with(appName, item)) { blacklisted = true; - log = std::format("application {} is blacklisted", appName); + log = std::format("application {} is blacklisted", appName); break; } } @@ -185,7 +173,7 @@ bool SharedParameters::executableBlacklisted( if (!cmdLine.empty()) { if (boost::algorithm::icontains(cmdLine, item)) { blacklisted = true; - log = std::format("command line {} is blacklisted", cmdLine); + log = std::format("command line {} is blacklisted", cmdLine); break; } } @@ -217,18 +205,18 @@ void SharedParameters::clearSkipFileSuffixes() std::vector SharedParameters::skipFileSuffixes() const { bi::scoped_lock lock(m_mutex); - return { m_fileSuffixSkipList.begin(), m_fileSuffixSkipList.end() }; + return {m_fileSuffixSkipList.begin(), m_fileSuffixSkipList.end()}; } -void SharedParameters::addSkipDirectory(const std::string& directory) +void SharedParameters::addSkipDirectory(const std::string& directory) { bi::scoped_lock lock(m_mutex); m_directorySkipList.insert(shared::StringT(directory.begin(), directory.end(), - m_directorySkipList.get_allocator())); + m_directorySkipList.get_allocator())); } -void SharedParameters::clearSkipDirectories() +void SharedParameters::clearSkipDirectories() { bi::scoped_lock lock(m_mutex); m_directorySkipList.clear(); @@ -237,20 +225,20 @@ void SharedParameters::clearSkipDirectories() std::vector SharedParameters::skipDirectories() const { bi::scoped_lock lock(m_mutex); - return { m_directorySkipList.begin(), m_directorySkipList.end() }; + return {m_directorySkipList.begin(), m_directorySkipList.end()}; } -void SharedParameters::addForcedLibrary( - const std::string& processName, const std::string& libraryPath) +void SharedParameters::addForcedLibrary(const std::string& processName, + const std::string& libraryPath) { bi::scoped_lock lock(m_mutex); - m_forcedLibraries.push_front(ForcedLibrary( - processName, libraryPath, m_forcedLibraries.get_allocator())); + m_forcedLibraries.push_front( + ForcedLibrary(processName, libraryPath, m_forcedLibraries.get_allocator())); } -std::vector SharedParameters::forcedLibraries( - const std::string& processName) +std::vector +SharedParameters::forcedLibraries(const std::string& processName) { std::vector v; @@ -273,4 +261,4 @@ void SharedParameters::clearForcedLibraries() m_forcedLibraries.clear(); } -} // namespace +} // namespace usvfs diff --git a/src/usvfs_dll/stringcast_boost.h b/src/usvfs_dll/stringcast_boost.h index 81d98ad..d2544ec 100644 --- a/src/usvfs_dll/stringcast_boost.h +++ b/src/usvfs_dll/stringcast_boost.h @@ -20,17 +20,23 @@ along with usvfs. If not, see . */ #include -namespace usvfs { -namespace shared { +namespace usvfs +{ +namespace shared +{ -template -class string_cast_impl> { -public: - static ToT cast(const boost::container::basic_string &source, CodePage codePage, size_t sourceLength) + template + class string_cast_impl> { - return string_cast_impl::cast(source.c_str(), codePage, sourceLength); - } -}; + public: + static ToT + cast(const boost::container::basic_string& source, + CodePage codePage, size_t sourceLength) + { + return string_cast_impl::cast(source.c_str(), codePage, + sourceLength); + } + }; -} -} +} // namespace shared +} // namespace usvfs diff --git a/src/usvfs_dll/usvfs.cpp b/src/usvfs_dll/usvfs.cpp index 7b38143..1f30f7b 100644 --- a/src/usvfs_dll/usvfs.cpp +++ b/src/usvfs_dll/usvfs.cpp @@ -19,18 +19,18 @@ You should have received a copy of the GNU General Public License along with usvfs. If not, see . */ #include "usvfs.h" -#include "usvfs_version.h" #include "hookmanager.h" -#include "usvfsparametersprivate.h" -#include "redirectiontree.h" #include "loghelpers.h" -#include -#include -#include -#include +#include "redirectiontree.h" +#include "usvfs_version.h" +#include "usvfsparametersprivate.h" #include -#include +#include #include +#include +#include +#include +#include // note that there's a mix of boost and std filesystem stuff in this file and // that they're not completely compatible @@ -43,10 +43,10 @@ namespace ba = boost::algorithm; using usvfs::log::ConvertLogLevel; -usvfs::HookManager *manager = nullptr; -usvfs::HookContext *context = nullptr; -HMODULE dllModule = nullptr; -PVOID exceptionHandler = nullptr; +usvfs::HookManager* manager = nullptr; +usvfs::HookContext* context = nullptr; +HMODULE dllModule = nullptr; +PVOID exceptionHandler = nullptr; CrashDumpsType usvfs_dump_type = CrashDumpsType::None; std::wstring usvfs_dump_path; @@ -55,9 +55,9 @@ std::wstring usvfs_dump_path; // template bool extensionMatchesCI( - std::string_view name, - const std::array& extensionsLC, - const std::array& extensionsUC) + std::string_view name, + const std::array& extensionsLC, + const std::array& extensionsUC) { constexpr std::size_t longestExtensionWithDot = LongestExtension + 1; @@ -67,8 +67,8 @@ bool extensionMatchesCI( } // for each extension - for (std::size_t i=0; i("usvfs") @@ -155,7 +155,8 @@ void InitLoggingInternal(bool toConsole, bool connectExistingSHM) logger->set_level(spdlog::level::debug); } catch (const std::exception&) { // TODO should really report this - //OutputDebugStringA((boost::format("init exception: %1%\n") % e.what()).str().c_str()); + // OutputDebugStringA((boost::format("init exception: %1%\n") % + // e.what()).str().c_str()); if (spdlog::get("usvfs").get() == nullptr) { spdlog::create("usvfs"); } @@ -164,17 +165,17 @@ void InitLoggingInternal(bool toConsole, bool connectExistingSHM) } } - spdlog::get("usvfs")->info("usvfs dll {} initialized in process {}", USVFS_VERSION_STRING, GetCurrentProcessId()); + spdlog::get("usvfs")->info("usvfs dll {} initialized in process {}", + USVFS_VERSION_STRING, GetCurrentProcessId()); } - void WINAPI usvfsInitLogging(bool toConsole) { InitLoggingInternal(toConsole, false); } -extern "C" DLLEXPORT bool WINAPI usvfsGetLogMessages( - LPSTR buffer, size_t size, bool blocking) +extern "C" DLLEXPORT bool WINAPI usvfsGetLogMessages(LPSTR buffer, size_t size, + bool blocking) { buffer[0] = '\0'; try { @@ -184,9 +185,9 @@ extern "C" DLLEXPORT bool WINAPI usvfsGetLogMessages( } else { return SHMLogger::instance().tryGet(buffer, size); } - } catch (const std::exception &e) { + } catch (const std::exception& e) { _snprintf_s(buffer, size, _TRUNCATE, "Failed to retrieve log messages: %s", - e.what()); + e.what()); return false; } } @@ -199,30 +200,27 @@ void SetLogLevel(LogLevel level) void WINAPI usvfsUpdateParameters(usvfsParameters* p) { - spdlog::get("usvfs")->info( - "updating parameters:\n" - " . debugMode: {}\n" - " . log level: {}\n" - " . dump type: {}\n" - " . dump path: {}\n" - " . delay process: {}ms", - p->debugMode, usvfsLogLevelToString(p->logLevel), - usvfsCrashDumpTypeToString(p->crashDumpsType), p->crashDumpsPath, - p->delayProcessMs); + spdlog::get("usvfs")->info("updating parameters:\n" + " . debugMode: {}\n" + " . log level: {}\n" + " . dump type: {}\n" + " . dump path: {}\n" + " . delay process: {}ms", + p->debugMode, usvfsLogLevelToString(p->logLevel), + usvfsCrashDumpTypeToString(p->crashDumpsType), + p->crashDumpsPath, p->delayProcessMs); // update actual values used: usvfs_dump_type = p->crashDumpsType; - usvfs_dump_path = ush::string_cast( - p->crashDumpsPath, ush::CodePage::UTF8); + usvfs_dump_path = + ush::string_cast(p->crashDumpsPath, ush::CodePage::UTF8); SetLogLevel(p->logLevel); // update parameters in context so spawned process will inherit changes: - context->setDebugParameters( - p->logLevel, p->crashDumpsType, p->crashDumpsPath, - std::chrono::milliseconds(p->delayProcessMs)); + context->setDebugParameters(p->logLevel, p->crashDumpsType, p->crashDumpsPath, + std::chrono::milliseconds(p->delayProcessMs)); } - // // Structured Exception handling // @@ -241,17 +239,20 @@ std::wstring generate_minidump_name(const wchar_t* dumpPath) while (winapi::ex::wide::fileExists(dmpFile)) { if (++count > 99) return std::wstring(); - _snwprintf_s(dmpFile, _TRUNCATE, L"%s\\%s-%lu_%02d.dmp", dumpPath, pname, pid, count); + _snwprintf_s(dmpFile, _TRUNCATE, L"%s\\%s-%lu_%02d.dmp", dumpPath, pname, pid, + count); } return dmpFile; } -int createMiniDumpImpl(PEXCEPTION_POINTERS exceptionPtrs, CrashDumpsType type, const wchar_t* dumpPath, HMODULE dbgDLL) +int createMiniDumpImpl(PEXCEPTION_POINTERS exceptionPtrs, CrashDumpsType type, + const wchar_t* dumpPath, HMODULE dbgDLL) { - typedef BOOL (WINAPI *FuncMiniDumpWriteDump)(HANDLE process, DWORD pid, HANDLE file, MINIDUMP_TYPE dumpType, - const PMINIDUMP_EXCEPTION_INFORMATION exceptionParam, - const PMINIDUMP_USER_STREAM_INFORMATION userStreamParam, - const PMINIDUMP_CALLBACK_INFORMATION callbackParam); + typedef BOOL(WINAPI * FuncMiniDumpWriteDump)( + HANDLE process, DWORD pid, HANDLE file, MINIDUMP_TYPE dumpType, + const PMINIDUMP_EXCEPTION_INFORMATION exceptionParam, + const PMINIDUMP_USER_STREAM_INFORMATION userStreamParam, + const PMINIDUMP_CALLBACK_INFORMATION callbackParam); // notice we avoid logging here on purpose because this is called from the VEHandler // and the logger can crash it in extreme cases. @@ -262,46 +263,50 @@ int createMiniDumpImpl(PEXCEPTION_POINTERS exceptionPtrs, CrashDumpsType type, c if (dmpName.empty()) return 4; - FuncMiniDumpWriteDump funcDump = reinterpret_cast(GetProcAddress(dbgDLL, "MiniDumpWriteDump")); + FuncMiniDumpWriteDump funcDump = reinterpret_cast( + GetProcAddress(dbgDLL, "MiniDumpWriteDump")); if (!funcDump) return 5; - HANDLE dumpFile = winapi::wide::createFile(dmpName).createAlways().access(GENERIC_WRITE).share(FILE_SHARE_WRITE)(); + HANDLE dumpFile = winapi::wide::createFile(dmpName) + .createAlways() + .access(GENERIC_WRITE) + .share(FILE_SHARE_WRITE)(); if (dumpFile != INVALID_HANDLE_VALUE) { - DWORD dumpType = MiniDumpNormal | MiniDumpWithHandleData | MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData; + DWORD dumpType = MiniDumpNormal | MiniDumpWithHandleData | + MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData; if (type == CrashDumpsType::Data) dumpType |= MiniDumpWithDataSegs; if (type == CrashDumpsType::Full) dumpType |= MiniDumpWithFullMemory; _MINIDUMP_EXCEPTION_INFORMATION exceptionInfo; - exceptionInfo.ThreadId = GetCurrentThreadId(); + exceptionInfo.ThreadId = GetCurrentThreadId(); exceptionInfo.ExceptionPointers = exceptionPtrs; - exceptionInfo.ClientPointers = FALSE; + exceptionInfo.ClientPointers = FALSE; - BOOL success = - funcDump(GetCurrentProcess(), GetCurrentProcessId(), dumpFile, static_cast(dumpType), &exceptionInfo, nullptr, nullptr); + BOOL success = funcDump(GetCurrentProcess(), GetCurrentProcessId(), dumpFile, + static_cast(dumpType), &exceptionInfo, + nullptr, nullptr); CloseHandle(dumpFile); return success ? 0 : 7; - } - else + } else return 6; } -int WINAPI usvfsCreateMiniDump(PEXCEPTION_POINTERS exceptionPtrs, CrashDumpsType type, const wchar_t* dumpPath) +int WINAPI usvfsCreateMiniDump(PEXCEPTION_POINTERS exceptionPtrs, CrashDumpsType type, + const wchar_t* dumpPath) { if (type == CrashDumpsType::None) return 0; int res = 1; - if (HMODULE dbgDLL = LoadLibraryW(L"dbghelp.dll")) - { + if (HMODULE dbgDLL = LoadLibraryW(L"dbghelp.dll")) { try { res = createMiniDumpImpl(exceptionPtrs, type, dumpPath, dbgDLL); - } - catch (...) { + } catch (...) { res = 2; } FreeLibrary(dbgDLL); @@ -309,48 +314,50 @@ int WINAPI usvfsCreateMiniDump(PEXCEPTION_POINTERS exceptionPtrs, CrashDumpsType return res; } -static bool exceptionInUSVFS(PEXCEPTION_POINTERS exceptionPtrs) { - if (!dllModule) // shouldn't happen, check just in case - return true; // create dump to better understand how this could happen +static bool exceptionInUSVFS(PEXCEPTION_POINTERS exceptionPtrs) +{ + if (!dllModule) // shouldn't happen, check just in case + return true; // create dump to better understand how this could happen std::pair range = winapi::ex::getSectionRange(dllModule); uintptr_t exceptionAddress = - reinterpret_cast(exceptionPtrs->ExceptionRecord->ExceptionAddress); + reinterpret_cast(exceptionPtrs->ExceptionRecord->ExceptionAddress); return range.first <= exceptionAddress && exceptionAddress < range.second; } LONG WINAPI VEHandler(PEXCEPTION_POINTERS exceptionPtrs) { - // NOTICE: don't use logger in VEHandler as it can cause another fault causing VEHandler - // to be called again and so on. + // NOTICE: don't use logger in VEHandler as it can cause another fault causing + // VEHandler to be called again and so on. - if ( (exceptionPtrs->ExceptionRecord->ExceptionCode < 0x80000000) // non-critical - || (exceptionPtrs->ExceptionRecord->ExceptionCode == 0xe06d7363)) { // cpp exception + if ((exceptionPtrs->ExceptionRecord->ExceptionCode < 0x80000000) // non-critical + || + (exceptionPtrs->ExceptionRecord->ExceptionCode == 0xe06d7363)) { // cpp exception // don't report non-critical exceptions return EXCEPTION_CONTINUE_SEARCH; } /* - if (((exceptionPtrs->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) != 0) || - (exceptionPtrs->ExceptionRecord->ExceptionCode == 0xe06d7363)) { - // don't want to break on non-critical exceptions. 0xe06d7363 indicates a C++ exception. why are those marked non-continuable? - return EXCEPTION_CONTINUE_SEARCH; + if (((exceptionPtrs->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) != 0) + || (exceptionPtrs->ExceptionRecord->ExceptionCode == 0xe06d7363)) { + // don't want to break on non-critical exceptions. 0xe06d7363 indicates a C++ + exception. why are those marked non-continuable? return EXCEPTION_CONTINUE_SEARCH; } */ // VEHandler is called on "first-chance" exceptions which might be caught and handled. - // Ideally we would like to use an UnhandledExceptionFilter but that fails to catch crashes - // inside our hooks at least on x64, which is the main reason why want a crash collection - // from usvfs. - // As a workaround/compromise we catch vectored exception but only ones that originate - // directly within the usvfs code: + // Ideally we would like to use an UnhandledExceptionFilter but that fails to catch + // crashes inside our hooks at least on x64, which is the main reason why want a crash + // collection from usvfs. As a workaround/compromise we catch vectored exception but + // only ones that originate directly within the usvfs code: if (!exceptionInUSVFS(exceptionPtrs)) return EXCEPTION_CONTINUE_SEARCH; // disable our hooking mechanism to increase chances the dump writing won't crash HookLib::TrampolinePool& trampPool = HookLib::TrampolinePool::instance(); - if (&trampPool) { // need to test this in case of crash before TrampolinePool initialized + if (&trampPool) { // need to test this in case of crash before TrampolinePool + // initialized trampPool.forceUnlockBarrier(); trampPool.setBlock(true); } @@ -369,8 +376,9 @@ void __cdecl InitHooks(LPVOID parameters, size_t) InitLoggingInternal(false, true); const usvfsParameters* params = reinterpret_cast(parameters); - usvfs_dump_type = params->crashDumpsType; - usvfs_dump_path = ush::string_cast(params->crashDumpsPath, ush::CodePage::UTF8); + usvfs_dump_type = params->crashDumpsType; + usvfs_dump_path = + ush::string_cast(params->crashDumpsPath, ush::CodePage::UTF8); if (params->delayProcessMs > 0) { ::Sleep(static_cast(params->delayProcessMs)); @@ -386,56 +394,52 @@ void __cdecl InitHooks(LPVOID parameters, size_t) // how did this happen?? } - spdlog::get("usvfs") - ->info("inithooks called {0} in process {1}:{2} (log level {3}, dump type {4}, dump path {5})", - params->instanceName, - winapi::ansi::getModuleFileName(nullptr), - ::GetCurrentProcessId(), - static_cast(params->logLevel), - static_cast(params->crashDumpsType), - params->crashDumpsPath); + spdlog::get("usvfs")->info( + "inithooks called {0} in process {1}:{2} (log level {3}, dump type {4}, dump " + "path {5})", + params->instanceName, winapi::ansi::getModuleFileName(nullptr), + ::GetCurrentProcessId(), static_cast(params->logLevel), + static_cast(params->crashDumpsType), params->crashDumpsPath); try { manager = new usvfs::HookManager(*params, dllModule); - auto context = manager->context(); - auto exePath = boost::dll::program_location(); + auto context = manager->context(); + auto exePath = boost::dll::program_location(); auto libraries = context->librariesToForceLoad(exePath.filename().c_str()); for (auto library : libraries) { if (std::filesystem::exists(library)) { const auto ret = LoadLibraryExW(library.c_str(), NULL, 0); if (ret) { - spdlog::get("usvfs") - ->info("inithooks succeeded to force load {0}", ush::string_cast(library).c_str()); + spdlog::get("usvfs")->info("inithooks succeeded to force load {0}", + ush::string_cast(library).c_str()); } else { - spdlog::get("usvfs") - ->critical("inithooks failed to force load {0}", ush::string_cast(library).c_str()); + spdlog::get("usvfs")->critical( + "inithooks failed to force load {0}", + ush::string_cast(library).c_str()); } } } - spdlog::get("usvfs") - ->info("inithooks in process {0} successful", ::GetCurrentProcessId()); + spdlog::get("usvfs")->info("inithooks in process {0} successful", + ::GetCurrentProcessId()); - } catch (const std::exception &e) { + } catch (const std::exception& e) { spdlog::get("usvfs")->debug("failed to initialise hooks: {0}", e.what()); } } - -void WINAPI usvfsGetCurrentVFSName(char *buffer, size_t size) +void WINAPI usvfsGetCurrentVFSName(char* buffer, size_t size) { ush::strncpy_sz(buffer, context->callParameters().currentSHMName, size); } - BOOL WINAPI usvfsCreateVFS(const usvfsParameters* p) { usvfs::HookContext::remove(p->instanceName); return usvfsConnectVFS(p); } - BOOL WINAPI usvfsConnectVFS(const usvfsParameters* params) { if (spdlog::get("usvfs").get() == nullptr) { @@ -448,13 +452,12 @@ BOOL WINAPI usvfsConnectVFS(const usvfsParameters* params) context = new usvfs::HookContext(*params, dllModule); return TRUE; - } catch (const std::exception &e) { + } catch (const std::exception& e) { spdlog::get("usvfs")->debug("failed to connect to vfs: {}", e.what()); return FALSE; } } - void WINAPI usvfsDisconnectVFS() { if (spdlog::get("usvfs").get() == nullptr) { @@ -476,7 +479,6 @@ void WINAPI usvfsDisconnectVFS() } } - bool processStillActive(DWORD pid) { HANDLE proc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); @@ -486,22 +488,21 @@ bool processStillActive(DWORD pid) } ON_BLOCK_EXIT([&]() { - if (proc != INVALID_HANDLE_VALUE) - ::CloseHandle(proc); + if (proc != INVALID_HANDLE_VALUE) + ::CloseHandle(proc); }); DWORD exitCode; if (!GetExitCodeProcess(proc, &exitCode)) { - spdlog::get("usvfs")->warn("failed to query exit code on process {}: {}", - pid, ::GetLastError()); + spdlog::get("usvfs")->warn("failed to query exit code on process {}: {}", pid, + ::GetLastError()); return false; } else { return exitCode == STILL_ACTIVE; } } - -BOOL WINAPI usvfsGetVFSProcessList(size_t *count, LPDWORD processIDs) +BOOL WINAPI usvfsGetVFSProcessList(size_t* count, LPDWORD processIDs) { if (count == nullptr) { SetLastError(ERROR_INVALID_PARAMETER); @@ -512,7 +513,7 @@ BOOL WINAPI usvfsGetVFSProcessList(size_t *count, LPDWORD processIDs) *count = 0; } else { std::vector pids = context->registeredProcesses(); - size_t realCount = 0; + size_t realCount = 0; for (DWORD pid : pids) { if (processStillActive(pid)) { if ((realCount < *count) && (processIDs != nullptr)) { @@ -520,7 +521,7 @@ BOOL WINAPI usvfsGetVFSProcessList(size_t *count, LPDWORD processIDs) } ++realCount; - } // else the process has already ended + } // else the process has already ended } *count = realCount; } @@ -534,11 +535,11 @@ BOOL WINAPI usvfsGetVFSProcessList2(size_t* count, DWORD** buffer) return FALSE; } - *count = 0; + *count = 0; *buffer = nullptr; std::vector pids = context->registeredProcesses(); - auto last = std::remove_if(pids.begin(), pids.end(), [](DWORD id) { + auto last = std::remove_if(pids.begin(), pids.end(), [](DWORD id) { return !processStillActive(id); }); @@ -548,7 +549,7 @@ BOOL WINAPI usvfsGetVFSProcessList2(size_t* count, DWORD** buffer) return TRUE; } - *count = pids.size(); + *count = pids.size(); *buffer = static_cast(std::calloc(pids.size(), sizeof(DWORD))); std::copy(pids.begin(), pids.end(), *buffer); @@ -568,28 +569,25 @@ void WINAPI usvfsClearVirtualMappings() /// directory, this returns false /// \todo if this fails (i.e. not all intermediate directories exists) any /// intermediate directories already created aren't removed -bool assertPathExists(usvfs::RedirectionTreeContainer &table, LPCWSTR path) +bool assertPathExists(usvfs::RedirectionTreeContainer& table, LPCWSTR path) { bfs::path p(path); p = p.parent_path(); - usvfs::RedirectionTree::NodeT *current = table.get(); + usvfs::RedirectionTree::NodeT* current = table.get(); - for (auto iter = p.begin(); iter != p.end(); - iter = ush::nextIter(iter, p.end())) { + for (auto iter = p.begin(); iter != p.end(); iter = ush::nextIter(iter, p.end())) { if (current->exists(iter->string().c_str())) { // subdirectory exists virtually, all good - usvfs::RedirectionTree::NodePtrT found - = current->node(iter->string().c_str()); - current = found.get().get(); + usvfs::RedirectionTree::NodePtrT found = current->node(iter->string().c_str()); + current = found.get().get(); } else { // targetPath is relative to the last rerouted "real" path. This means // that if virtual c:/foo maps to real c:/windows then creating virtual // c:/foo/bar will map to real c:/windows/bar - bfs::path targetPath - = current->data().linkTarget.size() > 0 - ? bfs::path(current->data().linkTarget.c_str()) / *iter - : *iter / "\\"; + bfs::path targetPath = current->data().linkTarget.size() > 0 + ? bfs::path(current->data().linkTarget.c_str()) / *iter + : *iter / "\\"; // is_directory returns false for symlinks and reparse points, // which causes this function to fail if the target path contains @@ -598,10 +596,10 @@ bool assertPathExists(usvfs::RedirectionTreeContainer &table, LPCWSTR path) // this check could have a false positive if the path contains a // symlink to a file, but such a scenario is extremely unlikely. if (is_directory(targetPath) || is_symlink(targetPath) || - status(targetPath).type() == bfs::file_type::reparse_file) { - usvfs::RedirectionTree::NodePtrT newNode = table.addDirectory( - current->path() / *iter, targetPath.string().c_str(), - ush::FLAG_DUMMY, false); + status(targetPath).type() == bfs::file_type::reparse_file) { + usvfs::RedirectionTree::NodePtrT newNode = + table.addDirectory(current->path() / *iter, targetPath.string().c_str(), + ush::FLAG_DUMMY, false); current = newNode.get().get(); } else { spdlog::get("usvfs")->info("{} doesn't exist", targetPath.c_str()); @@ -641,7 +639,7 @@ static bool fileNameInSkipDirectories(const std::string& directoryNameUtf8, } BOOL WINAPI usvfsVirtualLinkFile(LPCWSTR source, LPCWSTR destination, - unsigned int flags) + unsigned int flags) { // TODO difference between winapi and ntdll api regarding system32 vs syswow64 // (and other windows links?) @@ -666,11 +664,11 @@ BOOL WINAPI usvfsVirtualLinkFile(LPCWSTR source, LPCWSTR destination, !(flags & LINKFLAG_FAILIFEXISTS)); if (shouldAddToInverseTree(sourceU8)) { - std::string destinationU8 - = ush::string_cast(destination, ush::CodePage::UTF8); + std::string destinationU8 = + ush::string_cast(destination, ush::CodePage::UTF8); - context->inverseTable().addFile( - bfs::path(source), usvfs::RedirectionDataLocal(destinationU8), true); + context->inverseTable().addFile(bfs::path(source), + usvfs::RedirectionDataLocal(destinationU8), true); } context->updateParameters(); @@ -684,7 +682,7 @@ BOOL WINAPI usvfsVirtualLinkFile(LPCWSTR source, LPCWSTR destination, } else { return TRUE; } - } catch (const std::exception &e) { + } catch (const std::exception& e) { spdlog::get("usvfs")->error("failed to copy file {}", e.what()); // TODO: no clue what's wrong SetLastError(ERROR_INVALID_DATA); @@ -704,12 +702,12 @@ static usvfs::shared::TreeFlags convertRedirectionFlags(unsigned int flags) return result; } -BOOL WINAPI usvfsVirtualLinkDirectoryStatic(LPCWSTR source, LPCWSTR destination, unsigned int flags) +BOOL WINAPI usvfsVirtualLinkDirectoryStatic(LPCWSTR source, LPCWSTR destination, + unsigned int flags) { // TODO change notification not yet implemented try { - if ((flags & LINKFLAG_FAILIFEXISTS) - && winapi::ex::wide::fileExists(destination)) { + if ((flags & LINKFLAG_FAILIFEXISTS) && winapi::ex::wide::fileExists(destination)) { SetLastError(ERROR_FILE_EXISTS); return FALSE; } @@ -719,13 +717,13 @@ BOOL WINAPI usvfsVirtualLinkDirectoryStatic(LPCWSTR source, LPCWSTR destination, return FALSE; } - std::string sourceU8 - = ush::string_cast(source, ush::CodePage::UTF8) + "\\"; + std::string sourceU8 = + ush::string_cast(source, ush::CodePage::UTF8) + "\\"; context->redirectionTable().addDirectory( - destination, usvfs::RedirectionDataLocal(sourceU8), - usvfs::shared::FLAG_DIRECTORY | convertRedirectionFlags(flags), - (flags & LINKFLAG_CREATETARGET) != 0); + destination, usvfs::RedirectionDataLocal(sourceU8), + usvfs::shared::FLAG_DIRECTORY | convertRedirectionFlags(flags), + (flags & LINKFLAG_CREATETARGET) != 0); const auto skipDirectories = context->skipDirectories(); const auto skipFileSuffixes = context->skipFileSuffixes(); @@ -748,7 +746,8 @@ BOOL WINAPI usvfsVirtualLinkDirectoryStatic(LPCWSTR source, LPCWSTR destination, if (fileNameInSkipDirectories(nameU8, skipDirectories)) { // Fail if we desire to fail when a dir/file is skipped if (flags & LINKFLAG_FAILIFSKIPPED) { - spdlog::get("usvfs")->debug("directory '{}' skipped, failing as defined by link flags", nameU8); + spdlog::get("usvfs")->debug( + "directory '{}' skipped, failing as defined by link flags", nameU8); return FALSE; } @@ -756,16 +755,19 @@ BOOL WINAPI usvfsVirtualLinkDirectoryStatic(LPCWSTR source, LPCWSTR destination, } usvfsVirtualLinkDirectoryStatic((sourceW + file.fileName).c_str(), - (destinationW + file.fileName).c_str(), flags); + (destinationW + file.fileName).c_str(), + flags); } } else { - const auto nameU8 = ush::string_cast(file.fileName.c_str(), ush::CodePage::UTF8); + const auto nameU8 = + ush::string_cast(file.fileName.c_str(), ush::CodePage::UTF8); // Check if the file should be skipped if (fileNameInSkipSuffixes(nameU8, skipFileSuffixes)) { // Fail if we desire to fail when a dir/file is skipped if (flags & LINKFLAG_FAILIFSKIPPED) { - spdlog::get("usvfs")->debug("file '{}' skipped, failing as defined by link flags", nameU8); + spdlog::get("usvfs")->debug( + "file '{}' skipped, failing as defined by link flags", nameU8); return FALSE; } @@ -779,9 +781,8 @@ BOOL WINAPI usvfsVirtualLinkDirectoryStatic(LPCWSTR source, LPCWSTR destination, usvfs::RedirectionDataLocal(sourceU8 + nameU8), true); if (shouldAddToInverseTree(nameU8)) { - std::string destinationU8 = ush::string_cast( - destination, ush::CodePage::UTF8) - + "\\"; + std::string destinationU8 = + ush::string_cast(destination, ush::CodePage::UTF8) + "\\"; context->inverseTable().addFile( bfs::path(source) / nameU8, @@ -794,7 +795,7 @@ BOOL WINAPI usvfsVirtualLinkDirectoryStatic(LPCWSTR source, LPCWSTR destination, context->updateParameters(); return TRUE; - } catch (const std::exception &e) { + } catch (const std::exception& e) { spdlog::get("usvfs")->error("failed to copy file {}", e.what()); // TODO: no clue what's wrong SetLastError(ERROR_INVALID_DATA); @@ -802,30 +803,25 @@ BOOL WINAPI usvfsVirtualLinkDirectoryStatic(LPCWSTR source, LPCWSTR destination, } } - -BOOL WINAPI usvfsCreateProcessHooked(LPCWSTR lpApplicationName - , LPWSTR lpCommandLine - , LPSECURITY_ATTRIBUTES lpProcessAttributes - , LPSECURITY_ATTRIBUTES lpThreadAttributes - , BOOL bInheritHandles - , DWORD dwCreationFlags - , LPVOID lpEnvironment - , LPCWSTR lpCurrentDirectory - , LPSTARTUPINFOW lpStartupInfo - , LPPROCESS_INFORMATION lpProcessInformation) +BOOL WINAPI usvfsCreateProcessHooked(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, DWORD dwCreationFlags, + LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation) { - BOOL susp = dwCreationFlags & CREATE_SUSPENDED; + BOOL susp = dwCreationFlags & CREATE_SUSPENDED; DWORD flags = dwCreationFlags | CREATE_SUSPENDED; BOOL blacklisted = context->executableBlacklisted(lpApplicationName, lpCommandLine); - BOOL res = CreateProcessW(lpApplicationName, lpCommandLine - , lpProcessAttributes, lpThreadAttributes - , bInheritHandles, flags - , lpEnvironment, lpCurrentDirectory - , lpStartupInfo, lpProcessInformation); + BOOL res = CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, + lpThreadAttributes, bInheritHandles, flags, lpEnvironment, + lpCurrentDirectory, lpStartupInfo, lpProcessInformation); if (!res) { - spdlog::get("usvfs")->error("failed to spawn {}", ush::string_cast(lpCommandLine)); + spdlog::get("usvfs")->error("failed to spawn {}", + ush::string_cast(lpCommandLine)); return FALSE; } @@ -835,7 +831,7 @@ BOOL WINAPI usvfsCreateProcessHooked(LPCWSTR lpApplicationName try { usvfs::injectProcess(p.parent_path().wstring(), context->callParameters(), *lpProcessInformation); - } catch (const std::exception &e) { + } catch (const std::exception& e) { spdlog::get("usvfs")->error("failed to inject: {}", e.what()); logExtInfo(e, LogLevel::Error); ::TerminateProcess(lpProcessInformation->hProcess, 1); @@ -851,8 +847,7 @@ BOOL WINAPI usvfsCreateProcessHooked(LPCWSTR lpApplicationName return TRUE; } - -BOOL WINAPI usvfsCreateVFSDump(LPSTR buffer, size_t *size) +BOOL WINAPI usvfsCreateVFSDump(LPSTR buffer, size_t* size) { assert(size != nullptr); std::ostringstream output; @@ -862,69 +857,61 @@ BOOL WINAPI usvfsCreateVFSDump(LPSTR buffer, size_t *size) strncpy_s(buffer, *size, str.c_str(), _TRUNCATE); } bool success = *size >= str.length(); - *size = str.length(); + *size = str.length(); return success ? TRUE : FALSE; } - VOID WINAPI usvfsBlacklistExecutable(LPCWSTR executableName) { context->blacklistExecutable(executableName); } - VOID WINAPI usvfsClearExecutableBlacklist() { context->clearExecutableBlacklist(); } - VOID WINAPI usvfsAddSkipFileSuffix(LPCWSTR fileSuffix) { context->addSkipFileSuffix(fileSuffix); } - VOID WINAPI usvfsClearSkipFileSuffixes() { context->clearSkipFileSuffixes(); } - VOID WINAPI usvfsAddSkipDirectory(LPCWSTR directory) { context->addSkipDirectory(directory); } - VOID WINAPI usvfsClearSkipDirectories() { context->clearSkipDirectories(); } - VOID WINAPI usvfsForceLoadLibrary(LPCWSTR processName, LPCWSTR libraryPath) { context->forceLoadLibrary(processName, libraryPath); } - VOID WINAPI usvfsClearLibraryForceLoads() { context->clearLibraryForceLoads(); } - VOID WINAPI usvfsPrintDebugInfo() { - spdlog::get("usvfs") - ->warn("===== debug {} =====", context->redirectionTable().shmName()); - void *buffer = nullptr; + spdlog::get("usvfs")->warn("===== debug {} =====", + context->redirectionTable().shmName()); + void* buffer = nullptr; size_t bufferSize = 0; context->redirectionTable().getBuffer(buffer, bufferSize); std::ostringstream temp; for (size_t i = 0; i < bufferSize; ++i) { - temp << std::hex << std::setfill('0') << std::setw(2) << (unsigned)reinterpret_cast(buffer)[i] << " "; + temp << std::hex << std::setfill('0') << std::setw(2) + << (unsigned)reinterpret_cast(buffer)[i] << " "; if ((i % 16) == 15) { spdlog::get("usvfs")->info("{}", temp.str()); temp.str(""); @@ -934,8 +921,8 @@ VOID WINAPI usvfsPrintDebugInfo() if (!temp.str().empty()) { spdlog::get("usvfs")->info("{}", temp.str()); } - spdlog::get("usvfs") - ->warn("===== / debug {} =====", context->redirectionTable().shmName()); + spdlog::get("usvfs")->warn("===== / debug {} =====", + context->redirectionTable().shmName()); } const char* WINAPI usvfsVersionString() @@ -947,22 +934,20 @@ const char* WINAPI usvfsVersionString() // DllMain // -BOOL APIENTRY DllMain(HMODULE module, - DWORD reasonForCall, - LPVOID) +BOOL APIENTRY DllMain(HMODULE module, DWORD reasonForCall, LPVOID) { switch (reasonForCall) { - case DLL_PROCESS_ATTACH: { - dllModule = module; - } break; - case DLL_PROCESS_DETACH: { - if (exceptionHandler) - ::RemoveVectoredExceptionHandler(exceptionHandler); - } break; - case DLL_THREAD_ATTACH: { - } break; - case DLL_THREAD_DETACH: { - } break; + case DLL_PROCESS_ATTACH: { + dllModule = module; + } break; + case DLL_PROCESS_DETACH: { + if (exceptionHandler) + ::RemoveVectoredExceptionHandler(exceptionHandler); + } break; + case DLL_THREAD_ATTACH: { + } break; + case DLL_THREAD_DETACH: { + } break; } return TRUE; diff --git a/src/usvfs_dll/usvfsparameters.cpp b/src/usvfs_dll/usvfsparameters.cpp index de8a996..7059ec2 100644 --- a/src/usvfs_dll/usvfsparameters.cpp +++ b/src/usvfs_dll/usvfsparameters.cpp @@ -1,9 +1,9 @@ #include "usvfsparametersprivate.h" #include -usvfsParameters::usvfsParameters() : - debugMode(false), logLevel(LogLevel::Debug), - crashDumpsType(CrashDumpsType::None), delayProcessMs(0) +usvfsParameters::usvfsParameters() + : debugMode(false), logLevel(LogLevel::Debug), crashDumpsType(CrashDumpsType::None), + delayProcessMs(0) { std::fill(std::begin(instanceName), std::end(instanceName), 0); std::fill(std::begin(currentSHMName), std::end(currentSHMName), 0); @@ -11,39 +11,28 @@ usvfsParameters::usvfsParameters() : std::fill(std::begin(crashDumpsPath), std::end(crashDumpsPath), 0); } -usvfsParameters::usvfsParameters( - const char *instanceName, - const char *currentSHMName, - const char *currentInverseSHMName, - bool debugMode, - LogLevel logLevel, - CrashDumpsType crashDumpsType, - const char *crashDumpsPath, - int delayProcessMs) - : usvfsParameters() +usvfsParameters::usvfsParameters(const char* instanceName, const char* currentSHMName, + const char* currentInverseSHMName, bool debugMode, + LogLevel logLevel, CrashDumpsType crashDumpsType, + const char* crashDumpsPath, int delayProcessMs) + : usvfsParameters() { strncpy_s(this->instanceName, instanceName, _TRUNCATE); strncpy_s(this->currentSHMName, currentSHMName, _TRUNCATE); strncpy_s(this->currentInverseSHMName, currentInverseSHMName, _TRUNCATE); - this->debugMode = debugMode; - this->logLevel = logLevel; + this->debugMode = debugMode; + this->logLevel = logLevel; this->crashDumpsType = crashDumpsType; strncpy_s(this->crashDumpsPath, crashDumpsPath, _TRUNCATE); this->delayProcessMs = delayProcessMs; } -usvfsParameters::usvfsParameters(const USVFSParameters& oldParams) : - usvfsParameters( - oldParams.instanceName, - oldParams.currentSHMName, - oldParams.currentInverseSHMName, - oldParams.debugMode, - oldParams.logLevel, - oldParams.crashDumpsType, - oldParams.crashDumpsPath, - 0) -{ -} +usvfsParameters::usvfsParameters(const USVFSParameters& oldParams) + : usvfsParameters(oldParams.instanceName, oldParams.currentSHMName, + oldParams.currentInverseSHMName, oldParams.debugMode, + oldParams.logLevel, oldParams.crashDumpsType, + oldParams.crashDumpsPath, 0) +{} void usvfsParameters::setInstanceName(const char* name) { @@ -71,12 +60,12 @@ void usvfsParameters::setCrashDumpType(CrashDumpsType type) void usvfsParameters::setCrashDumpPath(const char* path) { if (path && *path && strlen(path) < _countof(crashDumpsPath)) { - memcpy(crashDumpsPath, path, strlen(path)+1); + memcpy(crashDumpsPath, path, strlen(path) + 1); } else { // crashDumpsPath invalid or overflow of USVFSParameters variable so disable // crash dumps: crashDumpsPath[0] = 0; - crashDumpsType = CrashDumpsType::None; + crashDumpsType = CrashDumpsType::None; } } @@ -85,14 +74,12 @@ void usvfsParameters::setProcessDelay(int milliseconds) delayProcessMs = milliseconds; } - extern "C" { -const char* usvfsLogLevelToString(LogLevel lv) -{ - switch (lv) + const char* usvfsLogLevelToString(LogLevel lv) { + switch (lv) { case LogLevel::Debug: return "debug"; @@ -107,13 +94,12 @@ const char* usvfsLogLevelToString(LogLevel lv) default: return "unknown"; + } } -} -const char* usvfsCrashDumpTypeToString(CrashDumpsType t) -{ - switch (t) + const char* usvfsCrashDumpTypeToString(CrashDumpsType t) { + switch (t) { case CrashDumpsType::None: return "none"; @@ -128,81 +114,80 @@ const char* usvfsCrashDumpTypeToString(CrashDumpsType t) default: return "unknown"; - } -} - - -usvfsParameters* usvfsCreateParameters() -{ - return new (std::nothrow) usvfsParameters; -} - -usvfsParameters* usvfsDupeParameters(usvfsParameters* p) -{ - if (!p) { - return nullptr; + } } - auto* dupe = usvfsCreateParameters(); - if (!dupe) { - return nullptr; + usvfsParameters* usvfsCreateParameters() + { + return new (std::nothrow) usvfsParameters; } - *dupe = *p; + usvfsParameters* usvfsDupeParameters(usvfsParameters* p) + { + if (!p) { + return nullptr; + } - return dupe; -} + auto* dupe = usvfsCreateParameters(); + if (!dupe) { + return nullptr; + } -void usvfsCopyParameters(const usvfsParameters* source, usvfsParameters* dest) -{ - *dest = *source; -} + *dupe = *p; -void usvfsFreeParameters(usvfsParameters* p) -{ - delete p; -} - -void usvfsSetInstanceName(usvfsParameters* p, const char* name) -{ - if (p) { - p->setInstanceName(name); + return dupe; } -} -void usvfsSetDebugMode(usvfsParameters* p, BOOL debugMode) -{ - if (p) { - p->setDebugMode(debugMode); + void usvfsCopyParameters(const usvfsParameters* source, usvfsParameters* dest) + { + *dest = *source; } -} -void usvfsSetLogLevel(usvfsParameters* p, LogLevel level) -{ - if (p) { - p->setLogLevel(level); + void usvfsFreeParameters(usvfsParameters* p) + { + delete p; } -} -void usvfsSetCrashDumpType(usvfsParameters* p, CrashDumpsType type) -{ - if (p) { - p->setCrashDumpType(type); + void usvfsSetInstanceName(usvfsParameters* p, const char* name) + { + if (p) { + p->setInstanceName(name); + } } -} -void usvfsSetCrashDumpPath(usvfsParameters* p, const char* path) -{ - if (p) { - p->setCrashDumpPath(path); + void usvfsSetDebugMode(usvfsParameters* p, BOOL debugMode) + { + if (p) { + p->setDebugMode(debugMode); + } } -} -void usvfsSetProcessDelay(usvfsParameters* p, int milliseconds) -{ - if (p) { - p->setProcessDelay(milliseconds); + void usvfsSetLogLevel(usvfsParameters* p, LogLevel level) + { + if (p) { + p->setLogLevel(level); + } } -} -} // extern "C" + void usvfsSetCrashDumpType(usvfsParameters* p, CrashDumpsType type) + { + if (p) { + p->setCrashDumpType(type); + } + } + + void usvfsSetCrashDumpPath(usvfsParameters* p, const char* path) + { + if (p) { + p->setCrashDumpPath(path); + } + } + + void usvfsSetProcessDelay(usvfsParameters* p, int milliseconds) + { + if (p) { + p->setProcessDelay(milliseconds); + } + } + +} // extern "C" diff --git a/src/usvfs_helper/inject.cpp b/src/usvfs_helper/inject.cpp index fd6f414..bb1cb58 100644 --- a/src/usvfs_helper/inject.cpp +++ b/src/usvfs_helper/inject.cpp @@ -25,34 +25,33 @@ along with usvfs. If not, see . #include -#include #include "inject.h" +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include namespace ush = usvfs::shared; using namespace winapi; -void usvfs::injectProcess(const std::wstring &applicationPath - , const usvfsParameters ¶meters - , const PROCESS_INFORMATION &processInfo) +void usvfs::injectProcess(const std::wstring& applicationPath, + const usvfsParameters& parameters, + const PROCESS_INFORMATION& processInfo) { injectProcess(applicationPath, parameters, processInfo.hProcess, processInfo.hThread); } -void usvfs::injectProcess(const std::wstring &applicationPath - , const usvfsParameters ¶meters - , HANDLE processHandle - , HANDLE threadHandle) +void usvfs::injectProcess(const std::wstring& applicationPath, + const usvfsParameters& parameters, HANDLE processHandle, + HANDLE threadHandle) { - bool proc64 = false; + bool proc64 = false; bool sameBitness = false; { SYSTEM_INFO info; @@ -60,7 +59,8 @@ void usvfs::injectProcess(const std::wstring &applicationPath BOOL wow64; IsWow64Process(processHandle, &wow64); if (wow64) { - // process is running under wow64 so it has to be a 32bit process running on 64bit windows + // process is running under wow64 so it has to be a 32bit process running on 64bit + // windows proc64 = false; BOOL temp; IsWow64Process(GetCurrentProcess(), &temp); @@ -69,7 +69,8 @@ void usvfs::injectProcess(const std::wstring &applicationPath BOOL selfWow64; IsWow64Process(GetCurrentProcess(), &selfWow64); if (selfWow64) { - // WE are a 32 bit process running on 64bit windows. the other process isn't, so its 64bit + // WE are a 32 bit process running on 64bit windows. the other process isn't, so + // its 64bit proc64 = true; } else { sameBitness = true; @@ -84,70 +85,76 @@ void usvfs::injectProcess(const std::wstring &applicationPath } boost::filesystem::path binPath = boost::filesystem::path(applicationPath); spdlog::get("usvfs")->info("injecting to process {} with {} bitness", - ::GetProcessId(processHandle), sameBitness ? "same" : "different"); + ::GetProcessId(processHandle), + sameBitness ? "same" : "different"); if (sameBitness) { static constexpr auto USVFS_DLL = #ifdef _WIN64 - L"usvfs_x64.dll"; + L"usvfs_x64.dll"; #else - L"usvfs_x86.dll"; + L"usvfs_x86.dll"; #endif - const auto& preferedDll = binPath / USVFS_DLL; + const auto& preferedDll = binPath / USVFS_DLL; boost::filesystem::path dllPath = preferedDll; - bool dllFound = boost::filesystem::exists(dllPath); + bool dllFound = boost::filesystem::exists(dllPath); // support for runing tests using a usvfs dll in lib folder (and proxy under bin): if (!dllFound && binPath.filename() == L"bin") { - dllPath = binPath.parent_path() / L"lib" / USVFS_DLL; + dllPath = binPath.parent_path() / L"lib" / USVFS_DLL; dllFound = boost::filesystem::exists(dllPath); } if (!dllFound) { USVFS_THROW_EXCEPTION( file_not_found_error() - << ex_msg(std::string("dll missing: ") - + ush::string_cast(preferedDll.wstring()).c_str())); + << ex_msg(std::string("dll missing: ") + + ush::string_cast(preferedDll.wstring()).c_str())); } spdlog::get("usvfs")->info("dll path: {}", dllPath.wstring()); - InjectLib::InjectDLL(processHandle, threadHandle, dllPath.c_str(), - "InitHooks", ¶meters, sizeof(parameters)); + InjectLib::InjectDLL(processHandle, threadHandle, dllPath.c_str(), "InitHooks", + ¶meters, sizeof(parameters)); - spdlog::get("usvfs")->info("injection to same bitness process {} successful", ::GetProcessId(processHandle)); + spdlog::get("usvfs")->info("injection to same bitness process {} successful", + ::GetProcessId(processHandle)); } else { // first try platform specific proxy exe: static constexpr auto USVFS_PREFERED_EXE = #ifdef _WIN64 - L"usvfs_proxy_x86.exe"; + L"usvfs_proxy_x86.exe"; #else - L"usvfs_proxy_x64.exe"; + L"usvfs_proxy_x64.exe"; #endif - const auto& preferedExe = binPath / USVFS_PREFERED_EXE; + const auto& preferedExe = binPath / USVFS_PREFERED_EXE; boost::filesystem::path exePath = preferedExe; - bool exeFound = boost::filesystem::exists(exePath); + bool exeFound = boost::filesystem::exists(exePath); // support for runing tests using a usvfs dll in lib folder (and proxy under bin): if (!exeFound && binPath.filename() == L"lib") { - exePath = binPath.parent_path() / L"bin" / USVFS_PREFERED_EXE; + exePath = binPath.parent_path() / L"bin" / USVFS_PREFERED_EXE; exeFound = boost::filesystem::exists(exePath); } - // finally fallback to old proxy naming (but only for 64bit as we don't have a 64bit proxy in this case): + // finally fallback to old proxy naming (but only for 64bit as we don't have a 64bit + // proxy in this case): #ifdef _WIN64 if (!exeFound) { - exePath = binPath / L"usvfs_proxy.exe"; + exePath = binPath / L"usvfs_proxy.exe"; exeFound = boost::filesystem::exists(exePath); } #endif if (!exeFound) { USVFS_THROW_EXCEPTION(file_not_found_error() << ex_msg( - std::string("usvfs proxy not found: ") - + ush::string_cast(preferedExe.wstring()))); - } - else - spdlog::get("usvfs")->info("using usvfs proxy: {}", ush::string_cast(preferedExe.wstring())); + std::string("usvfs proxy not found: ") + + ush::string_cast(preferedExe.wstring()))); + } else + spdlog::get("usvfs")->info("using usvfs proxy: {}", + ush::string_cast(preferedExe.wstring())); // need to use proxy aplication to inject - auto proxyProcess = std::move(wide::createProcess(exePath.wstring()) - .arg(L"--instance").arg(ush::string_cast(parameters.instanceName)) - .arg(L"--pid").arg(GetProcessId(processHandle))); + auto proxyProcess = + std::move(wide::createProcess(exePath.wstring()) + .arg(L"--instance") + .arg(ush::string_cast(parameters.instanceName)) + .arg(L"--pid") + .arg(GetProcessId(processHandle))); if (threadHandle != INVALID_HANDLE_VALUE) { proxyProcess.arg("--tid").arg(GetThreadId(threadHandle)); @@ -155,29 +162,31 @@ void usvfs::injectProcess(const std::wstring &applicationPath process::Result result = proxyProcess(); if (!result.valid) { USVFS_THROW_EXCEPTION(unknown_error() - << ex_msg(std::string("failed to start proxy ") - + ush::string_cast(exePath.wstring())) + << ex_msg(std::string("failed to start proxy ") + + ush::string_cast(exePath.wstring())) << ex_win_errcode(result.errorCode)); } else { - // wait for proxy completion. this shouldn't take long, 15 seconds is very generous + // wait for proxy completion. this shouldn't take long, 15 seconds is very + // generous switch (WaitForSingleObject(result.processInfo.hProcess, 15000)) { - case WAIT_TIMEOUT: { - spdlog::get("usvfs")->debug("proxy timeout"); - TerminateProcess(result.processInfo.hProcess, 1); - USVFS_THROW_EXCEPTION(timeout_error() - << ex_msg(std::string("proxy didn't complete in time"))); - } break; - case WAIT_FAILED: { - spdlog::get("usvfs")->debug("proxy wait failed"); - TerminateProcess(result.processInfo.hProcess, 1); - USVFS_THROW_EXCEPTION(unknown_error() - << ex_msg(std::string("failed to wait for proxy completion")) - << ex_win_errcode(result.errorCode)); - } break; - default: { - spdlog::get("usvfs")->debug("proxy run successful"); - // nop - } break; + case WAIT_TIMEOUT: { + spdlog::get("usvfs")->debug("proxy timeout"); + TerminateProcess(result.processInfo.hProcess, 1); + USVFS_THROW_EXCEPTION(timeout_error() + << ex_msg(std::string("proxy didn't complete in time"))); + } break; + case WAIT_FAILED: { + spdlog::get("usvfs")->debug("proxy wait failed"); + TerminateProcess(result.processInfo.hProcess, 1); + USVFS_THROW_EXCEPTION(unknown_error() + << ex_msg( + std::string("failed to wait for proxy completion")) + << ex_win_errcode(result.errorCode)); + } break; + default: { + spdlog::get("usvfs")->debug("proxy run successful"); + // nop + } break; } } } diff --git a/src/usvfs_helper/inject.h b/src/usvfs_helper/inject.h index cfec39a..10f179f 100644 --- a/src/usvfs_helper/inject.h +++ b/src/usvfs_helper/inject.h @@ -21,10 +21,11 @@ along with usvfs. If not, see . #pragma once #include "usvfsparameters.h" -#include #include +#include -namespace usvfs { +namespace usvfs +{ /** * @brief inject usvfs to a process @@ -32,20 +33,19 @@ namespace usvfs { * @param parameters * @param processInfo */ -void injectProcess(const std::wstring &applicationPath - , const usvfsParameters ¶meters - , const PROCESS_INFORMATION &processInfo); +void injectProcess(const std::wstring& applicationPath, + const usvfsParameters& parameters, + const PROCESS_INFORMATION& processInfo); /** * @brief inject usvfs to a process * @param applicationPath path to usvfs * @param parameters * @param process process handle to inject to - * @param thread main thread inside that process. This can be set to INVALID_HANDLE_VALUE in which case - * a new thread is created in the process + * @param thread main thread inside that process. This can be set to + * INVALID_HANDLE_VALUE in which case a new thread is created in the process */ -void injectProcess(const std::wstring &applicationPath - , const usvfsParameters ¶meters - , HANDLE process, HANDLE thread); +void injectProcess(const std::wstring& applicationPath, + const usvfsParameters& parameters, HANDLE process, HANDLE thread); -} +} // namespace usvfs diff --git a/src/usvfs_proxy/main.cpp b/src/usvfs_proxy/main.cpp index 40ef557..88d4696 100644 --- a/src/usvfs_proxy/main.cpp +++ b/src/usvfs_proxy/main.cpp @@ -20,33 +20,31 @@ along with usvfs. If not, see . */ #include "pch.h" -#include -#include -#include -#include #include <../usvfs_dll/hookcontext.h> -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include - -namespace bi = boost::interprocess; +namespace bi = boost::interprocess; namespace bfs = boost::filesystem; -using usvfs::shared::SharedMemoryT; using usvfs::SharedParameters; - +using usvfs::shared::SharedMemoryT; template -T getParameter(std::vector &arguments, const std::string &key, bool consume) +T getParameter(std::vector& arguments, const std::string& key, + bool consume) { auto iter = std::find(arguments.begin(), arguments.end(), std::string("--") + key); - if ((iter != arguments.end()) - && ((iter + 1) != arguments.end())) { + if ((iter != arguments.end()) && ((iter + 1) != arguments.end())) { T result = boost::lexical_cast(*(iter + 1)); if (consume) { arguments.erase(iter, iter + 2); @@ -58,11 +56,11 @@ T getParameter(std::vector &arguments, const std::string &key, bool } template -T getParameter(std::vector &arguments, const std::string &key, const T &def, bool consume) +T getParameter(std::vector& arguments, const std::string& key, + const T& def, bool consume) { auto iter = std::find(arguments.begin(), arguments.end(), std::string("--") + key); - if ((iter != arguments.end()) - && ((iter + 1) != arguments.end())) { + if ((iter != arguments.end()) && ((iter + 1) != arguments.end())) { T result = boost::lexical_cast(*(iter + 1)); if (consume) { arguments.erase(iter, iter + 2); @@ -73,7 +71,8 @@ T getParameter(std::vector &arguments, const std::string &key, cons } } -static void exceptionDialog(int line, int num, ...) { +static void exceptionDialog(int line, int num, ...) +{ va_list args; va_start(args, num); @@ -82,9 +81,9 @@ static void exceptionDialog(int line, int num, ...) { wstr.append(L"Unhandled USVFS proxy exception (line "); wsprintf(buf, L"%d): ", line); wstr.append(buf); - for (int i = 0; i < num; i++ ) { - wsprintf(buf, L"%S", va_arg(args, const char *)); - if (i < num-1) + for (int i = 0; i < num; i++) { + wsprintf(buf, L"%S", va_arg(args, const char*)); + if (i < num - 1) wsprintf(buf, L", "); wstr.append(buf); } @@ -94,7 +93,8 @@ static void exceptionDialog(int line, int num, ...) { va_end(args); } -int main(int argc, char **argv) { +int main(int argc, char** argv) +{ std::shared_ptr logger; std::vector arguments; @@ -107,17 +107,17 @@ int main(int argc, char **argv) { logger->set_pattern("%H:%M:%S.%e [%L] (proxy) %v"); instance = getParameter(arguments, "instance", true); - } catch (const std::exception &e) { + } catch (const std::exception& e) { if (logger.get() == nullptr) { exceptionDialog(__LINE__, 1, e.what()); return 1; } try { logger->critical("{}", e.what()); - } catch (const spdlog::spdlog_ex &e2) { + } catch (const spdlog::spdlog_ex& e2) { exceptionDialog(__LINE__, 2, e.what(), e2.what()); // no way to log this - } catch (const std::exception &) { + } catch (const std::exception&) { logger->critical(e.what()); } return 1; @@ -146,7 +146,7 @@ int main(int argc, char **argv) { logger->info("size: {}", configurationSHM.get_size()); logger->info("addr: {0:p}", configurationSHM.get_address()); logger->info("objs: {}", configurationSHM.get_num_named_objects()); - std::pair params = + std::pair params = configurationSHM.find("parameters"); if (params.first == nullptr) { logger->error("failed to open shared configuration for {}", instance); @@ -157,7 +157,7 @@ int main(int argc, char **argv) { if (executable.empty()) { HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); - HANDLE threadHandle = INVALID_HANDLE_VALUE; + HANDLE threadHandle = INVALID_HANDLE_VALUE; if (tid != 0) { threadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, tid); } @@ -165,7 +165,8 @@ int main(int argc, char **argv) { BOOL blacklisted = FALSE; TCHAR szModName[MAX_PATH]; - if (GetModuleFileNameEx(processHandle, NULL, szModName, sizeof(szModName) / sizeof(TCHAR))) { + if (GetModuleFileNameEx(processHandle, NULL, szModName, + sizeof(szModName) / sizeof(TCHAR))) { const auto appName = usvfs::shared::string_cast(szModName); if (params.first->executableBlacklisted(appName, {})) { @@ -175,9 +176,8 @@ int main(int argc, char **argv) { } if (!blacklisted) { - usvfs::injectProcess( - p.parent_path().wstring(), params.first->makeLocal(), - processHandle, threadHandle); + usvfs::injectProcess(p.parent_path().wstring(), params.first->makeLocal(), + processHandle, threadHandle); } } else { winapi::process::Result process = @@ -193,30 +193,28 @@ int main(int argc, char **argv) { BOOL blacklisted = FALSE; if (params.first->executableBlacklisted(executable, {})) { - logger->info( - "not injecting {} as application is blacklisted", executable); + logger->info("not injecting {} as application is blacklisted", executable); blacklisted = TRUE; } if (!blacklisted) { - usvfs::injectProcess( - p.parent_path().wstring(), params.first->makeLocal(), - process.processInfo); + usvfs::injectProcess(p.parent_path().wstring(), params.first->makeLocal(), + process.processInfo); } ResumeThread(process.processInfo.hThread); } return 0; - } catch (const std::exception &e) { + } catch (const std::exception& e) { try { logger->critical("unhandled exception: {}", e.what()); logExtInfo(e); - } catch (const spdlog::spdlog_ex &e2) { + } catch (const spdlog::spdlog_ex& e2) { // no way to log this exceptionDialog(__LINE__, 2, e.what(), e2.what()); - } catch (const std::exception &) { + } catch (const std::exception&) { logger->critical(e.what()); } } diff --git a/test/fixtures/usvfs_test/basic/source.postmortem/root1.txt b/test/fixtures/usvfs_test/basic/source.postmortem/root1.txt index 2181765..5aa129b 100644 --- a/test/fixtures/usvfs_test/basic/source.postmortem/root1.txt +++ b/test/fixtures/usvfs_test/basic/source.postmortem/root1.txt @@ -1 +1 @@ -root1 source file \ No newline at end of file +root1 source file diff --git a/test/fixtures/usvfs_test/basic/source.postmortem/root1w.txt b/test/fixtures/usvfs_test/basic/source.postmortem/root1w.txt index 779d147..0c04aa5 100644 --- a/test/fixtures/usvfs_test/basic/source.postmortem/root1w.txt +++ b/test/fixtures/usvfs_test/basic/source.postmortem/root1w.txt @@ -1 +1 @@ -root1w source file \ No newline at end of file +root1w source file diff --git a/test/fixtures/usvfs_test/basic/source.postmortem/root2.txt b/test/fixtures/usvfs_test/basic/source.postmortem/root2.txt index 75ada99..4ac40bb 100644 --- a/test/fixtures/usvfs_test/basic/source.postmortem/root2.txt +++ b/test/fixtures/usvfs_test/basic/source.postmortem/root2.txt @@ -1 +1 @@ -root2 source file \ No newline at end of file +root2 source file diff --git a/test/fixtures/usvfs_test/basic/source.postmortem/root2w.txt b/test/fixtures/usvfs_test/basic/source.postmortem/root2w.txt index 6679bd4..83ddb42 100644 --- a/test/fixtures/usvfs_test/basic/source.postmortem/root2w.txt +++ b/test/fixtures/usvfs_test/basic/source.postmortem/root2w.txt @@ -1 +1 @@ -root2w source file \ No newline at end of file +root2w source file diff --git a/test/fixtures/usvfs_test/basic/source/root1.txt b/test/fixtures/usvfs_test/basic/source/root1.txt index 2181765..5aa129b 100644 --- a/test/fixtures/usvfs_test/basic/source/root1.txt +++ b/test/fixtures/usvfs_test/basic/source/root1.txt @@ -1 +1 @@ -root1 source file \ No newline at end of file +root1 source file diff --git a/test/fixtures/usvfs_test/basic/source/root1w.txt b/test/fixtures/usvfs_test/basic/source/root1w.txt index 779d147..0c04aa5 100644 --- a/test/fixtures/usvfs_test/basic/source/root1w.txt +++ b/test/fixtures/usvfs_test/basic/source/root1w.txt @@ -1 +1 @@ -root1w source file \ No newline at end of file +root1w source file diff --git a/test/fixtures/usvfs_test/basic/source/root2.txt b/test/fixtures/usvfs_test/basic/source/root2.txt index 75ada99..4ac40bb 100644 --- a/test/fixtures/usvfs_test/basic/source/root2.txt +++ b/test/fixtures/usvfs_test/basic/source/root2.txt @@ -1 +1 @@ -root2 source file \ No newline at end of file +root2 source file diff --git a/test/fixtures/usvfs_test/basic/source/root2w.txt b/test/fixtures/usvfs_test/basic/source/root2w.txt index 6679bd4..83ddb42 100644 --- a/test/fixtures/usvfs_test/basic/source/root2w.txt +++ b/test/fixtures/usvfs_test/basic/source/root2w.txt @@ -1 +1 @@ -root2w source file \ No newline at end of file +root2w source file diff --git a/test/gtest_utils/gtest_utils.cpp b/test/gtest_utils/gtest_utils.cpp index 28fd3a9..f292dfd 100644 --- a/test/gtest_utils/gtest_utils.cpp +++ b/test/gtest_utils/gtest_utils.cpp @@ -119,4 +119,4 @@ std::optional read_content(const std::filesystem::path& path, } return ::testing::AssertionSuccess(); -} \ No newline at end of file +} diff --git a/test/gtest_utils/gtest_utils.h b/test/gtest_utils/gtest_utils.h index 5837ca6..1dba70c 100644 --- a/test/gtest_utils/gtest_utils.h +++ b/test/gtest_utils/gtest_utils.h @@ -26,4 +26,4 @@ // or lines in file) // #define ASSERT_CONTENT_EQ(Expected, Path) \ - ASSERT_TRUE(AssertContentEquals(Expected, Path)) \ No newline at end of file + ASSERT_TRUE(AssertContentEquals(Expected, Path)) diff --git a/test/shared_test/main.cpp b/test/shared_test/main.cpp index 5563435..c6b5be6 100644 --- a/test/shared_test/main.cpp +++ b/test/shared_test/main.cpp @@ -1,11 +1,11 @@ +#include +#include +#include #include +#include +#include #include #include -#include -#include -#include -#include -#include #define PRIVATE public #include @@ -17,44 +17,48 @@ using namespace usvfs::shared; using namespace boost::interprocess; - static const char g_SHMName[] = "treetest_shm"; -static const char TreeName[] = "treetest_tree"; +static const char TreeName[] = "treetest_tree"; typedef DirectoryTree TreeType; typedef TreeContainer ContainerType; -typedef boost::container::scoped_allocator_adaptor> VoidAllocator; +typedef boost::container::scoped_allocator_adaptor< + boost::interprocess::allocator> + VoidAllocator; typedef VoidAllocator::rebind::other CharAllocator; typedef basic_string, CharAllocator> SHMString; typedef DirectoryTree ComplexTreeType; typedef TreeContainer ComplexContainerType; - - -template<> -struct usvfs::shared::SHMDataCreator { - static int create(int source, const VoidAllocatorT&) { - return source; - } +template <> +struct usvfs::shared::SHMDataCreator +{ + static int create(int source, const VoidAllocatorT&) { return source; } }; -template <> inline int usvfs::shared::createDataEmpty(const typename VoidAllocatorT&) +template <> +inline int usvfs::shared::createDataEmpty(const typename VoidAllocatorT&) { return 0; } -template <> inline void usvfs::shared::dataAssign(int &destination, const int &source) +template <> +inline void usvfs::shared::dataAssign(int& destination, const int& source) { destination = source; } -template <> inline SHMString usvfs::shared::createDataEmpty(const typename VoidAllocatorT &allocator) +template <> +inline SHMString +usvfs::shared::createDataEmpty(const typename VoidAllocatorT& allocator) { return SHMString("", allocator); } -template <> inline void usvfs::shared::dataAssign(SHMString &destination, const SHMString &source) +template <> +inline void usvfs::shared::dataAssign(SHMString& destination, + const SHMString& source) { destination.assign(source.c_str()); } @@ -108,15 +112,18 @@ TEST(DirectoryTreeTest, FindNode) EXPECT_EQ(nullptr, tree->findNode(R"(C:\temp\bla\blubb)").get()); } -struct TestVisitor { +struct TestVisitor +{ TreeType::NodePtrT lastNode; - bool flag40 { false }; + bool flag40{false}; - void operator()(const TreeType::NodePtrT &node) { + void operator()(const TreeType::NodePtrT& node) + { lastNode = node; - flag40 = node->hasFlag(0x40); + flag40 = node->hasFlag(0x40); logger()->debug("{0} - {1}", lastNode->name(), flag40); - //BOOST_LOG_SEV(globalLogger::get(), LogLevel::Debug) << lastNode->name() << " - " << flag40; + // BOOST_LOG_SEV(globalLogger::get(), LogLevel::Debug) << lastNode->name() << " - " + // << flag40; } }; @@ -129,7 +136,9 @@ TEST(DirectoryTreeTest, VisitPath) TestVisitor visitor; tree->visitPath(R"(C:\temp\bla\blubb)", - TreeType::VisitorFunction([&](const TreeType::NodePtrT &node) { visitor(node); })); + TreeType::VisitorFunction([&](const TreeType::NodePtrT& node) { + visitor(node); + })); EXPECT_TRUE(visitor.flag40); EXPECT_EQ("bla", visitor.lastNode->name()); } @@ -149,7 +158,7 @@ TEST(DirectoryTreeTest, WildCardFind) EXPECT_NE(nullptr, tree->node("C:")); EXPECT_EQ(1, tree->node("C:")->find("*").size()); EXPECT_NE(nullptr, tree->node("C:")->node("temp")); - EXPECT_EQ(3, tree->node("C:")->node("temp")->find("*").size()); // alternative + EXPECT_EQ(3, tree->node("C:")->node("temp")->find("*").size()); // alternative // search on the top-level EXPECT_EQ(1, tree->find("*").size()); // * should work @@ -166,17 +175,17 @@ TEST(DirectoryTreeTest, SHMAllocation) EXPECT_NO_THROW({ ContainerType create(g_SHMName, 64 * 1024); - { // creation + { // creation create.addFile(R"(C:\temp\abc)", 1, false); create.addFile(R"(C:\temp\abd)", 2, false); create.addFile(R"(C:\temp\ace)", 3, false); } - { // access + { // access ContainerType access(g_SHMName, 64 * 1024); EXPECT_NE(nullptr, access.get()); std::vector res = access->find(R"(C:\temp\*)"); - EXPECT_EQ(3, res.size()); // matches the three files + EXPECT_EQ(3, res.size()); // matches the three files EXPECT_EQ(access->m_Self.lock().get(), access->node("C:")->parent().get()); } }); @@ -197,9 +206,9 @@ TEST(DirectoryTreeTest, SHMAllocationError) EXPECT_EQ(1, tree->node("C:")->node("temp")->node("aa", MissingThrow)->data()); EXPECT_EQ(26, tree->node("C:")->node("temp")->node("az", MissingThrow)->data()); - } catch (const std::exception &e) { + } catch (const std::exception& e) { logger()->error("{0}", e.what()); - //BOOST_LOG_SEV(globalLogger::get(), LogLevel::Error) << e.what(); + // BOOST_LOG_SEV(globalLogger::get(), LogLevel::Error) << e.what(); throw; } }); @@ -217,16 +226,21 @@ TEST(DirectoryTreeTest, SHMAllocationErrorComplex) tree.addFile(name, str, false); } } - EXPECT_STREQ(str.c_str(), tree->node("C:")->node("temp")->node("aa", MissingThrow)->data().c_str()); - EXPECT_STREQ(str.c_str(), tree->node("C:")->node("temp")->node("az", MissingThrow)->data().c_str()); - } catch (const std::exception &e) { + EXPECT_STREQ( + str.c_str(), + tree->node("C:")->node("temp")->node("aa", MissingThrow)->data().c_str()); + EXPECT_STREQ( + str.c_str(), + tree->node("C:")->node("temp")->node("az", MissingThrow)->data().c_str()); + } catch (const std::exception& e) { logger()->error("{}", e.what()); throw; } }); } -int main(int argc, char **argv) { +int main(int argc, char** argv) +{ auto logger = spdlog::stdout_logger_mt("usvfs"); logger->set_level(spdlog::level::warn); testing::InitGoogleTest(&argc, argv); diff --git a/test/test_utils/test_helpers.cpp b/test/test_utils/test_helpers.cpp index bcf762f..2daf3bb 100644 --- a/test/test_utils/test_helpers.cpp +++ b/test/test_utils/test_helpers.cpp @@ -5,234 +5,244 @@ #include "test_helpers.h" #include "winapi.h" -namespace test { +namespace test +{ - std::string FuncFailed::msg(std::string_view func, const char* arg1, const unsigned long* res, const char* what) - { - std::string buffer; - buffer.reserve(128); +std::string FuncFailed::msg(std::string_view func, const char* arg1, + const unsigned long* res, const char* what) +{ + std::string buffer; + buffer.reserve(128); - std::format_to(std::back_inserter(buffer), "{}() {}", func, what ? what : "failed"); - const char* sep = " : "; - if (arg1) { - std::format_to(std::back_inserter(buffer), "{}{}", sep, arg1); - sep = ", "; - } - if (res) { - std::format_to(std::back_inserter(buffer), "{}result = {} ({:#x})", sep, *res, *res); - } - return buffer; + std::format_to(std::back_inserter(buffer), "{}() {}", func, what ? what : "failed"); + const char* sep = " : "; + if (arg1) { + std::format_to(std::back_inserter(buffer), "{}{}", sep, arg1); + sep = ", "; } - - - ScopedFILE ScopedFILE::open(const std::filesystem::path& filepath, std::wstring_view mode, errno_t& err) { - FILE* fp = nullptr; - err = _wfopen_s(&fp, filepath.c_str(), mode.data()); - if (err || !fp) { - return ScopedFILE(); - } - return ScopedFILE(fp); + if (res) { + std::format_to(std::back_inserter(buffer), "{}result = {} ({:#x})", sep, *res, + *res); } + return buffer; +} - ScopedFILE ScopedFILE::open(const std::filesystem::path& filepath, std::wstring_view mode) { - errno_t err; - auto file = open(filepath, mode, err); - if (err || !file) { - throw_testWinFuncFailed("_wfopen_s", filepath.string().c_str(), err); - } - return file; +ScopedFILE ScopedFILE::open(const std::filesystem::path& filepath, + std::wstring_view mode, errno_t& err) +{ + FILE* fp = nullptr; + err = _wfopen_s(&fp, filepath.c_str(), mode.data()); + if (err || !fp) { + return ScopedFILE(); } + return ScopedFILE(fp); +} - path path_of_test_bin(const path& relative) { - path base(winapi::wide::getModuleFileName(nullptr)); - return relative.empty() ? base.parent_path() : base.parent_path() / relative; +ScopedFILE ScopedFILE::open(const std::filesystem::path& filepath, + std::wstring_view mode) +{ + errno_t err; + auto file = open(filepath, mode, err); + if (err || !file) { + throw_testWinFuncFailed("_wfopen_s", filepath.string().c_str(), err); } + return file; +} - path path_of_test_temp(const path& relative) { - return path_of_test_bin().parent_path() / "temp" / relative; - } +path path_of_test_bin(const path& relative) +{ + path base(winapi::wide::getModuleFileName(nullptr)); + return relative.empty() ? base.parent_path() : base.parent_path() / relative; +} - path path_of_test_fixtures(const path& relative) { - return path_of_test_bin().parent_path() / "fixtures" / relative; - } +path path_of_test_temp(const path& relative) +{ + return path_of_test_bin().parent_path() / "temp" / relative; +} - path path_of_usvfs_lib(const path& relative) { - return path_of_test_bin().parent_path().parent_path() / "lib" / relative; - } +path path_of_test_fixtures(const path& relative) +{ + return path_of_test_bin().parent_path() / "fixtures" / relative; +} - std::string platform_dependant_executable(const char* name, const char* ext, const char* platform) - { - std::string res = name; - res += "_"; - if (platform) - res += platform; - else +path path_of_usvfs_lib(const path& relative) +{ + return path_of_test_bin().parent_path().parent_path() / "lib" / relative; +} + +std::string platform_dependant_executable(const char* name, const char* ext, + const char* platform) +{ + std::string res = name; + res += "_"; + if (platform) + res += platform; + else #if _WIN64 - res += "x64"; + res += "x64"; #else - res += "x86"; + res += "x86"; #endif - res += "."; - res += ext; - return res; + res += "."; + res += ext; + return res; +} + +path path_as_relative(const path& base, const path& full_path) +{ + auto rel_begin = full_path.begin(); + auto base_iter = base.begin(); + while (rel_begin != full_path.end() && base_iter != base.end() && + *rel_begin == *base_iter) { + ++rel_begin; + ++base_iter; } - path path_as_relative(const path& base, const path& full_path) - { - auto rel_begin = full_path.begin(); - auto base_iter = base.begin(); - while (rel_begin != full_path.end() && base_iter != base.end() && *rel_begin == *base_iter) { - ++rel_begin; - ++base_iter; - } + if (base_iter != base.end()) // full_path is not a sub-folder of base + return full_path; - if (base_iter != base.end()) // full_path is not a sub-folder of base - return full_path; + if (rel_begin == full_path.end()) // full_path == base + return path(L"."); - if (rel_begin == full_path.end()) // full_path == base - return path(L"."); + // full_path is a sub-folder of base so take only relative path + path result; + for (; rel_begin != full_path.end(); ++rel_begin) + result /= *rel_begin; + return result; +} - // full_path is a sub-folder of base so take only relative path - path result; - for (; rel_begin != full_path.end(); ++rel_begin) - result /= *rel_begin; - return result; - } +std::vector read_small_file(const path& file, bool binary) +{ + using namespace std; + const auto f = ScopedFILE::open(file, binary ? L"rb" : L"rt"); - std::vector read_small_file(const path& file, bool binary) - { - using namespace std; + if (fseek(f, 0, SEEK_END)) + throw_testWinFuncFailed("fseek", (unsigned long)0); - const auto f = ScopedFILE::open(file, binary ? L"rb" : L"rt"); + long size = ftell(f); + if (size < 0) + throw_testWinFuncFailed("ftell", (unsigned long)size); + if (size > 0x10000000) // sanity check limit to 256M + throw test::FuncFailed("read_small_file", "file size too large", + (unsigned long)size); - if (fseek(f, 0, SEEK_END)) - throw_testWinFuncFailed("fseek", (unsigned long) 0); + if (fseek(f, 0, SEEK_SET)) + throw_testWinFuncFailed("fseek", (unsigned long)0); - long size = ftell(f); - if (size < 0) - throw_testWinFuncFailed("ftell", (unsigned long) size); - if (size > 0x10000000) // sanity check limit to 256M - throw test::FuncFailed("read_small_file", "file size too large", (unsigned long) size); + std::vector content(static_cast(size)); + content.resize(fread(content.data(), sizeof(char), content.size(), f)); - if (fseek(f, 0, SEEK_SET)) - throw_testWinFuncFailed("fseek", (unsigned long) 0); + return content; +} - std::vector content(static_cast(size)); - content.resize(fread(content.data(), sizeof(char), content.size(), f)); +bool compare_files(const path& file1, const path& file2, bool binary) +{ + // TODO: if this is ever used for big file should read files in chunks + return read_small_file(file1, binary) == read_small_file(file2, binary); +} - return content; - } +bool is_empty_folder(const path& dpath, bool or_doesnt_exist) +{ + bool isDir = false; + if (!winapi::ex::wide::fileExists(dpath.c_str(), &isDir)) + return or_doesnt_exist; - bool compare_files(const path& file1, const path& file2, bool binary) - { - // TODO: if this is ever used for big file should read files in chunks - return read_small_file(file1, binary) == read_small_file(file2, binary); - } + if (!isDir) + return false; - bool is_empty_folder(const path& dpath, bool or_doesnt_exist) - { - bool isDir = false; - if (!winapi::ex::wide::fileExists(dpath.c_str(), &isDir)) - return or_doesnt_exist; - - if (!isDir) + for (const auto& f : winapi::ex::wide::quickFindFiles(dpath.c_str(), L"*")) + if (f.fileName != L"." && f.fileName != L"..") return false; + return true; +} - for (const auto& f : winapi::ex::wide::quickFindFiles(dpath.c_str(), L"*")) - if (f.fileName != L"." && f.fileName != L"..") - return false; - return true; +void delete_file(const path& file) +{ + if (!DeleteFileW(file.c_str())) { + auto err = GetLastError(); + if (err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND) + throw_testWinFuncFailed("DeleteFile", file.string()); } +} - void delete_file(const path& file) - { - if (!DeleteFileW(file.c_str())) { - auto err = GetLastError(); - if (err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND) - throw_testWinFuncFailed("DeleteFile", file.string()); - } - } - - void recursive_delete_files(const path& dpath) - { - bool isDir = false; - if (!winapi::ex::wide::fileExists(dpath.c_str(), &isDir)) - return; - if (!isDir) - delete_file(dpath); - else { - // dpath exists and its a directory: - std::vector recurse; - for (const auto& f : winapi::ex::wide::quickFindFiles(dpath.c_str(), L"*")) - { - if (f.fileName == L"." || f.fileName == L"..") - continue; - if (f.attributes & FILE_ATTRIBUTE_DIRECTORY) - recurse.push_back(f.fileName); - else - delete_file(dpath / f.fileName); - } - for (auto r : recurse) - recursive_delete_files(dpath / r); - if (!RemoveDirectoryW(dpath.c_str())) - throw_testWinFuncFailed("RemoveDirectory", dpath.string().c_str()); - } - if (winapi::ex::wide::fileExists(dpath.c_str())) - throw FuncFailed("delete_directory_tree", dpath.string().c_str()); - } - - void recursive_copy_files(const path& src_path, const path& dest_path, bool overwrite) - { - bool srcIsDir = false, destIsDir = false; - if (!winapi::ex::wide::fileExists(src_path.c_str(), &srcIsDir)) - throw FuncFailed("recursive_copy", "source doesn't exist", src_path.string().c_str()); - if (!winapi::ex::wide::fileExists(dest_path.c_str(), &destIsDir) && srcIsDir) - { - winapi::ex::wide::createPath(dest_path.c_str()); - destIsDir = true; - } - - if (!srcIsDir) - if (!destIsDir) - { - if (!CopyFileW(src_path.c_str(), dest_path.c_str(), overwrite)) - throw_testWinFuncFailed("CopyFile", (src_path.string() + " => " + dest_path.string()).c_str()); - return; - } - else - throw FuncFailed("recursive_copy", "source is a file but destination is a directory", - (src_path.string() + ", " + dest_path.string()).c_str()); - - if (!destIsDir) - throw FuncFailed("recursive_copy", "source is a directory but destination is a file", - (src_path.string() + ", " + dest_path.string()).c_str()); - - // source and destination are both directories: +void recursive_delete_files(const path& dpath) +{ + bool isDir = false; + if (!winapi::ex::wide::fileExists(dpath.c_str(), &isDir)) + return; + if (!isDir) + delete_file(dpath); + else { + // dpath exists and its a directory: std::vector recurse; - for (const auto& f : winapi::ex::wide::quickFindFiles(src_path.c_str(), L"*")) - { + for (const auto& f : winapi::ex::wide::quickFindFiles(dpath.c_str(), L"*")) { if (f.fileName == L"." || f.fileName == L"..") continue; if (f.attributes & FILE_ATTRIBUTE_DIRECTORY) recurse.push_back(f.fileName); else - if (!CopyFileW((src_path / f.fileName).c_str(), (dest_path / f.fileName).c_str(), overwrite)) - throw_testWinFuncFailed("CopyFile", - ((src_path / f.fileName).string() + " => " + (dest_path / f.fileName).string())); + delete_file(dpath / f.fileName); } for (auto r : recurse) - recursive_copy_files(src_path / r, dest_path / r, overwrite); + recursive_delete_files(dpath / r); + if (!RemoveDirectoryW(dpath.c_str())) + throw_testWinFuncFailed("RemoveDirectory", dpath.string().c_str()); + } + if (winapi::ex::wide::fileExists(dpath.c_str())) + throw FuncFailed("delete_directory_tree", dpath.string().c_str()); +} + +void recursive_copy_files(const path& src_path, const path& dest_path, bool overwrite) +{ + bool srcIsDir = false, destIsDir = false; + if (!winapi::ex::wide::fileExists(src_path.c_str(), &srcIsDir)) + throw FuncFailed("recursive_copy", "source doesn't exist", + src_path.string().c_str()); + if (!winapi::ex::wide::fileExists(dest_path.c_str(), &destIsDir) && srcIsDir) { + winapi::ex::wide::createPath(dest_path.c_str()); + destIsDir = true; } - ScopedLoadLibrary::ScopedLoadLibrary(const wchar_t* dll_path) + if (!srcIsDir) + if (!destIsDir) { + if (!CopyFileW(src_path.c_str(), dest_path.c_str(), overwrite)) + throw_testWinFuncFailed( + "CopyFile", (src_path.string() + " => " + dest_path.string()).c_str()); + return; + } else + throw FuncFailed("recursive_copy", + "source is a file but destination is a directory", + (src_path.string() + ", " + dest_path.string()).c_str()); + + if (!destIsDir) + throw FuncFailed("recursive_copy", + "source is a directory but destination is a file", + (src_path.string() + ", " + dest_path.string()).c_str()); + + // source and destination are both directories: + std::vector recurse; + for (const auto& f : winapi::ex::wide::quickFindFiles(src_path.c_str(), L"*")) { + if (f.fileName == L"." || f.fileName == L"..") + continue; + if (f.attributes & FILE_ATTRIBUTE_DIRECTORY) + recurse.push_back(f.fileName); + else if (!CopyFileW((src_path / f.fileName).c_str(), + (dest_path / f.fileName).c_str(), overwrite)) + throw_testWinFuncFailed("CopyFile", ((src_path / f.fileName).string() + " => " + + (dest_path / f.fileName).string())); + } + for (auto r : recurse) + recursive_copy_files(src_path / r, dest_path / r, overwrite); +} + +ScopedLoadLibrary::ScopedLoadLibrary(const wchar_t* dll_path) : m_mod(LoadLibrary(dll_path)) - { - } - ScopedLoadLibrary::~ScopedLoadLibrary() - { - if (m_mod) - FreeLibrary(m_mod); - } +{} +ScopedLoadLibrary::~ScopedLoadLibrary() +{ + if (m_mod) + FreeLibrary(m_mod); +} -}; +}; // namespace test diff --git a/test/test_utils/test_helpers.h b/test/test_utils/test_helpers.h index 1bc846a..7ea8950 100644 --- a/test/test_utils/test_helpers.h +++ b/test/test_utils/test_helpers.h @@ -2,152 +2,164 @@ #include "windows_sane.h" +#include #include #include -#include namespace test { - class FuncFailed : public std::runtime_error +class FuncFailed : public std::runtime_error +{ +public: + FuncFailed(const char* func) : std::runtime_error(msg(func)) {} + FuncFailed(const char* func, unsigned long res) + : std::runtime_error(msg(func, nullptr, &res)) + {} + FuncFailed(const char* func, const char* arg1) : std::runtime_error(msg(func, arg1)) + {} + FuncFailed(const char* func, const char* arg1, unsigned long res) + : std::runtime_error(msg(func, arg1, &res)) + {} + FuncFailed(const char* func, const char* what, const char* arg1) + : std::runtime_error(msg(func, arg1, nullptr, what)) + {} + FuncFailed(const char* func, const char* what, const char* arg1, unsigned long res) + : std::runtime_error(msg(func, arg1, &res, what)) + {} + +private: + std::string msg(std::string_view func, const char* arg1 = nullptr, + const unsigned long* res = nullptr, const char* what = nullptr); +}; + +class WinFuncFailed : public std::runtime_error +{ +public: + using runtime_error::runtime_error; +}; + +class WinFuncFailedGenerator +{ +public: + WinFuncFailedGenerator(DWORD gle = GetLastError()) : m_gle(gle) {} + WinFuncFailedGenerator(const WinFuncFailedGenerator&) = delete; + + DWORD lastError() const { return m_gle; } + + WinFuncFailed operator()(std::basic_string_view func) { - public: - FuncFailed(const char *func) - : std::runtime_error(msg(func)) {} - FuncFailed(const char *func, unsigned long res) - : std::runtime_error(msg(func, nullptr, &res)) {} - FuncFailed(const char *func, const char *arg1) - : std::runtime_error(msg(func, arg1)) {} - FuncFailed(const char *func, const char *arg1, unsigned long res) - : std::runtime_error(msg(func, arg1, &res)) {} - FuncFailed(const char *func, const char *what, const char *arg1) - : std::runtime_error(msg(func, arg1, nullptr, what)) {} - FuncFailed(const char *func, const char *what, const char *arg1, unsigned long res) - : std::runtime_error(msg(func, arg1, &res, what)) {} - - private: - std::string msg(std::string_view func, const char *arg1 = nullptr, const unsigned long *res = nullptr, const char *what = nullptr); - }; - - class WinFuncFailed : public std::runtime_error - { - public: - using runtime_error::runtime_error; - }; - - class WinFuncFailedGenerator - { - public: - WinFuncFailedGenerator(DWORD gle = GetLastError()) : m_gle(gle) {} - WinFuncFailedGenerator(const WinFuncFailedGenerator &) = delete; - - DWORD lastError() const { return m_gle; } - - WinFuncFailed operator()(std::basic_string_view func) - { - return WinFuncFailed(std::format("{} failed : lastError={}", func, m_gle)); - } - - WinFuncFailed operator()(std::basic_string_view func, unsigned long res) - { - return WinFuncFailed(std::format("{} failed : result=({:#x}), lastError={}", func, res, m_gle)); - } - - WinFuncFailed operator()(std::string_view func, std::basic_string_view arg1) - { - return WinFuncFailed(std::format("{} failed : {}, lastError={}", func, arg1, m_gle)); - } - - WinFuncFailed operator()(std::string_view func, std::basic_string_view arg1, unsigned long res) - { - return WinFuncFailed(std::format("{} failed : {}, result=({:#x}), lastError={}", func, arg1, res, m_gle)); - } - - private: - DWORD m_gle; - }; - - // trick to guarantee the evalutation of GetLastError() before the evalution of the parameters to the WinFuncFailed message generation - template - [[noreturn]] void throw_testWinFuncFailed(std::string_view func, Args &&...args) - { - ::test::WinFuncFailedGenerator exceptionGenerator; - throw exceptionGenerator(func, std::forward(args)...); + return WinFuncFailed(std::format("{} failed : lastError={}", func, m_gle)); } - class ScopedFILE + WinFuncFailed operator()(std::basic_string_view func, unsigned long res) { - public: - // try to open the given filepath with the given mode, if it fails, set err to - // the return code of _wfopen_s and return a nulled scoped file - // - static ScopedFILE open(const std::filesystem::path &filepath, std::wstring_view mode, errno_t &err); + return WinFuncFailed( + std::format("{} failed : result=({:#x}), lastError={}", func, res, m_gle)); + } - // same as above but throw a WinFuncFailed() exception if opening the file failed - // - static ScopedFILE open(const std::filesystem::path &filepath, std::wstring_view mode); - - public: - ScopedFILE(FILE *f = nullptr) : m_f(f, &fclose) {} - - ScopedFILE(ScopedFILE &&other) noexcept = default; - ~ScopedFILE() = default; - - ScopedFILE(const ScopedFILE &) = delete; - - void close() { m_f = nullptr; } - - operator bool() const { return static_cast(m_f); } - operator FILE *() const { return m_f.get(); } - - private: - std::unique_ptr m_f; - }; - - using std::filesystem::path; - - // path functions assume they are called by a test executable - // (calculate the requested path relative to the current executable path) - - path path_of_test_bin(const path &relative = path()); - path path_of_test_temp(const path &relative = path()); - path path_of_test_fixtures(const path &relative = path()); - path path_of_usvfs_lib(const path &relative = path()); - - std::string platform_dependant_executable(const char *name, const char *ext = "exe", const char *platform = nullptr); - - // if full_path is a subfolder of base returns only the relative path, - // if full_path and base are the same folder "." is returned, - // otherwise full_path is returned unchanged - path path_as_relative(const path &base, const path &full_path); - - std::vector read_small_file(const path &file, bool binary = true); - - // true iff the the contents of the two files is exactly the same - bool compare_files(const path &file1, const path &file2, bool binary = true); - - // return true iff the given path is an empty (optionally true also if path doesn't exist) - bool is_empty_folder(const path &dpath, bool or_doesnt_exist = false); - - void delete_file(const path &file); - - // Recursively deletes the given path and all the files and directories under it - // Use with care!!! - void recursive_delete_files(const path &dpath); - - // Recursively copies all files and directories from srcPath to destPath - void recursive_copy_files(const path &src_path, const path &dest_path, bool overwrite); - - class ScopedLoadLibrary + WinFuncFailed operator()(std::string_view func, std::basic_string_view arg1) { - public: - ScopedLoadLibrary(const wchar_t *dll_path); - ~ScopedLoadLibrary(); + return WinFuncFailed( + std::format("{} failed : {}, lastError={}", func, arg1, m_gle)); + } - // returns zero if load library failed - operator HMODULE() const { return m_mod; } + WinFuncFailed operator()(std::string_view func, std::basic_string_view arg1, + unsigned long res) + { + return WinFuncFailed(std::format("{} failed : {}, result=({:#x}), lastError={}", + func, arg1, res, m_gle)); + } - private: - HMODULE m_mod; - }; +private: + DWORD m_gle; }; + +// trick to guarantee the evalutation of GetLastError() before the evalution of the +// parameters to the WinFuncFailed message generation +template +[[noreturn]] void throw_testWinFuncFailed(std::string_view func, Args&&... args) +{ + ::test::WinFuncFailedGenerator exceptionGenerator; + throw exceptionGenerator(func, std::forward(args)...); +} + +class ScopedFILE +{ +public: + // try to open the given filepath with the given mode, if it fails, set err to + // the return code of _wfopen_s and return a nulled scoped file + // + static ScopedFILE open(const std::filesystem::path& filepath, std::wstring_view mode, + errno_t& err); + + // same as above but throw a WinFuncFailed() exception if opening the file failed + // + static ScopedFILE open(const std::filesystem::path& filepath, std::wstring_view mode); + +public: + ScopedFILE(FILE* f = nullptr) : m_f(f, &fclose) {} + + ScopedFILE(ScopedFILE&& other) noexcept = default; + ~ScopedFILE() = default; + + ScopedFILE(const ScopedFILE&) = delete; + + void close() { m_f = nullptr; } + + operator bool() const { return static_cast(m_f); } + operator FILE*() const { return m_f.get(); } + +private: + std::unique_ptr m_f; +}; + +using std::filesystem::path; + +// path functions assume they are called by a test executable +// (calculate the requested path relative to the current executable path) + +path path_of_test_bin(const path& relative = path()); +path path_of_test_temp(const path& relative = path()); +path path_of_test_fixtures(const path& relative = path()); +path path_of_usvfs_lib(const path& relative = path()); + +std::string platform_dependant_executable(const char* name, const char* ext = "exe", + const char* platform = nullptr); + +// if full_path is a subfolder of base returns only the relative path, +// if full_path and base are the same folder "." is returned, +// otherwise full_path is returned unchanged +path path_as_relative(const path& base, const path& full_path); + +std::vector read_small_file(const path& file, bool binary = true); + +// true iff the the contents of the two files is exactly the same +bool compare_files(const path& file1, const path& file2, bool binary = true); + +// return true iff the given path is an empty (optionally true also if path doesn't +// exist) +bool is_empty_folder(const path& dpath, bool or_doesnt_exist = false); + +void delete_file(const path& file); + +// Recursively deletes the given path and all the files and directories under it +// Use with care!!! +void recursive_delete_files(const path& dpath); + +// Recursively copies all files and directories from srcPath to destPath +void recursive_copy_files(const path& src_path, const path& dest_path, bool overwrite); + +class ScopedLoadLibrary +{ +public: + ScopedLoadLibrary(const wchar_t* dll_path); + ~ScopedLoadLibrary(); + + // returns zero if load library failed + operator HMODULE() const { return m_mod; } + +private: + HMODULE m_mod; +}; +}; // namespace test diff --git a/test/thooklib_test/main.cpp b/test/thooklib_test/main.cpp index e679488..df48198 100644 --- a/test/thooklib_test/main.cpp +++ b/test/thooklib_test/main.cpp @@ -1,34 +1,37 @@ -#include #include #include +#include #include #include #include -//#include +// #include #include -#include -#include #include +#include +#include #include namespace fs = boost::filesystem; #include - using namespace std; using namespace HookLib; -class TempFile { +class TempFile +{ public: - TempFile(const wchar_t* relative) - : wpath(winapi::wide::getModuleFileName(nullptr)) + TempFile(const wchar_t* relative) : wpath(winapi::wide::getModuleFileName(nullptr)) { size_t path_end = wpath.rfind(L'\\'); if (path_end != std::wstring::npos) { - wpath.erase(path_end + 1); wpath += L"..\\temp\\"; wpath += relative; - } else wpath = relative; - path = usvfs::shared::string_cast(wpath, usvfs::shared::CodePage::UTF8); + wpath.erase(path_end + 1); + wpath += L"..\\temp\\"; + wpath += relative; + } else + wpath = relative; + path = + usvfs::shared::string_cast(wpath, usvfs::shared::CodePage::UTF8); } const char* c_str() const { return path.c_str(); } @@ -40,12 +43,11 @@ private: }; static const HANDLE MARKERHANDLE = reinterpret_cast(0x1CC0FFEE); -static const TempFile VALID_FILENAME{ L"VALID_FILENAME" }; -static const TempFile INVALID_FILENAME{ L"\\<>/" }; +static const TempFile VALID_FILENAME{L"VALID_FILENAME"}; +static const TempFile INVALID_FILENAME{L"\\<>/"}; #include "test_hooks.cpp" - static bool stubCalled = false; void __cdecl CreateFileStub(LPVOID) @@ -56,21 +58,21 @@ void __cdecl CreateFileStub(LPVOID) class HookingTest : public testing::Test { public: - void SetUp() { -/* typedef sinks::synchronous_sink text_sink; - boost::shared_ptr sink = boost::make_shared(); + void SetUp() + { + /* typedef sinks::synchronous_sink text_sink; + boost::shared_ptr sink = boost::make_shared(); - // Add a stream to write log to - sink->locked_backend()->add_stream(boost::make_shared("c:\\temp\\testing_out.log")); + // Add a stream to write log to + sink->locked_backend()->add_stream(boost::make_shared("c:\\temp\\testing_out.log")); - // Register the sink in the logging core - logging::core::get()->add_sink(sink); + // Register the sink in the logging core + logging::core::get()->add_sink(sink); - sink->set_filter(expr::attr("Severity") >= LogLevel::Debug);*/ + sink->set_filter(expr::attr("Severity") >= LogLevel::Debug);*/ } - void TearDown() { - } + void TearDown() {} private: }; @@ -79,16 +81,16 @@ TEST(GetProcAddressTest, ReturnsValidResults) { HMODULE mh = GetModuleHandleA("KernelBase.dll"); EXPECT_NE(nullptr, mh); - EXPECT_EQ(GetProcAddress(mh, "CreateFileA") , MyGetProcAddress(mh, "CreateFileA")); + EXPECT_EQ(GetProcAddress(mh, "CreateFileA"), MyGetProcAddress(mh, "CreateFileA")); } TEST_F(HookingTest, CanHook) { - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); + HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); HOOKHANDLE hook = InstallHook(k32Mod, "CreateFileW", THCreateFileW_1); if (hook == INVALID_HOOK) { k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallHook(k32Mod, "CreateFileW", THCreateFileW_1); + hook = InstallHook(k32Mod, "CreateFileW", THCreateFileW_1); } EXPECT_NE(INVALID_HOOK, hook); RemoveHook(hook); @@ -96,11 +98,11 @@ TEST_F(HookingTest, CanHook) TEST_F(HookingTest, CanStub) { - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); + HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); HOOKHANDLE hook = InstallStub(k32Mod, "CreateFileW", CreateFileStub); if (hook == INVALID_HOOK) { k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallStub(k32Mod, "CreateFileW", CreateFileStub); + hook = InstallStub(k32Mod, "CreateFileW", CreateFileStub); } EXPECT_NE(INVALID_HOOK, hook); RemoveHook(hook); @@ -109,17 +111,17 @@ TEST_F(HookingTest, CanStub) TEST_F(HookingTest, RemoveHook) { // test that we can remove a hook - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); + HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); HOOKHANDLE hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); if (hook == INVALID_HOOK) { k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); + hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); } EXPECT_NE(INVALID_HOOK, hook); RemoveHook(hook); - HANDLE test = CreateFileA(INVALID_FILENAME.c_str(), GENERIC_READ, 0, - nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + HANDLE test = CreateFileA(INVALID_FILENAME.c_str(), GENERIC_READ, 0, nullptr, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); EXPECT_EQ(INVALID_HANDLE_VALUE, test); } @@ -127,15 +129,15 @@ TEST_F(HookingTest, CreateFileStubTest) { stubCalled = false; // test if our stub works - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); + HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); HOOKHANDLE hook = InstallStub(k32Mod, "CreateFileA", CreateFileStub); if (hook == INVALID_HOOK) { k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallStub(k32Mod, "CreateFileA", CreateFileStub); + hook = InstallStub(k32Mod, "CreateFileA", CreateFileStub); } EXPECT_NE(INVALID_HOOK, hook); - HANDLE test = CreateFileA(INVALID_FILENAME.c_str(), GENERIC_READ, 0, - nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + HANDLE test = CreateFileA(INVALID_FILENAME.c_str(), GENERIC_READ, 0, nullptr, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); RemoveHook(hook); EXPECT_EQ(true, stubCalled); EXPECT_EQ(INVALID_HANDLE_VALUE, test); @@ -144,14 +146,14 @@ TEST_F(HookingTest, CreateFileStubTest) TEST_F(HookingTest, CreateFileHook) { // test if our hook works - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); + HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); HOOKHANDLE hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); if (hook == INVALID_HOOK) { k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); + hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); } - HANDLE test = CreateFileA(INVALID_FILENAME.c_str(), GENERIC_READ, 0, - nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + HANDLE test = CreateFileA(INVALID_FILENAME.c_str(), GENERIC_READ, 0, nullptr, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); RemoveHook(hook); EXPECT_EQ(MARKERHANDLE, test); } @@ -159,14 +161,14 @@ TEST_F(HookingTest, CreateFileHook) TEST_F(HookingTest, CreateFileWHook) { // test if our hook works - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); + HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); HOOKHANDLE hook = InstallHook(k32Mod, "CreateFileW", THCreateFileW_1); if (hook == INVALID_HOOK) { k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallHook(k32Mod, "CreateFileW", THCreateFileW_1); + hook = InstallHook(k32Mod, "CreateFileW", THCreateFileW_1); } HANDLE test = CreateFileW(INVALID_FILENAME.w_str(), 0x42, 0x43, - (LPSECURITY_ATTRIBUTES)0x44, 0x45, 0x46, (HANDLE)0x47); + (LPSECURITY_ATTRIBUTES)0x44, 0x45, 0x46, (HANDLE)0x47); RemoveHook(hook); EXPECT_EQ(MARKERHANDLE, test); } @@ -175,14 +177,14 @@ TEST_F(HookingTest, CreateFileHookRecursion) { // test that the trampoline works, so we can call the original function from // within the hook - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); + HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); HOOKHANDLE hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); if (hook == INVALID_HOOK) { k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); + hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); } - HANDLE test = CreateFileA(VALID_FILENAME.c_str(), GENERIC_READ, 0, - nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + HANDLE test = CreateFileA(VALID_FILENAME.c_str(), GENERIC_READ, 0, nullptr, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); RemoveHook(hook); EXPECT_NE(MARKERHANDLE, test); } @@ -197,33 +199,34 @@ TEST_F(HookingTest, Threading) // being hooked! static const int NUM_THREADS = 100; - static const int NUM_TRIES = 1000; + static const int NUM_TRIES = 1000; - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); + HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); HOOKHANDLE hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); if (hook == INVALID_HOOK) { k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); + hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); } std::thread threads[NUM_THREADS]; for (int i = 0; i < NUM_THREADS; ++i) { threads[i] = std::thread([i] { for (int count = 0; count < NUM_TRIES; ++count) { - HANDLE test = CreateFileA(INVALID_FILENAME.c_str(), GENERIC_READ, 0, - nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + HANDLE test = CreateFileA(INVALID_FILENAME.c_str(), GENERIC_READ, 0, nullptr, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); EXPECT_EQ(MARKERHANDLE, test); } }); } - for (int i= 0; i < NUM_THREADS; ++i) { + for (int i = 0; i < NUM_THREADS; ++i) { threads[i].join(); } RemoveHook(hook); } -int main(int argc, char **argv) { +int main(int argc, char** argv) +{ auto logger = spdlog::stdout_logger_mt("usvfs"); logger->set_level(spdlog::level::warn); TrampolinePool::initialize(); diff --git a/test/thooklib_test/test_hooks.cpp b/test/thooklib_test/test_hooks.cpp index f755c06..edde2c8 100644 --- a/test/thooklib_test/test_hooks.cpp +++ b/test/thooklib_test/test_hooks.cpp @@ -1,32 +1,26 @@ #include #include - -HANDLE WINAPI THCreateFileA_1(LPCSTR lpFileName, - DWORD dwDesiredAccess, +HANDLE WINAPI THCreateFileA_1(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, - DWORD dwFlagsAndAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { if (strcmp(lpFileName, INVALID_FILENAME.c_str()) == 0) { return MARKERHANDLE; } else { - HANDLE res = ::CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, - lpSecurityAttributes, dwCreationDisposition, - dwFlagsAndAttributes, hTemplateFile); + HANDLE res = + ::CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); return res; } } - -HANDLE WINAPI THCreateFileW_1(LPCWSTR lpFileName, - DWORD dwDesiredAccess, +HANDLE WINAPI THCreateFileW_1(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, - DWORD dwFlagsAndAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { if (wcscmp(lpFileName, INVALID_FILENAME.w_str()) == 0) { @@ -38,9 +32,7 @@ HANDLE WINAPI THCreateFileW_1(LPCWSTR lpFileName, EXPECT_EQ(0x47, (int)hTemplateFile); return MARKERHANDLE; } else { - return ::CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, - lpSecurityAttributes, dwCreationDisposition, - dwFlagsAndAttributes, hTemplateFile); + return ::CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } } - diff --git a/test/tinjectlib_test/main.cpp b/test/tinjectlib_test/main.cpp index 402673f..ce48f83 100644 --- a/test/tinjectlib_test/main.cpp +++ b/test/tinjectlib_test/main.cpp @@ -1,10 +1,10 @@ +#include +#include #include #include -#include -#include -#include -#include #include +#include +#include using namespace usvfs::shared; using namespace InjectLib; @@ -30,29 +30,22 @@ static std::shared_ptr logger() return result; } -bool spawn(HANDLE &processHandle, HANDLE &threadHandle) +bool spawn(HANDLE& processHandle, HANDLE& threadHandle) { STARTUPINFO si; ::ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); PROCESS_INFORMATION pi; - BOOL success = ::CreateProcess(INJECT_BIN, - nullptr, - nullptr, nullptr, - FALSE, - CREATE_SUSPENDED, - nullptr, - nullptr, - &si, &pi - ); + BOOL success = ::CreateProcess(INJECT_BIN, nullptr, nullptr, nullptr, FALSE, + CREATE_SUSPENDED, nullptr, nullptr, &si, &pi); if (!success) { throw windows_error("failed to start process"); } processHandle = pi.hProcess; - threadHandle = pi.hThread; + threadHandle = pi.hThread; return true; } @@ -66,9 +59,9 @@ TEST(InjectingTest, InjectionNoInit) EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB)); ResumeThread(thread); - DWORD res = WaitForSingleObject(process, INFINITE); + DWORD res = WaitForSingleObject(process, INFINITE); DWORD exitCode = NO_ERROR; - res = GetExitCodeProcess(process, &exitCode); + res = GetExitCodeProcess(process, &exitCode); EXPECT_EQ(NOERROR, exitCode); CloseHandle(process); @@ -81,14 +74,13 @@ TEST(InjectingTest, InjectionSimpleInit) HANDLE process, thread; spawn(process, thread); - EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB, - "InitNoParam")); + EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB, "InitNoParam")); ResumeThread(thread); - DWORD res = WaitForSingleObject(process, INFINITE); + DWORD res = WaitForSingleObject(process, INFINITE); DWORD exitCode = NO_ERROR; - res = GetExitCodeProcess(process, &exitCode); - EXPECT_EQ(10001, exitCode); // used init function exits process with this exit code + res = GetExitCodeProcess(process, &exitCode); + EXPECT_EQ(10001, exitCode); // used init function exits process with this exit code CloseHandle(process); CloseHandle(thread); @@ -101,17 +93,16 @@ TEST(InjectingTest, InjectionComplexInit) static const WCHAR param[] = L"magic_parameter"; HANDLE process, thread; spawn(process, thread); - EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB, - "InitComplexParam", + EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB, "InitComplexParam", reinterpret_cast(param), wcslen(param) * sizeof(WCHAR))); ResumeThread(thread); - DWORD res = WaitForSingleObject(process, INFINITE); + DWORD res = WaitForSingleObject(process, INFINITE); DWORD exitCode = NO_ERROR; - res = GetExitCodeProcess(process, &exitCode); - EXPECT_EQ(10002, exitCode); // used init function exits process with this exit code + res = GetExitCodeProcess(process, &exitCode); + EXPECT_EQ(10002, exitCode); // used init function exits process with this exit code CloseHandle(process); CloseHandle(thread); @@ -123,14 +114,13 @@ TEST(InjectingTest, InjectionNoQuitInit) HANDLE process, thread; spawn(process, thread); - EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB, - "InitNoQuit")); + EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB, "InitNoQuit")); ResumeThread(thread); - DWORD res = WaitForSingleObject(process, INFINITE); + DWORD res = WaitForSingleObject(process, INFINITE); DWORD exitCode = NO_ERROR; - res = GetExitCodeProcess(process, &exitCode); - EXPECT_EQ(0, exitCode); // expect regular exit from process + res = GetExitCodeProcess(process, &exitCode); + EXPECT_EQ(0, exitCode); // expect regular exit from process CloseHandle(process); CloseHandle(thread); @@ -142,20 +132,21 @@ TEST(InjectingTest, InjectionSkipInit) HANDLE process, thread; spawn(process, thread); - EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB, - "__InitInvalid", nullptr, 0, true)); + EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB, "__InitInvalid", + nullptr, 0, true)); ResumeThread(thread); - DWORD res = WaitForSingleObject(process, INFINITE); + DWORD res = WaitForSingleObject(process, INFINITE); DWORD exitCode = NO_ERROR; - res = GetExitCodeProcess(process, &exitCode); + res = GetExitCodeProcess(process, &exitCode); EXPECT_EQ(NOERROR, exitCode); CloseHandle(process); CloseHandle(thread); } -int main(int argc, char **argv) { +int main(int argc, char** argv) +{ auto logger = spdlog::stdout_logger_mt("usvfs"); logger->set_level(spdlog::level::warn); diff --git a/test/tinjectlib_test/testinject_bin/main.cpp b/test/tinjectlib_test/testinject_bin/main.cpp index 86f2cd1..f8b643a 100644 --- a/test/tinjectlib_test/testinject_bin/main.cpp +++ b/test/tinjectlib_test/testinject_bin/main.cpp @@ -2,4 +2,3 @@ int main() { return 0; } - diff --git a/test/tinjectlib_test/testinject_dll/main.cpp b/test/tinjectlib_test/testinject_dll/main.cpp index 0ac6be5..8339e97 100644 --- a/test/tinjectlib_test/testinject_dll/main.cpp +++ b/test/tinjectlib_test/testinject_dll/main.cpp @@ -10,7 +10,6 @@ void __cdecl InitNoParam(LPVOID, size_t) ExitProcess(10001); } - void __cdecl InitComplexParam(LPVOID userData, size_t) { LPCWSTR string = (LPCWSTR)userData; @@ -21,20 +20,17 @@ void __cdecl InitComplexParam(LPVOID userData, size_t) } } - -BOOL APIENTRY DllMain(HMODULE, - DWORD reasonForCall, - LPVOID) +BOOL APIENTRY DllMain(HMODULE, DWORD reasonForCall, LPVOID) { switch (reasonForCall) { - case DLL_PROCESS_ATTACH: { - } break; - case DLL_PROCESS_DETACH: { - } break; - case DLL_THREAD_ATTACH: { - } break; - case DLL_THREAD_DETACH: { - } break; + case DLL_PROCESS_ATTACH: { + } break; + case DLL_PROCESS_DETACH: { + } break; + case DLL_THREAD_ATTACH: { + } break; + case DLL_THREAD_DETACH: { + } break; } return TRUE; } diff --git a/test/tinjectlib_test/testinject_dll/main.h b/test/tinjectlib_test/testinject_dll/main.h index 9c42f1d..6faf800 100644 --- a/test/tinjectlib_test/testinject_dll/main.h +++ b/test/tinjectlib_test/testinject_dll/main.h @@ -3,6 +3,9 @@ #define WIN32_LEAN_AND_MEAN #include -extern "C" __declspec(dllexport) void __cdecl InitNoQuit(LPVOID userData, size_t userDataSize); -extern "C" __declspec(dllexport) void __cdecl InitNoParam(LPVOID userData, size_t userDataSize); -extern "C" __declspec(dllexport) void __cdecl InitComplexParam(LPVOID userData, size_t userDataSize); +extern "C" + __declspec(dllexport) void __cdecl InitNoQuit(LPVOID userData, size_t userDataSize); +extern "C" __declspec(dllexport) void __cdecl InitNoParam(LPVOID userData, + size_t userDataSize); +extern "C" __declspec(dllexport) void __cdecl InitComplexParam(LPVOID userData, + size_t userDataSize); diff --git a/test/tvfs_test/main.cpp b/test/tvfs_test/main.cpp index 0c61a43..8eebb40 100644 --- a/test/tvfs_test/main.cpp +++ b/test/tvfs_test/main.cpp @@ -404,12 +404,13 @@ TEST_F(USVFSTest, NtQueryObjectVirtualFile) char buffer[1024]; IO_STATUS_BLOCK status; const auto res = usvfs::hook_NtQueryInformationFile( - hdl, &status, buffer, sizeof(buffer), FileNameInformation); + hdl, &status, buffer, sizeof(buffer), FileNameInformation); ASSERT_EQ(STATUS_SUCCESS, status.Status); FILE_NAME_INFORMATION* fileNameInfo = reinterpret_cast(buffer); - ASSERT_EQ(L"\\np.exe", std::wstring(fileNameInfo->FileName, fileNameInfo->FileNameLength / 2)); + ASSERT_EQ(L"\\np.exe", + std::wstring(fileNameInfo->FileName, fileNameInfo->FileNameLength / 2)); } { @@ -423,33 +424,35 @@ TEST_F(USVFSTest, NtQueryObjectVirtualFile) FILE_NAME_INFORMATION* fileNameInfo = reinterpret_cast(buffer); - ASSERT_EQ(L"\\np.exe", std::wstring(fileNameInfo->FileName, fileNameInfo->FileNameLength / 2)); + ASSERT_EQ(L"\\np.exe", + std::wstring(fileNameInfo->FileName, fileNameInfo->FileNameLength / 2)); } // buffer of size should be too small for the original path (\Windows\notepad.exe) // but not for \np.exe { - // the required size should be sizeof(ULONG) + 7 * 2 but apparently that is + // the required size should be sizeof(ULONG) + 7 * 2 but apparently that is // not enough for the CI so using 16 * 2 which should be large enough for // the hooked version, but still too short for the non-hooked one char buffer[sizeof(ULONG) + 7 * 2]; IO_STATUS_BLOCK status; NTSTATUS res; - res = ::NtQueryInformationFile( - hdl, &status, buffer, sizeof(buffer), FileNameInformation); + res = ::NtQueryInformationFile(hdl, &status, buffer, sizeof(buffer), + FileNameInformation); ASSERT_EQ(STATUS_BUFFER_OVERFLOW, res); ASSERT_EQ(STATUS_BUFFER_OVERFLOW, status.Status); - res = usvfs::hook_NtQueryInformationFile( - hdl, &status, buffer, sizeof(buffer), FileNameInformation); + res = usvfs::hook_NtQueryInformationFile(hdl, &status, buffer, sizeof(buffer), + FileNameInformation); ASSERT_EQ(STATUS_SUCCESS, res); ASSERT_EQ(STATUS_SUCCESS, status.Status); ASSERT_EQ(sizeof(ULONG) + 7 * 2, status.Information); FILE_NAME_INFORMATION* fileNameInfo = reinterpret_cast(buffer); - ASSERT_EQ(L"\\np.exe", std::wstring(fileNameInfo->FileName, fileNameInfo->FileNameLength / 2)); + ASSERT_EQ(L"\\np.exe", + std::wstring(fileNameInfo->FileName, fileNameInfo->FileNameLength / 2)); } { @@ -473,12 +476,15 @@ TEST_F(USVFSTest, NtQueryObjectVirtualFile) ULONG requiredLength; NTSTATUS res; char buffer[2048]; - - res = usvfs::hook_NtQueryObject(hdl, ObjectNameInformation, buffer, sizeof(OBJECT_NAME_INFORMATION) - 1, &requiredLength); + + res = + usvfs::hook_NtQueryObject(hdl, ObjectNameInformation, buffer, + sizeof(OBJECT_NAME_INFORMATION) - 1, &requiredLength); ASSERT_EQ(STATUS_INFO_LENGTH_MISMATCH, res); ASSERT_EQ(expectedLength, requiredLength); - res = usvfs::hook_NtQueryObject(hdl, ObjectNameInformation, buffer, sizeof(OBJECT_NAME_INFORMATION), &requiredLength); + res = usvfs::hook_NtQueryObject(hdl, ObjectNameInformation, buffer, + sizeof(OBJECT_NAME_INFORMATION), &requiredLength); ASSERT_EQ(STATUS_BUFFER_OVERFLOW, res); ASSERT_EQ(expectedLength, requiredLength); } diff --git a/test/usvfs_global_test_runner/usvfs_global_test/usvfs_global_test.cpp b/test/usvfs_global_test_runner/usvfs_global_test/usvfs_global_test.cpp index 7de2f60..9e7560a 100644 --- a/test/usvfs_global_test_runner/usvfs_global_test/usvfs_global_test.cpp +++ b/test/usvfs_global_test_runner/usvfs_global_test/usvfs_global_test.cpp @@ -159,4 +159,4 @@ int main(int argc, char* argv[]) } return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/test/usvfs_global_test_runner/usvfs_global_test_fixture.h b/test/usvfs_global_test_runner/usvfs_global_test_fixture.h index 277e78e..aeafc25 100644 --- a/test/usvfs_global_test_runner/usvfs_global_test_fixture.h +++ b/test/usvfs_global_test_runner/usvfs_global_test_fixture.h @@ -79,4 +79,4 @@ private: std::filesystem::path m_data_folder = m_temporary_folder / "data"; std::filesystem::path m_mods_folder = m_temporary_folder / "mods"; std::filesystem::path m_overwrite_folder = m_temporary_folder / "overwrite"; -}; \ No newline at end of file +}; diff --git a/test/usvfs_global_test_runner/usvfs_global_test_runner.cpp b/test/usvfs_global_test_runner/usvfs_global_test_runner.cpp index afe219e..28e3fc2 100644 --- a/test/usvfs_global_test_runner/usvfs_global_test_runner.cpp +++ b/test/usvfs_global_test_runner/usvfs_global_test_runner.cpp @@ -1,8 +1,8 @@ #include +#include #include #include -#include #include "usvfs_global_test_fixture.h" diff --git a/test/usvfs_test_runner/test_file_operations/test_file_operations.cpp b/test/usvfs_test_runner/test_file_operations/test_file_operations.cpp index e642550..2135df3 100644 --- a/test/usvfs_test_runner/test_file_operations/test_file_operations.cpp +++ b/test/usvfs_test_runner/test_file_operations/test_file_operations.cpp @@ -1,61 +1,87 @@ #include #include -#include #include +#include #include -#include #include "test_ntapi.h" #include "test_w32api.h" +#include #define WIN32_LEAN_AND_MEAN #include -using usvfs::shared::string_cast; using usvfs::shared::CodePage; +using usvfs::shared::string_cast; -void print_usage(const char* myname) { +void print_usage(const char* myname) +{ using namespace std; fprintf(stderr, "usage: %s [] [] ...\n", myname); - fprintf(stderr, "options and commands are parsed and executed in the order they appear.\n"); + fprintf(stderr, + "options and commands are parsed and executed in the order they appear.\n"); fprintf(stderr, "\nsupported commands:\n"); - fprintf(stderr, " -list

: lists the given directory and outputs the results.\n"); - fprintf(stderr, " -listcontents : lists the given directory, reading all files and outputs the results.\n"); - fprintf(stderr, " -read : reads the given file and outputs the results.\n"); - fprintf(stderr, " -overwrite : overwrites the file at the given path with the given line (creating directories if in recursive mode).\n"); - fprintf(stderr, " -deleteoverwrite : shorthand for -delete -overwrite \n"); - fprintf(stderr, " -rewrite : rewrites the file at the given path with the given line (fails if file doesn't exist; uses read/write access).\n"); - fprintf(stderr, " -touch : updates last write timestamp of specified file.\n"); - fprintf(stderr, " -touchw : updates last write timestamp using full write permissions.\n"); + fprintf( + stderr, + " -list : lists the given directory and outputs the results.\n"); + fprintf(stderr, " -listcontents : lists the given directory, reading all files " + "and outputs the results.\n"); + fprintf(stderr, + " -read : reads the given file and outputs the results.\n"); + fprintf(stderr, " -overwrite : overwrites the file at the given path " + "with the given line (creating directories if in recursive mode).\n"); + fprintf(stderr, " -deleteoverwrite : shorthand for -delete " + "-overwrite \n"); + fprintf(stderr, + " -rewrite : rewrites the file at the given path with the " + "given line (fails if file doesn't exist; uses read/write access).\n"); + fprintf(stderr, + " -touch : updates last write timestamp of specified file.\n"); + fprintf(stderr, " -touchw : updates last write timestamp using full " + "write permissions.\n"); fprintf(stderr, " -delete : deletes the given file.\n"); fprintf(stderr, " -copy : copies the given file.\n"); - fprintf(stderr, " -copyover : copies the given file (replacing existing destination).\n"); + fprintf(stderr, " -copyover : copies the given file (replacing existing " + "destination).\n"); fprintf(stderr, " -rename : renames the given file.\n"); - fprintf(stderr, " -renameover : renames the given file (replacing existing destination).\n"); - fprintf(stderr, " -deleterename : shorthand for -delete -rename .\n"); - fprintf(stderr, " -move : moves the given file (not supported by ntapi).\n"); - fprintf(stderr, " -moveover : moves the given file (replacing existing destination; not supported by ntapi).\n"); - fprintf(stderr, " -deletemove : shorthand for -delete -move .\n"); - fprintf(stderr, " -debug : shows a message box and wait for a debugger to connect.\n"); + fprintf(stderr, " -renameover : renames the given file (replacing " + "existing destination).\n"); + fprintf(stderr, " -deleterename : shorthand for -delete -rename " + " .\n"); + fprintf(stderr, + " -move : moves the given file (not supported by ntapi).\n"); + fprintf(stderr, " -moveover : moves the given file (replacing existing " + "destination; not supported by ntapi).\n"); + fprintf( + stderr, + " -deletemove : shorthand for -delete -move .\n"); + fprintf(stderr, " -debug : shows a message box and wait for a debugger " + "to connect.\n"); fprintf(stderr, "\nsupported options:\n"); - fprintf(stderr, " -out : file to log output to (use \"-\" for the stdout; otherwise path to output should exist).\n"); - fprintf(stderr, " -out+ : similar to -out but appends the file instead of overwriting it.\n"); - fprintf(stderr, " -cout : similar to -out but does not log PID and other info which may change between runs.\n"); - fprintf(stderr, " -cout+ : similar to -cout but appends the file instead of overwriting it.\n"); + fprintf(stderr, " -out : file to log output to (use \"-\" for the " + "stdout; otherwise path to output should exist).\n"); + fprintf(stderr, " -out+ : similar to -out but appends the file instead " + "of overwriting it.\n"); + fprintf(stderr, " -cout : similar to -out but does not log PID and " + "other info which may change between runs.\n"); + fprintf(stderr, " -cout+ : similar to -cout but appends the file " + "instead of overwriting it.\n"); fprintf(stderr, " -r : recursively list/create directories.\n"); - fprintf(stderr, " -r- : don't recursively list/create directories.\n"); - fprintf(stderr, " -basedir : any paths under the basedir will outputed in a relative manner (default is current directory).\n"); - fprintf(stderr, " -w32api : use regular Win32 API for file access (default).\n"); - fprintf(stderr, " -ntapi : use lower level ntdll functions for file access.\n"); + fprintf(stderr, + " -r- : don't recursively list/create directories.\n"); + fprintf(stderr, " -basedir : any paths under the basedir will outputed in " + "a relative manner (default is current directory).\n"); + fprintf(stderr, + " -w32api : use regular Win32 API for file access (default).\n"); + fprintf(stderr, + " -ntapi : use lower level ntdll functions for file access.\n"); } class CommandExecuter { public: - CommandExecuter() - : m_output(stdout) - , m_api(&w32api) + CommandExecuter() : m_output(stdout), m_api(&w32api) { set_basedir(TestFileSystem::current_directory().string().c_str()); } @@ -66,15 +92,9 @@ public: fclose(m_output); } - FILE* output() const - { - return m_output; - } + FILE* output() const { return m_output; } - bool file_output() const - { - return m_output != stdout; - } + bool file_output() const { return m_output != stdout; } // Options: @@ -86,29 +106,25 @@ public: } m_cleanoutput = clean; - m_output = nullptr; - errno_t err = fopen_s(&m_output, output_file, append ? "at" : "wt"); + m_output = nullptr; + errno_t err = fopen_s(&m_output, output_file, append ? "at" : "wt"); if (err || !m_output) test::throw_testWinFuncFailed("fopen_s", output_file, err); else { if (m_cleanoutput) - fprintf(m_output, "#> Output log openned for: %s\n", clean_cmdline_heuristic(cmdline).c_str()); + fprintf(m_output, "#> Output log openned for: %s\n", + clean_cmdline_heuristic(cmdline).c_str()); else - fprintf(m_output, "#> Output log openned for (pid %d): %s\n", GetCurrentProcessId(), cmdline); + fprintf(m_output, "#> Output log openned for (pid %d): %s\n", + GetCurrentProcessId(), cmdline); w32api.set_output(m_output, m_cleanoutput); ntapi.set_output(m_output, m_cleanoutput); } } - bool cleanoutput() const - { - return m_cleanoutput; - } + bool cleanoutput() const { return m_cleanoutput; } - void set_recursive(bool recursive) - { - m_recursive = recursive; - } + void set_recursive(bool recursive) { m_recursive = recursive; } void set_basedir(const char* basedir) { @@ -128,41 +144,49 @@ public: void list(const char* dir, bool read_files) { - if (debug_pending()) __debugbreak(); + if (debug_pending()) + __debugbreak(); list_impl(m_api->real_path(dir), read_files); } void read(const char* path) { - if (debug_pending()) __debugbreak(); + if (debug_pending()) + __debugbreak(); m_api->read_file(m_api->real_path(path)); } void overwrite(const char* path, const char* value) { - if (debug_pending()) __debugbreak(); + if (debug_pending()) + __debugbreak(); const auto& real = real_path_create_if_necessary(path); - m_api->write_file(real, value, strlen(value), true, TestFileSystem::write_mode::overwrite); + m_api->write_file(real, value, strlen(value), true, + TestFileSystem::write_mode::overwrite); } void rewrite(const char* path, const char* value) { - if (debug_pending()) __debugbreak(); + if (debug_pending()) + __debugbreak(); const auto& real = real_path_create_if_necessary(path); - // Use read/write access when rewriting to "simulate" the harder case where it is not known if the file is going to actually be changed - m_api->write_file(real, value, strlen(value), false, TestFileSystem::write_mode::manual_truncate, true); + // Use read/write access when rewriting to "simulate" the harder case where it is + // not known if the file is going to actually be changed + m_api->write_file(real, value, strlen(value), false, + TestFileSystem::write_mode::manual_truncate, true); m_api->write_file(real, "\r\n", 2, false, TestFileSystem::write_mode::append); } void touch(const char* path, bool full_write_access) { - if (debug_pending()) __debugbreak(); + if (debug_pending()) + __debugbreak(); const auto& real = real_path_create_if_necessary(path); @@ -171,29 +195,32 @@ public: void deletef(const char* path) { - if (debug_pending()) __debugbreak(); + if (debug_pending()) + __debugbreak(); m_api->delete_file(m_api->real_path(path)); } void rename(const char* source, const char* destination, bool replace_existing) { - if (debug_pending()) __debugbreak(); + if (debug_pending()) + __debugbreak(); - m_api->copy_file(m_api->real_path(source), m_api->real_path(destination), replace_existing); + m_api->copy_file(m_api->real_path(source), m_api->real_path(destination), + replace_existing); } - void rename(const char* source, const char* destination, bool replace_existing, bool allow_copy) + void rename(const char* source, const char* destination, bool replace_existing, + bool allow_copy) { - if (debug_pending()) __debugbreak(); + if (debug_pending()) + __debugbreak(); - m_api->rename_file(m_api->real_path(source), m_api->real_path(destination), replace_existing, allow_copy); + m_api->rename_file(m_api->real_path(source), m_api->real_path(destination), + replace_existing, allow_copy); } - void debug() - { - m_debug_pending = true; - } + void debug() { m_debug_pending = true; } bool debug_pending() { @@ -201,7 +228,8 @@ public: return false; m_debug_pending = false; if (!IsDebuggerPresent()) - MessageBoxA(NULL, "Connect a debugger and press OK to trigger a breakpoint", "DEBUG", 0); + MessageBoxA(NULL, "Connect a debugger and press OK to trigger a breakpoint", + "DEBUG", 0); return IsDebuggerPresent(); } @@ -212,17 +240,19 @@ public: std::vector recurse; { auto files = m_api->list_directory(real); - fprintf(m_output, ">> Listing directory {%s}:\n", m_api->relative_path(real).string().c_str()); + fprintf(m_output, ">> Listing directory {%s}:\n", + m_api->relative_path(real).string().c_str()); for (auto f : files) { if (f.is_dir()) { fprintf(m_output, "[%s] DIR (attributes 0x%x)\n", - string_cast(f.name, CodePage::UTF8).c_str(), f.attributes); + string_cast(f.name, CodePage::UTF8).c_str(), + f.attributes); if (m_recursive && f.name != L"." && f.name != L"..") recurse.push_back(real / f.name); - } - else { + } else { fprintf(m_output, "[%s] FILE (attributes 0x%x, %lld bytes)\n", - string_cast(f.name, CodePage::UTF8).c_str(), f.attributes, f.size); + string_cast(f.name, CodePage::UTF8).c_str(), + f.attributes, f.size); if (read_files) m_api->read_file(real / f.name); } @@ -238,13 +268,12 @@ private: auto real = m_api->real_path(path); if (m_recursive) try { - m_api->create_path(real.parent_path()); - } - catch (const std::exception& e) { - throw std::runtime_error(std::format( - "Failed to create_path [{}] : {}", m_api->relative_path(real.parent_path()).string(), e.what() - )); - } + m_api->create_path(real.parent_path()); + } catch (const std::exception& e) { + throw std::runtime_error( + std::format("Failed to create_path [{}] : {}", + m_api->relative_path(real.parent_path()).string(), e.what())); + } return std::move(real); } @@ -252,13 +281,15 @@ private: { if (arg_start == arg_end) return std::string(); - bool quoted = *arg_start == '\"' && *(arg_end - 1) == '\"'; + bool quoted = *arg_start == '\"' && *(arg_end - 1) == '\"'; const char* last_sep = arg_end; - while (last_sep != arg_start && *last_sep != '\\') --last_sep; - if (arg_end - arg_start < (quoted ? 5 : 3) || arg_start[0] == '-' || arg_start[quoted ? 2 : 1] != ':' || last_sep == arg_start) + while (last_sep != arg_start && *last_sep != '\\') + --last_sep; + if (arg_end - arg_start < (quoted ? 5 : 3) || arg_start[0] == '-' || + arg_start[quoted ? 2 : 1] != ':' || last_sep == arg_start) return std::string(arg_start, arg_end); std::string res = quoted ? "\"" : ""; - res.append(last_sep+1, arg_end); + res.append(last_sep + 1, arg_end); return res; } @@ -276,14 +307,15 @@ private: res.push_back(' '); res += clean_cmdline_arg(cmdline, end); cmdline = end; - while (*cmdline == ' ') ++cmdline; + while (*cmdline == ' ') + ++cmdline; } return res; } FILE* m_output; - bool m_cleanoutput = false; - bool m_recursive = false; + bool m_cleanoutput = false; + bool m_recursive = false; bool m_debug_pending = false; TestFileSystem* m_api; @@ -291,11 +323,12 @@ private: static TestNtApi ntapi; }; -//static +// static TestW32Api CommandExecuter::w32api(stdout); TestNtApi CommandExecuter::ntapi(stdout); -class abort_invalid_argument : std::exception {}; +class abort_invalid_argument : std::exception +{}; bool verify_args_exist(const char* flag, int params, int index, int count) { @@ -309,141 +342,134 @@ bool verify_args_exist(const char* flag, int params, int index, int count) const char* UntouchedCommandLineArguments() { const char* cmd = GetCommandLineA(); - for (; *cmd && *cmd != ' '; ++cmd) - { + for (; *cmd && *cmd != ' '; ++cmd) { if (*cmd == '"') { int escaped = 0; for (++cmd; *cmd && (*cmd != '"' || escaped % 2 != 0); ++cmd) escaped = *cmd == '\\' ? escaped + 1 : 0; } } - while (*cmd == ' ') ++cmd; + while (*cmd == ' ') + ++cmd; return cmd; } -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { bool found_commands = false; CommandExecuter executer; TestFileSystem::path exe_path = argv[0]; - std::string exename = exe_path.filename().string(); - std::string cmdline = exename + " " + UntouchedCommandLineArguments(); - fprintf(stdout, "#> process %d started with commandline: %s\n", GetCurrentProcessId(), cmdline.c_str()); + std::string exename = exe_path.filename().string(); + std::string cmdline = exename + " " + UntouchedCommandLineArguments(); + fprintf(stdout, "#> process %d started with commandline: %s\n", GetCurrentProcessId(), + cmdline.c_str()); - for (int ai = 1; ai < argc; ++ai) - { - try - { + for (int ai = 1; ai < argc; ++ai) { + try { SetLastError(0); // options: - if (strcmp(argv[ai], "-out") == 0 && verify_args_exist("-out", 1, ai, argc) - || strcmp(argv[ai], "-out+") == 0 && verify_args_exist("-out+", 1, ai, argc) - || strcmp(argv[ai], "-cout") == 0 && verify_args_exist("-cout", 1, ai, argc) - || strcmp(argv[ai], "-cout+") == 0 && verify_args_exist("-cout+", 1, ai, argc)) - { - bool clean = argv[ai][1] == 'c'; - bool append = argv[ai][clean?5:4] == '+'; + if (strcmp(argv[ai], "-out") == 0 && verify_args_exist("-out", 1, ai, argc) || + strcmp(argv[ai], "-out+") == 0 && verify_args_exist("-out+", 1, ai, argc) || + strcmp(argv[ai], "-cout") == 0 && verify_args_exist("-cout", 1, ai, argc) || + strcmp(argv[ai], "-cout+") == 0 && verify_args_exist("-cout+", 1, ai, argc)) { + bool clean = argv[ai][1] == 'c'; + bool append = argv[ai][clean ? 5 : 4] == '+'; executer.set_output(argv[++ai], clean, append, cmdline.c_str()); - } - else if (strcmp(argv[ai], "-r") == 0) + } else if (strcmp(argv[ai], "-r") == 0) executer.set_recursive(true); else if (strcmp(argv[ai], "-r-") == 0) executer.set_recursive(false); - else if (strcmp(argv[ai], "-basedir") == 0 && verify_args_exist("-basedir", 1, ai, argc)) { + else if (strcmp(argv[ai], "-basedir") == 0 && + verify_args_exist("-basedir", 1, ai, argc)) { executer.set_basedir(argv[++ai]); - } - else if (strcmp(argv[ai], "-w32api") == 0) + } else if (strcmp(argv[ai], "-w32api") == 0) executer.set_ntapi(false); else if (strcmp(argv[ai], "-ntapi") == 0) executer.set_ntapi(true); // commands: - else if ((strcmp(argv[ai], "-list") == 0 - || strcmp(argv[ai], "-listcontents") == 0) - && verify_args_exist("-list", 1, ai, argc)) - { + else if ((strcmp(argv[ai], "-list") == 0 || + strcmp(argv[ai], "-listcontents") == 0) && + verify_args_exist("-list", 1, ai, argc)) { bool contents = strcmp(argv[ai], "-listcontents") == 0; executer.list(argv[++ai], contents); found_commands = true; - } - else if (strcmp(argv[ai], "-read") == 0 && verify_args_exist("-read", 1, ai, argc)) - { + } else if (strcmp(argv[ai], "-read") == 0 && + verify_args_exist("-read", 1, ai, argc)) { executer.read(argv[++ai]); found_commands = true; - } - else if (strcmp(argv[ai], "-overwrite") == 0 && verify_args_exist("-overwrite", 2, ai, argc) - || strcmp(argv[ai], "-deleteoverwrite") == 0 && verify_args_exist("-deleteoverwrite", 2, ai, argc)) { + } else if (strcmp(argv[ai], "-overwrite") == 0 && + verify_args_exist("-overwrite", 2, ai, argc) || + strcmp(argv[ai], "-deleteoverwrite") == 0 && + verify_args_exist("-deleteoverwrite", 2, ai, argc)) { if (argv[ai][1] == 'd') executer.deletef(argv[ai + 1]); executer.overwrite(argv[ai + 1], argv[ai + 2]); - ++++ai; + ++ ++ai; found_commands = true; - } - else if (strcmp(argv[ai], "-rewrite") == 0 && verify_args_exist("-rewrite", 2, ai, argc)) { + } else if (strcmp(argv[ai], "-rewrite") == 0 && + verify_args_exist("-rewrite", 2, ai, argc)) { executer.rewrite(argv[ai + 1], argv[ai + 2]); - ++++ai; + ++ ++ai; found_commands = true; - } - else if (strcmp(argv[ai], "-touch") == 0 && verify_args_exist("-touch", 1, ai, argc) - || strcmp(argv[ai], "-touchw") == 0 && verify_args_exist("-touchw", 1, ai, argc)) - { + } else if (strcmp(argv[ai], "-touch") == 0 && + verify_args_exist("-touch", 1, ai, argc) || + strcmp(argv[ai], "-touchw") == 0 && + verify_args_exist("-touchw", 1, ai, argc)) { bool write_access = argv[ai][6] == 'w'; executer.touch(argv[++ai], write_access); found_commands = true; - } - else if (strcmp(argv[ai], "-delete") == 0 && verify_args_exist("-delete", 1, ai, argc)) - { + } else if (strcmp(argv[ai], "-delete") == 0 && + verify_args_exist("-delete", 1, ai, argc)) { executer.deletef(argv[++ai]); found_commands = true; - } - else if (strcmp(argv[ai], "-copy") == 0 && verify_args_exist("-copy", 2, ai, argc) - || strcmp(argv[ai], "-copyover") == 0 && verify_args_exist("-copyover", 2, ai, argc)) - { + } else if (strcmp(argv[ai], "-copy") == 0 && + verify_args_exist("-copy", 2, ai, argc) || + strcmp(argv[ai], "-copyover") == 0 && + verify_args_exist("-copyover", 2, ai, argc)) { bool over = argv[ai][5] == 'o'; executer.rename(argv[ai + 1], argv[ai + 2], over); - ++++ai; + ++ ++ai; found_commands = true; - } - else if (strcmp(argv[ai], "-rename") == 0 && verify_args_exist("-rename", 2, ai, argc) - || strcmp(argv[ai], "-renameover") == 0 && verify_args_exist("-renameover", 2, ai, argc) - || strcmp(argv[ai], "-deleterename") == 0 && verify_args_exist("-deleterename", 2, ai, argc) - || strcmp(argv[ai], "-move") == 0 && verify_args_exist("-move", 2, ai, argc) - || strcmp(argv[ai], "-moveover") == 0 && verify_args_exist("-moveover", 2, ai, argc) - || strcmp(argv[ai], "-deletemove") == 0 && verify_args_exist("-deletemove", 2, ai, argc)) - { - bool del = argv[ai][1] == 'd'; + } else if (strcmp(argv[ai], "-rename") == 0 && + verify_args_exist("-rename", 2, ai, argc) || + strcmp(argv[ai], "-renameover") == 0 && + verify_args_exist("-renameover", 2, ai, argc) || + strcmp(argv[ai], "-deleterename") == 0 && + verify_args_exist("-deleterename", 2, ai, argc) || + strcmp(argv[ai], "-move") == 0 && + verify_args_exist("-move", 2, ai, argc) || + strcmp(argv[ai], "-moveover") == 0 && + verify_args_exist("-moveover", 2, ai, argc) || + strcmp(argv[ai], "-deletemove") == 0 && + verify_args_exist("-deletemove", 2, ai, argc)) { + bool del = argv[ai][1] == 'd'; bool move = argv[ai][del ? 7 : 1] == 'm'; bool over = !del && argv[ai][move ? 5 : 7] == 'o'; if (del) executer.deletef(argv[ai + 2]); executer.rename(argv[ai + 1], argv[ai + 2], over, move); - ++++ai; + ++ ++ai; found_commands = true; - } - else if (strcmp(argv[ai], "-debug") == 0) { + } else if (strcmp(argv[ai], "-debug") == 0) { executer.debug(); - } - else { + } else { if (executer.file_output()) fprintf(executer.output(), "ERROR: invalid argument {%s}\n", argv[ai]); fprintf(stderr, "ERROR: invalid argument {%s}\n", argv[ai]); return 1; } - } - catch (const abort_invalid_argument&) { + } catch (const abort_invalid_argument&) { return 1; } -#if 1 // just a convient way to not catch exception when debugging - catch (const std::exception& e) - { +#if 1 // just a convient way to not catch exception when debugging + catch (const std::exception& e) { if (executer.file_output()) fprintf(executer.output(), "ERROR: %hs\n", e.what()); fprintf(stderr, "ERROR: %hs\n", e.what()); return 1; - } - catch (...) - { + } catch (...) { if (executer.file_output()) fprintf(executer.output(), "ERROR: unknown exception"); fprintf(stderr, "ERROR: unknown exception\n"); @@ -461,8 +487,10 @@ int main(int argc, char *argv[]) if (executer.cleanoutput()) fprintf(executer.output(), "#< %s ended properly.\n", exename.c_str()); else - fprintf(executer.output(), "#< %s ended properly in process %d.\n", exename.c_str(), GetCurrentProcessId()); - fprintf(stdout, "#< %s ended properly in process %d.\n", exename.c_str(), GetCurrentProcessId()); + fprintf(executer.output(), "#< %s ended properly in process %d.\n", + exename.c_str(), GetCurrentProcessId()); + fprintf(stdout, "#< %s ended properly in process %d.\n", exename.c_str(), + GetCurrentProcessId()); return 0; } diff --git a/test/usvfs_test_runner/test_file_operations/test_filesystem.cpp b/test/usvfs_test_runner/test_file_operations/test_filesystem.cpp index d584fbf..dcfd5a1 100644 --- a/test/usvfs_test_runner/test_file_operations/test_filesystem.cpp +++ b/test/usvfs_test_runner/test_file_operations/test_filesystem.cpp @@ -16,16 +16,14 @@ bool TestFileSystem::FileInformation::is_file() const return (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0; } -TestFileSystem::TestFileSystem(FILE* output) - : m_output(output) -{} +TestFileSystem::TestFileSystem(FILE* output) : m_output(output) {} TestFileSystem::path TestFileSystem::current_directory() { DWORD res = GetCurrentDirectoryW(0, NULL); if (!res) throw_testWinFuncFailed("GetCurrentDirectory", res); - std::wstring buf(res + 1,'\0'); + std::wstring buf(res + 1, '\0'); res = GetCurrentDirectoryW(buf.length(), &buf[0]); if (!res || res >= buf.length()) throw_testWinFuncFailed("GetCurrentDirectory", res); @@ -38,7 +36,7 @@ TestFileSystem::path TestFileSystem::relative_path(path full_path) return test::path_as_relative(m_basepath, full_path); } -//static +// static const char* TestFileSystem::write_operation_name(write_mode mode) { switch (mode) { @@ -58,8 +56,9 @@ const char* TestFileSystem::write_operation_name(write_mode mode) return "Unknown write operation?!"; } -//static -const char* TestFileSystem::rename_operation_name(bool replace_existing, bool allow_copy) +// static +const char* TestFileSystem::rename_operation_name(bool replace_existing, + bool allow_copy) { if (allow_copy) return replace_existing ? "Moving file over" : "Moving file"; @@ -70,16 +69,22 @@ const char* TestFileSystem::rename_operation_name(bool replace_existing, bool al void TestFileSystem::print_operation(const char* operation, const path& target) { if (m_output) - fprintf(m_output, "# (%s) %s {%s}\n", id(), operation, relative_path(target).string().c_str()); + fprintf(m_output, "# (%s) %s {%s}\n", id(), operation, + relative_path(target).string().c_str()); } -void TestFileSystem::print_operation(const char* operation, const path& source, const path& target) +void TestFileSystem::print_operation(const char* operation, const path& source, + const path& target) { if (m_output) - fprintf(m_output, "# (%s) %s {%s} {%s}\n", id(), operation, relative_path(source).string().c_str(), relative_path(target).string().c_str()); + fprintf(m_output, "# (%s) %s {%s} {%s}\n", id(), operation, + relative_path(source).string().c_str(), + relative_path(target).string().c_str()); } -static inline void print_op_with_result(FILE* output, const char* prefix, const char* operation, const uint32_t* result, DWORD* last_error, const char* opt_arg) +static inline void print_op_with_result(FILE* output, const char* prefix, + const char* operation, const uint32_t* result, + DWORD* last_error, const char* opt_arg) { if (output) { fprintf(output, "%s%s", prefix, operation); @@ -93,33 +98,43 @@ static inline void print_op_with_result(FILE* output, const char* prefix, const } } -void TestFileSystem::print_result(const char* operation, uint32_t result, bool with_last_error, const char* opt_arg, bool hide_result) +void TestFileSystem::print_result(const char* operation, uint32_t result, + bool with_last_error, const char* opt_arg, + bool hide_result) { - if (m_output) - { - DWORD last_error = GetLastError(); - std::string prefix = "# ("; prefix += id(); prefix += ") "; - print_op_with_result(m_output, prefix.c_str(), operation, hide_result ? nullptr : &result, with_last_error ? &last_error : nullptr, opt_arg); + if (m_output) { + DWORD last_error = GetLastError(); + std::string prefix = "# ("; + prefix += id(); + prefix += ") "; + print_op_with_result(m_output, prefix.c_str(), operation, + hide_result ? nullptr : &result, + with_last_error ? &last_error : nullptr, opt_arg); SetLastError(last_error); } } -void TestFileSystem::print_error(const char* operation, uint32_t result, bool with_last_error, const char* opt_arg) +void TestFileSystem::print_error(const char* operation, uint32_t result, + bool with_last_error, const char* opt_arg) { DWORD last_error = with_last_error ? GetLastError() : 0; - print_op_with_result(stderr, "ERROR: ", operation, &result, with_last_error ? &last_error : nullptr, opt_arg); + print_op_with_result(stderr, "ERROR: ", operation, &result, + with_last_error ? &last_error : nullptr, opt_arg); if (m_output && m_output != stdout) - print_op_with_result(m_output, "ERROR: ", operation, &result, with_last_error ? &last_error : nullptr, opt_arg); + print_op_with_result(m_output, "ERROR: ", operation, &result, + with_last_error ? &last_error : nullptr, opt_arg); } -void TestFileSystem::print_write_success(const void* data, std::size_t size, std::size_t written) +void TestFileSystem::print_write_success(const void* data, std::size_t size, + std::size_t written) { - if (m_output) - { - fprintf(m_output, "# Successfully written %u bytes ", static_cast(written)); + if (m_output) { + fprintf(m_output, "# Successfully written %u bytes ", + static_cast(written)); // heuristics to print nicer one liners: - if (size == 1 && reinterpret_cast(data)[0] == '\n' - || size == 2 && reinterpret_cast(data)[0] == '\r' && reinterpret_cast(data)[1] == '\n') + if (size == 1 && reinterpret_cast(data)[0] == '\n' || + size == 2 && reinterpret_cast(data)[0] == '\r' && + reinterpret_cast(data)[1] == '\n') fprintf(m_output, ""); else { fprintf(m_output, "{"); diff --git a/test/usvfs_test_runner/test_file_operations/test_filesystem.h b/test/usvfs_test_runner/test_file_operations/test_filesystem.h index 0d8e4e4..3a5f53b 100644 --- a/test/usvfs_test_runner/test_file_operations/test_filesystem.h +++ b/test/usvfs_test_runner/test_file_operations/test_filesystem.h @@ -1,9 +1,9 @@ #pragma once -#include -#include -#include #include +#include +#include +#include class TestFileSystem { @@ -17,9 +17,14 @@ public: TestFileSystem(FILE* output); - void set_output(FILE* output, bool clean) { m_output = output; m_cleanoutput = clean; } + void set_output(FILE* output, bool clean) + { + m_output = output; + m_cleanoutput = clean; + } - // base path used to trim outputs (which is important so we can compare tests ran at different base paths) + // base path used to trim outputs (which is important so we can compare tests ran at + // different base paths) void set_basepath(const char* path) { m_basepath = real_path(path); } // returns the path relative to the base path @@ -29,13 +34,14 @@ public: virtual path real_path(const char* abs_or_rel_path) = 0; - struct FileInformation { + struct FileInformation + { std::wstring name; uint32_t attributes; uint64_t size; FileInformation(const std::wstring& iname, uint32_t iattributes, uint64_t isize) - : name(iname), attributes(iattributes), size(isize) + : name(iname), attributes(iattributes), size(isize) {} bool is_dir() const; @@ -49,28 +55,44 @@ public: virtual void read_file(const path& file_path) = 0; - enum class write_mode { manual_truncate, truncate, create, overwrite, opencreate, append }; - virtual void write_file(const path& file_path, const void* data, std::size_t size, bool add_new_line, write_mode mode, bool rw_access = false) = 0; + enum class write_mode + { + manual_truncate, + truncate, + create, + overwrite, + opencreate, + append + }; + virtual void write_file(const path& file_path, const void* data, std::size_t size, + bool add_new_line, write_mode mode, + bool rw_access = false) = 0; virtual void touch_file(const path& file_path, bool full_write_access = false) = 0; virtual void delete_file(const path& file_path) = 0; - virtual void copy_file(const path& source_path, const path& destination_path, bool replace_existing) = 0; + virtual void copy_file(const path& source_path, const path& destination_path, + bool replace_existing) = 0; - virtual void rename_file(const path& source_path, const path& destination_path, bool replace_existing, bool allow_copy) = 0; + virtual void rename_file(const path& source_path, const path& destination_path, + bool replace_existing, bool allow_copy) = 0; protected: FILE* output() { return m_output; } - bool cleanoutput() const { return m_cleanoutput; } + bool cleanoutput() const { return m_cleanoutput; } static const char* write_operation_name(write_mode mode); static const char* rename_operation_name(bool replace_existing, bool allow_copy); -public: // mainly for derived class (but also used by helper classes like SafeHandle so public) +public: // mainly for derived class (but also used by helper classes like SafeHandle so + // public) void print_operation(const char* operation, const path& target); void print_operation(const char* operation, const path& source, const path& target); - void print_result(const char* operation, uint32_t result, bool with_last_error = false, const char* opt_arg = nullptr, bool hide_result = false); - void print_error(const char* operation, uint32_t result, bool with_last_error = false, const char* opt_arg = nullptr); + void print_result(const char* operation, uint32_t result, + bool with_last_error = false, const char* opt_arg = nullptr, + bool hide_result = false); + void print_error(const char* operation, uint32_t result, bool with_last_error = false, + const char* opt_arg = nullptr); void print_write_success(const void* data, std::size_t size, std::size_t written); uint32_t clean_attributes(uint32_t attr); diff --git a/test/usvfs_test_runner/test_file_operations/test_ntapi.cpp b/test/usvfs_test_runner/test_file_operations/test_ntapi.cpp index 447c542..c9de9b2 100644 --- a/test/usvfs_test_runner/test_file_operations/test_ntapi.cpp +++ b/test/usvfs_test_runner/test_file_operations/test_ntapi.cpp @@ -1,29 +1,34 @@ #include "test_ntapi.h" -#include #include #include +#include #include #define WIN32_LEAN_AND_MEAN +#include "test_ntdll_declarations.h" #include #include -#include "test_ntdll_declarations.h" #include class TestNtApi::SafeHandle { public: - SafeHandle(TestFileSystem* tfs, HANDLE handle = NULL) : m_handle(handle), m_tfs(tfs) {} + SafeHandle(TestFileSystem* tfs, HANDLE handle = NULL) : m_handle(handle), m_tfs(tfs) + {} SafeHandle(const SafeHandle&) = delete; - SafeHandle(SafeHandle&& other) : m_handle(other.m_handle), m_tfs(other.m_tfs) { other.m_handle = nullptr; } + SafeHandle(SafeHandle&& other) : m_handle(other.m_handle), m_tfs(other.m_tfs) + { + other.m_handle = nullptr; + } operator HANDLE() { return m_handle; } operator PHANDLE() { return &m_handle; } bool valid() const { return m_handle != NULL; } - ~SafeHandle() { + ~SafeHandle() + { if (m_handle) { NTSTATUS status = NtClose(m_handle); if (m_tfs) @@ -52,17 +57,16 @@ TestNtApi::path TestNtApi::real_path(const char* abs_or_rel_path) if (!abs_or_rel_path || !abs_or_rel_path[0]) return path(); - static constexpr char nt_path_prefix[] = "\\??\\"; + static constexpr char nt_path_prefix[] = "\\??\\"; static constexpr wchar_t nt_path_prefix_w[] = L"\\??\\"; bool path_dos = strncmp(abs_or_rel_path, nt_path_prefix, strlen(nt_path_prefix)) == 0; bool path_has_drive = abs_or_rel_path[1] == ':'; - bool path_unc = abs_or_rel_path[0] == '\\' && abs_or_rel_path[1] == '\\'; - bool path_absolute = path_has_drive || abs_or_rel_path[0] == '\\'; + bool path_unc = abs_or_rel_path[0] == '\\' && abs_or_rel_path[1] == '\\'; + bool path_absolute = path_has_drive || abs_or_rel_path[0] == '\\'; path result; - if (!path_dos) - { + if (!path_dos) { if (!path_unc) result.assign(nt_path_prefix_w); if (!path_absolute) @@ -74,20 +78,20 @@ TestNtApi::path TestNtApi::real_path(const char* abs_or_rel_path) } int result_size = 0; - for (auto r : result) ++result_size; + for (auto r : result) + ++result_size; // now append abs_or_rel_path, handling ".." and "." properly: - path arp{ abs_or_rel_path }; + path arp{abs_or_rel_path}; int base_size = path_unc ? 3 : 4; - for (auto p : arp) - { + for (auto p : arp) { if (p == "..") { - if (result_size > base_size) { // refuse to remove top level element (i.e. \??\C:\ which is 4 elements) + if (result_size > base_size) { // refuse to remove top level element (i.e. + // \??\C:\ which is 4 elements) result.remove_filename(); --result_size; } - } - else if (!p.empty() && p != ".") { + } else if (!p.empty() && p != ".") { result /= p; ++result_size; } @@ -96,7 +100,8 @@ TestNtApi::path TestNtApi::real_path(const char* abs_or_rel_path) return result; } -TestNtApi::SafeHandle TestNtApi::open_directory(const path& directory_path, bool create, bool allow_non_existence, long* pstatus) +TestNtApi::SafeHandle TestNtApi::open_directory(const path& directory_path, bool create, + bool allow_non_existence, long* pstatus) { print_operation(create ? "Creating directory" : "Openning directory", directory_path); @@ -104,24 +109,24 @@ TestNtApi::SafeHandle TestNtApi::open_directory(const path& directory_path, bool RtlInitUnicodeString(&unicode_path, directory_path.c_str()); OBJECT_ATTRIBUTES attributes; - InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, NULL); + InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, + NULL); SafeHandle dir(this); IO_STATUS_BLOCK iosb; - NTSTATUS status = - NtCreateFile(dir, - FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE, - &attributes, &iosb, NULL, FILE_ATTRIBUTE_DIRECTORY, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NTSTATUS status = NtCreateFile( + dir, FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE, &attributes, &iosb, NULL, + FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, create ? FILE_OPEN_IF : FILE_OPEN, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, - NULL, 0); + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); print_result("NtCreateFile", status); if (pstatus) *pstatus = status; - if ((status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND) && allow_non_existence) + if ((status == STATUS_OBJECT_NAME_NOT_FOUND || + status == STATUS_OBJECT_PATH_NOT_FOUND) && + allow_non_existence) return NULL; if (!NT_SUCCESS(status)) throw test::FuncFailed("NtCreateFile", status); @@ -138,14 +143,13 @@ TestFileSystem::FileInfoList TestNtApi::list_directory(const path& directory_pat print_operation("Querying directory", directory_path); FileInfoList files; - while (true) - { - char buf[4096]{ 0 }; + while (true) { + char buf[4096]{0}; IO_STATUS_BLOCK iosb; NTSTATUS status = - NtQueryDirectoryFile(dir, NULL, NULL, NULL, - &iosb, buf, sizeof(buf), MyFileBothDirectoryInformation, FALSE, NULL, FALSE); + NtQueryDirectoryFile(dir, NULL, NULL, NULL, &iosb, buf, sizeof(buf), + MyFileBothDirectoryInformation, FALSE, NULL, FALSE); print_result("NtQueryDirectoryFile", status); if (status == STATUS_NO_MORE_FILES) @@ -154,17 +158,20 @@ TestFileSystem::FileInfoList TestNtApi::list_directory(const path& directory_pat throw test::FuncFailed("NtQueryDirectoryFile", status); if (!NT_SUCCESS(iosb.Status)) throw test::FuncFailed("NtQueryDirectoryFile", "bad iosb.Status", iosb.Status); - if (iosb.Information == 0) // This shouldn't happend unless the filename (not full path) is larger then sizeof(buf) - throw test::FuncFailed("NtQueryDirectoryFile", "buffer too small", iosb.Information); + if (iosb.Information == 0) // This shouldn't happend unless the filename (not full + // path) is larger then sizeof(buf) + throw test::FuncFailed("NtQueryDirectoryFile", "buffer too small", + iosb.Information); PFILE_BOTH_DIR_INFORMATION info = reinterpret_cast(buf); - while (true) - { + while (true) { files.push_back(FileInformation( - std::wstring(info->FileName, info->FileNameLength / sizeof(info->FileName[0])), - clean_attributes(info->FileAttributes), info->EndOfFile.QuadPart)); + std::wstring(info->FileName, + info->FileNameLength / sizeof(info->FileName[0])), + clean_attributes(info->FileAttributes), info->EndOfFile.QuadPart)); if (info->NextEntryOffset) - info = reinterpret_cast(reinterpret_cast(info) + info->NextEntryOffset); + info = reinterpret_cast( + reinterpret_cast(info) + info->NextEntryOffset); else break; } @@ -184,8 +191,10 @@ void TestNtApi::create_path(const path& directory_path) if (open_directory(directory_path, false, true, &status).valid()) return; - if (status != STATUS_OBJECT_NAME_NOT_FOUND) // STATUS_OBJECT_NAME_NOT_FOUND means parent directory already exists - create_path(directory_path.parent_path()); // otherwise create parent directory (recursively) + if (status != STATUS_OBJECT_NAME_NOT_FOUND) // STATUS_OBJECT_NAME_NOT_FOUND means + // parent directory already exists + create_path(directory_path + .parent_path()); // otherwise create parent directory (recursively) open_directory(directory_path, true); } @@ -198,12 +207,13 @@ void TestNtApi::read_file(const path& file_path) RtlInitUnicodeString(&unicode_path, file_path.c_str()); OBJECT_ATTRIBUTES attributes; - InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, NULL); + InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, + NULL); SafeHandle file(this); IO_STATUS_BLOCK iosb; - NTSTATUS status = - NtOpenFile(file, GENERIC_READ|SYNCHRONIZE, &attributes, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT); + NTSTATUS status = NtOpenFile(file, GENERIC_READ | SYNCHRONIZE, &attributes, &iosb, + FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT); print_result("NtOpenFile", status); if (!NT_SUCCESS(status)) @@ -211,9 +221,9 @@ void TestNtApi::read_file(const path& file_path) if (!NT_SUCCESS(iosb.Status)) throw test::FuncFailed("NtOpenFile", "bad iosb.Status", iosb.Status); - uint32_t total = 0; + uint32_t total = 0; bool ends_with_newline = true; - bool pending_prefix = true; + bool pending_prefix = true; while (true) { char buf[4096]; @@ -227,11 +237,12 @@ void TestNtApi::read_file(const path& file_path) total += iosb.Information; char* begin = buf; - char* end = begin + iosb.Information; + char* end = begin + iosb.Information; while (begin != end) { if (pending_prefix) { if (output()) - fwrite(FILE_CONTENTS_PRINT_PREFIX, 1, strlen(FILE_CONTENTS_PRINT_PREFIX), output()); + fwrite(FILE_CONTENTS_PRINT_PREFIX, 1, strlen(FILE_CONTENTS_PRINT_PREFIX), + output()); pending_prefix = false; } bool skip_newline = false; @@ -241,12 +252,10 @@ void TestNtApi::read_file(const path& file_path) if (print_end > begin && *(print_end - 1) == '\r') { // convert \r\n => \n: *(print_end - 1) = '\n'; - skip_newline = true; - } - else // only a '\n' so just print it + skip_newline = true; + } else // only a '\n' so just print it ++print_end; - } - else { + } else { print_end = end; if (print_end > begin && *(print_end - 1) == '\r') { // buffer ends with \r so skip it under the hope it will be followed with a \n @@ -257,7 +266,7 @@ void TestNtApi::read_file(const path& file_path) if (output()) fwrite(begin, 1, print_end - begin, output()); ends_with_newline = print_end > begin && *(print_end - 1) == '\n'; - begin = print_end; + begin = print_end; if (skip_newline) ++begin; } @@ -266,13 +275,13 @@ void TestNtApi::read_file(const path& file_path) ends_with_newline = true; } } - if (output()) - { + if (output()) { fprintf(output(), "# Successfully read %u bytes.\n", total); } } -void TestNtApi::write_file(const path& file_path, const void* data, std::size_t size, bool add_new_line, write_mode mode, bool rw_access) +void TestNtApi::write_file(const path& file_path, const void* data, std::size_t size, + bool add_new_line, write_mode mode, bool rw_access) { print_operation(write_operation_name(mode), file_path); @@ -280,10 +289,11 @@ void TestNtApi::write_file(const path& file_path, const void* data, std::size_t RtlInitUnicodeString(&unicode_path, file_path.c_str()); OBJECT_ATTRIBUTES attributes; - InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, NULL); + InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, + NULL); ACCESS_MASK access = GENERIC_WRITE | SYNCHRONIZE; - ULONG disposition = FILE_OPEN; + ULONG disposition = FILE_OPEN; switch (mode) { case write_mode::truncate: disposition = FILE_OVERWRITE; @@ -299,7 +309,7 @@ void TestNtApi::write_file(const path& file_path, const void* data, std::size_t break; case write_mode::append: disposition = FILE_OPEN_IF; - access = FILE_APPEND_DATA | SYNCHRONIZE; + access = FILE_APPEND_DATA | SYNCHRONIZE; break; } if (rw_access) @@ -308,9 +318,8 @@ void TestNtApi::write_file(const path& file_path, const void* data, std::size_t SafeHandle file(this); IO_STATUS_BLOCK iosb; NTSTATUS status = - NtCreateFile( - file, access, &attributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, 0, - disposition, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + NtCreateFile(file, access, &attributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, 0, + disposition, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); print_result("NtCreateFile", status); if (!NT_SUCCESS(status)) @@ -318,11 +327,10 @@ void TestNtApi::write_file(const path& file_path, const void* data, std::size_t if (!NT_SUCCESS(iosb.Status)) throw test::FuncFailed("NtCreateFile", "bad iosb.Status", iosb.Status); - if (mode == write_mode::manual_truncate) - { - FILE_END_OF_FILE_INFORMATION eofinfo{ 0 }; - status = - NtSetInformationFile(file, &iosb, &eofinfo, sizeof(eofinfo), MyFileEndOfFileInformation); + if (mode == write_mode::manual_truncate) { + FILE_END_OF_FILE_INFORMATION eofinfo{0}; + status = NtSetInformationFile(file, &iosb, &eofinfo, sizeof(eofinfo), + MyFileEndOfFileInformation); print_result("NtSetInformationFile", status, false, "EOF"); if (!NT_SUCCESS(status)) @@ -334,10 +342,9 @@ void TestNtApi::write_file(const path& file_path, const void* data, std::size_t // finally write the data: size_t total = 0; - if (data) - { - status = - NtWriteFile(file, NULL, NULL, NULL, &iosb, const_cast(data), static_cast(size), NULL, NULL); + if (data) { + status = NtWriteFile(file, NULL, NULL, NULL, &iosb, const_cast(data), + static_cast(size), NULL, NULL); print_result("NtWriteFile", status); if (!NT_SUCCESS(status)) throw test::FuncFailed("NtWriteFile", status); @@ -345,11 +352,9 @@ void TestNtApi::write_file(const path& file_path, const void* data, std::size_t throw test::FuncFailed("NtWriteFile", "bad iosb.Status", iosb.Status); total += iosb.Information; - if (add_new_line) - { + if (add_new_line) { char buffer[] = "\r\n"; - status = - NtWriteFile(file, NULL, NULL, NULL, &iosb, buffer, 2, NULL, NULL); + status = NtWriteFile(file, NULL, NULL, NULL, &iosb, buffer, 2, NULL, NULL); print_result("NtWriteFile", status); if (!NT_SUCCESS(status)) throw test::FuncFailed("NtWriteFile", status); @@ -376,16 +381,17 @@ void TestNtApi::touch_file(const path& file_path, bool full_write_access) RtlInitUnicodeString(&unicode_path, file_path.c_str()); OBJECT_ATTRIBUTES attributes; - InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, NULL); + InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, + NULL); SafeHandle file(this); IO_STATUS_BLOCK iosb; auto share_all = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - auto access = (full_write_access ? GENERIC_WRITE : FILE_WRITE_ATTRIBUTES) | SYNCHRONIZE; + auto access = + (full_write_access ? GENERIC_WRITE : FILE_WRITE_ATTRIBUTES) | SYNCHRONIZE; NTSTATUS status = - NtCreateFile( - file, access, &attributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, share_all, - FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + NtCreateFile(file, access, &attributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, + share_all, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); print_result("NtCreateFile", status); if (!NT_SUCCESS(status)) @@ -393,11 +399,11 @@ void TestNtApi::touch_file(const path& file_path, bool full_write_access) if (!NT_SUCCESS(iosb.Status)) throw test::FuncFailed("NtCreateFile", "bad iosb.Status", iosb.Status); - FILE_BASIC_INFORMATION basicinfo{ 0 }; - basicinfo.LastWriteTime.LowPart = ft.dwLowDateTime; + FILE_BASIC_INFORMATION basicinfo{0}; + basicinfo.LastWriteTime.LowPart = ft.dwLowDateTime; basicinfo.LastWriteTime.HighPart = ft.dwHighDateTime; - status = - NtSetInformationFile(file, &iosb, &basicinfo, sizeof(basicinfo), MyFileBasicInformation); + status = NtSetInformationFile(file, &iosb, &basicinfo, sizeof(basicinfo), + MyFileBasicInformation); print_result("NtSetInformationFile", status, false, "Basic"); if (!NT_SUCCESS(status)) @@ -414,41 +420,44 @@ void TestNtApi::delete_file(const path& file_path) RtlInitUnicodeString(&unicode_path, file_path.c_str()); OBJECT_ATTRIBUTES attributes; - InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, NULL); + InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, + NULL); - NTSTATUS status = - NtDeleteFile(&attributes); + NTSTATUS status = NtDeleteFile(&attributes); print_result("NtCreateFile", status); if (!NT_SUCCESS(status)) throw test::FuncFailed("NtDeleteFile", status); } -void TestNtApi::copy_file(const path& source_path, const path& destination_path, bool replace_existing) +void TestNtApi::copy_file(const path& source_path, const path& destination_path, + bool replace_existing) { throw test::FuncFailed("copy_file", "ntapi does not support file copy"); } -void TestNtApi::rename_file(const path& source_path, const path& destination_path, bool replace_existing, bool allow_copy) +void TestNtApi::rename_file(const path& source_path, const path& destination_path, + bool replace_existing, bool allow_copy) { if (allow_copy) throw test::FuncFailed("rename_file", "ntapi does not support file move"); - print_operation(rename_operation_name(replace_existing, allow_copy), source_path, destination_path); + print_operation(rename_operation_name(replace_existing, allow_copy), source_path, + destination_path); UNICODE_STRING unicode_path; RtlInitUnicodeString(&unicode_path, source_path.c_str()); OBJECT_ATTRIBUTES attributes; - InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, NULL); + InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, + NULL); SafeHandle file(this); IO_STATUS_BLOCK iosb; - NTSTATUS status = - NtCreateFile( - file, FILE_READ_ATTRIBUTES|DELETE|SYNCHRONIZE, &attributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + NTSTATUS status = NtCreateFile(file, FILE_READ_ATTRIBUTES | DELETE | SYNCHRONIZE, + &attributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); print_result("NtCreateFile", status); if (!NT_SUCCESS(status)) @@ -457,16 +466,19 @@ void TestNtApi::rename_file(const path& source_path, const path& destination_pat throw test::FuncFailed("NtCreateFile", "bad iosb.Status", iosb.Status); bool dest_full_path = source_path.parent_path() != destination_path.parent_path(); - std::wstring dest = dest_full_path ? destination_path : destination_path.filename(); - std::vector buf(sizeof(FILE_RENAME_INFORMATION) + sizeof(wchar_t)*dest.length()); - FILE_RENAME_INFORMATION* rename = reinterpret_cast(buf.data()); + std::wstring dest = dest_full_path ? destination_path : destination_path.filename(); + std::vector buf(sizeof(FILE_RENAME_INFORMATION) + + sizeof(wchar_t) * dest.length()); + FILE_RENAME_INFORMATION* rename = + reinterpret_cast(buf.data()); rename->ReplaceIfExists = replace_existing ? TRUE : FALSE; - rename->FileNameLength = sizeof(wchar_t)*dest.length(); - memcpy(&rename->FileName[0], dest.data(), sizeof(wchar_t)*dest.length()); + rename->FileNameLength = sizeof(wchar_t) * dest.length(); + memcpy(&rename->FileName[0], dest.data(), sizeof(wchar_t) * dest.length()); status = - NtSetInformationFile(file, &iosb, rename, buf.size(), MyFileRenameInformation); - print_result("NtSetInformationFile", status, false, dest_full_path ? "rename full path" : "rename filename"); + NtSetInformationFile(file, &iosb, rename, buf.size(), MyFileRenameInformation); + print_result("NtSetInformationFile", status, false, + dest_full_path ? "rename full path" : "rename filename"); if (!NT_SUCCESS(status)) throw test::FuncFailed("NtSetInformationFile", status); diff --git a/test/usvfs_test_runner/test_file_operations/test_ntapi.h b/test/usvfs_test_runner/test_file_operations/test_ntapi.h index 4581b0b..fc6434e 100644 --- a/test/usvfs_test_runner/test_file_operations/test_ntapi.h +++ b/test/usvfs_test_runner/test_file_operations/test_ntapi.h @@ -15,20 +15,24 @@ public: void read_file(const path& file_path) override; - void write_file(const path& file_path, const void* data, std::size_t size, bool add_new_line, write_mode mode, bool rw_access = false) override; + void write_file(const path& file_path, const void* data, std::size_t size, + bool add_new_line, write_mode mode, bool rw_access = false) override; void touch_file(const path& file_path, bool full_write_access = false) override; void delete_file(const path& file_path) override; - void copy_file(const path& source_path, const path& destination_path, bool replace_existing) override; + void copy_file(const path& source_path, const path& destination_path, + bool replace_existing) override; - void rename_file(const path& source_path, const path& destination_path, bool replace_existing, bool allow_copy) override; + void rename_file(const path& source_path, const path& destination_path, + bool replace_existing, bool allow_copy) override; const char* id() override; private: class SafeHandle; - SafeHandle open_directory(const path& directory_path, bool create, bool allow_non_existence=false, long* pstatus=nullptr); + SafeHandle open_directory(const path& directory_path, bool create, + bool allow_non_existence = false, long* pstatus = nullptr); }; diff --git a/test/usvfs_test_runner/test_file_operations/test_ntdll_declarations.h b/test/usvfs_test_runner/test_file_operations/test_ntdll_declarations.h index 2c44d05..e3799ac 100644 --- a/test/usvfs_test_runner/test_file_operations/test_ntdll_declarations.h +++ b/test/usvfs_test_runner/test_file_operations/test_ntdll_declarations.h @@ -1,26 +1,28 @@ #pragma once -#define STATUS_NO_MORE_FILES 0x80000006 -#define STATUS_END_OF_FILE 0xC0000011 -#define STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034 -#define STATUS_OBJECT_PATH_NOT_FOUND 0xC000003A +#define STATUS_NO_MORE_FILES 0x80000006 +#define STATUS_END_OF_FILE 0xC0000011 +#define STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034 +#define STATUS_OBJECT_PATH_NOT_FOUND 0xC000003A -#define FILE_WRITE_TO_END_OF_FILE 0xffffffff +#define FILE_WRITE_TO_END_OF_FILE 0xffffffff #define FILE_USE_FILE_POINTER_POSITION 0xfffffffe -#define InitializeObjectAttributes( p, n, a, r, s ) { \ - (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \ - (p)->RootDirectory = r; \ - (p)->Attributes = a; \ - (p)->ObjectName = n; \ - (p)->SecurityDescriptor = s; \ - (p)->SecurityQualityOfService = NULL; \ - } +#define InitializeObjectAttributes(p, n, a, r, s) \ + { \ + (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = n; \ + (p)->SecurityDescriptor = s; \ + (p)->SecurityQualityOfService = NULL; \ + } // winternl.h of course defines a joke FILE_INFORMATION_CLASS (why?!) // so added MY_ to avoid name collision but this is FILE_INFORMATION_CLASS -typedef enum _MY_FILE_INFORMATION_CLASS { +typedef enum _MY_FILE_INFORMATION_CLASS +{ MyFileDirectoryInformation = 1, MyFileFullDirectoryInformation, MyFileBothDirectoryInformation, @@ -88,9 +90,11 @@ typedef enum _MY_FILE_INFORMATION_CLASS { MyFileRenameInformationEx, MyFileRenameInformationExBypassAccessCheck, MyFileMaximumInformation -} MY_FILE_INFORMATION_CLASS, *PMY_FILE_INFORMATION_CLASS; +} MY_FILE_INFORMATION_CLASS, + *PMY_FILE_INFORMATION_CLASS; -typedef struct _FILE_BOTH_DIR_INFORMATION { +typedef struct _FILE_BOTH_DIR_INFORMATION +{ ULONG NextEntryOffset; ULONG FileIndex; LARGE_INTEGER CreationTime; @@ -107,86 +111,47 @@ typedef struct _FILE_BOTH_DIR_INFORMATION { WCHAR FileName[1]; } FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; -typedef struct _FILE_BASIC_INFORMATION { +typedef struct _FILE_BASIC_INFORMATION +{ LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; - ULONG FileAttributes; + ULONG FileAttributes; } FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; -typedef struct _FILE_END_OF_FILE_INFORMATION { +typedef struct _FILE_END_OF_FILE_INFORMATION +{ LARGE_INTEGER EndOfFile; } FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; -typedef struct _FILE_RENAME_INFORMATION { +typedef struct _FILE_RENAME_INFORMATION +{ BOOLEAN ReplaceIfExists; - HANDLE RootDirectory; - ULONG FileNameLength; - WCHAR FileName[1]; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; } FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION; -extern "C" -__kernel_entry NTSTATUS -NTAPI -NtQueryDirectoryFile( - IN HANDLE FileHandle, - IN HANDLE Event, - IN PIO_APC_ROUTINE ApcRoutine, - IN PVOID ApcContext, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID FileInformation, - IN ULONG Length, - IN MY_FILE_INFORMATION_CLASS FileInformationClass, - IN BOOLEAN ReturnSingleEntry, - IN PUNICODE_STRING FileName, - IN BOOLEAN RestartScan -); +extern "C" __kernel_entry NTSTATUS NTAPI NtQueryDirectoryFile( + IN HANDLE FileHandle, IN HANDLE Event, IN PIO_APC_ROUTINE ApcRoutine, + IN PVOID ApcContext, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, + IN ULONG Length, IN MY_FILE_INFORMATION_CLASS FileInformationClass, + IN BOOLEAN ReturnSingleEntry, IN PUNICODE_STRING FileName, IN BOOLEAN RestartScan); -extern "C" -__kernel_entry NTSTATUS -NTAPI -NtReadFile( - IN HANDLE FileHandle, - IN HANDLE Event, - IN PIO_APC_ROUTINE ApcRoutine, - IN PVOID ApcContext, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID Buffer, - IN ULONG Length, - IN PLARGE_INTEGER ByteOffset, - IN PULONG Key -); +extern "C" __kernel_entry NTSTATUS NTAPI +NtReadFile(IN HANDLE FileHandle, IN HANDLE Event, IN PIO_APC_ROUTINE ApcRoutine, + IN PVOID ApcContext, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID Buffer, + IN ULONG Length, IN PLARGE_INTEGER ByteOffset, IN PULONG Key); -extern "C" -__kernel_entry NTSTATUS -NTAPI -NtWriteFile( - IN HANDLE FileHandle, - IN HANDLE Event, - IN PIO_APC_ROUTINE ApcRoutine, - IN PVOID ApcContext, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PVOID Buffer, - IN ULONG Length, - IN PLARGE_INTEGER ByteOffset, - IN PULONG Key -); +extern "C" __kernel_entry NTSTATUS NTAPI +NtWriteFile(IN HANDLE FileHandle, IN HANDLE Event, IN PIO_APC_ROUTINE ApcRoutine, + IN PVOID ApcContext, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID Buffer, + IN ULONG Length, IN PLARGE_INTEGER ByteOffset, IN PULONG Key); -extern "C" -__kernel_entry NTSTATUS -NTAPI -NtSetInformationFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PVOID FileInformation, - IN ULONG Length, - IN MY_FILE_INFORMATION_CLASS FileInformationClass -); +extern "C" __kernel_entry NTSTATUS NTAPI NtSetInformationFile( + IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID FileInformation, + IN ULONG Length, IN MY_FILE_INFORMATION_CLASS FileInformationClass); -extern "C" -__kernel_entry NTSTATUS -NTAPI -NtDeleteFile( - IN POBJECT_ATTRIBUTES ObjectAttributes -); +extern "C" __kernel_entry NTSTATUS NTAPI +NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes); diff --git a/test/usvfs_test_runner/test_file_operations/test_w32api.cpp b/test/usvfs_test_runner/test_file_operations/test_w32api.cpp index 7aa53b8..372a6f3 100644 --- a/test/usvfs_test_runner/test_file_operations/test_w32api.cpp +++ b/test/usvfs_test_runner/test_file_operations/test_w32api.cpp @@ -1,8 +1,8 @@ #include "test_w32api.h" -#include #include #include +#include #define WIN32_LEAN_AND_MEAN #include @@ -12,17 +12,25 @@ using test::throw_testWinFuncFailed; class TestW32Api::SafeHandle { public: - SafeHandle(TestFileSystem* tfs, HANDLE handle = NULL) : m_handle(handle), m_tfs(tfs) {} + SafeHandle(TestFileSystem* tfs, HANDLE handle = NULL) : m_handle(handle), m_tfs(tfs) + {} SafeHandle(const SafeHandle&) = delete; - SafeHandle(SafeHandle&& other) : m_handle(other.m_handle), m_tfs(other.m_tfs) { other.m_handle = nullptr; } + SafeHandle(SafeHandle&& other) : m_handle(other.m_handle), m_tfs(other.m_tfs) + { + other.m_handle = nullptr; + } operator HANDLE() { return m_handle; } operator PHANDLE() { return &m_handle; } - uint32_t result_for_print() { return static_cast(reinterpret_cast(m_handle)); } + uint32_t result_for_print() + { + return static_cast(reinterpret_cast(m_handle)); + } bool valid() const { return m_handle != INVALID_HANDLE_VALUE; } - ~SafeHandle() { + ~SafeHandle() + { if (m_handle != INVALID_HANDLE_VALUE) { BOOL res = CloseHandle(m_handle); if (m_tfs) @@ -44,17 +52,26 @@ private: class TestW32Api::SafeFindHandle { public: - SafeFindHandle(TestFileSystem* tfs, HANDLE handle = NULL) : m_handle(handle), m_tfs(tfs) {} + SafeFindHandle(TestFileSystem* tfs, HANDLE handle = NULL) + : m_handle(handle), m_tfs(tfs) + {} SafeFindHandle(const SafeFindHandle&) = delete; - SafeFindHandle(SafeFindHandle&& other) : m_handle(other.m_handle), m_tfs(other.m_tfs) { other.m_handle = nullptr; } + SafeFindHandle(SafeFindHandle&& other) : m_handle(other.m_handle), m_tfs(other.m_tfs) + { + other.m_handle = nullptr; + } operator HANDLE() { return m_handle; } operator PHANDLE() { return &m_handle; } - uint32_t result_for_print() { return static_cast(reinterpret_cast(m_handle)); } + uint32_t result_for_print() + { + return static_cast(reinterpret_cast(m_handle)); + } bool valid() const { return m_handle != INVALID_HANDLE_VALUE; } - ~SafeFindHandle() { + ~SafeFindHandle() + { if (m_handle != INVALID_HANDLE_VALUE) { BOOL res = FindClose(m_handle); if (m_tfs) @@ -95,16 +112,16 @@ TestFileSystem::FileInfoList TestW32Api::list_directory(const path& directory_pa print_operation("Querying directory", directory_path); WIN32_FIND_DATA fd; - SafeFindHandle find(this, - FindFirstFileW((directory_path / L"*").c_str(), &fd)); + SafeFindHandle find(this, FindFirstFileW((directory_path / L"*").c_str(), &fd)); print_result("FindFirstFileW", 0, true, nullptr, true); if (!find.valid()) throw_testWinFuncFailed("FindFirstFileW"); FileInfoList files; - while (true) - { - files.push_back(FileInformation(fd.cFileName, clean_attributes(fd.dwFileAttributes), fd.nFileSizeHigh*(MAXDWORD + 1) + fd.nFileSizeLow)); + while (true) { + files.push_back( + FileInformation(fd.cFileName, clean_attributes(fd.dwFileAttributes), + fd.nFileSizeHigh * (MAXDWORD + 1) + fd.nFileSizeLow)); BOOL res = FindNextFileW(find, &fd); print_result("FindNextFileW", res, true); if (!res) @@ -123,19 +140,21 @@ void TestW32Api::create_path(const path& directory_path) print_operation("Checking directory", directory_path); DWORD attr = GetFileAttributesW(directory_path.c_str()); - DWORD err = GetLastError(); + DWORD err = GetLastError(); print_result("GetFileAttributesW", clean_attributes(attr), true); if (attr != INVALID_FILE_ATTRIBUTES) { if (attr & FILE_ATTRIBUTE_DIRECTORY) - return; // if directory already exists all is good + return; // if directory already exists all is good else throw std::runtime_error("path exists but not a directory"); } if (err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND) throw_testWinFuncFailed("GetFileAttributesW"); - if (err != ERROR_FILE_NOT_FOUND) // ERROR_FILE_NOT_FOUND means parent directory already exists - create_path(directory_path.parent_path()); // otherwise create parent directory (recursively) + if (err != ERROR_FILE_NOT_FOUND) // ERROR_FILE_NOT_FOUND means parent directory + // already exists + create_path(directory_path + .parent_path()); // otherwise create parent directory (recursively) print_operation("Creating directory", directory_path); @@ -149,48 +168,47 @@ void TestW32Api::read_file(const path& file_path) { print_operation("Reading file", file_path); - SafeHandle file(this, - CreateFileW(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); + SafeHandle file(this, CreateFileW(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); print_result("CreateFileW", 0, true, nullptr, true); if (!file.valid()) throw_testWinFuncFailed("CreateFileW"); - uint32_t total = 0; + uint32_t total = 0; bool ends_with_newline = true; - bool pending_prefix = true; - while (true) { + bool pending_prefix = true; + while (true) { char buf[4096]; DWORD read = 0; - BOOL res = ReadFile(file, buf, sizeof(buf), &read, NULL); + BOOL res = ReadFile(file, buf, sizeof(buf), &read, NULL); print_result("ReadFile", res, true); if (!res) throw_testWinFuncFailed("ReadFile"); - if (!read) // eof + if (!read) // eof break; total += read; char* begin = buf; - char* end = begin + read; + char* end = begin + read; while (begin != end) { if (pending_prefix) { if (output()) - fwrite(FILE_CONTENTS_PRINT_PREFIX, 1, strlen(FILE_CONTENTS_PRINT_PREFIX), output()); + fwrite(FILE_CONTENTS_PRINT_PREFIX, 1, strlen(FILE_CONTENTS_PRINT_PREFIX), + output()); pending_prefix = false; } bool skip_newline = false; char* print_end = reinterpret_cast(std::memchr(begin, '\n', end - begin)); if (print_end) { pending_prefix = true; - if (print_end > begin && *(print_end-1) == '\r') { + if (print_end > begin && *(print_end - 1) == '\r') { // convert \r\n => \n: - *(print_end-1) = '\n'; - skip_newline = true; - } - else // only a '\n' so just print it + *(print_end - 1) = '\n'; + skip_newline = true; + } else // only a '\n' so just print it ++print_end; - } - else { + } else { print_end = end; if (print_end > begin && *(print_end - 1) == '\r') { // buffer ends with \r so skip it under the hope it will be followed with a \n @@ -201,7 +219,7 @@ void TestW32Api::read_file(const path& file_path) if (output()) fwrite(begin, 1, print_end - begin, output()); ends_with_newline = print_end > begin && *(print_end - 1) == '\n'; - begin = print_end; + begin = print_end; if (skip_newline) ++begin; } @@ -210,18 +228,18 @@ void TestW32Api::read_file(const path& file_path) ends_with_newline = true; } } - if (output()) - { + if (output()) { fprintf(output(), "# Successfully read %u bytes.\n", total); } } -void TestW32Api::write_file(const path& file_path, const void* data, std::size_t size, bool add_new_line, write_mode mode, bool rw_access) +void TestW32Api::write_file(const path& file_path, const void* data, std::size_t size, + bool add_new_line, write_mode mode, bool rw_access) { print_operation(write_operation_name(mode), file_path); ACCESS_MASK access = GENERIC_WRITE; - DWORD disposition = OPEN_EXISTING; + DWORD disposition = OPEN_EXISTING; switch (mode) { case write_mode::truncate: disposition = TRUNCATE_EXISTING; @@ -237,28 +255,26 @@ void TestW32Api::write_file(const path& file_path, const void* data, std::size_t break; case write_mode::append: disposition = OPEN_ALWAYS; - access = FILE_APPEND_DATA; + access = FILE_APPEND_DATA; break; } if (rw_access) access |= GENERIC_READ; - SafeHandle file(this, - CreateFile(file_path.c_str(), access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL)); + SafeHandle file(this, CreateFile(file_path.c_str(), access, 0, NULL, disposition, + FILE_ATTRIBUTE_NORMAL, NULL)); print_result("CreateFileW", 0, true, nullptr, true); if (!file.valid()) throw_testWinFuncFailed("CreateFile"); - if (mode == write_mode::manual_truncate) - { + if (mode == write_mode::manual_truncate) { BOOL res = SetEndOfFile(file); print_result("SetEndOfFile", res, true); if (!res) throw_testWinFuncFailed("SetEndOfFile"); } - if (mode == write_mode::append) - { + if (mode == write_mode::append) { DWORD res = SetFilePointer(file, 0, NULL, FILE_END); print_result("SetFilePointer(FILE_END)", res, true); if (res == INVALID_SET_FILE_POINTER) @@ -267,11 +283,10 @@ void TestW32Api::write_file(const path& file_path, const void* data, std::size_t size_t total = 0; - if (data) - { + if (data) { // finally write the data: DWORD written = 0; - BOOL res = WriteFile(file, data, static_cast(size), &written, NULL); + BOOL res = WriteFile(file, data, static_cast(size), &written, NULL); print_result("WriteFile", written, true); if (!res) throw_testWinFuncFailed("WriteFile"); @@ -300,9 +315,9 @@ void TestW32Api::touch_file(const path& file_path, bool full_write_access) throw_testWinFuncFailed("SystemTimeToFileTime"); auto share_all = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - auto access = full_write_access ? GENERIC_WRITE : FILE_WRITE_ATTRIBUTES; - SafeHandle file(this, - CreateFile(file_path.c_str(), access, share_all, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); + auto access = full_write_access ? GENERIC_WRITE : FILE_WRITE_ATTRIBUTES; + SafeHandle file(this, CreateFile(file_path.c_str(), access, share_all, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); print_result("CreateFileW", 0, true, nullptr, true); if (!file.valid()) throw_testWinFuncFailed("CreateFile"); @@ -313,7 +328,6 @@ void TestW32Api::touch_file(const path& file_path, bool full_write_access) throw_testWinFuncFailed("SetFileTime"); } - void TestW32Api::delete_file(const path& file_path) { print_operation("Deleting file", file_path); @@ -324,19 +338,24 @@ void TestW32Api::delete_file(const path& file_path) throw_testWinFuncFailed("DeleteFileW"); } -void TestW32Api::copy_file(const path& source_path, const path& destination_path, bool replace_existing) +void TestW32Api::copy_file(const path& source_path, const path& destination_path, + bool replace_existing) { - print_operation(replace_existing ? "Copy file over" : "Copy file", source_path, destination_path); + print_operation(replace_existing ? "Copy file over" : "Copy file", source_path, + destination_path); - BOOL res = CopyFileW(source_path.c_str(), destination_path.c_str(), !replace_existing); + BOOL res = + CopyFileW(source_path.c_str(), destination_path.c_str(), !replace_existing); print_result("CopyFileW", res, true); if (!res) throw_testWinFuncFailed("CopyFileW"); } -void TestW32Api::rename_file(const path& source_path, const path& destination_path, bool replace_existing, bool allow_copy) +void TestW32Api::rename_file(const path& source_path, const path& destination_path, + bool replace_existing, bool allow_copy) { - print_operation(rename_operation_name(replace_existing, allow_copy), source_path, destination_path); + print_operation(rename_operation_name(replace_existing, allow_copy), source_path, + destination_path); DWORD flags = 0; if (replace_existing) diff --git a/test/usvfs_test_runner/test_file_operations/test_w32api.h b/test/usvfs_test_runner/test_file_operations/test_w32api.h index 85bdfa2..cab8e54 100644 --- a/test/usvfs_test_runner/test_file_operations/test_w32api.h +++ b/test/usvfs_test_runner/test_file_operations/test_w32api.h @@ -15,15 +15,18 @@ public: void read_file(const path& file_path) override; - void write_file(const path& file_path, const void* data, std::size_t size, bool add_new_line, write_mode mode, bool rw_access = false) override; + void write_file(const path& file_path, const void* data, std::size_t size, + bool add_new_line, write_mode mode, bool rw_access = false) override; void touch_file(const path& file_path, bool full_write_access = false) override; void delete_file(const path& file_path) override; - void copy_file(const path& source_path, const path& destination_path, bool replace_existing) override; + void copy_file(const path& source_path, const path& destination_path, + bool replace_existing) override; - void rename_file(const path& source_path, const path& destination_path, bool replace_existing, bool allow_copy) override; + void rename_file(const path& source_path, const path& destination_path, + bool replace_existing, bool allow_copy) override; const char* id() override; diff --git a/test/usvfs_test_runner/usvfs_test/usvfs_basic_test.cpp b/test/usvfs_test_runner/usvfs_test/usvfs_basic_test.cpp index 186e941..c5fb3a1 100644 --- a/test/usvfs_test_runner/usvfs_test/usvfs_basic_test.cpp +++ b/test/usvfs_test_runner/usvfs_test/usvfs_basic_test.cpp @@ -7,19 +7,22 @@ const char* usvfs_basic_test::scenario_name() bool usvfs_basic_test::scenario_run() { - // Note: For regression purposes we don't really need to verify the results of most our operations - // as the usvfs_test_base postmortem_check will verify the final state. + // Note: For regression purposes we don't really need to verify the results of most + // our operations as the usvfs_test_base postmortem_check will verify the final state. // We still also verify the results here because: // A. In some cases a later step may change the results. - // B. It is easier to understand and maintain the test when the important checks are together with + // B. It is easier to understand and maintain the test when the important checks are + // together with // their related operations. - // C. For open issues the verifications here serve as a "documentation" of the issue (i.e. not having + // C. For open issues the verifications here serve as a "documentation" of the issue + // (i.e. not having // proper copy_on_write, etc.). // Cases not covered by the test: - // - When a "temporary" virtualized directory is created (meaning the directory is created only to "shadow" - // a real directory) and is then emptied. This needs to be tested within the same prcoess and across - // different processes. + // - When a "temporary" virtualized directory is created (meaning the directory is + // created only to "shadow" + // a real directory) and is then emptied. This needs to be tested within the same + // prcoess and across different processes. ops_list(LR"(.)", true, true); @@ -30,45 +33,69 @@ bool usvfs_basic_test::scenario_run() verify_source_existance(LR"(overwrite\mfolder3)", false); verify_source_existance(LR"(overwrite\mfolder4)", false); - ops_overwrite(LR"(mfolder1\newfolder1\newfile1.txt)", R"(newfile1.txt nonrecursive overwrite subfolder)", false); + ops_overwrite(LR"(mfolder1\newfolder1\newfile1.txt)", + R"(newfile1.txt nonrecursive overwrite subfolder)", false); verify_source_existance(LR"(overwrite\mfolder1\newfolder1\newfile1.txt)"); - ops_overwrite(LR"(mfolder1\newfile1.txt)", R"(newfile1.txt nonrecursive overwrite)", false); + ops_overwrite(LR"(mfolder1\newfile1.txt)", R"(newfile1.txt nonrecursive overwrite)", + false); ops_read(LR"(mfolder1\newfile1.txt)"); - ops_overwrite(LR"(mfolder2\newfile2.txt)", R"(newfile2.txt recursive overwrite)", true); + ops_overwrite(LR"(mfolder2\newfile2.txt)", R"(newfile2.txt recursive overwrite)", + true); ops_read(LR"(mfolder2\newfile2.txt)"); - verify_source_contents(LR"(overwrite\mfolder2\newfile2.txt)", R"(newfile2.txt recursive overwrite)"); - ops_overwrite(LR"(mfolder2\newfile2.txt\fail)", R"(newfile2.txt is a file so folder creation should fail)", true, false); - verify_source_contents(LR"(overwrite\mfolder2\newfile2.txt)", R"(newfile2.txt recursive overwrite)"); - ops_overwrite(LR"(mfolder2\mfile.txt\fail)", R"(mfile.txt is a file so folder creation should fail)", true, false); + verify_source_contents(LR"(overwrite\mfolder2\newfile2.txt)", + R"(newfile2.txt recursive overwrite)"); + ops_overwrite(LR"(mfolder2\newfile2.txt\fail)", + R"(newfile2.txt is a file so folder creation should fail)", true, + false); + verify_source_contents(LR"(overwrite\mfolder2\newfile2.txt)", + R"(newfile2.txt recursive overwrite)"); + ops_overwrite(LR"(mfolder2\mfile.txt\fail)", + R"(mfile.txt is a file so folder creation should fail)", true, false); verify_source_existance(LR"(overwrite\mfolder2\mfile.txt)", false); - ops_overwrite(LR"(mfolder3\newfolder3\newfile3.txt)", R"(newfile3.txt recursive overwrite)", true); + ops_overwrite(LR"(mfolder3\newfolder3\newfile3.txt)", + R"(newfile3.txt recursive overwrite)", true); ops_read(LR"(mfolder3\newfolder3\newfile3.txt)"); - verify_source_contents(LR"(overwrite\mfolder3\newfolder3\newfile3.txt)", R"(newfile3.txt recursive overwrite)"); - // repeat mfolder3\newfolder3 test as that folder now exists in overwrite and that changes things - ops_overwrite(LR"(mfolder3\newfolder3\newfile3e.txt)", R"(newfile3e.txt recursive overwrite)", true); + verify_source_contents(LR"(overwrite\mfolder3\newfolder3\newfile3.txt)", + R"(newfile3.txt recursive overwrite)"); + // repeat mfolder3\newfolder3 test as that folder now exists in overwrite and that + // changes things + ops_overwrite(LR"(mfolder3\newfolder3\newfile3e.txt)", + R"(newfile3e.txt recursive overwrite)", true); ops_read(LR"(mfolder3\newfolder3\newfile3e.txt)"); - verify_source_contents(LR"(overwrite\mfolder3\newfolder3\newfile3e.txt)", R"(newfile3e.txt recursive overwrite)"); + verify_source_contents(LR"(overwrite\mfolder3\newfolder3\newfile3e.txt)", + R"(newfile3e.txt recursive overwrite)"); - ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4.txt)", R"(newfile4.txt recursive overwrite)", true); + ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4.txt)", + R"(newfile4.txt recursive overwrite)", true); ops_read(LR"(mfolder4\newfolder4\d\e\e\p\newfile4.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4.txt)", R"(newfile4.txt recursive overwrite)"); - // repeat mfolder4\newfolder4\d\e\e\p test as that folder now exists in overwrite and that changes things - ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4e.txt)", R"(newfile4e.txt recursive overwrite)", true); + verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4.txt)", + R"(newfile4.txt recursive overwrite)"); + // repeat mfolder4\newfolder4\d\e\e\p test as that folder now exists in overwrite and + // that changes things + ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4e.txt)", + R"(newfile4e.txt recursive overwrite)", true); ops_read(LR"(mfolder4\newfolder4\d\e\e\p\newfile4e.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4e.txt)", R"(newfile4e.txt recursive overwrite)"); + verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4e.txt)", + R"(newfile4e.txt recursive overwrite)"); // and finally verify also non-recursive works - ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)", R"(newfile4enr.txt nonrecursive overwrite)", false); + ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)", + R"(newfile4enr.txt nonrecursive overwrite)", false); ops_read(LR"(mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)", R"(newfile4enr.txt nonrecursive overwrite)"); + verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)", + R"(newfile4enr.txt nonrecursive overwrite)"); // finally check an intermediate folder: - ops_overwrite(LR"(mfolder4\newfolder4\d\e\epnewfile4r.txt)", R"(epnewfile4r.txt recursive overwrite)", true); + ops_overwrite(LR"(mfolder4\newfolder4\d\e\epnewfile4r.txt)", + R"(epnewfile4r.txt recursive overwrite)", true); ops_read(LR"(mfolder4\newfolder4\d\e\epnewfile4r.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\epnewfile4r.txt)", R"(epnewfile4r.txt recursive overwrite)"); - ops_overwrite(LR"(mfolder4\newfolder4\d\e\epnewfile4.txt)", R"(epnewfile4.txt nonrecursive overwrite)", false); + verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\epnewfile4r.txt)", + R"(epnewfile4r.txt recursive overwrite)"); + ops_overwrite(LR"(mfolder4\newfolder4\d\e\epnewfile4.txt)", + R"(epnewfile4.txt nonrecursive overwrite)", false); ops_read(LR"(mfolder4\newfolder4\d\e\epnewfile4.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\epnewfile4.txt)", R"(epnewfile4.txt nonrecursive overwrite)"); + verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\epnewfile4.txt)", + R"(epnewfile4.txt nonrecursive overwrite)"); verify_mount_existance(LR"(rfolder\rcopyme4.txt)"); verify_source_existance(LR"(overwrite\mfolder4\newfolder4p)", false); @@ -79,22 +106,32 @@ bool usvfs_basic_test::scenario_run() ops_copy(LR"(rfolder\rcopyme4.txt)", LR"(mfolder4\rcopyme4.txt)", false); verify_source_existance(LR"(overwrite\mfolder4\rcopyme4.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4.txt)", R"(newfile4.txt recursive overwrite)"); - // repeat mfolder4\newfolder4\d\e\e\p test as that folder now exists in overwrite and that changes things - ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4e.txt)", R"(newfile4e.txt recursive overwrite)", true); + verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4.txt)", + R"(newfile4.txt recursive overwrite)"); + // repeat mfolder4\newfolder4\d\e\e\p test as that folder now exists in overwrite and + // that changes things + ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4e.txt)", + R"(newfile4e.txt recursive overwrite)", true); ops_read(LR"(mfolder4\newfolder4\d\e\e\p\newfile4e.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4e.txt)", R"(newfile4e.txt recursive overwrite)"); + verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4e.txt)", + R"(newfile4e.txt recursive overwrite)"); // and finally verify also non-recursive works - ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)", R"(newfile4enr.txt nonrecursive overwrite)", false); + ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)", + R"(newfile4enr.txt nonrecursive overwrite)", false); ops_read(LR"(mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)", R"(newfile4enr.txt nonrecursive overwrite)"); + verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)", + R"(newfile4enr.txt nonrecursive overwrite)"); // finally check an intermediate folder: - ops_overwrite(LR"(mfolder4\newfolder4\d\e\epnewfile4r.txt)", R"(epnewfile4r.txt recursive overwrite)", true); + ops_overwrite(LR"(mfolder4\newfolder4\d\e\epnewfile4r.txt)", + R"(epnewfile4r.txt recursive overwrite)", true); ops_read(LR"(mfolder4\newfolder4\d\e\epnewfile4r.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\epnewfile4r.txt)", R"(epnewfile4r.txt recursive overwrite)"); - ops_overwrite(LR"(mfolder4\newfolder4\d\e\epnewfile4.txt)", R"(epnewfile4.txt nonrecursive overwrite)", false); + verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\epnewfile4r.txt)", + R"(epnewfile4r.txt recursive overwrite)"); + ops_overwrite(LR"(mfolder4\newfolder4\d\e\epnewfile4.txt)", + R"(epnewfile4.txt nonrecursive overwrite)", false); ops_read(LR"(mfolder4\newfolder4\d\e\epnewfile4.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\epnewfile4.txt)", R"(epnewfile4.txt nonrecursive overwrite)"); + verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\epnewfile4.txt)", + R"(epnewfile4.txt nonrecursive overwrite)"); // test copy on write/delete against source "mod": @@ -120,18 +157,21 @@ bool usvfs_basic_test::scenario_run() ops_touch(LR"(mfolder1\mfilew.txt)", true); verify_source_existance(LR"(overwrite\mfolder1\mfilew.txt)", false); - { const auto& old_contents = source_contents(LR"(mod4\mfolder4\mfileoverwrite.txt)"); - verify_source_contents(LR"(mod4\mfolder4\mfileoverwrite.txt)", old_contents.c_str()); - ops_overwrite(LR"(mfolder4\mfileoverwrite.txt)", R"(mfolder4\mfileoverwrite.txt overwrite)", false); + verify_source_contents(LR"(mod4\mfolder4\mfileoverwrite.txt)", + old_contents.c_str()); + ops_overwrite(LR"(mfolder4\mfileoverwrite.txt)", + R"(mfolder4\mfileoverwrite.txt overwrite)", false); ops_read(LR"(mfolder4\mfileoverwrite.txt)"); if (bool protect_virtualized = false) { - verify_source_contents(LR"(mod4\mfolder4\mfileoverwrite.txt)", old_contents.c_str()); - verify_source_contents(LR"(overwrite\mfolder4\mfileoverwrite.txt)", R"(mfolder4\mfileoverwrite.txt overwrite)"); - } - else { - verify_source_contents(LR"(mod4\mfolder4\mfileoverwrite.txt)", R"(mfolder4\mfileoverwrite.txt overwrite)"); + verify_source_contents(LR"(mod4\mfolder4\mfileoverwrite.txt)", + old_contents.c_str()); + verify_source_contents(LR"(overwrite\mfolder4\mfileoverwrite.txt)", + R"(mfolder4\mfileoverwrite.txt overwrite)"); + } else { + verify_source_contents(LR"(mod4\mfolder4\mfileoverwrite.txt)", + R"(mfolder4\mfileoverwrite.txt overwrite)"); verify_source_existance(LR"(overwrite\mfolder4\mfileoverwrite.txt)", false); } } @@ -139,14 +179,17 @@ bool usvfs_basic_test::scenario_run() { const auto& old_contents = source_contents(LR"(mod4\mfolder4\mfilerewrite.txt)"); verify_source_contents(LR"(mod4\mfolder4\mfilerewrite.txt)", old_contents.c_str()); - ops_rewrite(LR"(mfolder4\mfilerewrite.txt)", R"(mfolder4\mfilerewrite.txt rewrite)"); + ops_rewrite(LR"(mfolder4\mfilerewrite.txt)", + R"(mfolder4\mfilerewrite.txt rewrite)"); ops_read(LR"(mfolder4\mfilerewrite.txt)"); if (auto copy_on_readwrite_implemented = false) { - verify_source_contents(LR"(mod4\mfolder4\mfilerewrite.txt)", old_contents.c_str()); - verify_source_contents(LR"(overwrite\mfolder4\mfilerewrite.txt)", R"(mfolder4\mfilerewrite.txt rewrite)"); - } - else { - verify_source_contents(LR"(mod4\mfolder4\mfilerewrite.txt)", R"(mfolder4\mfilerewrite.txt rewrite)"); + verify_source_contents(LR"(mod4\mfolder4\mfilerewrite.txt)", + old_contents.c_str()); + verify_source_contents(LR"(overwrite\mfolder4\mfilerewrite.txt)", + R"(mfolder4\mfilerewrite.txt rewrite)"); + } else { + verify_source_contents(LR"(mod4\mfolder4\mfilerewrite.txt)", + R"(mfolder4\mfilerewrite.txt rewrite)"); verify_source_existance(LR"(overwrite\mfolder4\mfilerewrite.txt)", false); } } @@ -154,97 +197,125 @@ bool usvfs_basic_test::scenario_run() { const auto& old_contents = source_contents(LR"(mod4\mfolder4\mfilemoveover.txt)"); verify_source_contents(LR"(mod4\mfolder4\mfilemoveover.txt)", old_contents.c_str()); - ops_overwrite(LR"(mfolder4\temp_mfilemoveover.txt)", R"(mfolder4\mfilemoveover.txt overwrite)", false); - verify_source_contents(LR"(overwrite\mfolder4\temp_mfilemoveover.txt)", R"(mfolder4\mfilemoveover.txt overwrite)"); - ops_rename(LR"(mfolder4\temp_mfilemoveover.txt)", LR"(mfolder4\mfilemoveover.txt)", true); + ops_overwrite(LR"(mfolder4\temp_mfilemoveover.txt)", + R"(mfolder4\mfilemoveover.txt overwrite)", false); + verify_source_contents(LR"(overwrite\mfolder4\temp_mfilemoveover.txt)", + R"(mfolder4\mfilemoveover.txt overwrite)"); + ops_rename(LR"(mfolder4\temp_mfilemoveover.txt)", LR"(mfolder4\mfilemoveover.txt)", + true); ops_read(LR"(mfolder4\mfilemoveover.txt)"); verify_source_existance(LR"(overwrite\mfolder4\temp_mfilemoveover.txt)", false); if (bool protect_virtualized = false) { - verify_source_contents(LR"(mod4\mfolder4\mfilemoveover.txt)", old_contents.c_str()); - verify_source_contents(LR"(overwrite\mfolder4\mfilemoveover.txt)", R"(mfolder4\mfilemoveover.txt overwrite)"); - } - else { - verify_source_contents(LR"(mod4\mfolder4\mfilemoveover.txt)", R"(mfolder4\mfilemoveover.txt overwrite)"); + verify_source_contents(LR"(mod4\mfolder4\mfilemoveover.txt)", + old_contents.c_str()); + verify_source_contents(LR"(overwrite\mfolder4\mfilemoveover.txt)", + R"(mfolder4\mfilemoveover.txt overwrite)"); + } else { + verify_source_contents(LR"(mod4\mfolder4\mfilemoveover.txt)", + R"(mfolder4\mfilemoveover.txt overwrite)"); verify_source_existance(LR"(overwrite\mfolder4\mfilemoveover.txt)", false); } } { - const auto& old_contents = source_contents(LR"(mod4\mfolder4\mfiledeletewrite.txt)"); - verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite.txt)", old_contents.c_str()); - ops_deleteoverwrite(LR"(mfolder4\mfiledeletewrite.txt)", R"(mfolder4\mfiledeletewrite.txt overwrite)", false); + const auto& old_contents = + source_contents(LR"(mod4\mfolder4\mfiledeletewrite.txt)"); + verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite.txt)", + old_contents.c_str()); + ops_deleteoverwrite(LR"(mfolder4\mfiledeletewrite.txt)", + R"(mfolder4\mfiledeletewrite.txt overwrite)", false); ops_read(LR"(mfolder4\mfiledeletewrite.txt)"); if (bool protect_virtualized = false) { - verify_source_contents(LR"(overwrite\mfolder4\mfiledeletewrite.txt)", R"(mfolder4\mfiledeletewrite.txt overwrite)"); + verify_source_contents(LR"(overwrite\mfolder4\mfiledeletewrite.txt)", + R"(mfolder4\mfiledeletewrite.txt overwrite)"); if (auto proper_delete_implemented = false) - verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite.txt)", old_contents.c_str()); + verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite.txt)", + old_contents.c_str()); else verify_source_existance(LR"(mod4\mfolder4\mfiledeletewrite.txt)", false); - } - else { - verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite.txt)", R"(mfolder4\mfiledeletewrite.txt overwrite)"); + } else { + verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite.txt)", + R"(mfolder4\mfiledeletewrite.txt overwrite)"); verify_source_existance(LR"(overwrite\mfolder4\mfiledeletewrite.txt)", false); } } { - const auto& old_contents = source_contents(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)"); - verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)", old_contents.c_str()); + const auto& old_contents = + source_contents(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)"); + verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)", + old_contents.c_str()); ops_delete(LR"(mfolder4\mfiledeletewrite2p.txt)"); - ops_overwrite(LR"(mfolder4\mfiledeletewrite2p.txt)", R"(mfolder4\mfiledeletewrite2p.txt overwrite)", false); + ops_overwrite(LR"(mfolder4\mfiledeletewrite2p.txt)", + R"(mfolder4\mfiledeletewrite2p.txt overwrite)", false); ops_read(LR"(mfolder4\mfiledeletewrite2p.txt)"); - if (bool protect_virtualized_or_track_deleted_only_in_current_process = true) { - verify_source_contents(LR"(overwrite\mfolder4\mfiledeletewrite2p.txt)", R"(mfolder4\mfiledeletewrite2p.txt overwrite)"); + if (bool protect_virtualized_or_track_deleted_only_in_current_process = true) { + verify_source_contents(LR"(overwrite\mfolder4\mfiledeletewrite2p.txt)", + R"(mfolder4\mfiledeletewrite2p.txt overwrite)"); if (auto proper_delete_implemented = false) - verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)", old_contents.c_str()); + verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)", + old_contents.c_str()); else verify_source_existance(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)", false); - } - else { - verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)", R"(mfolder4\mfiledeletewrite2p.txt overwrite)"); + } else { + verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)", + R"(mfolder4\mfiledeletewrite2p.txt overwrite)"); verify_source_existance(LR"(overwrite\mfolder4\mfiledeletewrite2p.txt)", false); } } { const auto& old_contents = source_contents(LR"(mod4\mfolder4\mfiledeletemove.txt)"); - verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove.txt)", old_contents.c_str()); - ops_overwrite(LR"(mfolder4\temp_mfiledeletemove.txt)", R"(mfolder4\mfiledeletemove.txt overwrite)", false); - verify_source_contents(LR"(overwrite\mfolder4\temp_mfiledeletemove.txt)", R"(mfolder4\mfiledeletemove.txt overwrite)"); - ops_deleterename(LR"(mfolder4\temp_mfiledeletemove.txt)", LR"(mfolder4\mfiledeletemove.txt)"); + verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove.txt)", + old_contents.c_str()); + ops_overwrite(LR"(mfolder4\temp_mfiledeletemove.txt)", + R"(mfolder4\mfiledeletemove.txt overwrite)", false); + verify_source_contents(LR"(overwrite\mfolder4\temp_mfiledeletemove.txt)", + R"(mfolder4\mfiledeletemove.txt overwrite)"); + ops_deleterename(LR"(mfolder4\temp_mfiledeletemove.txt)", + LR"(mfolder4\mfiledeletemove.txt)"); ops_read(LR"(mfolder4\mfiledeletemove.txt)"); verify_source_existance(LR"(overwrite\mfolder4\temp_mfiledeletemove.txt)", false); if (bool protect_virtualized = false) { - verify_source_contents(LR"(overwrite\mfolder4\mfiledeletemove.txt)", R"(mfolder4\mfiledeletemove.txt overwrite)"); + verify_source_contents(LR"(overwrite\mfolder4\mfiledeletemove.txt)", + R"(mfolder4\mfiledeletemove.txt overwrite)"); if (auto proper_delete_implemented = false) - verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove.txt)", old_contents.c_str()); + verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove.txt)", + old_contents.c_str()); else verify_source_existance(LR"(mod4\mfolder4\mfiledeletemove.txt)", false); - } - else { - verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove.txt)", R"(mfolder4\mfiledeletemove.txt overwrite)"); + } else { + verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove.txt)", + R"(mfolder4\mfiledeletemove.txt overwrite)"); verify_source_existance(LR"(overwrite\mfolder4\mfiledeletemove.txt)", false); } } { - const auto& old_contents = source_contents(LR"(mod4\mfolder4\mfiledeletemove2p.txt)"); - verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove2p.txt)", old_contents.c_str()); + const auto& old_contents = + source_contents(LR"(mod4\mfolder4\mfiledeletemove2p.txt)"); + verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove2p.txt)", + old_contents.c_str()); ops_delete(LR"(mfolder4\mfiledeletemove2p.txt)"); - ops_overwrite(LR"(mfolder4\temp_mfiledeletemove2p.txt)", R"(mfolder4\mfiledeletemove2p.txt overwrite)", false); - verify_source_contents(LR"(overwrite\mfolder4\temp_mfiledeletemove2p.txt)", R"(mfolder4\mfiledeletemove2p.txt overwrite)"); - ops_rename(LR"(mfolder4\temp_mfiledeletemove2p.txt)", LR"(mfolder4\mfiledeletemove2p.txt)", false); + ops_overwrite(LR"(mfolder4\temp_mfiledeletemove2p.txt)", + R"(mfolder4\mfiledeletemove2p.txt overwrite)", false); + verify_source_contents(LR"(overwrite\mfolder4\temp_mfiledeletemove2p.txt)", + R"(mfolder4\mfiledeletemove2p.txt overwrite)"); + ops_rename(LR"(mfolder4\temp_mfiledeletemove2p.txt)", + LR"(mfolder4\mfiledeletemove2p.txt)", false); ops_read(LR"(mfolder4\mfiledeletemove2p.txt)"); verify_source_existance(LR"(overwrite\mfolder4\temp_mfiledeletemove2p.txt)", false); if (bool protect_virtualized_or_track_deleted_only_in_current_process = true) { - verify_source_contents(LR"(overwrite\mfolder4\mfiledeletemove2p.txt)", R"(mfolder4\mfiledeletemove2p.txt overwrite)"); + verify_source_contents(LR"(overwrite\mfolder4\mfiledeletemove2p.txt)", + R"(mfolder4\mfiledeletemove2p.txt overwrite)"); if (auto proper_delete_implemented = false) - verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove2p.txt)", old_contents.c_str()); + verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove2p.txt)", + old_contents.c_str()); else verify_source_existance(LR"(mod4\mfolder4\mfiledeletemove2p.txt)", false); - } - else { - verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove2p.txt)", R"(mfolder4\mfiledeletemove2p.txt overwrite)"); + } else { + verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove2p.txt)", + R"(mfolder4\mfiledeletemove2p.txt overwrite)"); verify_source_existance(LR"(overwrite\mfolder4\mfiledeletemove2p.txt)", false); } } @@ -257,35 +328,45 @@ bool usvfs_basic_test::scenario_run() ops_read(LR"(rfolder\rfilerewrite.txt)"); if (auto copy_on_readwrite_implemented = false) { verify_mount_contents(LR"(rfolder\rfilerewrite.txt)", old_contents.c_str()); - verify_source_contents(LR"(overwrite\rfolder\rfilerewrite.txt)", R"(rfolder\rfilerewrite.txt rewrite)"); - } - else { - verify_mount_contents(LR"(rfolder\rfilerewrite.txt)", R"(rfolder\rfilerewrite.txt rewrite)"); + verify_source_contents(LR"(overwrite\rfolder\rfilerewrite.txt)", + R"(rfolder\rfilerewrite.txt rewrite)"); + } else { + verify_mount_contents(LR"(rfolder\rfilerewrite.txt)", + R"(rfolder\rfilerewrite.txt rewrite)"); verify_source_existance(LR"(overwrite\rfolder\rfilerewrite.txt)", false); } } - ops_overwrite(LR"(rfolder\rfilerewrite.txt\fail)", R"(rfilerewrite.txt is a file so folder creation should fail)", true, false); - verify_mount_existance(LR"(rfolder\rfilerewrite.txt)"); // verifies its a file and not a directory + ops_overwrite(LR"(rfolder\rfilerewrite.txt\fail)", + R"(rfilerewrite.txt is a file so folder creation should fail)", true, + false); + verify_mount_existance( + LR"(rfolder\rfilerewrite.txt)"); // verifies its a file and not a directory if (auto copy_on_readwrite_implemented = false) - verify_source_existance(LR"(overwrite\rfolder\rfilerewrite.txt)"); // verifies its a file and not a directory + verify_source_existance( + LR"(overwrite\rfolder\rfilerewrite.txt)"); // verifies its a file and not a + // directory else verify_source_existance(LR"(overwrite\rfolder\rfilerewrite.txt)", false); - ops_overwrite(LR"(rfolder\rfile0.txt\fail)", R"(rfile0.txt is a file so folder creation should fail)", true, false); - verify_mount_existance(LR"(rfolder\rfile0.txt)"); // verifies its a file and not a directory + ops_overwrite(LR"(rfolder\rfile0.txt\fail)", + R"(rfile0.txt is a file so folder creation should fail)", true, false); + verify_mount_existance( + LR"(rfolder\rfile0.txt)"); // verifies its a file and not a directory { const auto& old_contents = mount_contents(LR"(rfolder\rfiledeletewrite.txt)"); - ops_deleteoverwrite(LR"(rfolder\rfiledeletewrite.txt)", R"(rfolder\rfiledeletewrite.txt overwrite)", false); + ops_deleteoverwrite(LR"(rfolder\rfiledeletewrite.txt)", + R"(rfolder\rfiledeletewrite.txt overwrite)", false); ops_read(LR"(rfolder\rfiledeletewrite.txt)"); if (bool protect_virtualized = false) { - verify_source_contents(LR"(overwrite\rfolder\rfiledeletewrite.txt)", R"(rfolder\rfiledeletewrite.txt overwrite)"); + verify_source_contents(LR"(overwrite\rfolder\rfiledeletewrite.txt)", + R"(rfolder\rfiledeletewrite.txt overwrite)"); if (auto proper_delete_implemented = false) verify_mount_contents(LR"(rfolder\rfiledeletewrite.txt)", old_contents.c_str()); else verify_mount_existance(LR"(rfolder\rfiledeletewrite.txt)", false); - } - else { - verify_mount_contents(LR"(rfolder\rfiledeletewrite.txt)", R"(rfolder\rfiledeletewrite.txt overwrite)"); + } else { + verify_mount_contents(LR"(rfolder\rfiledeletewrite.txt)", + R"(rfolder\rfiledeletewrite.txt overwrite)"); verify_source_existance(LR"(overwrite\rfolder\rfiledeletewrite.txt)", false); } } @@ -302,10 +383,12 @@ bool usvfs_basic_test::scenario_run() { const auto& old_contents = mount_contents(LR"(rfolder\rfileoldname.txt)"); - ops_rename(LR"(rfolder\rfileoldname.txt)", LR"(rfolder\rfilenewname.txt)", false, false); + ops_rename(LR"(rfolder\rfileoldname.txt)", LR"(rfolder\rfilenewname.txt)", false, + false); ops_read(LR"(rfolder\rfileoldname.txt)", false); ops_read(LR"(rfolder\rfilenewname.txt)"); - verify_source_contents(LR"(overwrite\rfolder\rfilenewname.txt)", old_contents.c_str()); + verify_source_contents(LR"(overwrite\rfolder\rfilenewname.txt)", + old_contents.c_str()); verify_mount_existance(LR"(rfolder\rfilenewname.txt)", false); if (auto copy_on_move_implemented = false) verify_mount_contents(LR"(rfolder\rfileoldname.txt)", old_contents.c_str()); diff --git a/test/usvfs_test_runner/usvfs_test/usvfs_test.cpp b/test/usvfs_test_runner/usvfs_test/usvfs_test.cpp index d6d67d2..e6e6bb1 100644 --- a/test/usvfs_test_runner/usvfs_test/usvfs_test.cpp +++ b/test/usvfs_test_runner/usvfs_test/usvfs_test.cpp @@ -9,31 +9,58 @@ #include "usvfs_basic_test.h" #include -void print_usage(const std::wstring& exe_name, const std::wstring& test_name) { +void print_usage(const std::wstring& exe_name, const std::wstring& test_name) +{ using namespace std; wcerr << "usage: " << exe_name << " [] [: