aboutsummaryrefslogtreecommitdiff
path: root/libs/usvfs/src/usvfs_dll/hooks
diff options
context:
space:
mode:
Diffstat (limited to 'libs/usvfs/src/usvfs_dll/hooks')
-rw-r--r--libs/usvfs/src/usvfs_dll/hooks/file_information_utils.h263
-rw-r--r--libs/usvfs/src/usvfs_dll/hooks/kernel32.cpp1860
-rw-r--r--libs/usvfs/src/usvfs_dll/hooks/kernel32.h116
-rw-r--r--libs/usvfs/src/usvfs_dll/hooks/ntdll.cpp1520
-rw-r--r--libs/usvfs/src/usvfs_dll/hooks/ntdll.h57
-rw-r--r--libs/usvfs/src/usvfs_dll/hooks/sharedids.h9
6 files changed, 0 insertions, 3825 deletions
diff --git a/libs/usvfs/src/usvfs_dll/hooks/file_information_utils.h b/libs/usvfs/src/usvfs_dll/hooks/file_information_utils.h
deleted file mode 100644
index dbd3597..0000000
--- a/libs/usvfs/src/usvfs_dll/hooks/file_information_utils.h
+++ /dev/null
@@ -1,263 +0,0 @@
-#pragma once
-
-/**
- * This header defines function to deal with the various FileInformationClass
- * enumeration.
- */
-
-#include <type_traits>
-
-#include <ntdll_declarations.h>
-
-#include <windows.h>
-
-namespace usvfs::details
-{
-
-#define DECLARE_HAS_FIELD(Field) \
- template <typename T> \
- constexpr auto HasFieldImpl##Field(int)->decltype(std::declval<T>().Field, void(), \
- std::true_type()) \
- { \
- return {}; \
- } \
- template <typename T> \
- constexpr auto HasFieldImpl##Field(...) \
- { \
- return std::false_type{}; \
- } \
- template <typename T> \
- constexpr auto HasField##Field() \
- { \
- return HasFieldImpl##Field<T>(0); \
- }
-
-DECLARE_HAS_FIELD(FileName)
-DECLARE_HAS_FIELD(NextEntryOffset)
-DECLARE_HAS_FIELD(ShortName)
-
-#undef DECLARE_HAS_FIELD
-
-template <FILE_INFORMATION_CLASS fileInformationClass, class FileInformationClass>
-struct FileInformationClassUtilsImpl
-{
- static void get_data(LPCVOID address, ULONG& offset, std::wstring& fileName)
- {
- const FileInformationClass* info =
- reinterpret_cast<const FileInformationClass*>(address);
-
- // default value
- offset = sizeof(FileInformationClass);
-
- if constexpr (HasFieldFileName<FileInformationClass>()) {
- if constexpr (HasFieldNextEntryOffset<FileInformationClass>()) {
- offset = info->NextEntryOffset;
- }
- fileName = std::wstring(info->FileName, info->FileNameLength / sizeof(WCHAR));
- }
- }
-
- static void set_offset(LPVOID address, ULONG offset)
- {
- FileInformationClass* info = reinterpret_cast<FileInformationClass*>(address);
-
- if constexpr (HasFieldNextEntryOffset<FileInformationClass>()) {
- info->NextEntryOffset = offset;
- }
- }
-
- static void set_filename(LPVOID address, const std::wstring& fileName)
- {
- FileInformationClass* info = reinterpret_cast<FileInformationClass*>(address);
-
- if constexpr (HasFieldFileName<FileInformationClass>()) {
- memset(info->FileName, L'\0', info->FileNameLength);
- info->FileNameLength = static_cast<ULONG>(fileName.length() * sizeof(WCHAR));
-
- // doesn't need to be 0-terminated
- memcpy(info->FileName, fileName.c_str(), info->FileNameLength);
-
- if constexpr (HasFieldShortName<FileInformationClass>()) {
- if (info->ShortNameLength > 0) {
- info->ShortNameLength = static_cast<CCHAR>(
- GetShortPathNameW(fileName.c_str(), info->ShortName, 8));
- }
- }
- }
- }
-};
-
-template <FILE_INFORMATION_CLASS fileInformationClass>
-struct FileInformationClassUtils;
-
-template <>
-struct FileInformationClassUtils<FileDirectoryInformation>
- : FileInformationClassUtilsImpl<FileDirectoryInformation,
- FILE_DIRECTORY_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileFullDirectoryInformation>
- : FileInformationClassUtilsImpl<FileFullDirectoryInformation,
- FILE_FULL_DIR_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileBothDirectoryInformation>
- : FileInformationClassUtilsImpl<FileBothDirectoryInformation,
- FILE_BOTH_DIR_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileStandardInformation>
- : FileInformationClassUtilsImpl<FileStandardInformation, FILE_STANDARD_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileNameInformation>
- : FileInformationClassUtilsImpl<FileNameInformation, FILE_NAME_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileRenameInformation>
- : FileInformationClassUtilsImpl<FileRenameInformation, FILE_RENAME_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileNamesInformation>
- : FileInformationClassUtilsImpl<FileNamesInformation, FILE_NAMES_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileObjectIdInformation>
- : FileInformationClassUtilsImpl<FileObjectIdInformation, FILE_OBJECTID_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileReparsePointInformation>
- : FileInformationClassUtilsImpl<FileReparsePointInformation,
- FILE_REPARSE_POINT_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileIdBothDirectoryInformation>
- : FileInformationClassUtilsImpl<FileIdBothDirectoryInformation,
- FILE_ID_BOTH_DIR_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileIdFullDirectoryInformation>
- : FileInformationClassUtilsImpl<FileIdFullDirectoryInformation,
- FILE_ID_FULL_DIR_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileNormalizedNameInformation>
- : FileInformationClassUtilsImpl<FileNormalizedNameInformation,
- FILE_NAME_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileIdExtdDirectoryInformation>
- : FileInformationClassUtilsImpl<FileIdExtdDirectoryInformation,
- FILE_ID_EXTD_DIR_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileIdExtdBothDirectoryInformation>
- : FileInformationClassUtilsImpl<FileIdExtdBothDirectoryInformation,
- FILE_ID_EXTD_BOTH_DIR_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileId64ExtdDirectoryInformation>
- : FileInformationClassUtilsImpl<FileId64ExtdDirectoryInformation,
- FILE_ID_64_EXTD_DIR_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileId64ExtdBothDirectoryInformation>
- : FileInformationClassUtilsImpl<FileId64ExtdBothDirectoryInformation,
- FILE_ID_64_EXTD_BOTH_DIR_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileIdAllExtdDirectoryInformation>
- : FileInformationClassUtilsImpl<FileIdAllExtdDirectoryInformation,
- FILE_ID_ALL_EXTD_DIR_INFORMATION>
-{};
-template <>
-struct FileInformationClassUtils<FileIdAllExtdBothDirectoryInformation>
- : FileInformationClassUtilsImpl<FileIdAllExtdBothDirectoryInformation,
- FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION>
-{};
-
-// FILE_ALL_INFORMATION needs to be handled differently because it has a field that
-// is itself a structure
-template <>
-struct FileInformationClassUtils<FileAllInformation>
-{
- static void get_data(LPCVOID address, ULONG& offset, std::wstring& fileName)
- {
- FileInformationClassUtils<FileNameInformation>::get_data(
- &reinterpret_cast<const FILE_ALL_INFORMATION*>(address)->NameInformation,
- offset, fileName);
- }
-
- static void set_offset(LPVOID address, ULONG offset)
- {
- // this is a no-op but it's consistent to do that everywhere
- FileInformationClassUtils<FileNameInformation>::set_offset(
- &reinterpret_cast<FILE_ALL_INFORMATION*>(address)->NameInformation, offset);
- }
-
- static void set_filename(LPVOID address, const std::wstring& fileName)
- {
- FileInformationClassUtils<FileNameInformation>::set_filename(
- &reinterpret_cast<FILE_ALL_INFORMATION*>(address)->NameInformation, fileName);
- }
-};
-
-} // namespace usvfs::details
-
-#define _APP_FINFO_CASE(clazz, fn, ...) \
- case clazz: \
- return usvfs::details::FileInformationClassUtils<clazz>::fn(__VA_ARGS__);
-
-#define _APPLY_FILEINFO_FN(fn, ...) \
- _APP_FINFO_CASE(FileAllInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileDirectoryInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileFullDirectoryInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileBothDirectoryInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileStandardInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileNameInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileRenameInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileNamesInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileObjectIdInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileReparsePointInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileIdBothDirectoryInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileIdFullDirectoryInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileNormalizedNameInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileIdExtdDirectoryInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileIdExtdBothDirectoryInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileId64ExtdDirectoryInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileId64ExtdBothDirectoryInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileIdAllExtdDirectoryInformation, fn, __VA_ARGS__) \
- _APP_FINFO_CASE(FileIdAllExtdBothDirectoryInformation, fn, __VA_ARGS__)
-
-void GetFileInformationData(FILE_INFORMATION_CLASS fileInformationClass,
- LPCVOID address, ULONG& offset, std::wstring& fileName)
-{
- switch (fileInformationClass) {
- _APPLY_FILEINFO_FN(get_data, address, offset, fileName);
- default:
- offset = ULONG_MAX;
- }
-}
-
-void SetFileInformationOffset(FILE_INFORMATION_CLASS fileInformationClass,
- LPVOID address, ULONG offset)
-{
- switch (fileInformationClass) {
- _APPLY_FILEINFO_FN(set_offset, address, offset);
- default:
- break;
- }
-}
-
-void SetFileInformationFileName(FILE_INFORMATION_CLASS fileInformationClass,
- LPVOID address, const std::wstring& fileName)
-{
- switch (fileInformationClass) {
- _APPLY_FILEINFO_FN(set_filename, address, fileName);
- default:
- break;
- }
-}
-
-#undef _APP_FINFO_CASE
-#undef _APPLY_FILEINFO_FN
diff --git a/libs/usvfs/src/usvfs_dll/hooks/kernel32.cpp b/libs/usvfs/src/usvfs_dll/hooks/kernel32.cpp
deleted file mode 100644
index 6599eb0..0000000
--- a/libs/usvfs/src/usvfs_dll/hooks/kernel32.cpp
+++ /dev/null
@@ -1,1860 +0,0 @@
-#include "kernel32.h"
-#include "sharedids.h"
-
-#include "../hookcallcontext.h"
-#include "../hookcontext.h"
-#include "../hookmanager.h"
-#include "../maptracker.h"
-#include <formatters.h>
-#include <inject.h>
-#include <loghelpers.h>
-#include <stringcast.h>
-#include <stringutils.h>
-#include <usvfs.h>
-#include <winapi.h>
-#include <winbase.h>
-
-namespace ush = usvfs::shared;
-using ush::CodePage;
-using ush::string_cast;
-
-namespace usvfs
-{
-MapTracker k32DeleteTracker;
-MapTracker k32FakeDirTracker;
-} // namespace usvfs
-
-class CurrentDirectoryTracker
-{
-public:
- using wstring = std::wstring;
-
- 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<std::string>(forRelativePath),
- static_cast<char>('A' + index)); // prints '@' for m_currentDrive == -1
- if (index < 0)
- return false;
-
- std::shared_lock<std::shared_mutex> lock(m_mutex);
- if (m_perDrive[index].empty())
- return false;
- else {
- currentDir = m_perDrive[index];
- return true;
- }
- }
-
- bool set(const wstring& currentDir)
- {
- int index = -1;
- bool good = !currentDir.empty() && getDriveIndex(currentDir.c_str(), index) &&
- currentDir[1] == ':';
- std::unique_lock<std::shared_mutex> lock(m_mutex);
- m_currentDrive = good ? index : -1;
- if (good)
- m_perDrive[index] = currentDir;
- return good;
- }
-
-private:
- static bool getDriveIndex(const wchar_t* path, int& index)
- {
- if (*path >= 'a' && *path <= 'z')
- index = *path - 'a';
- else if (*path >= 'A' && *path <= 'Z')
- index = *path - 'A';
- else
- return false;
- return true;
- }
-
- mutable std::shared_mutex m_mutex;
- wstring m_perDrive['z' - 'a' + 1];
- int m_currentDrive{-1};
-};
-
-CurrentDirectoryTracker k32CurrentDirectoryTracker;
-
-// attempts to copy source to destination and return the error code
-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();
-}
-
-static inline WCHAR pathNameDriveLetter(LPCWSTR path)
-{
- if (!path || !path[0])
- return 0;
- if (path[1] == ':')
- 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;
- 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] == ':')
- return path[4];
- // give up
- return 0;
-}
-
-// returns false also in case we fail to determine the drive letter of the path
-static inline bool pathsOnDifferentDrives(LPCWSTR path1, LPCWSTR path2)
-{
- WCHAR drive1 = pathNameDriveLetter(path1);
- WCHAR drive2 = pathNameDriveLetter(path2);
- return drive1 && drive2 && towupper(drive1) != towupper(drive2);
-}
-
-HMODULE WINAPI usvfs::hook_LoadLibraryExA(LPCSTR lpFileName, HANDLE hFile,
- DWORD dwFlags)
-{
- HMODULE res = nullptr;
-
- HOOK_START_GROUP(MutExHookGroup::LOAD_LIBRARY)
- const std::wstring fileName = ush::string_cast<std::wstring>(lpFileName);
-
- PRE_REALCALL
- res = LoadLibraryExW(fileName.c_str(), hFile, dwFlags);
- POST_REALCALL
-
- HOOK_END
- return res;
-}
-
-HMODULE WINAPI usvfs::hook_LoadLibraryExW(LPCWSTR lpFileName, HANDLE hFile,
- DWORD dwFlags)
-{
- HMODULE res = nullptr;
-
- HOOK_START_GROUP(MutExHookGroup::LOAD_LIBRARY)
- // Why is the usual if (!callContext.active()... check missing?
-
- RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, lpFileName);
- PRE_REALCALL
- res = ::LoadLibraryExW(reroute.fileName(), hFile, dwFlags);
- POST_REALCALL
-
- if (reroute.wasRerouted()) {
- LOG_CALL()
- .PARAM(lpFileName)
- .PARAM(reroute.fileName())
- .PARAM(res)
- .PARAM(callContext.lastError());
- }
-
- HOOK_END
-
- return res;
-}
-
-/// determine name of the binary to run based on parameters for createprocess
-std::wstring getBinaryName(LPCWSTR applicationName, LPCWSTR lpCommandLine)
-{
- if (applicationName != nullptr) {
- std::pair<std::wstring, std::wstring> fullPath =
- winapi::wide::getFullPathName(applicationName);
- return fullPath.second;
- } else {
- if (lpCommandLine[0] == '"') {
- const wchar_t* endQuote = wcschr(lpCommandLine, '"');
- if (endQuote != nullptr) {
- return std::wstring(lpCommandLine + 1, endQuote - 1);
- }
- }
-
- // according to the documentation, if the commandline is unquoted and has
- // spaces, it will be interpreted in multiple ways, i.e.
- // c:\program.exe files\sub dir\program name
- // c:\program files\sub.exe dir\program name
- // c:\program files\sub dir\program.exe name
- // c:\program files\sub dir\program name.exe
- LPCWSTR space = wcschr(lpCommandLine, L' ');
- while (space != nullptr) {
- std::wstring subString(lpCommandLine, space);
- bool isDirectory = true;
- if (winapi::ex::wide::fileExists(subString.c_str(), &isDirectory) &&
- !isDirectory) {
- return subString;
- } else {
- space = wcschr(space + 1, L' ');
- }
- }
- return std::wstring(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::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)
-{
- BOOL res = FALSE;
-
- HOOK_START_GROUP(MutExHookGroup::CREATE_PROCESS)
- if (!callContext.active()) {
- res = CreateProcessInternalW(
- token, lpApplicationName, lpCommandLine, lpProcessAttributes,
- lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
- lpCurrentDirectory, lpStartupInfo, lpProcessInformation, newToken);
- callContext.updateLastError();
- return res;
- }
-
- // remember if the caller wanted the process to be suspended. If so, we
- // don't resume when we're done
- BOOL susp = dwCreationFlags & CREATE_SUSPENDED;
- dwCreationFlags |= CREATE_SUSPENDED;
-
- RerouteW applicationReroute;
- RerouteW cmdReroute;
- LPWSTR cend = nullptr;
-
- std::wstring dllPath;
- usvfsParameters callParameters;
-
- { // 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 the first argument is quoted we trust its is quoted correctly
- for (cend = lpCommandLine; *cend && *cend != ' '; ++cend)
- if (*cend == '"') {
- int escaped = 0;
- for (++cend; *cend && (*cend != '"' || escaped % 2 != 0); ++cend)
- escaped = *cend == '\\' ? escaped + 1 : 0;
- }
-
- if (*(cend - 1) == '"')
- --cend;
- auto old_cend = *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:
- cend = lpCommandLine;
- while (true) {
- while (*cend && *cend != ' ')
- ++cend;
-
- auto old_cend = *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:
- cend = nullptr;
- break;
- }
- }
- }
- }
-
- applicationReroute = RerouteW::create(context, callContext, lpApplicationName);
-
- dllPath = context->dllPath();
- callParameters = context->callParameters();
- }
-
- std::wstring cmdline;
- if (cend && cmdReroute.fileName()) {
- auto fileName = cmdReroute.fileName();
- cmdline.reserve(wcslen(fileName) + wcslen(cend) + 2);
- if (*fileName != '"')
- cmdline += L"\"";
- cmdline += fileName;
- if (*fileName != '"')
- cmdline += L"\"";
- cmdline += cend;
- }
-
- PRE_REALCALL
- 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
- auto context = READ_CONTEXT();
- blacklisted = context->executableBlacklisted(applicationReroute.fileName(),
- cmdReroute.fileName());
- }
-
- 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<LPCWSTR>(lpCommandLine),
- e.what());
- }
- }
-
- // resume unless process is supposed to start suspended
- if (!susp && (ResumeThread(lpProcessInformation->hThread) == (DWORD)-1)) {
- spdlog::get("hooks")->error("failed to inject into spawned process");
- res = FALSE;
- }
- }
-
- LOG_CALL()
- .PARAM(lpApplicationName)
- .PARAM(applicationReroute.fileName())
- .PARAM(cmdReroute.fileName())
- .PARAM(res)
- .PARAM(callContext.lastError())
- .PARAM(cmdline);
- HOOK_END
-
- return res;
-}
-
-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)) {
- res = GetFileAttributesExA(lpFileName, fInfoLevelId, lpFileInformation);
- callContext.updateLastError();
- return res;
- }
- HOOK_END
-
- HOOK_START
- const std::wstring fileName = ush::string_cast<std::wstring>(lpFileName);
-
- PRE_REALCALL
- res = GetFileAttributesExW(fileName.c_str(), fInfoLevelId, lpFileInformation);
- POST_REALCALL
-
- HOOK_END
- return res;
-}
-
-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)) {
- res = GetFileAttributesExW(lpFileName, fInfoLevelId, lpFileInformation);
- callContext.updateLastError();
- return res;
- }
-
- fs::path canonicalFile = RerouteW::canonizePath(RerouteW::absolutePath(lpFileName));
-
- RerouteW reroute =
- RerouteW::create(READ_CONTEXT(), callContext, canonicalFile.c_str());
-
- PRE_REALCALL
- res = ::GetFileAttributesExW(reroute.fileName(), fInfoLevelId, lpFileInformation);
- POST_REALCALL
-
- DWORD originalError = callContext.lastError();
- 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) {
- // 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))
- 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))
- fixedError = ERROR_FILE_NOT_FOUND;
- }
- }
- if (fixedError != originalError)
- callContext.updateLastError(fixedError);
-
- if (reroute.wasRerouted() || fixedError != originalError) {
- DWORD resAttrib;
- if (res && fInfoLevelId == GetFileExInfoStandard && lpFileInformation)
- resAttrib = reinterpret_cast<WIN32_FILE_ATTRIBUTE_DATA*>(lpFileInformation)
- ->dwFileAttributes;
- else
- resAttrib = (DWORD)-1;
- LOG_CALL()
- .PARAM(lpFileName)
- .PARAM(reroute.fileName())
- .PARAMHEX(fInfoLevelId)
- .PARAMHEX(res)
- .PARAMHEX(resAttrib)
- .PARAM(originalError)
- .PARAM(fixedError);
- }
-
- HOOK_END
-
- return res;
-}
-
-DWORD WINAPI usvfs::hook_GetFileAttributesA(LPCSTR lpFileName)
-{
- BOOL res = FALSE;
-
- HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES)
- if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) {
- res = GetFileAttributesA(lpFileName);
- callContext.updateLastError();
- return res;
- }
- HOOK_END
-
- HOOK_START
- const std::wstring fileName = ush::string_cast<std::wstring>(lpFileName);
-
- PRE_REALCALL
- res = GetFileAttributesW(fileName.c_str());
- POST_REALCALL
-
- HOOK_END
- return res;
-}
-
-DWORD WINAPI usvfs::hook_GetFileAttributesW(LPCWSTR lpFileName)
-{
- DWORD res = 0UL;
-
- HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES)
- if (!callContext.active() || !RerouteW::interestingPath(lpFileName)) {
- res = GetFileAttributesW(lpFileName);
- callContext.updateLastError();
- return res;
- }
-
- fs::path canonicalFile = RerouteW::canonizePath(RerouteW::absolutePath(lpFileName));
-
- RerouteW reroute =
- RerouteW::create(READ_CONTEXT(), callContext, canonicalFile.c_str());
-
- if (reroute.wasRerouted())
- PRE_REALCALL
- res = ::GetFileAttributesW(reroute.fileName());
- POST_REALCALL
-
- DWORD originalError = callContext.lastError();
- 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) {
- // 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))
- 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))
- fixedError = ERROR_FILE_NOT_FOUND;
- }
- }
- if (fixedError != originalError)
- callContext.updateLastError(fixedError);
-
- if (reroute.wasRerouted() || fixedError != originalError) {
- LOG_CALL()
- .PARAM(lpFileName)
- .PARAM(reroute.fileName())
- .PARAMHEX(res)
- .PARAM(originalError)
- .PARAM(fixedError);
- }
-
- HOOK_ENDP(lpFileName);
-
- return res;
-}
-
-DWORD WINAPI usvfs::hook_SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes)
-{
- DWORD res = 0UL;
-
- HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES)
- // Why is the usual if (!callContext.active()... check missing?
-
- RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, lpFileName);
- PRE_REALCALL
- res = ::SetFileAttributesW(reroute.fileName(), dwFileAttributes);
- POST_REALCALL
-
- if (reroute.wasRerouted()) {
- LOG_CALL().PARAM(reroute.fileName()).PARAM(res).PARAM(callContext.lastError());
- }
-
- HOOK_END
-
- return res;
-}
-
-BOOL WINAPI usvfs::hook_DeleteFileW(LPCWSTR lpFileName)
-{
- BOOL res = FALSE;
-
- 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();
-
- RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, path.c_str());
-
- PRE_REALCALL
- if (reroute.wasRerouted()) {
- res = ::DeleteFileW(reroute.fileName());
- } else {
- res = ::DeleteFileW(path.c_str());
- }
- POST_REALCALL
-
- if (res) {
- reroute.removeMapping(READ_CONTEXT());
- }
-
- if (reroute.wasRerouted())
- LOG_CALL()
- .PARAM(lpFileName)
- .PARAM(reroute.fileName())
- .PARAM(res)
- .PARAM(callContext.lastError());
-
- HOOK_END
-
- return res;
-}
-
-BOOL rewriteChangedDrives(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName,
- const usvfs::RerouteW& readReroute,
- const usvfs::CreateRerouter& writeReroute)
-{
- return ((readReroute.wasRerouted() || writeReroute.wasRerouted()) &&
- pathsOnDifferentDrives(readReroute.fileName(), writeReroute.fileName()) &&
- !pathsOnDifferentDrives(lpExistingFileName, lpNewFileName));
-}
-
-BOOL WINAPI usvfs::hook_MoveFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
-{
- BOOL res = FALSE;
-
- HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP)
-
- if (!callContext.active()) {
- res = MoveFileA(lpExistingFileName, lpNewFileName);
- callContext.updateLastError();
- return res;
- }
-
- HOOK_END
- HOOK_START
-
- const auto& existingFileName = ush::string_cast<std::wstring>(lpExistingFileName);
- const auto& newFileName = ush::string_cast<std::wstring>(lpNewFileName);
-
- PRE_REALCALL
- res = MoveFileW(existingFileName.c_str(), newFileName.c_str());
- POST_REALCALL
-
- HOOK_END
-
- return res;
-}
-
-BOOL WINAPI usvfs::hook_MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
-{
- BOOL res = FALSE;
-
- HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP)
- if (!callContext.active()) {
- res = MoveFileW(lpExistingFileName, lpNewFileName);
- callContext.updateLastError();
- return res;
- }
-
- RerouteW readReroute;
- CreateRerouter writeReroute;
- bool callOriginal = true;
- DWORD newFlags = 0;
-
- {
- auto context = READ_CONTEXT();
- 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 (movedDrives)
- newFlags |= MOVEFILE_COPY_ALLOWED;
-
- bool isDirectory = pathIsDirectory(readReroute.fileName());
-
- PRE_REALCALL
- 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) {
- case 0x78:
- callContext.updateLastError(ERROR_ACCESS_DENIED);
- break;
- case 0x7C:
- callContext.updateLastError(ERROR_FILE_NOT_FOUND);
- break;
- case 0x7E:
- case 0x80:
- callContext.updateLastError(ERROR_FILE_EXISTS);
- break;
- default:
- callContext.updateLastError(shRes);
- }
- res = shRes == 0;
- } else if (newFlags)
- res = ::MoveFileExW(readReroute.fileName(), writeReroute.fileName(), newFlags);
- else
- res = ::MoveFileW(readReroute.fileName(), writeReroute.fileName());
- POST_REALCALL
-
- if (res)
- SetLastError(ERROR_SUCCESS);
-
- writeReroute.updateResult(callContext, res);
-
- if (res) {
- readReroute.removeMapping(
- READ_CONTEXT(), isDirectory); // Updating the rerouteCreate to check deleted
- // file entries should make this okay
-
- if (writeReroute.newReroute()) {
- if (isDirectory)
- RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName),
- fs::path(writeReroute.fileName()));
- else
- writeReroute.insertMapping(WRITE_CONTEXT());
- }
- }
-
- if (readReroute.wasRerouted() || writeReroute.wasRerouted() ||
- writeReroute.changedError())
- LOG_CALL()
- .PARAM(readReroute.fileName())
- .PARAM(writeReroute.fileName())
- .PARAMWRAP(newFlags)
- .PARAM(res)
- .PARAM(writeReroute.originalError())
- .PARAM(callContext.lastError());
- }
-
- HOOK_END
-
- return res;
-}
-
-BOOL WINAPI usvfs::hook_MoveFileExA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName,
- DWORD dwFlags)
-{
- BOOL res = FALSE;
-
- HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP)
-
- if (!callContext.active()) {
- res = MoveFileExA(lpExistingFileName, lpNewFileName, dwFlags);
- callContext.updateLastError();
- return res;
- }
-
- HOOK_END
- HOOK_START
-
- const std::wstring existingFileName =
- ush::string_cast<std::wstring>(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;
-
- if (lpNewFileName) {
- newFileNameWstring = ush::string_cast<std::wstring>(lpNewFileName);
- newFileName = newFileNameWstring.c_str();
- }
-
- PRE_REALCALL
- res = MoveFileExW(existingFileName.c_str(), newFileName, dwFlags);
- POST_REALCALL
-
- HOOK_END
-
- return res;
-}
-
-BOOL WINAPI usvfs::hook_MoveFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName,
- DWORD dwFlags)
-{
- BOOL res = FALSE;
-
- HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP)
- if (!callContext.active()) {
- res = MoveFileExW(lpExistingFileName, lpNewFileName, dwFlags);
- callContext.updateLastError();
- return res;
- }
-
- RerouteW readReroute;
- CreateRerouter writeReroute;
- bool callOriginal = true;
- DWORD newFlags = dwFlags;
-
- {
- auto context = READ_CONTEXT();
- readReroute = RerouteW::create(context, callContext, lpExistingFileName);
- callOriginal = writeReroute.rerouteNew(context, callContext, lpNewFileName,
- newFlags & MOVEFILE_REPLACE_EXISTING,
- "hook_MoveFileExW");
- }
-
- if (callOriginal) {
- bool movedDrives = rewriteChangedDrives(lpExistingFileName, lpNewFileName,
- readReroute, writeReroute);
-
- bool isDirectory = pathIsDirectory(readReroute.fileName());
-
- PRE_REALCALL
- 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) {
- case 0x78:
- callContext.updateLastError(ERROR_ACCESS_DENIED);
- break;
- case 0x7C:
- callContext.updateLastError(ERROR_FILE_NOT_FOUND);
- break;
- case 0x7E:
- case 0x80:
- callContext.updateLastError(ERROR_FILE_EXISTS);
- break;
- default:
- callContext.updateLastError(shRes);
- }
- res = shRes == 0;
- } else
- res = ::MoveFileExW(readReroute.fileName(), writeReroute.fileName(), newFlags);
- POST_REALCALL
-
- if (res)
- SetLastError(ERROR_SUCCESS);
-
- writeReroute.updateResult(callContext, res);
-
- if (res) {
- readReroute.removeMapping(
- READ_CONTEXT(), isDirectory); // Updating the rerouteCreate to check deleted
- // file entries should make this okay
-
- if (writeReroute.newReroute()) {
- if (isDirectory)
- RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName),
- fs::path(writeReroute.fileName()));
- else
- writeReroute.insertMapping(WRITE_CONTEXT());
- }
- }
-
- if (readReroute.wasRerouted() || writeReroute.wasRerouted() ||
- writeReroute.changedError())
- LOG_CALL()
- .PARAM(readReroute.fileName())
- .PARAM(writeReroute.fileName())
- .PARAMWRAP(dwFlags)
- .PARAMWRAP(newFlags)
- .PARAM(res)
- .PARAM(writeReroute.originalError())
- .PARAM(callContext.lastError());
- }
-
- HOOK_END
-
- return res;
-}
-
-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);
- callContext.updateLastError();
- return res;
- }
-
- HOOK_END
- HOOK_START
-
- const auto& existingFileName = ush::string_cast<std::wstring>(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;
-
- if (lpNewFileName) {
- newFileNameWstring = ush::string_cast<std::wstring>(lpNewFileName);
- newFileName = newFileNameWstring.c_str();
- }
-
- PRE_REALCALL
- res = MoveFileWithProgressW(existingFileName.c_str(), newFileName, lpProgressRoutine,
- lpData, dwFlags);
- POST_REALCALL
-
- HOOK_END
-
- return res;
-}
-
-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.
- BOOL res = FALSE;
-
- HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP)
- if (!callContext.active()) {
- res = MoveFileWithProgressW(lpExistingFileName, lpNewFileName, lpProgressRoutine,
- lpData, dwFlags);
- callContext.updateLastError();
- return res;
- }
-
- RerouteW readReroute;
- usvfs::CreateRerouter writeReroute;
- bool callOriginal = true;
- DWORD newFlags = dwFlags;
-
- {
- auto context = READ_CONTEXT();
- readReroute = RerouteW::create(context, callContext, lpExistingFileName);
- callOriginal = writeReroute.rerouteNew(context, callContext, lpNewFileName,
- newFlags & MOVEFILE_REPLACE_EXISTING,
- "hook_MoveFileWithProgressW");
- }
-
- 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) {
- 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) {
- case 0x78:
- callContext.updateLastError(ERROR_ACCESS_DENIED);
- break;
- case 0x7C:
- callContext.updateLastError(ERROR_FILE_NOT_FOUND);
- break;
- case 0x7E:
- case 0x80:
- callContext.updateLastError(ERROR_FILE_EXISTS);
- break;
- default:
- callContext.updateLastError(shRes);
- }
- res = shRes == 0;
- } else
- res = ::MoveFileWithProgressW(readReroute.fileName(), writeReroute.fileName(),
- lpProgressRoutine, lpData, newFlags);
- POST_REALCALL
-
- if (res)
- SetLastError(ERROR_SUCCESS);
-
- 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 (writeReroute.newReroute()) {
- if (isDirectory)
- RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName),
- fs::path(writeReroute.fileName()));
- else
- writeReroute.insertMapping(WRITE_CONTEXT());
- }
- }
-
- if (readReroute.wasRerouted() || writeReroute.wasRerouted() ||
- writeReroute.changedError())
- LOG_CALL()
- .PARAM(readReroute.fileName())
- .PARAM(writeReroute.fileName())
- .PARAMWRAP(dwFlags)
- .PARAMWRAP(newFlags)
- .PARAM(res)
- .PARAM(writeReroute.originalError())
- .PARAM(callContext.lastError());
- }
-
- HOOK_END
-
- return res;
-}
-
-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);
- callContext.updateLastError();
- return res;
- }
-
- RerouteW readReroute;
- usvfs::CreateRerouter writeReroute;
- bool callOriginal = true;
-
- {
- 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");
- }
-
- if (callOriginal) {
- PRE_REALCALL
- res = ::CopyFileExW(readReroute.fileName(), writeReroute.fileName(),
- lpProgressRoutine, lpData, pbCancel, dwCopyFlags);
- POST_REALCALL
- writeReroute.updateResult(callContext, res);
-
- if (res && writeReroute.newReroute())
- writeReroute.insertMapping(WRITE_CONTEXT());
-
- if (readReroute.wasRerouted() || writeReroute.wasRerouted() ||
- writeReroute.changedError())
- LOG_CALL()
- .PARAM(readReroute.fileName())
- .PARAM(writeReroute.fileName())
- .PARAM(res)
- .PARAM(writeReroute.originalError())
- .PARAM(callContext.lastError());
- }
-
- HOOK_END
-
- return res;
-}
-
-DWORD WINAPI usvfs::hook_GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer)
-{
- DWORD res = 0;
-
- HOOK_START
-
- std::wstring buffer;
- buffer.resize(nBufferLength);
-
- PRE_REALCALL
- res = GetCurrentDirectoryW(nBufferLength, &buffer[0]);
- POST_REALCALL
-
- if (res > 0) {
- res = WideCharToMultiByte(CP_ACP, 0, buffer.c_str(), res + 1, lpBuffer,
- nBufferLength, nullptr, nullptr);
- }
-
- HOOK_END
-
- return res;
-}
-
-DWORD WINAPI usvfs::hook_GetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer)
-{
- DWORD res = FALSE;
-
- HOOK_START
-
- std::wstring actualCWD;
-
- if (!k32CurrentDirectoryTracker.get(actualCWD)) {
- PRE_REALCALL
- res = ::GetCurrentDirectoryW(nBufferLength, lpBuffer);
- POST_REALCALL
- } else {
- ush::wcsncpy_sz(lpBuffer, &actualCWD[0],
- std::min(static_cast<size_t>(nBufferLength), actualCWD.size() + 1));
-
- // yupp, that's how GetCurrentDirectory actually works...
- if (actualCWD.size() < nBufferLength) {
- res = static_cast<DWORD>(actualCWD.size());
- } else {
- res = static_cast<DWORD>(actualCWD.size() + 1);
- }
- }
-
- if (nBufferLength)
- LOG_CALL()
- .PARAM(std::wstring(lpBuffer, res))
- .PARAM(nBufferLength)
- .PARAM(actualCWD.size())
- .PARAM(res)
- .PARAM(callContext.lastError());
-
- HOOK_END
-
- return res;
-}
-
-BOOL WINAPI usvfs::hook_SetCurrentDirectoryA(LPCSTR lpPathName)
-{
- return SetCurrentDirectoryW(ush::string_cast<std::wstring>(lpPathName).c_str());
-}
-
-BOOL WINAPI usvfs::hook_SetCurrentDirectoryW(LPCWSTR lpPathName)
-{
- BOOL res = FALSE;
-
- HOOK_START
-
- 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 {
- WCHAR processDir[MAX_PATH];
- 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()) {
- std::wstring reroutedPath = rerouteTest.fileName();
- if (routedName.wstring().find(processDir) != std::string::npos) {
- fs::path finalPath(reroutedPath);
- finalRoute = finalPath.parent_path().wstring();
- found = TRUE;
- }
- }
- }
-
- if (!found) {
- RerouteW reroute =
- RerouteW::create(READ_CONTEXT(), callContext, realPathStr.c_str());
- finalRoute = reroute.fileName();
- }
- }
-
- PRE_REALCALL
- res = ::SetCurrentDirectoryW(finalRoute.c_str());
- POST_REALCALL
-
- if (res)
- if (!k32CurrentDirectoryTracker.set(realPathStr))
- spdlog::get("usvfs")->warn("Updating actual current directory failed: {} ?!",
- string_cast<std::string>(realPathStr));
-
- LOG_CALL()
- .PARAM(lpPathName)
- .PARAM(realPathStr)
- .PARAM(finalRoute)
- .PARAM(res)
- .PARAM(callContext.lastError());
-
- HOOK_END
-
- return res;
-}
-
-DLLEXPORT BOOL WINAPI usvfs::hook_CreateDirectoryW(
- LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
-{
- BOOL res = FALSE;
- HOOK_START
-
- RerouteW reroute = RerouteW::createOrNew(READ_CONTEXT(), callContext, lpPathName);
-
- PRE_REALCALL
- res = ::CreateDirectoryW(reroute.fileName(), lpSecurityAttributes);
- POST_REALCALL
-
- if (res && reroute.newReroute())
- reroute.insertMapping(WRITE_CONTEXT(), true);
-
- if (reroute.wasRerouted())
- LOG_CALL()
- .PARAM(lpPathName)
- .PARAM(reroute.fileName())
- .PARAM(res)
- .PARAM(callContext.lastError());
-
- HOOK_END
-
- return res;
-}
-
-DLLEXPORT BOOL WINAPI usvfs::hook_RemoveDirectoryW(LPCWSTR lpPathName)
-{
-
- BOOL res = FALSE;
-
- HOOK_START_GROUP(MutExHookGroup::DELETE_FILE)
- // Why is the usual if (!callContext.active()... check missing?
-
- RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, lpPathName);
-
- PRE_REALCALL
- if (reroute.wasRerouted()) {
- res = ::RemoveDirectoryW(reroute.fileName());
- } else {
- res = ::RemoveDirectoryW(lpPathName);
- }
- POST_REALCALL
-
- if (res) {
- reroute.removeMapping(READ_CONTEXT(), true);
- }
-
- if (reroute.wasRerouted())
- 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 res = 0UL;
-
- HOOK_START_GROUP(MutExHookGroup::FULL_PATHNAME)
- if (!callContext.active()) {
- res = GetFullPathNameA(lpFileName, nBufferLength, lpBuffer, lpFilePart);
- callContext.updateLastError();
- return res;
- }
-
- std::string resolvedWithCMD;
-
- std::wstring actualCWD;
- fs::path filePath = ush::string_cast<std::wstring>(lpFileName, CodePage::UTF8);
- if (k32CurrentDirectoryTracker.get(actualCWD, filePath.wstring().c_str())) {
- if (!filePath.is_absolute())
- resolvedWithCMD = ush::string_cast<std::string>(
- (actualCWD / filePath.relative_path()).wstring());
- }
-
- PRE_REALCALL
- res =
- ::GetFullPathNameA(resolvedWithCMD.empty() ? lpFileName : resolvedWithCMD.c_str(),
- nBufferLength, lpBuffer, lpFilePart);
- POST_REALCALL
-
- if (false && nBufferLength)
- LOG_CALL()
- .PARAM(lpFileName)
- .PARAM(resolvedWithCMD)
- .PARAM(std::string(lpBuffer, res))
- .PARAM(nBufferLength)
- .PARAM(res)
- .PARAM(callContext.lastError());
-
- HOOK_END
-
- return res;
-}
-
-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()) {
- res = GetFullPathNameW(lpFileName, nBufferLength, lpBuffer, lpFilePart);
- callContext.updateLastError();
- return res;
- }
-
- std::wstring resolvedWithCMD;
-
- std::wstring actualCWD;
- 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);
- POST_REALCALL
-
- if (false && nBufferLength)
- LOG_CALL()
- .PARAM(lpFileName)
- .PARAM(resolvedWithCMD)
- .PARAM(std::wstring(lpBuffer, res))
- .PARAM(nBufferLength)
- .PARAM(res)
- .PARAM(callContext.lastError());
-
- HOOK_END
-
- return res;
-}
-
-DWORD WINAPI usvfs::hook_GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename,
- DWORD nSize)
-{
- DWORD res = 0UL;
-
- HOOK_START_GROUP(MutExHookGroup::ALL_GROUPS)
-
- PRE_REALCALL
- res = ::GetModuleFileNameA(hModule, lpFilename, nSize);
- POST_REALCALL
- if ((res != 0) && callContext.active()) {
- std::vector<char> buf;
- // If GetModuleFileNameA 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) {
- buf_size = std::max(static_cast<size_t>(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<std::wstring>(buf.empty() ? lpFilename : buf.data()).c_str(),
- true);
- if (reroute.wasRerouted()) {
- DWORD reroutedSize = static_cast<DWORD>(wcslen(reroute.fileName()));
- if (reroutedSize >= nSize) {
- reroutedSize = nSize - 1;
- callContext.updateLastError(ERROR_INSUFFICIENT_BUFFER);
- res = nSize;
- } else
- res = reroutedSize;
- memcpy(lpFilename, ush::string_cast<std::string>(reroute.fileName()).c_str(),
- reroutedSize * sizeof(lpFilename[0]));
- lpFilename[reroutedSize] = 0;
-
- LOG_CALL()
- .PARAM(hModule)
- .addParam("lpFilename", (res != 0UL) ? lpFilename : "<not set>")
- .PARAM(nSize)
- .PARAM(res)
- .PARAM(callContext.lastError());
- }
- }
- HOOK_END
-
- return res;
-}
-
-DWORD WINAPI usvfs::hook_GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename,
- DWORD nSize)
-{
- DWORD res = 0UL;
-
- HOOK_START_GROUP(MutExHookGroup::ALL_GROUPS)
-
- PRE_REALCALL
- res = ::GetModuleFileNameW(hModule, lpFilename, nSize);
- POST_REALCALL
- if ((res != 0) && callContext.active()) {
- std::vector<WCHAR> 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;
- size_t buf_size = nSize;
- while (full_res == buf_size) {
- buf_size = std::max(static_cast<size_t>(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()) {
- DWORD reroutedSize = static_cast<DWORD>(wcslen(reroute.fileName()));
- if (reroutedSize >= nSize) {
- reroutedSize = nSize - 1;
- callContext.updateLastError(ERROR_INSUFFICIENT_BUFFER);
- res = nSize;
- } else
- res = reroutedSize;
- memcpy(lpFilename, reroute.fileName(), reroutedSize * sizeof(lpFilename[0]));
- lpFilename[reroutedSize] = 0;
-
- LOG_CALL()
- .PARAM(hModule)
- .addParam("lpFilename", (res != 0UL) ? lpFilename : L"<not set>")
- .PARAM(nSize)
- .PARAM(res)
- .PARAM(callContext.lastError());
- }
- }
- HOOK_END
-
- return res;
-}
-
-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);
- callContext.updateLastError();
- return res;
- }
-
- // FindFirstFileEx() must fail early if the path ends with a slash
- 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());
- return INVALID_HANDLE_VALUE;
- }
- }
- }
-
- fs::path finalPath;
- RerouteW reroute;
- fs::path originalPath;
-
- 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.
- originalPath = RerouteW::canonizePath(RerouteW::absolutePath(lpFileName));
- PRE_REALCALL
- 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();
- std::wstring findPath = parentPath.wstring();
- while (findPath.find(L"*?<>\"", 0, 1) != std::wstring::npos) {
- searchPath = parentPath.filename() / searchPath;
- parentPath = parentPath.parent_path();
- findPath = parentPath.wstring();
- }
- reroute = RerouteW::create(READ_CONTEXT(), callContext, parentPath.c_str());
- if (reroute.wasRerouted()) {
- finalPath = reroute.fileName();
- finalPath /= searchPath.wstring();
- }
- if (!finalPath.empty()) {
- PRE_REALCALL
- usedRewrite = true;
- res = ::FindFirstFileExW(finalPath.c_str(), fInfoLevelId, lpFindFileData,
- fSearchOp, lpSearchFilter, dwAdditionalFlags);
- POST_REALCALL
- }
- }
-
- if (res != INVALID_HANDLE_VALUE) {
- // store the original search path for use during iteration
- WRITE_CONTEXT()->customData<SearchHandleMap>(SearchHandles)[res] = lpFileName;
- }
-
- 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());
-
- HOOK_END
-
- return res;
-}
-
-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 res = E_FAIL;
-
- typedef HRESULT(WINAPI * CopyFile2_t)(PCWSTR, PCWSTR, COPYFILE2_EXTENDED_PARAMETERS*);
-
- HOOK_START_GROUP(MutExHookGroup::SHELL_FILEOP)
- if (!callContext.active()) {
- res = CopyFile2(pwszExistingFileName, pwszNewFileName, pExtendedParameters);
- callContext.updateLastError();
- return res;
- }
-
- RerouteW readReroute;
- CreateRerouter writeReroute;
- bool callOriginal = true;
-
- {
- 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");
- }
-
- if (callOriginal) {
- PRE_REALCALL
- 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())
- LOG_CALL()
- .PARAM(readReroute.fileName())
- .PARAM(writeReroute.fileName())
- .PARAM(res)
- .PARAM(writeReroute.originalError())
- .PARAM(callContext.lastError());
- }
-
- HOOK_END
-
- return res;
-}
-
-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);
- callContext.updateLastError();
- return res;
- }
-
- RerouteW reroute = RerouteW::create(
- READ_CONTEXT(), callContext, ush::string_cast<std::wstring>(lpFileName).c_str());
-
- PRE_REALCALL
- res = ::GetPrivateProfileStringA(
- lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize,
- ush::string_cast<std::string>(reroute.fileName()).c_str());
- POST_REALCALL
-
- if (reroute.wasRerouted()) {
- LOG_CALL()
- .PARAM(lpAppName)
- .PARAM(lpKeyName)
- .PARAM(lpFileName)
- .PARAM(reroute.fileName())
- .PARAMHEX(res)
- .PARAM(callContext.lastError());
- }
-
- HOOK_END
-
- return res;
-}
-
-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);
- callContext.updateLastError();
- return res;
- }
-
- RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, lpFileName);
-
- PRE_REALCALL
- res = ::GetPrivateProfileStringW(lpAppName, lpKeyName, lpDefault, lpReturnedString,
- nSize, reroute.fileName());
- POST_REALCALL
-
- if (reroute.wasRerouted()) {
- LOG_CALL()
- .PARAM(lpAppName)
- .PARAM(lpKeyName)
- .PARAM(lpFileName)
- .PARAM(reroute.fileName())
- .PARAMHEX(res)
- .PARAM(callContext.lastError());
- }
-
- HOOK_END
-
- return res;
-}
-
-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)) {
- res = ::GetPrivateProfileSectionA(lpAppName, lpReturnedString, nSize, lpFileName);
- callContext.updateLastError();
- return res;
- }
-
- RerouteW reroute = RerouteW::create(
- READ_CONTEXT(), callContext, ush::string_cast<std::wstring>(lpFileName).c_str());
-
- PRE_REALCALL
- res = ::GetPrivateProfileSectionA(
- lpAppName, lpReturnedString, nSize,
- ush::string_cast<std::string>(reroute.fileName()).c_str());
- POST_REALCALL
-
- if (reroute.wasRerouted()) {
- LOG_CALL()
- .PARAM(lpAppName)
- .PARAM(lpFileName)
- .PARAM(reroute.fileName())
- .PARAMHEX(res)
- .PARAM(callContext.lastError());
- }
-
- HOOK_END
-
- return res;
-}
-
-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)) {
- res = ::GetPrivateProfileSectionW(lpAppName, lpReturnedString, nSize, lpFileName);
- callContext.updateLastError();
- return res;
- }
-
- RerouteW reroute = RerouteW::create(READ_CONTEXT(), callContext, lpFileName);
-
- PRE_REALCALL
- res = ::GetPrivateProfileSectionW(lpAppName, lpReturnedString, nSize,
- reroute.fileName());
- POST_REALCALL
-
- if (reroute.wasRerouted()) {
- LOG_CALL()
- .PARAM(lpAppName)
- .PARAM(lpFileName)
- .PARAM(reroute.fileName())
- .PARAMHEX(res)
- .PARAM(callContext.lastError());
- }
-
- HOOK_END
-
- return res;
-}
-
-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)) {
- res = ::WritePrivateProfileStringA(lpAppName, lpKeyName, lpString, lpFileName);
- callContext.updateLastError();
- return res;
- }
-
- CreateRerouter reroute;
- bool callOriginal = reroute.rerouteNew(
- READ_CONTEXT(), callContext, ush::string_cast<std::wstring>(lpFileName).c_str(),
- true, "hook_WritePrivateProfileStringA");
-
- if (callOriginal) {
- PRE_REALCALL
- res = ::WritePrivateProfileStringA(
- lpAppName, lpKeyName, lpString,
- ush::string_cast<std::string>(reroute.fileName()).c_str());
- POST_REALCALL
- reroute.updateResult(callContext, res);
-
- if (res && reroute.newReroute())
- reroute.insertMapping(WRITE_CONTEXT());
-
- if (reroute.wasRerouted() || reroute.changedError())
- LOG_CALL()
- .PARAM(lpAppName)
- .PARAM(lpKeyName)
- .PARAM(lpFileName)
- .PARAM(reroute.fileName())
- .PARAMHEX(res)
- .PARAM(reroute.originalError())
- .PARAM(callContext.lastError());
- }
-
- HOOK_END
-
- return res;
-}
-
-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)) {
- res = ::WritePrivateProfileStringW(lpAppName, lpKeyName, lpString, lpFileName);
- callContext.updateLastError();
- return res;
- }
-
- CreateRerouter reroute;
- bool callOriginal = reroute.rerouteNew(READ_CONTEXT(), callContext, lpFileName, true,
- "hook_WritePrivateProfileStringW");
-
- if (callOriginal) {
- PRE_REALCALL
- res = ::WritePrivateProfileStringW(lpAppName, lpKeyName, lpString,
- reroute.fileName());
- POST_REALCALL
- reroute.updateResult(callContext, res);
-
- if (res && reroute.newReroute())
- reroute.insertMapping(WRITE_CONTEXT());
-
- if (reroute.wasRerouted() || reroute.changedError())
- LOG_CALL()
- .PARAM(lpAppName)
- .PARAM(lpKeyName)
- .PARAM(lpFileName)
- .PARAM(reroute.fileName())
- .PARAMHEX(res)
- .PARAM(reroute.originalError())
- .PARAM(callContext.lastError());
- }
-
- HOOK_END
-
- return res;
-}
-
-VOID WINAPI usvfs::hook_ExitProcess(UINT exitCode)
-{
- HOOK_START
-
- {
- HookContext::Ptr context = WRITE_CONTEXT();
-
- std::vector<std::future<int>>& delayed = context->delayed();
-
- if (!delayed.empty()) {
- // ensure all delayed tasks are completed before we exit the process
- for (std::future<int>& delayedOp : delayed) {
- delayedOp.get();
- }
- delayed.clear();
- }
- }
-
- // exitprocess doesn't return so logging the call after the real call doesn't
- // make much sense.
- // nor does any pre/post call macro
- LOG_CALL().PARAM(exitCode);
-
- usvfsDisconnectVFS();
-
- // HookManager::instance().removeHook("ExitProcess");
- // PRE_REALCALL
- ::ExitProcess(exitCode);
- // POST_REALCALL
-
- HOOK_END
-}
diff --git a/libs/usvfs/src/usvfs_dll/hooks/kernel32.h b/libs/usvfs/src/usvfs_dll/hooks/kernel32.h
deleted file mode 100644
index 7087b2e..0000000
--- a/libs/usvfs/src/usvfs_dll/hooks/kernel32.h
+++ /dev/null
@@ -1,116 +0,0 @@
-#pragma once
-
-#include "ntdll_declarations.h"
-#include <dllimport.h>
-
-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 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_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 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_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);
-
-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);
-
-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 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/libs/usvfs/src/usvfs_dll/hooks/ntdll.cpp b/libs/usvfs/src/usvfs_dll/hooks/ntdll.cpp
deleted file mode 100644
index ad53418..0000000
--- a/libs/usvfs/src/usvfs_dll/hooks/ntdll.cpp
+++ /dev/null
@@ -1,1520 +0,0 @@
-#include "ntdll.h"
-
-#include <mutex>
-#include <queue>
-#include <set>
-
-#include <boost/filesystem.hpp>
-
-#include <addrtools.h>
-#include <loghelpers.h>
-#include <stringcast.h>
-#include <stringutils.h>
-#include <unicodestring.h>
-#include <usvfs.h>
-
-#include "../hookcallcontext.h"
-#include "../hookcontext.h"
-#include "../maptracker.h"
-#include "../stringcast_boost.h"
-
-#include "file_information_utils.h"
-#include "sharedids.h"
-
-namespace ulog = usvfs::log;
-namespace ush = usvfs::shared;
-namespace bfs = boost::filesystem;
-
-using usvfs::UnicodeString;
-
-// flag definitions below are copied from winternl.h
-#define FILE_SUPERSEDE 0x00000000
-#define FILE_OPEN 0x00000001
-#define FILE_CREATE 0x00000002
-#define FILE_OPEN_IF 0x00000003
-#define FILE_OVERWRITE 0x00000004
-#define FILE_OVERWRITE_IF 0x00000005
-#define FILE_MAXIMUM_DISPOSITION 0x00000005
-
-template <typename T>
-using unique_ptr_deleter = std::unique_ptr<T, void (*)(T*)>;
-
-class RedirectionInfo
-{
-public:
- UnicodeString path;
- bool redirected;
-
- RedirectionInfo() {}
- RedirectionInfo(UnicodeString path, bool redirected)
- : path(path), redirected(redirected)
- {}
-};
-
-class HandleTracker
-{
-public:
- using handle_type = HANDLE;
- using info_type = UnicodeString;
-
- HandleTracker() { insert_current_directory(); }
-
- info_type lookup(handle_type handle) const
- {
- if (valid_handle(handle)) {
- std::shared_lock<std::shared_mutex> lock(m_mutex);
- auto find = m_map.find(handle);
- if (find != m_map.end())
- return find->second;
- }
- return info_type();
- }
-
- void insert(handle_type handle, const info_type& info)
- {
- if (!valid_handle(handle))
- return;
- std::unique_lock<std::shared_mutex> lock(m_mutex);
- m_map[handle] = info;
- }
-
- void erase(handle_type handle)
- {
- if (!valid_handle(handle))
- return;
- std::unique_lock<std::shared_mutex> lock(m_mutex);
- m_map.erase(handle);
- }
-
-private:
- 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);
- if (status >= 0) {
- 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));
- }
- RtlReleaseRelativeName(&r);
- if (p.Buffer)
- HeapFree(GetProcessHeap(), 0, p.Buffer);
- }
- }
-
- mutable std::shared_mutex m_mutex;
- std::unordered_map<handle_type, info_type> m_map;
-};
-
-HandleTracker ntdllHandleTracker;
-
-UnicodeString CreateUnicodeString(const OBJECT_ATTRIBUTES* objectAttributes)
-{
- UnicodeString result = ntdllHandleTracker.lookup(objectAttributes->RootDirectory);
- if (objectAttributes->ObjectName != nullptr) {
- result.appendPath(objectAttributes->ObjectName);
- }
- return result;
-}
-
-std::ostream& operator<<(std::ostream& os, const _UNICODE_STRING& str)
-{
- try {
- // 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 case scenario we truncate
- // the string
- os << ush::string_cast<std::string>(str.Buffer, ush::CodePage::UTF8,
- str.Length / sizeof(WCHAR));
- } catch (const std::exception& e) {
- os << e.what();
- }
-
- return os;
-}
-
-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 result;
- result.path = inPath;
- result.redirected = false;
-
- if (callContext.active()) {
- // see if the file exists in the redirection tree
- std::string lookupPath = ush::string_cast<std::string>(
- static_cast<LPCWSTR>(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())) {
- std::wstring reroutePath;
-
- if (node->data().linkTarget.length() > 0) {
- reroutePath = ush::string_cast<std::wstring>(node->data().linkTarget.c_str(),
- ush::CodePage::UTF8);
- } else {
- reroutePath =
- ush::string_cast<std::wstring>(node->path().c_str(), ush::CodePage::UTF8);
- }
- if ((*reroutePath.rbegin() == L'\\') && (*lookupPath.rbegin() != '\\')) {
- reroutePath.resize(reroutePath.size() - 1);
- }
- std::replace(reroutePath.begin(), reroutePath.end(), L'/', L'\\');
- if (reroutePath[1] == L'\\')
- reroutePath[1] = L'?';
- result.path = LR"(\??\)" + reroutePath;
- result.redirected = true;
- }
- }
- return result;
-}
-
-RedirectionInfo applyReroute(const usvfs::CreateRerouter& rerouter)
-{
- RedirectionInfo result;
- result.path = rerouter.fileName();
- result.redirected = rerouter.wasRerouted();
-
- std::wstring reroutePath(static_cast<LPCWSTR>(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'\\'))) {
- result.path = LR"(\??\)" + reroutePath;
- }
-
- return result;
-}
-
-struct FindCreateTarget
-{
- usvfs::RedirectionTree::NodePtrT target;
- void operator()(usvfs::RedirectionTree::NodePtrT node)
- {
- if (node->hasFlag(usvfs::shared::FLAG_CREATETARGET)) {
- target = node;
- }
- }
-};
-
-std::pair<UnicodeString, UnicodeString>
-findCreateTarget(const usvfs::HookContext::ConstPtr& context,
- const UnicodeString& inPath)
-{
- std::pair<UnicodeString, UnicodeString> result;
- result.first = inPath;
- result.second = UnicodeString();
-
- std::string lookupPath = ush::string_cast<std::string>(
- static_cast<LPCWSTR>(result.first) + 4, ush::CodePage::UTF8);
- FindCreateTarget visitor;
- usvfs::RedirectionTree::VisitorFunction visitorWrapper =
- [&](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 target(visitor.target->data().linkTarget.c_str());
- target /= relativePath;
-
- result.second = UnicodeString(target.wstring().c_str());
- winapi::ex::wide::createPath(target.parent_path());
- }
- return result;
-}
-
-RedirectionInfo applyReroute(const usvfs::HookContext::ConstPtr& context,
- const usvfs::HookCallContext& callContext,
- POBJECT_ATTRIBUTES inAttributes)
-{
- return applyReroute(context, callContext, CreateUnicodeString(inAttributes));
-}
-
-int NextDividableBy(int number, int divider)
-{
- return static_cast<int>(
- ceilf(static_cast<float>(number) / static_cast<float>(divider)) * divider);
-}
-
-// Something is trying to create a variety of files starting with "\Device\",
-// such as "\Device\DeviceApi\Dev\Query", "\Device\MMCSS\MmThread",
-// "\Device\DeviceApi\CMNotify", etc.
-//
-// This used to create a bunch of spurious "Device" and "MMCSS" folders when
-// using Explorer++. Some of these names seem to part of PnP, others from the
-// "Multimedia Class Scheduler Service".
-//
-// There's basically zero information on this stuff online.
-//
-// Regardless, these files ended up being rerouted, so they became something
-// like C:\game\Data\Somewhere\Device\MMCSS\MmThread, which ended up being
-// rerouted to overwrite and created as a fake path
-// "overwrite\Somewhere\Device\MMCSS"
-//
-// These paths are weird, they feel like pipes or something. It's not clear how
-// they should be reliably recognized, so this is a hardcoded check for any
-// path that starts with "\Device\". These paths will be forwarded directly
-// to NtCreateFile/NtOpenFile
-//
-bool isDeviceFile(std::wstring_view name)
-{
- static const std::wstring_view DevicePrefix(L"\\Device\\");
-
- // starts with
- if (name.size() < DevicePrefix.size()) {
- return false;
- } else {
- return (_wcsnicmp(name.data(), DevicePrefix.data(), DevicePrefix.size()) == 0);
- }
-}
-
-NTSTATUS addNtSearchData(HANDLE hdl, PUNICODE_STRING FileName,
- const std::wstring& fakeName,
- FILE_INFORMATION_CLASS FileInformationClass, PVOID& buffer,
- ULONG& bufferSize, std::set<std::wstring>& 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;
- IO_STATUS_BLOCK status;
- 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;
-
- while (totalOffset < status.Information) {
- ULONG offset;
- std::wstring fileName;
- GetFileInformationData(FileInformationClass, buffer, offset, fileName);
- // in case this is a single-file search result and the specified
- // filename differs from the file name found, replace it in the
- // information structure
- 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))) {
- res = STATUS_BUFFER_OVERFLOW;
- break;
- }
- // WARNING for the case where the fake name is longer this needs to
- // move back all further results and update the offset first
- SetFileInformationFileName(FileInformationClass, buffer, fakeName);
- fileName = fakeName;
- }
- 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
- }
- if (!add) {
- if (lastSkipPos == nullptr) {
- lastSkipPos = buffer;
- }
- } else {
- if (lastSkipPos != nullptr) {
- memmove(lastSkipPos, buffer, status.Information - totalOffset);
- ULONG delta = static_cast<ULONG>(ush::AddrDiff(buffer, lastSkipPos));
- totalOffset -= delta;
-
- buffer = lastSkipPos;
- lastSkipPos = nullptr;
- }
- lastValidRecord = buffer;
- }
-
- if (offset == 0) {
- offset = static_cast<ULONG>(status.Information) - totalOffset;
- }
- buffer = ush::AddrAdd(buffer, offset);
- totalOffset += offset;
- }
-
- if (lastSkipPos != nullptr) {
- buffer = lastSkipPos;
- bufferSize = static_cast<ULONG>(ush::AddrDiff(buffer, bufferInit));
- // null out the unused rest if there is some
- memset(lastSkipPos, 0, status.Information - bufferSize);
- } else {
- bufferSize = static_cast<ULONG>(ush::AddrDiff(buffer, bufferInit));
- }
- }
- if (lastValidRecord != nullptr) {
- SetFileInformationOffset(FileInformationClass, lastValidRecord, 0);
- }
- }
- return res;
-}
-
-DATA_ID(SearchInfo);
-
-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
- // directory)
- // this is left empty when a folder with all its content is mapped to the
- // search directory
- std::wstring virtualName;
- };
-
- Info() : currentSearchHandle(INVALID_HANDLE_VALUE) {}
- std::set<std::wstring> foundFiles;
- HANDLE currentSearchHandle;
- std::queue<VirtualMatch> virtualMatches;
- UnicodeString searchPattern;
- bool regularComplete{false};
- };
-
- Searches() = default;
-
- // must provide a special copy constructor because boost::mutex is
- // non-copyable
- Searches(const Searches& reference) : info(reference.info) {}
-
- Searches& operator=(const Searches&) = delete;
-
- std::recursive_mutex queryMutex;
-
- std::map<HANDLE, Info> info;
-};
-
-void gatherVirtualEntries(const UnicodeString& dirName,
- const usvfs::RedirectionTreeContainer& redir,
- PUNICODE_STRING FileName, Searches::Info& info)
-{
- LPCWSTR dirNameW = static_cast<LPCWSTR>(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)) {
- dirNameW += 4;
- }
- auto node = redir->findNode(boost::filesystem::path(dirNameW));
- if (node.get() != nullptr) {
- std::string searchPattern =
- FileName != nullptr
- ? ush::string_cast<std::string>(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<std::wstring>(subNode->name(), ush::CodePage::UTF8);
-
- Searches::Info::VirtualMatch m;
- if (subNode->data().linkTarget.length() > 0) {
- m = {ush::string_cast<std::wstring>(subNode->data().linkTarget.c_str(),
- ush::CodePage::UTF8),
- vName};
- } else {
- m = {ush::string_cast<std::wstring>(subNode->path().c_str(),
- ush::CodePage::UTF8),
- vName};
- }
-
- info.virtualMatches.push(m);
- info.foundFiles.insert(ush::to_upper(vName));
- }
- }
- }
-}
-
-/**
- * @brief insert a virtual entry into the search result
- * @param FileInformation
- * @param FileInformationClass
- * @param info
- * @param realPath path were the actual file resides
- * @param virtualName virtual file name (without path). will often be the same
- * as the name component of realpath
- * @param ReturnSingleEntry
- * @param dataRead
- * @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,
- FILE_INFORMATION_CLASS FileInformationClass,
- 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
- // return
- bfs::path fullPath(realPath);
- if (fullPath.filename().wstring() == L".") {
- fullPath = fullPath.parent_path();
- }
- if (info.currentSearchHandle == INVALID_HANDLE_VALUE) {
- 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);
- }
- std::wstring fileName =
- ush::string_cast<std::wstring>(fullPath.filename().string(), ush::CodePage::UTF8);
- NTSTATUS subRes = addNtSearchData(
- info.currentSearchHandle,
- (fileName != L".") ? static_cast<PUNICODE_STRING>(UnicodeString(fileName.c_str()))
- : nullptr,
- virtualName, FileInformationClass, FileInformation, dataRead, info.foundFiles,
- nullptr, nullptr, nullptr, ReturnSingleEntry);
- if (subRes == STATUS_SUCCESS) {
- return true;
- } else {
- // STATUS_NO_MORE_FILES merely means the search ended, everything else is an
- // error message. Either way, the search here is finished and we should
- // 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<uint32_t>(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)
-{
- PreserveGetLastError ntFunctionsDoNotChangeGetLastError;
-
- // this is quite messy...
- // first, this will gather the virtual locations mapping to the iterated one
- // then we return results from the real location, skipping those that exist
- // in the virtual locations, as those take precedence
- // finally the virtual results are returned, adding each result to a skip
- // list, so they don't get added twice
- //
- // if we don't add the regular files first, "." and ".." wouldn't be in the
- // first search result of wildcard searches which may confuse the caller
- 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);
- }
-
- // std::unique_lock<std::recursive_mutex> queryLock;
- std::map<HANDLE, Searches::Info>::iterator infoIter;
- bool firstSearch = false;
-
- { // scope to limit context lifetime
- HookContext::ConstPtr context = READ_CONTEXT();
- Searches& activeSearches = context->customData<Searches>(SearchInfo);
- // queryLock = std::unique_lock<std::recursive_mutex>(activeSearches.queryMutex);
-
- if (RestartScan) {
- auto iter = activeSearches.info.find(FileHandle);
- if (iter != activeSearches.info.end()) {
- activeSearches.info.erase(iter);
- }
- }
-
- // see if we already have a running search
- infoIter = activeSearches.info.find(FileHandle);
- firstSearch = (infoIter == activeSearches.info.end());
- }
-
- if (firstSearch) {
- HookContext::Ptr context = WRITE_CONTEXT();
- Searches& activeSearches = context->customData<Searches>(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->second.searchPattern.appendPath(FileName);
-
- SearchHandleMap& searchMap = context->customData<SearchHandleMap>(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 = ntdllHandleTracker.lookup(FileHandle);
- }
- gatherVirtualEntries(searchPath, context->redirectionTable(), FileName,
- infoIter->second);
- }
-
- 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 dataReturned = false;
- while (moreRegular && !dataReturned) {
- 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);
- moreRegular = subRes == STATUS_SUCCESS;
- if (moreRegular) {
- dataReturned = dataRead != 0;
- } else {
- infoIter->second.regularComplete = true;
- infoIter->second.foundFiles.clear();
- if (infoIter->second.currentSearchHandle != INVALID_HANDLE_VALUE) {
- ::CloseHandle(infoIter->second.currentSearchHandle);
- infoIter->second.currentSearchHandle = INVALID_HANDLE_VALUE;
- }
- }
- }
- if (!moreRegular) {
- // add virtual results
- while (!dataReturned && infoIter->second.virtualMatches.size() > 0) {
- auto match = infoIter->second.virtualMatches.front();
- if (match.realPath.size() != 0) {
- dataRead = Length;
- if (addVirtualSearchResult(FileInformationCurrent, FileInformationClass,
- 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;
- } else {
- // proceed to next search handle
-
- // TODO: doesn't append search results from more than one redirection
- // per call. This is bad for performance but otherwise we'd need to
- // re-write the offsets between information objects
- infoIter->second.virtualMatches.pop();
- CloseHandle(infoIter->second.currentSearchHandle);
- infoIter->second.currentSearchHandle = INVALID_HANDLE_VALUE;
- }
- }
- }
- }
-
- if (!dataReturned) {
- if (firstSearch) {
- res = STATUS_NO_SUCH_FILE;
- } else {
- res = STATUS_NO_MORE_FILES;
- }
- } else {
- res = STATUS_SUCCESS;
- }
- 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(numVirtualFiles)
- .PARAMWRAP(res);
- }
-
- HOOK_END
- return res;
-}
-
-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,
- PUNICODE_STRING FileName)
-{
- PreserveGetLastError ntFunctionsDoNotChangeGetLastError;
- NTSTATUS res = STATUS_NO_MORE_FILES;
-
- // this is quite messy...
- // first, this will gather the virtual locations mapping to the iterated one
- // then we return results from the real location, skipping those that exist
- // in the virtual locations, as those take precedence
- // finally the virtual results are returned, adding each result to a skip
- // list, so they don't get added twice
- //
- // if we don't add the regular files first, "." and ".." wouldn't be in the
- // first search result of wildcard searches which may confuse the caller
- HOOK_START_GROUP(MutExHookGroup::FIND_FILES)
- if (!callContext.active()) {
- return ::NtQueryDirectoryFileEx(FileHandle, Event, ApcRoutine, ApcContext,
- IoStatusBlock, FileInformation, Length,
- FileInformationClass, QueryFlags, FileName);
- }
-
- // std::unique_lock<std::recursive_mutex> queryLock;
- std::map<HANDLE, Searches::Info>::iterator infoIter;
- bool firstSearch = false;
-
- { // scope to limit context lifetime
- HookContext::ConstPtr context = READ_CONTEXT();
- Searches& activeSearches = context->customData<Searches>(SearchInfo);
- // queryLock = std::unique_lock<std::recursive_mutex>(activeSearches.queryMutex);
-
- if (QueryFlags & SL_RESTART_SCAN) {
- auto iter = activeSearches.info.find(FileHandle);
- if (iter != activeSearches.info.end()) {
- activeSearches.info.erase(iter);
- }
- }
-
- // see if we already have a running search
- infoIter = activeSearches.info.find(FileHandle);
- firstSearch = (infoIter == activeSearches.info.end());
- }
-
- if (firstSearch) {
- HookContext::Ptr context = WRITE_CONTEXT();
- Searches& activeSearches = context->customData<Searches>(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->second.searchPattern.appendPath(FileName);
-
- SearchHandleMap& searchMap = context->customData<SearchHandleMap>(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 = ntdllHandleTracker.lookup(FileHandle);
- }
- gatherVirtualEntries(searchPath, context->redirectionTable(), FileName,
- infoIter->second);
- }
-
- 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 dataReturned = false;
- while (moreRegular && !dataReturned) {
- 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, QueryFlags & SL_RETURN_SINGLE_ENTRY);
- moreRegular = subRes == STATUS_SUCCESS;
- if (moreRegular) {
- dataReturned = dataRead != 0;
- } else {
- infoIter->second.regularComplete = true;
- infoIter->second.foundFiles.clear();
- if (infoIter->second.currentSearchHandle != INVALID_HANDLE_VALUE) {
- ::CloseHandle(infoIter->second.currentSearchHandle);
- infoIter->second.currentSearchHandle = INVALID_HANDLE_VALUE;
- }
- }
- }
- if (!moreRegular) {
- // add virtual results
- while (!dataReturned && infoIter->second.virtualMatches.size() > 0) {
- auto match = infoIter->second.virtualMatches.front();
- if (match.realPath.size() != 0) {
- dataRead = Length;
- if (addVirtualSearchResult(FileInformationCurrent, FileInformationClass,
- 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 {
- // proceed to next search handle
-
- // TODO: doesn't append search results from more than one redirection
- // per call. This is bad for performance but otherwise we'd need to
- // re-write the offsets between information objects
- infoIter->second.virtualMatches.pop();
- CloseHandle(infoIter->second.currentSearchHandle);
- infoIter->second.currentSearchHandle = INVALID_HANDLE_VALUE;
- }
- }
- }
- }
-
- if (!dataReturned) {
- if (firstSearch) {
- res = STATUS_NO_SUCH_FILE;
- } else {
- res = STATUS_NO_MORE_FILES;
- }
- } else {
- res = STATUS_SUCCESS;
- }
- 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);
- }
-
- HOOK_END
- return res;
-}
-
-DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryObject(
- 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);
- }
-
- PRE_REALCALL
- res = ::NtQueryObject(Handle, ObjectInformationClass, ObjectInformation,
- ObjectInformationLength, ReturnLength);
- POST_REALCALL
-
- // we handle both SUCCESS and BUFFER_OVERFLOW since the fixed name might be
- // 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
- // (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)) {
- const auto trackerInfo = ntdllHandleTracker.lookup(Handle);
- const auto redir = applyReroute(READ_CONTEXT(), callContext, trackerInfo);
-
- OBJECT_NAME_INFORMATION* info =
- reinterpret_cast<OBJECT_NAME_INFORMATION*>(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
- //
- WCHAR deviceName[MAX_PATH];
- std::wstring buffer(static_cast<LPCWSTR>(trackerInfo));
- buffer[6] = L'\0';
-
- QueryDosDeviceW(buffer.data() + 4, deviceName, ARRAYSIZE(deviceName));
-
- 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;
- if (ObjectInformationLength < requiredLength) {
- // 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;
- }
-
- if (ReturnLength) {
- *ReturnLength = static_cast<ULONG>(requiredLength);
- }
- } else {
- // put the unicode buffer at the end of the object
- const USHORT unicodeBufferLength = static_cast<USHORT>(std::min(
- static_cast<unsigned long long>(std::numeric_limits<USHORT>::max()),
- static_cast<unsigned long long>(ObjectInformationLength -
- sizeof(OBJECT_NAME_INFORMATION))));
- LPWSTR unicodeBuffer = reinterpret_cast<LPWSTR>(
- static_cast<LPSTR>(ObjectInformation) + sizeof(OBJECT_NAME_INFORMATION));
-
- // copy the path into the buffer
- wmemcpy_s(unicodeBuffer, unicodeBufferLength, buffer.data(), buffer.size());
-
- // set the null character
- unicodeBuffer[buffer.size()] = L'\0';
-
- // update the actual unicode string
- info->Name.Buffer = unicodeBuffer;
- info->Name.Length = static_cast<USHORT>(buffer.size() * 2);
- info->Name.MaximumLength = unicodeBufferLength;
-
- 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);
-
- if (res == STATUS_SUCCESS) {
- logger.addParam("name_info", info->Name);
- } else {
- logger.addParam("name_info", "");
- }
- }
-
- HOOK_END
- return res;
-}
-
-DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryInformationFile(
- 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);
- }
-
- PRE_REALCALL
- res = ::NtQueryInformationFile(FileHandle, IoStatusBlock, FileInformation, Length,
- FileInformationClass);
- POST_REALCALL
-
- // we handle both SUCCESS and BUFFER_OVERFLOW since the fixed name might be
- // smaller than the original one
- //
- // 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)) ||
- (res == STATUS_SUCCESS && FileInformationClass == FileAllInformation)) {
-
- const auto trackerInfo = ntdllHandleTracker.lookup(FileHandle);
- 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)
- //
- // 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;
- if (FileInformationClass == FileAllInformation) {
- info = &reinterpret_cast<FILE_ALL_INFORMATION*>(FileInformation)->NameInformation;
- prefixStructLength = sizeof(FILE_ALL_INFORMATION) - 4;
- } else {
- info = reinterpret_cast<FILE_NAME_INFORMATION*>(FileInformation);
- prefixStructLength = sizeof(FILE_NAME_INFORMATION) - 4;
- }
-
- if (redir.redirected) {
- auto requiredLength = prefixStructLength + 2 * (trackerInfo.size() - 6);
- if (Length < requiredLength) {
- res = STATUS_BUFFER_OVERFLOW;
- } else {
- // strip the \??\X: prefix (X being the drive name)
- LPCWSTR filenameFixed = static_cast<LPCWSTR>(trackerInfo) + 6;
-
- // not using SetInfoFilename because the length is not set and we do not need to
- // 0-out the memory here
- info->FileNameLength = static_cast<ULONG>((trackerInfo.size() - 6) * 2);
- wmemcpy(info->FileName, filenameFixed, trackerInfo.size() - 6);
- res = STATUS_SUCCESS;
-
- // update status block, Information is the number of bytes written, basically
- // the required length
- IoStatusBlock->Status = STATUS_SUCCESS;
- IoStatusBlock->Information = static_cast<ULONG_PTR>(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,
- info->FileNameLength / sizeof(WCHAR)}
- : std::wstring{});
- }
-
- HOOK_END
- return res;
-}
-
-unique_ptr_deleter<OBJECT_ATTRIBUTES>
-makeObjectAttributes(RedirectionInfo& redirInfo, POBJECT_ATTRIBUTES attributeTemplate)
-{
- if (redirInfo.redirected) {
- unique_ptr_deleter<OBJECT_ATTRIBUTES> result(new OBJECT_ATTRIBUTES,
- [](OBJECT_ATTRIBUTES* ptr) {
- delete ptr;
- });
- memcpy(result.get(), attributeTemplate, sizeof(OBJECT_ATTRIBUTES));
- result->RootDirectory = nullptr;
- result->ObjectName = static_cast<PUNICODE_STRING>(redirInfo.path);
- return result;
- } else {
- // just reuse the template with a dummy deleter
- return unique_ptr_deleter<OBJECT_ATTRIBUTES>(attributeTemplate,
- [](OBJECT_ATTRIBUTES*) {});
- }
-}
-
-DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryInformationByName(
- 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);
- callContext.updateLastError();
- return res;
- }
-
- 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);
- POST_REALCALL
-
- LOG_CALL()
- .PARAMWRAP(res)
- .addParam("input_path", *ObjectAttributes->ObjectName)
- .addParam("reroute_path", redir.path);
- } else {
- PRE_REALCALL
- res = ::NtQueryInformationByName(ObjectAttributes, IoStatusBlock, FileInformation,
- Length, FileInformationClass);
- POST_REALCALL
- }
-
- HOOK_END
- return res;
-}
-
-NTSTATUS ntdll_mess_NtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess,
- POBJECT_ATTRIBUTES ObjectAttributes,
- PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess,
- ULONG OpenOptions)
-{
- using namespace usvfs;
-
- PreserveGetLastError ntFunctionsDoNotChangeGetLastError;
-
- NTSTATUS res = STATUS_NO_SUCH_FILE;
-
- HOOK_START_GROUP(MutExHookGroup::OPEN_FILE)
- // 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)) {
- // 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));*/
- storePath = true;
- }
-
- UnicodeString fullName = CreateUnicodeString(ObjectAttributes);
-
- if (isDeviceFile(static_cast<LPCWSTR>(fullName))) {
- return ::NtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock,
- ShareAccess, OpenOptions);
- }
-
- UnicodeString Path = ntdllHandleTracker.lookup(ObjectAttributes->RootDirectory);
-
- std::wstring checkpath =
- ush::string_cast<std::wstring>(static_cast<LPCWSTR>(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);
- }
- }
-
- try {
- RedirectionInfo redir = applyReroute(READ_CONTEXT(), callContext, fullName);
- unique_ptr_deleter<OBJECT_ATTRIBUTES> adjustedAttributes =
- makeObjectAttributes(redir, ObjectAttributes);
-
- PRE_REALCALL
- res = ::NtOpenFile(FileHandle, DesiredAccess, adjustedAttributes.get(),
- IoStatusBlock, ShareAccess, OpenOptions);
- POST_REALCALL
- if (SUCCEEDED(res) && storePath) {
- // store the original search path for use during iteration
- READ_CONTEXT()->customData<SearchHandleMap>(SearchHandles)[*FileHandle] =
- static_cast<LPCWSTR>(fullName);
-#pragma message("need to clean up this handle in CloseHandle call")
- }
-
- if (redir.redirected) {
- LOG_CALL()
- .addParam("source", ObjectAttributes)
- .addParam("rerouted", adjustedAttributes.get())
- .PARAM(*FileHandle)
- .PARAM(OpenOptions)
- .PARAMWRAP(res);
- }
- } catch (const std::exception&) {
- PRE_REALCALL
- res = ::NtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock,
- ShareAccess, OpenOptions);
- POST_REALCALL
- }
- HOOK_END
-
- return res;
-}
-
-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)
- 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)
-{
- using namespace usvfs;
-
- NTSTATUS res = STATUS_NO_SUCH_FILE;
-
- PreserveGetLastError ntFunctionsDoNotChangeGetLastError;
-
- HOOK_START_GROUP(MutExHookGroup::OPEN_FILE)
- if (!callContext.active()) {
- return ::NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock,
- AllocationSize, FileAttributes, ShareAccess,
- CreateDisposition, CreateOptions, EaBuffer, EaLength);
- }
-
- UnicodeString inPath = CreateUnicodeString(ObjectAttributes);
- LPCWSTR inPathW = static_cast<LPCWSTR>(inPath);
-
- if (inPath.size() == 0) {
- spdlog::get("hooks")->info(
- "failed to set from handle: {0}",
- ush::string_cast<std::string>(ObjectAttributes->ObjectName->Buffer));
- 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);
- }
-
- 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;
- }
-
- 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;
-
- 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;
- }
-
- RedirectionInfo redir = applyReroute(rerouter);
-
- unique_ptr_deleter<OBJECT_ATTRIBUTES> adjustedAttributes =
- makeObjectAttributes(redir, ObjectAttributes);
-
- PRE_REALCALL
- res = ::NtCreateFile(FileHandle, DesiredAccess, adjustedAttributes.get(),
- IoStatusBlock, AllocationSize, FileAttributes, ShareAccess,
- CreateDisposition, CreateOptions, EaBuffer, EaLength);
- POST_REALCALL
- rerouter.updateResult(callContext, res == STATUS_SUCCESS);
-
- if (res == STATUS_SUCCESS) {
- if (rerouter.newReroute())
- rerouter.insertMapping(WRITE_CONTEXT());
-
- 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<SearchHandleMap>(SearchHandles)[*FileHandle] =
- inPathW;
- }
- }
-
- 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());
- }
- } 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);
- POST_REALCALL
- }
-
- HOOK_END
-
- 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 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;
-}
-
-NTSTATUS WINAPI usvfs::hook_NtClose(HANDLE Handle)
-{
- PreserveGetLastError ntFunctionsDoNotChangeGetLastError;
-
- NTSTATUS res = STATUS_NO_SUCH_FILE;
-
- HOOK_START_GROUP(MutExHookGroup::ALL_GROUPS)
- bool log = false;
-
- 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<Searches>(SearchInfo);
- // std::lock_guard<std::recursive_mutex> lock(activeSearches.queryMutex);
- auto iter = activeSearches.info.find(Handle);
- if (iter != activeSearches.info.end()) {
- if (iter->second.currentSearchHandle != INVALID_HANDLE_VALUE) {
- ::CloseHandle(iter->second.currentSearchHandle);
- }
-
- activeSearches.info.erase(iter);
- log = true;
- }
- }
-
- {
- SearchHandleMap& searchHandles =
- context->customData<SearchHandleMap>(SearchHandles);
- auto iter = searchHandles.find(Handle);
- if (iter != searchHandles.end()) {
- searchHandles.erase(iter);
- log = true;
- }
- }
- }
-
- if (GetFileType(Handle) == FILE_TYPE_DISK)
- ntdllHandleTracker.erase(Handle);
-
- PRE_REALCALL
- res = ::NtClose(Handle);
- POST_REALCALL
-
- if (log) {
- LOG_CALL().PARAM(Handle).PARAMWRAP(res);
- }
-
- HOOK_END
-
- return res;
-}
-
-NTSTATUS WINAPI usvfs::hook_NtQueryAttributesFile(
- POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation)
-{
- PreserveGetLastError ntFunctionsDoNotChangeGetLastError;
-
- NTSTATUS res = STATUS_SUCCESS;
-
- HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES)
- // Why is the usual if (!callContext.active()... check missing?
-
- UnicodeString inPath = CreateUnicodeString(ObjectAttributes);
-
- RedirectionInfo redir = applyReroute(READ_CONTEXT(), callContext, inPath);
- unique_ptr_deleter<OBJECT_ATTRIBUTES> adjustedAttributes =
- makeObjectAttributes(redir, ObjectAttributes);
-
- PRE_REALCALL
- res = ::NtQueryAttributesFile(adjustedAttributes.get(), FileInformation);
- POST_REALCALL
-
- if (redir.redirected) {
- LOG_CALL()
- .addParam("source", ObjectAttributes)
- .addParam("rerouted", adjustedAttributes.get())
- .PARAMWRAP(res);
- }
-
- HOOK_END
-
- return res;
-}
-
-NTSTATUS WINAPI usvfs::hook_NtQueryFullAttributesFile(
- POBJECT_ATTRIBUTES ObjectAttributes, PFILE_NETWORK_OPEN_INFORMATION FileInformation)
-{
- PreserveGetLastError ntFunctionsDoNotChangeGetLastError;
-
- NTSTATUS res = STATUS_SUCCESS;
-
- HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES)
-
- if (!callContext.active()) {
- return ::NtQueryFullAttributesFile(ObjectAttributes, FileInformation);
- }
-
- UnicodeString inPath;
- try {
- inPath = CreateUnicodeString(ObjectAttributes);
- } catch (const std::exception&) {
- return ::NtQueryFullAttributesFile(ObjectAttributes, FileInformation);
- }
-
- RedirectionInfo redir = applyReroute(READ_CONTEXT(), callContext, inPath);
- unique_ptr_deleter<OBJECT_ATTRIBUTES> adjustedAttributes =
- makeObjectAttributes(redir, ObjectAttributes);
-
- PRE_REALCALL
- res = ::NtQueryFullAttributesFile(adjustedAttributes.get(), FileInformation);
- POST_REALCALL
-
- if (redir.redirected) {
- LOG_CALL()
- .addParam("source", ObjectAttributes)
- .addParam("rerouted", adjustedAttributes.get())
- .PARAMWRAP(res);
- }
-
- HOOK_END
-
- return res;
-}
-
-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
- //
- // if the current process exits normally, the ExitProcess() hook is called
- // and disconnects from the vfs; if the current process crashes, this hook
- // is not called, the process just dies
- //
- // but a process can also terminate itself, bypassing ExitProcess(), and
- // ending up here, in which case the vfs should be disconnected
- //
- // NtTerminateProcess() can be called two different ways to terminate the
- // current process:
- // - with a valid handle for the current process, or
- // - with -1, because that's what GetCurrentProcess() returns
- //
- // it's unclear what a NULL handle represents, the behaviour is not
- // documented anywhere, but looking at ReactOS, it's also interpreted as the
- // current process
-
- NTSTATUS res = STATUS_SUCCESS;
-
- HOOK_START
-
- const bool isCurrentProcess = ProcessHandle == (HANDLE)-1 || ProcessHandle == 0 ||
- GetProcessId(ProcessHandle) == GetCurrentProcessId();
-
- if (isCurrentProcess) {
- usvfsDisconnectVFS();
- }
-
- res = ::NtTerminateProcess(ProcessHandle, ExitStatus);
-
- HOOK_END
-
- return res;
-}
diff --git a/libs/usvfs/src/usvfs_dll/hooks/ntdll.h b/libs/usvfs/src/usvfs_dll/hooks/ntdll.h
deleted file mode 100644
index f3db4a6..0000000
--- a/libs/usvfs/src/usvfs_dll/hooks/ntdll.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#pragma once
-
-#include <dllimport.h>
-#include <loghelpers.h>
-#include <ntdll_declarations.h>
-
-namespace usvfs
-{
-
-DLLEXPORT NTSTATUS WINAPI
-hook_NtQueryFullAttributesFile(POBJECT_ATTRIBUTES ObjectAttributes,
- PFILE_NETWORK_OPEN_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_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_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_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_NtClose(HANDLE Handle);
-
-DLLEXPORT NTSTATUS WINAPI hook_NtTerminateProcess(HANDLE ProcessHandle,
- NTSTATUS ExitStatus);
-
-} // namespace usvfs
diff --git a/libs/usvfs/src/usvfs_dll/hooks/sharedids.h b/libs/usvfs/src/usvfs_dll/hooks/sharedids.h
deleted file mode 100644
index 9a7531c..0000000
--- a/libs/usvfs/src/usvfs_dll/hooks/sharedids.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#include "../hookcontext.h"
-
-typedef std::map<HANDLE, std::wstring> SearchHandleMap;
-
-// maps handles opened for searching to the original search path, which is
-// necessary if the handle creation was rerouted
-DATA_ID(SearchHandles);