Skip to content

Commit

Permalink
Add File & Directory skipping (#61)
Browse files Browse the repository at this point in the history
* Add File & Directory skipping
  • Loading branch information
Twinki14 authored Jun 8, 2024
1 parent 642aa2b commit beab783
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 8 deletions.
16 changes: 16 additions & 0 deletions include/sharedparameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ class DLLEXPORT SharedParameters
void clearExecutableBlacklist();
bool executableBlacklisted(const std::string& app, const std::string& cmd) const;

void addSkipFileSuffix(const std::string& fileSuffix);
void clearSkipFileSuffixes();
std::vector<std::string> skipFileSuffixes() const;

void addSkipDirectory(const std::string& directory);
void clearSkipDirectories();
std::vector<std::string> skipDirectories() const;

void addForcedLibrary(const std::string& process, const std::string& path);
std::vector<std::string> forcedLibraries(const std::string& processName);
void clearForcedLibraries();
Expand All @@ -77,6 +85,12 @@ class DLLEXPORT SharedParameters
using ProcessList = boost::container::flat_set<
DWORD, std::less<DWORD>, DWORDAllocatorT>;

using FileSuffixSkipList = boost::container::flat_set<
shared::StringT, std::less<shared::StringT>, StringAllocatorT>;

using DirectorySkipList = boost::container::flat_set<
shared::StringT, std::less<shared::StringT>, StringAllocatorT>;

using ForcedLibraries = boost::container::slist<
ForcedLibrary, ForcedLibraryAllocatorT>;

Expand All @@ -93,6 +107,8 @@ class DLLEXPORT SharedParameters
uint32_t m_userCount;
ProcessBlacklist m_processBlacklist;
ProcessList m_processList;
FileSuffixSkipList m_fileSuffixSkipList;
DirectorySkipList m_directorySkipList;
ForcedLibraries m_forcedLibraries;
};

Expand Down
33 changes: 32 additions & 1 deletion include/usvfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ static const unsigned int LINKFLAG_CREATETARGET = 0x00000004; // if set, file
// If there different create-target have been set for an element and one of its
// ancestors, the inner-most create-target is used
static const unsigned int LINKFLAG_RECURSIVE = 0x00000008; // if set, directories are linked recursively

static const unsigned int LINKFLAG_FAILIFSKIPPED = 0x00000010; // if set, linking fails if the file or directory is skipped
// files or directories are skipped depending on whats been added to
// the skip file suffixes or skip directories list in
// the sharedparameters class, those lists are checked during virtual linking

