Skip to content

Commit

Permalink
Merge pull request #6 from Modorganizer2/Develop
Browse files Browse the repository at this point in the history
Stage for 2.1.3 release
  • Loading branch information
LePresidente authored May 8, 2018
2 parents 3fff6ac + 0e6d788 commit 378aa38
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 84 deletions.
4 changes: 2 additions & 2 deletions include/usvfs_version.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#pragma once

#define USVFS_VERSION_MAJOR 0
#define USVFS_VERSION_MINOR 3
#define USVFS_VERSION_BUILD 1
#define USVFS_VERSION_MINOR 4
#define USVFS_VERSION_BUILD 0
#define USVFS_VERSION_REVISION 0

#define USVFS_BUILD_STRING ""
Expand Down
21 changes: 14 additions & 7 deletions src/shared/exceptionex.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,20 @@ typedef MyBoost::error_info<struct tag_message, DWORD> ex_win_errcode;
//#endif // _MSC_VER
typedef MyBoost::error_info<struct tag_message, std::string> ex_msg;

struct incompatibility_error : virtual MyBoost::exception, virtual std::exception {};
struct usage_error : virtual MyBoost::exception, virtual std::exception {};
struct data_error : virtual MyBoost::exception, virtual std::exception {};
struct file_not_found_error : virtual MyBoost::exception, virtual std::exception {};
struct timeout_error : virtual MyBoost::exception, virtual std::exception {};
struct unknown_error : virtual MyBoost::exception, virtual std::exception {};
struct node_missing_error : virtual MyBoost::exception, virtual std::exception {};
struct std_boost_exception : virtual MyBoost::exception, virtual std::exception
{
const char* what() const noexcept override {
return MyBoost::diagnostic_information_what(*this);
}
};

struct incompatibility_error : std_boost_exception {};
struct usage_error : std_boost_exception {};
struct data_error : std_boost_exception {};
struct file_not_found_error : std_boost_exception {};
struct timeout_error : std_boost_exception {};
struct unknown_error : std_boost_exception {};
struct node_missing_error : std_boost_exception {};



Expand Down
167 changes: 93 additions & 74 deletions src/usvfs_dll/hooks/kernel32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include <boost/algorithm/string/predicate.hpp>
namespace fs = boost::filesystem;
#else
namespace fs = std::tr2::sys;
namespace fs = std::sys;
#include <filesystem>
#endif

Expand Down Expand Up @@ -194,7 +194,7 @@ static inline WCHAR pathNameDriveLetter(LPCWSTR path)
}

