/*
Userspace Virtual Filesystem
Copyright (C) 2015 Sebastian Herbord. All rights reserved.
This file is part of usvfs.
usvfs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
usvfs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with usvfs. If not, see .
*/
#pragma once
#include "dllimport.h"
#include "redirectiontree.h"
#include "semaphore.h"
#include "tree_container.h"
#include
#include
#include
#include
#include
namespace usvfs
{
class DLLEXPORT SharedParameters;
/**
* @brief context available to hooks. This is protected by a many-reader
* single-writer mutex
*/
class HookContext
{
public:
typedef std::unique_ptr ConstPtr;
typedef std::unique_ptr Ptr;
typedef unsigned int DataIDT;
public:
HookContext(const usvfsParameters& params, HMODULE module);
HookContext(const HookContext& reference) = delete;
DLLEXPORT ~HookContext();
HookContext& operator=(const HookContext& reference) = delete;
static void remove(const char* instance);
/**
* @brief get read access to the context.
* @return smart ptr to the context. mutex will automatically be released when
* this leaves scope
*/
static ConstPtr readAccess(const char* source);
/**
* @brief get write access to the context.
* @return smart ptr to the context. mutex will automatically be released when
* this leaves scope
*/
static Ptr writeAccess(const char* source);
/**
* @return table containing file redirection information
*/
RedirectionTreeContainer& redirectionTable() { return m_Tree; }
/**
* @return table containing file redirection information
*/
const RedirectionTreeContainer& redirectionTable() const { return m_Tree; }
RedirectionTreeContainer& inverseTable() { return m_InverseTree; }
const RedirectionTreeContainer& inverseTable() const { return m_InverseTree; }
/**
* @return the parameters passed in on dll initialisation
*/
usvfsParameters callParameters() const;
/**
* @return path to the calling library itself
*/
std::wstring dllPath() const;
/**
* @brief get access to custom data
* @note the caller gains write access to the data, independent on the lock on
* the context
* as a whole. The caller himself has to ensure thread safety
*/
template
T& customData(DataIDT id) const
{
auto iter = m_CustomData.find(id);
if (iter == m_CustomData.end()) {
iter = m_CustomData.insert(std::make_pair(id, T())).first;
}
// std::map is supposed to not invalidate any iterators when elements are
// added
// so it should be safe to return a pointer here
T* res = boost::any_cast(&iter->second);
return *res;
}
void registerProcess(DWORD pid);
void unregisterCurrentProcess();
std::vector registeredProcesses() const;
void blacklistExecutable(const std::wstring& executableName);
void clearExecutableBlacklist();
BOOL executableBlacklisted(LPCWSTR lpApplicationName, LPCWSTR lpCommandLine) const;
void addSkipFileSuffix(const std::wstring& fileSuffix);
void clearSkipFileSuffixes();
std::vector skipFileSuffixes() const;
void addSkipDirectory(const std::wstring& directory);
void clearSkipDirectories();
std::vector skipDirectories() const;
void forceLoadLibrary(const std::wstring& processName,
const std::wstring& libraryPath);
void clearLibraryForceLoads();
std::vector librariesToForceLoad(const std::wstring& processName);
void setDebugParameters(LogLevel level, CrashDumpsType dumpType,
const std::string& dumpPath,
std::chrono::milliseconds delayProcess);
void updateParameters() const;
void registerDelayed(std::future delayed);
std::vector>& delayed();
private:
static void unlock(HookContext* instance);
static void unlockShared(const HookContext* instance);
SharedParameters* retrieveParameters(const usvfsParameters& params);
private:
static HookContext* s_Instance;
shared::SharedMemoryT m_ConfigurationSHM;
SharedParameters* m_Parameters{nullptr};
RedirectionTreeContainer m_Tree;
RedirectionTreeContainer m_InverseTree;
std::vector> m_Futures;
mutable std::map m_CustomData;
HMODULE m_DLLModule;
// mutable std::recursive_mutex m_Mutex;
mutable RecursiveBenaphore m_Mutex;
};
} // namespace usvfs
extern "C" DLLEXPORT usvfs::HookContext* WINAPI
usvfsCreateHookContext(const usvfsParameters& params, HMODULE module);
class PreserveGetLastError
{
public:
PreserveGetLastError() : m_err(GetLastError()) {}
~PreserveGetLastError() { SetLastError(m_err); }
private:
DWORD m_err;
};
// declare an identifier that is guaranteed to be unique across the application
#define DATA_ID(name) static const usvfs::HookContext::DataIDT name = __COUNTER__
// set of macros. These ensure a call context is created but most of all these
// ensure exceptions are caught.
#define READ_CONTEXT() HookContext::readAccess(__MYFUNC__)
#define WRITE_CONTEXT() HookContext::writeAccess(__MYFUNC__)
#define HOOK_START_GROUP(group) \
try { \
HookCallContext callContext(group);
#define HOOK_START \
try { \
HookCallContext callContext;
#define HOOK_END \
} \
catch (const std::exception& e) \
{ \
spdlog::get("usvfs")->error("exception in {0}: {1}", __MYFUNC__, e.what()); \
logExtInfo(e); \
}
#define HOOK_ENDP(param) \
} \
catch (const std::exception& e) \
{ \
spdlog::get("usvfs")->error("exception in {0} ({1}): {2}", __MYFUNC__, param, \
e.what()); \
logExtInfo(e); \
}
#define PRE_REALCALL callContext.restoreLastError();
#define POST_REALCALL callContext.updateLastError();