extern "C" {

Expand Down Expand Up @@ -154,6 +157,34 @@ DLLEXPORT VOID WINAPI BlacklistExecutable(LPWSTR executableName);
*/
DLLEXPORT VOID WINAPI ClearExecutableBlacklist();

/**
* adds a file suffix to a list to skip during file linking
* .txt and some_file.txt are both valid file suffixes,
* not to be confused with file extensions
* @param fileSuffix a valid file suffix
*/
DLLEXPORT VOID WINAPI usvfsAddSkipFileSuffix(LPWSTR fileSuffix);

/**
* clears the file suffix skip-list
*/
DLLEXPORT VOID WINAPI usvfsClearSkipFileSuffixes();

/**
* adds a directory name that will be skipped during directory linking.
* Not a path. Any directory matching the name will be skipped,
* regardless of it's path, for example if .git is added,
* any sub-path or root-path containing a .git directory
* will have the .git directory skipped during directory linking
* @param directory name of the directory
*/
DLLEXPORT VOID WINAPI usvfsAddSkipDirectory(LPWSTR directory);

/**
* clears the directory skip-list
*/
DLLEXPORT VOID WINAPI usvfsClearSkipDirectories();

/**
* adds a library to be force loaded when the given process is injected
* @param
Expand Down
46 changes: 46 additions & 0 deletions src/usvfs_dll/hookcontext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,52 @@ BOOL HookContext::executableBlacklisted(LPCWSTR wapp, LPCWSTR wcmd) const
return m_Parameters->executableBlacklisted(app, cmd);
}

void usvfs::HookContext::addSkipFileSuffix(const std::wstring& fileSuffix)
{
const auto fsuffix = shared::string_cast<std::string>(fileSuffix, shared::CodePage::UTF8);

if (fsuffix.empty()) {
return;
}

spdlog::get("usvfs")->debug("added skip file suffix '{}'", fsuffix);
m_Parameters->addSkipFileSuffix(fsuffix);
}

void usvfs::HookContext::clearSkipFileSuffixes()
{
spdlog::get("usvfs")->debug("clearing skip file suffixes");
m_Parameters->clearSkipFileSuffixes();
}

std::vector<std::string> usvfs::HookContext::skipFileSuffixes() const
{
return m_Parameters->skipFileSuffixes();
}

void usvfs::HookContext::addSkipDirectory(const std::wstring& directory)
{
const auto dir = shared::string_cast<std::string>(directory, shared::CodePage::UTF8);

if (dir.empty()) {
return;
}

spdlog::get("usvfs")->debug("added skip directory '{}'", dir);
m_Parameters->addSkipDirectory(dir);
}

void usvfs::HookContext::clearSkipDirectories()
{
spdlog::get("usvfs")->debug("clearing skip directories");
m_Parameters->clearSkipDirectories();
}

std::vector<std::string> usvfs::HookContext::skipDirectories() const
{
return m_Parameters->skipDirectories();
}

void HookContext::forceLoadLibrary(
const std::wstring& wprocess, const std::wstring& wpath)
{
Expand Down
8 changes: 8 additions & 0 deletions src/usvfs_dll/hookcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,14 @@ class HookContext
void clearExecutableBlacklist();
BOOL HookContext::executableBlacklisted(LPCWSTR lpApplicationName, LPCWSTR lpCommandLine) const;

void addSkipFileSuffix(const std::wstring& fileSuffix);
void clearSkipFileSuffixes();
std::vector<std::string> skipFileSuffixes() const;

void addSkipDirectory(const std::wstring& directory);
void clearSkipDirectories();
std::vector<std::string> skipDirectories () const;

void forceLoadLibrary(const std::wstring &processName, const std::wstring &libraryPath);
void clearLibraryForceLoads();
std::vector<std::wstring> librariesToForceLoad(const std::wstring &processName);
Expand Down
42 changes: 42 additions & 0 deletions src/usvfs_dll/sharedparameters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ SharedParameters::SharedParameters(const usvfsParameters& reference,
, m_userCount(1)
, m_processBlacklist(allocator)
, m_processList(allocator)
, m_fileSuffixSkipList(allocator)
, m_directorySkipList(allocator)
, m_forcedLibraries(allocator)
{
}
Expand Down Expand Up @@ -198,6 +200,46 @@ bool SharedParameters::executableBlacklisted(
return false;
}

void SharedParameters::addSkipFileSuffix(const std::string& fileSuffix)
{
bi::scoped_lock lock(m_mutex);

m_fileSuffixSkipList.insert(shared::StringT(fileSuffix.begin(), fileSuffix.end(),
m_fileSuffixSkipList.get_allocator()));
}

void SharedParameters::clearSkipFileSuffixes()
{
bi::scoped_lock lock(m_mutex);
m_fileSuffixSkipList.clear();
}

std::vector<std::string> SharedParameters::skipFileSuffixes() const
{
bi::scoped_lock lock(m_mutex);
return { m_fileSuffixSkipList.begin(), m_fileSuffixSkipList.end() };
}

void SharedParameters::addSkipDirectory(const std::string& directory)
{
bi::scoped_lock lock(m_mutex);

m_directorySkipList.insert(shared::StringT(directory.begin(), directory.end(),
m_directorySkipList.get_allocator()));
}

void SharedParameters::clearSkipDirectories()
{
bi::scoped_lock lock(m_mutex);
m_directorySkipList.clear();
}

std::vector<std::string> SharedParameters::skipDirectories() const
{
bi::scoped_lock lock(m_mutex);
return { m_directorySkipList.begin(), m_directorySkipList.end() };
}

void SharedParameters::addForcedLibrary(
const std::string& processName, const std::string& libraryPath)
{
Expand Down
98 changes: 91 additions & 7 deletions src/usvfs_dll/usvfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,33 @@ bool assertPathExists(usvfs::RedirectionTreeContainer &table, LPCWSTR path)
return true;
}

static bool fileNameInSkipSuffixes(const std::string& fileNameUtf8,
const std::vector<std::string>& skipFileSuffixes)
{
for (const auto& skipFileSuffix : skipFileSuffixes) {
if (boost::algorithm::iends_with(fileNameUtf8, skipFileSuffix)) {
spdlog::get("usvfs")->debug(
"file '{}' should be skipped, matches file suffix '{}'", fileNameUtf8,
skipFileSuffix);
return true;
}
}
return false;
}

static bool fileNameInSkipDirectories(const std::string& directoryNameUtf8,
const std::vector<std::string>& skipDirectories)
{
for (const auto& skipDir : skipDirectories) {
if (boost::algorithm::equals(directoryNameUtf8, skipDir)) {
spdlog::get("usvfs")->debug("directory '{}' should be skipped",
directoryNameUtf8);
return true;
}
}
return false;
}

BOOL WINAPI VirtualLinkFile(LPCWSTR source, LPCWSTR destination,
unsigned int flags)
{
Expand All @@ -683,8 +710,16 @@ BOOL WINAPI VirtualLinkFile(LPCWSTR source, LPCWSTR destination,
return FALSE;
}

std::string sourceU8
= ush::string_cast<std::string>(source, ush::CodePage::UTF8);
const auto skipFileSuffixes = context->skipFileSuffixes();

std::string sourceU8 = ush::string_cast<std::string>(source, ush::CodePage::UTF8);

// Check if the file should be skipped
if (fileNameInSkipSuffixes(sourceU8, skipFileSuffixes)) {
// return false when we want to fail when the file is skipped
return (flags & LINKFLAG_FAILIFSKIPPED) ? FALSE : TRUE;
}

auto res = context->redirectionTable().addFile(
bfs::path(destination), usvfs::RedirectionDataLocal(sourceU8),
!(flags & LINKFLAG_FAILIFEXISTS));
Expand Down Expand Up @@ -728,7 +763,6 @@ static usvfs::shared::TreeFlags convertRedirectionFlags(unsigned int flags)
return result;
}


BOOL WINAPI VirtualLinkDirectoryStatic(LPCWSTR source, LPCWSTR destination, unsigned int flags)
{
// TODO change notification not yet implemented
Expand All @@ -752,6 +786,9 @@ BOOL WINAPI VirtualLinkDirectoryStatic(LPCWSTR source, LPCWSTR destination, unsi
usvfs::shared::FLAG_DIRECTORY | convertRedirectionFlags(flags),
(flags & LINKFLAG_CREATETARGET) != 0);

const auto skipDirectories = context->skipDirectories();
const auto skipFileSuffixes = context->skipFileSuffixes();

if ((flags & LINKFLAG_RECURSIVE) != 0) {
std::wstring sourceP(source);
std::wstring sourceW = sourceP + L"\\";
Expand All @@ -763,13 +800,36 @@ BOOL WINAPI VirtualLinkDirectoryStatic(LPCWSTR source, LPCWSTR destination, unsi
winapi::ex::wide::quickFindFiles(sourceP.c_str(), L"*")) {
if (file.attributes & FILE_ATTRIBUTE_DIRECTORY) {
if ((file.fileName != L".") && (file.fileName != L"..")) {

const auto nameU8 = ush::string_cast<std::string>(file.fileName.c_str(),
ush::CodePage::UTF8);
// Check if the directory should be skipped
if (fileNameInSkipDirectories(nameU8, skipDirectories)) {
// Fail if we desire to fail when a dir/file is skipped
if (flags & LINKFLAG_FAILIFSKIPPED) {
spdlog::get("usvfs")->debug("directory '{}' skipped, failing as defined by link flags", nameU8);
return FALSE;
}

continue;
}

VirtualLinkDirectoryStatic((sourceW + file.fileName).c_str(),
(destinationW + file.fileName).c_str(),
flags);
(destinationW + file.fileName).c_str(), flags);
}
} else {
std::string nameU8 = ush::string_cast<std::string>(
file.fileName.c_str(), ush::CodePage::UTF8);
const auto nameU8 = ush::string_cast<std::string>(file.fileName.c_str(), ush::CodePage::UTF8);

// Check if the file should be skipped
if (fileNameInSkipSuffixes(nameU8, skipFileSuffixes)) {
// Fail if we desire to fail when a dir/file is skipped
if (flags & LINKFLAG_FAILIFSKIPPED) {
spdlog::get("usvfs")->debug("file '{}' skipped, failing as defined by link flags", nameU8);
return FALSE;
}

continue;
}

// TODO could save memory here by storing only the file name for the
// source and constructing the full name using the parent directory
Expand Down Expand Up @@ -878,6 +938,30 @@ VOID WINAPI ClearExecutableBlacklist()
}


VOID WINAPI usvfsAddSkipFileSuffix(LPWSTR fileSuffix)
{
context->addSkipFileSuffix(fileSuffix);
}


VOID WINAPI usvfsClearSkipFileSuffixes()
{
context->clearSkipFileSuffixes();
}


VOID WINAPI usvfsAddSkipDirectory(LPWSTR directory)
{
context->addSkipDirectory(directory);
}


VOID WINAPI usvfsClearSkipDirectories()
{
context->clearSkipDirectories();
}


VOID WINAPI ForceLoadLibrary(LPWSTR processName, LPWSTR libraryPath)
{
context->forceLoadLibrary(processName, libraryPath);
Expand Down

0 comments on commit beab783

Please sign in to comment.