// returns false also in case we fail to determine the drive letter of the path
static inline bool pathesOnDifferentDrives(LPCWSTR path1, LPCWSTR path2)
static inline bool pathsOnDifferentDrives(LPCWSTR path1, LPCWSTR path2)
{
WCHAR drive1 = pathNameDriveLetter(path1);
WCHAR drive2 = pathNameDriveLetter(path2);
Expand Down Expand Up @@ -485,29 +485,39 @@ class RerouteW
const auto& lookupPath = canonizePath(absolutePath(inPath));
result.m_RealPath = lookupPath.wstring();

const usvfs::RedirectionTreeContainer &table
= inverse ? context->inverseTable() : context->redirectionTable();
result.m_FileNode = table->findNode(lookupPath);
result.m_Buffer = k32DeleteTracker.lookup(result.m_RealPath);
bool found = !result.m_Buffer.empty();
if (found) {
spdlog::get("hooks")->info("Rerouting file open to location of deleted file: {}",
ush::string_cast<std::string>(result.m_Buffer));
result.m_NewReroute = true;
} else {
const usvfs::RedirectionTreeContainer &table
= inverse ? context->inverseTable() : context->redirectionTable();
result.m_FileNode = table->findNode(lookupPath);

if (result.m_FileNode.get()
&& (!result.m_FileNode->data().linkTarget.empty() || result.m_FileNode->isDirectory()))
{
if (!result.m_FileNode->data().linkTarget.empty()) {
result.m_Buffer = string_cast<std::wstring>(
result.m_FileNode->data().linkTarget.c_str(), CodePage::UTF8);
}
else
if (result.m_FileNode.get()
&& (!result.m_FileNode->data().linkTarget.empty() || result.m_FileNode->isDirectory()))
{
result.m_Buffer = result.m_FileNode->path().wstring();
if (!result.m_FileNode->data().linkTarget.empty()) {
result.m_Buffer = string_cast<std::wstring>(
result.m_FileNode->data().linkTarget.c_str(), CodePage::UTF8);
}
else
{
result.m_Buffer = result.m_FileNode->path().wstring();
}
found = true;
}
wchar_t inIt = inPath[wcslen(inPath) - 1];
}
if (found) {
result.m_Rerouted = true;

wchar_t inIt = inPath[wcslen(inPath) - 1];
std::wstring::iterator outIt = result.m_Buffer.end() - 1;
if ((*outIt == L'\\' || *outIt == L'/') && !(inIt == L'\\' || inIt == L'/'))
result.m_Buffer.erase(outIt);
if (result.m_Buffer.length() >= MAX_PATH && !ush::startswith(result.m_Buffer.c_str(), LR"(\\?\)"))
result.m_Buffer = LR"(\\?\)" + result.m_Buffer;
result.m_Buffer.erase(outIt);
std::replace(result.m_Buffer.begin(), result.m_Buffer.end(), L'/', L'\\');
result.m_Rerouted = true;
}
else
result.m_Buffer = inPath;
Expand Down Expand Up @@ -556,16 +566,22 @@ class RerouteW

if (found)
{
if (createPath)
if (createPath) {
try {
usvfs::FunctionGroupLock lock(usvfs::MutExHookGroup::ALL_GROUPS);
result.m_PathCreated =
createFakePath(fs::path(result.m_Buffer).parent_path(), securityAttributes);
} catch (const std::exception &e) {
}
catch (const std::exception &e) {
spdlog::get("hooks")->error("failed to create {}: {}",
ush::string_cast<std::string>(result.m_Buffer), e.what());
}
}

wchar_t inIt = inPath[wcslen(inPath) - 1];
std::wstring::iterator outIt = result.m_Buffer.end() - 1;
if ((*outIt == L'\\' || *outIt == L'/') && !(inIt == L'\\' || inIt == L'/'))
result.m_Buffer.erase(outIt);
std::replace(result.m_Buffer.begin(), result.m_Buffer.end(), L'/', L'\\');
result.m_Rerouted = true;
result.m_NewReroute = true;
Expand All @@ -575,11 +591,6 @@ class RerouteW
}
else if (inPath)
result.m_Buffer = inPath;
std::wstring::iterator it = result.m_Buffer.end() - 1;
wchar_t inIt = inPath[wcslen(inPath) - 1];
std::wstring::iterator outIt = result.m_Buffer.end() - 1;
if ((*outIt == L'\\' || *outIt == L'/') && !(inIt == L'\\' || inIt == L'/'))
result.m_Buffer.erase(outIt);

if (inPath)
result.m_FileName = result.m_Buffer.c_str();
Expand Down Expand Up @@ -859,15 +870,14 @@ HANDLE WINAPI usvfs::hook_CreateFileA(
namespace usvfs {
class CreateRerouter {
public:
bool rereouteCreate(const usvfs::HookContext::ConstPtr &context, const usvfs::HookCallContext &callContext,
bool rerouteCreate(const usvfs::HookContext::ConstPtr &context, const usvfs::HookCallContext &callContext,
LPCWSTR lpFileName, DWORD& dwCreationDisposition, DWORD dwDesiredAccess, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
enum class Open { existing, create, empty };
Open open = Open::existing;

// Notice since we are calling our patched GetFileAttributesW here this will also check virtualized paths
DWORD virtAttr = GetFileAttributesW(lpFileName);
m_directlyAvailable = virtAttr == INVALID_FILE_ATTRIBUTES && (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND);
bool isFile = virtAttr != INVALID_FILE_ATTRIBUTES && (virtAttr & FILE_ATTRIBUTE_DIRECTORY) == 0;
m_isDir = virtAttr != INVALID_FILE_ATTRIBUTES && (virtAttr & FILE_ATTRIBUTE_DIRECTORY);

Expand Down Expand Up @@ -911,11 +921,11 @@ namespace usvfs {
m_reroute = RerouteW::create(context, callContext, lpFileName);

if (m_reroute.wasRerouted() && open == Open::create && pathIsDirectory(m_reroute.fileName()))
m_reroute = RerouteW::createNew(context, callContext, lpFileName, m_directlyAvailable, lpSecurityAttributes);
m_reroute = RerouteW::createNew(context, callContext, lpFileName, true, lpSecurityAttributes);

if (!m_isDir && !isFile && !m_reroute.wasRerouted() && (open == Open::create || open == Open::empty))
{
m_reroute = RerouteW::createNew(context, callContext, lpFileName, m_directlyAvailable, lpSecurityAttributes);
m_reroute = RerouteW::createNew(context, callContext, lpFileName, true, lpSecurityAttributes);

bool newFile = !m_reroute.wasRerouted() && pathDirectlyAvailable(m_reroute.fileName());
if (newFile && open == Open::empty)
Expand All @@ -930,7 +940,7 @@ namespace usvfs {
bool rerouteNew(const usvfs::HookContext::ConstPtr &context, usvfs::HookCallContext &callContext, LPCWSTR lpFileName, bool replaceExisting, const char* hookName)
{
DWORD disposition = replaceExisting ? CREATE_ALWAYS : CREATE_NEW;
if (!rereouteCreate(context, callContext, lpFileName, disposition, GENERIC_WRITE, nullptr)) {
if (!rerouteCreate(context, callContext, lpFileName, disposition, GENERIC_WRITE, nullptr)) {
spdlog::get("hooks")->info(
"{} guaranteed failure, skipping original call: {}, replaceExisting={}, error={}",
hookName, ush::string_cast<std::string>(lpFileName, ush::CodePage::UTF8), replaceExisting ? "true" : "false", error());
Expand Down Expand Up @@ -996,7 +1006,7 @@ HANDLE WINAPI usvfs::hook_CreateFileW(

DWORD originalDisposition = dwCreationDisposition;
CreateRerouter rerouter;
if (rerouter.rereouteCreate(READ_CONTEXT(), callContext, lpFileName, dwCreationDisposition, dwDesiredAccess, lpSecurityAttributes))
if (rerouter.rerouteCreate(READ_CONTEXT(), callContext, lpFileName, dwCreationDisposition, dwDesiredAccess, lpSecurityAttributes))
{
PRE_REALCALL
res = ::CreateFileW(rerouter.fileName(), dwDesiredAccess, dwShareMode,
Expand Down Expand Up @@ -1062,7 +1072,7 @@ HANDLE WINAPI usvfs::hook_CreateFile2(LPCWSTR lpFileName, DWORD dwDesiredAccess,

DWORD originalDisposition = dwCreationDisposition;
CreateRerouter rerouter;
if (rerouter.rereouteCreate(READ_CONTEXT(), callContext, lpFileName, dwCreationDisposition, dwDesiredAccess,
if (rerouter.rerouteCreate(READ_CONTEXT(), callContext, lpFileName, dwCreationDisposition, dwDesiredAccess,
pCreateExParams ? pCreateExParams->lpSecurityAttributes : nullptr))
{
PRE_REALCALL
Expand Down Expand Up @@ -1290,11 +1300,11 @@ BOOL WINAPI usvfs::hook_DeleteFileW(LPCWSTR lpFileName)
}

BOOL rewriteChangedDrives(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName,
const RerouteW& readReroute, const usvfs::CreateRerouter& writeReroute, DWORD newFlags)
const RerouteW& readReroute, const usvfs::CreateRerouter& writeReroute)
{
return ((newFlags & MOVEFILE_COPY_ALLOWED) == 0 && (readReroute.wasRerouted() || writeReroute.wasRerouted())
&& pathesOnDifferentDrives(readReroute.fileName(), writeReroute.fileName())
&& !pathesOnDifferentDrives(lpExistingFileName, lpNewFileName));
return ((readReroute.wasRerouted() || writeReroute.wasRerouted())
&& pathsOnDifferentDrives(readReroute.fileName(), writeReroute.fileName())
&& !pathsOnDifferentDrives(lpExistingFileName, lpNewFileName));
}

BOOL WINAPI usvfs::hook_MoveFileA(LPCSTR lpExistingFileName,
Expand Down Expand Up @@ -1350,13 +1360,13 @@ BOOL WINAPI usvfs::hook_MoveFileW(LPCWSTR lpExistingFileName,

if (callOriginal)
{
bool movedDrives = rewriteChangedDrives(lpExistingFileName, lpNewFileName, readReroute, writeReroute, newFlags);
bool movedDrives = rewriteChangedDrives(lpExistingFileName, lpNewFileName, readReroute, writeReroute);
if (movedDrives) newFlags |= MOVEFILE_COPY_ALLOWED;

bool isDirectory = pathIsDirectory(readReroute.fileName());

PRE_REALCALL
if (isDirectory && movedDrives && newFlags) {
if (isDirectory && movedDrives) {
SHFILEOPSTRUCTW sf = { 0 };
sf.wFunc = FO_MOVE;
sf.hwnd = 0;
Expand Down Expand Up @@ -1390,12 +1400,13 @@ BOOL WINAPI usvfs::hook_MoveFileW(LPCWSTR lpExistingFileName,
writeReroute.updateResult(callContext, res);

if (res) {
//readReroute.removeMapping(READ_CONTEXT(), isDirectory); // Leaving a ghost fixes some problems with apps expecting the file to be gone
readReroute.removeMapping(READ_CONTEXT(), isDirectory); // Updating the rerouteCreate to check deleted file entries should make this okay

if (writeReroute.newReroute() && isDirectory) {
RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName), fs::path(writeReroute.fileName()));
} else {
writeReroute.insertMapping(WRITE_CONTEXT());
if (writeReroute.newReroute()) {
if (isDirectory)
RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName), fs::path(writeReroute.fileName()));
else
writeReroute.insertMapping(WRITE_CONTEXT());
}
}

Expand Down Expand Up @@ -1468,13 +1479,12 @@ BOOL WINAPI usvfs::hook_MoveFileExW(LPCWSTR lpExistingFileName,

if (callOriginal)
{
bool movedDrives = rewriteChangedDrives(lpExistingFileName, lpNewFileName, readReroute, writeReroute, newFlags);
if (movedDrives) newFlags |= MOVEFILE_COPY_ALLOWED;
bool movedDrives = rewriteChangedDrives(lpExistingFileName, lpNewFileName, readReroute, writeReroute);

bool isDirectory = pathIsDirectory(readReroute.fileName());

PRE_REALCALL
if (isDirectory && movedDrives && newFlags & MOVEFILE_COPY_ALLOWED) {
if (isDirectory && movedDrives) {
SHFILEOPSTRUCTW sf = { 0 };
sf.wFunc = FO_MOVE;
sf.hwnd = 0;
Expand Down Expand Up @@ -1506,12 +1516,13 @@ BOOL WINAPI usvfs::hook_MoveFileExW(LPCWSTR lpExistingFileName,
writeReroute.updateResult(callContext, res);

if (res) {
//readReroute.removeMapping(READ_CONTEXT(), isDirectory); // Leaving a ghost fixes some problems with apps expecting the file to be gone
readReroute.removeMapping(READ_CONTEXT(), isDirectory); // Updating the rerouteCreate to check deleted file entries should make this okay

if (writeReroute.newReroute() && isDirectory) {
RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName), fs::path(writeReroute.fileName()));
} else {
writeReroute.insertMapping(WRITE_CONTEXT());
if (writeReroute.newReroute()) {
if (isDirectory)
RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName), fs::path(writeReroute.fileName()));
else
writeReroute.insertMapping(WRITE_CONTEXT());
}
}

Expand Down Expand Up @@ -1583,13 +1594,13 @@ BOOL WINAPI usvfs::hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, LPCWST

if (callOriginal)
{
bool movedDrives = rewriteChangedDrives(lpExistingFileName, lpNewFileName, readReroute, writeReroute, newFlags);
bool movedDrives = rewriteChangedDrives(lpExistingFileName, lpNewFileName, readReroute, writeReroute);
if (movedDrives) newFlags |= MOVEFILE_COPY_ALLOWED;

bool isDirectory = pathIsDirectory(readReroute.fileName());

PRE_REALCALL
if (isDirectory && movedDrives && newFlags & MOVEFILE_COPY_ALLOWED) {
if (isDirectory && movedDrives) {
SHFILEOPSTRUCTW sf = { 0 };
sf.wFunc = FO_MOVE;
sf.hwnd = 0;
Expand Down Expand Up @@ -1621,12 +1632,13 @@ BOOL WINAPI usvfs::hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, LPCWST
writeReroute.updateResult(callContext, res);

if (res) {
//readReroute.removeMapping(READ_CONTEXT(), isDirectory); // Leaving a ghost fixes some problems with apps expecting the file to be gone
readReroute.removeMapping(READ_CONTEXT(), isDirectory); // Updating the rerouteCreate to check deleted file entries should make this okay

if (writeReroute.newReroute() && isDirectory) {
RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName), fs::path(writeReroute.fileName()));
} else {
writeReroute.insertMapping(WRITE_CONTEXT());
if (writeReroute.newReroute()) {
if (isDirectory)
RerouteW::addDirectoryMapping(WRITE_CONTEXT(), fs::path(lpNewFileName), fs::path(writeReroute.fileName()));
else
writeReroute.insertMapping(WRITE_CONTEXT());
}
}

Expand Down Expand Up @@ -1967,27 +1979,34 @@ DWORD WINAPI usvfs::hook_GetModuleFileNameW(HMODULE hModule,
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, lpFilename, true);
= RerouteW::create(READ_CONTEXT(), callContext, buf.empty() ? lpFilename : buf.data(), true);
if (reroute.wasRerouted()) {
DWORD reroutedSize = static_cast<DWORD>(reroute.buffer().size());
DWORD reroutedSize = static_cast<DWORD>(wcslen(reroute.fileName()));
if (reroutedSize >= nSize) {
callContext.updateLastError(ERROR_INSUFFICIENT_BUFFER);
reroutedSize = nSize - 1;
callContext.updateLastError(ERROR_INSUFFICIENT_BUFFER);
res = nSize;
}
// res can't be bigger than nSize-1 at this point
if (reroutedSize > 0) {
if (reroutedSize < res) {
// zero out the string windows has previously written to
memset(lpFilename, '\0', std::min(res, nSize) * sizeof(wchar_t));
}
// this truncates the string if the buffer is too small
ush::wcsncpy_sz(lpFilename, reroute.fileName(), reroutedSize + 1);
}
res = reroutedSize;
}
else
res = reroutedSize;
memcpy(lpFilename, reroute.fileName(), reroutedSize * sizeof(lpFilename[0]));
lpFilename[reroutedSize] = 0;

if (reroute.wasRerouted()) {
LOG_CALL()
.PARAM(hModule)
.addParam("lpFilename", usvfs::log::Wrap<LPCWSTR>(
Expand Down
2 changes: 1 addition & 1 deletion vsbuild/external_dependencies.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Import Project="external_dependencies_local.props" Condition="Exists('external_dependencies_local.props')"/>
</ImportGroup>
<PropertyGroup Label="UserMacros">
<BOOST_PATH Condition="'$(BOOST_PATH)'==''">..\..\boost_1_66_0</BOOST_PATH>
<BOOST_PATH Condition="'$(BOOST_PATH)'==''">..\..\boost_1_67_0</BOOST_PATH>
<BOOST_PATH Condition="'$(BOOST_PATH)'!=''">$(BOOST_PATH)</BOOST_PATH>
<GTEST_PATH Condition="'$(GTEST_PATH)'==''">..\..\googletest</GTEST_PATH>
</PropertyGroup>
Expand Down

0 comments on commit 378aa38

Please sign in to comment.