diff --git a/src/unlocker/cache-cleaner.cpp b/src/unlocker/cache-cleaner.cpp new file mode 100644 index 0000000..94d5f25 --- /dev/null +++ b/src/unlocker/cache-cleaner.cpp @@ -0,0 +1,138 @@ +#include "cache-cleaner.h" + +#include +#include + +#include +#include +#include + +#include + +CacheCleaner::CacheCleaner() : _running(false), _monitorThread(nullptr) +{ + _log = new seallib::Logger("Cache cleaner"); +} + +CacheCleaner::~CacheCleaner() +{ + shutdown(); + delete _log; +} + +void CacheCleaner::init() +{ + std::string localAppData = getLocalAppDataPath(); + if (localAppData.empty()) + { + _log->error("Failed to get LocalAppData"); + return; + } + + _cacheDir = localAppData + "\\DeadByDaylight\\Saved\\PersistentDownloadDir"; + + // this is pointless but just in case + std::filesystem::create_directories(_cacheDir); + + clearFolder(_cacheDir); + + _running = true; + + _monitorThread = std::make_unique(&CacheCleaner::monitorLoop, this); +} + +void CacheCleaner::shutdown() +{ + _log->verbose("shutting down"); + if (!_running) return; + _running = false; + + if (_monitorThread && _monitorThread->joinable()) _monitorThread->join(); + _monitorThread.reset(); +} + +std::string CacheCleaner::getLocalAppDataPath() +{ + char buffer[MAX_PATH]; + if (SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, buffer) == S_OK) + { + return std::string(buffer); + } + return ""; +} + +void CacheCleaner::clearFolder(std::string& path) +{ + try + { + for (const auto& entry : std::filesystem::directory_iterator(path)) + { + std::filesystem::remove_all(entry.path()); + } + } + catch (...) + { + } +} + +void CacheCleaner::monitorLoop() +{ + HANDLE changeHandle = FindFirstChangeNotificationA(_cacheDir.c_str(), TRUE, + FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_LAST_WRITE); + + if (changeHandle == INVALID_HANDLE_VALUE) + { + _log->error("Failed to create change notification"); + _running = false; + return; + } + + _log->verbose("Cache cleaner monitoring started"); + + std::unordered_set previousPids; + + while (_running) + { + for (int i = 0; i < 20 && _running; i++) + Sleep(100); + + if (!_running) break; + + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot == INVALID_HANDLE_VALUE) continue; + + PROCESSENTRY32 pe32; + pe32.dwSize = sizeof(PROCESSENTRY32); + + std::unordered_set currentPids; + + if (Process32First(hSnapshot, &pe32)) + { + do + { + DWORD pid = pe32.th32ProcessID; + currentPids.insert(pid); + + if (previousPids.find(pid) == previousPids.end()) + { + std::string processName(pe32.szExeFile); + + for (char& c : processName) + c = static_cast(tolower(c)); + + if (processName.find("deadbydaylight") != std::string::npos) + { + _log->verbose("New DeadByDaylight process detected (PID: {}), clearing cache", pid); + clearFolder(_cacheDir); + } + } + } while (Process32Next(hSnapshot, &pe32)); + } + + CloseHandle(hSnapshot); + previousPids = std::move(currentPids); + } + + FindCloseChangeNotification(changeHandle); +} diff --git a/src/unlocker/cache-cleaner.h b/src/unlocker/cache-cleaner.h new file mode 100644 index 0000000..bc70c83 --- /dev/null +++ b/src/unlocker/cache-cleaner.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +#include + +class CacheCleaner +{ + public: + CacheCleaner(); + ~CacheCleaner(); + + void init(); + void shutdown(); + + private: + std::string getLocalAppDataPath(); + void clearFolder(std::string& path); + void monitorLoop(); + + std::atomic _running; + std::unique_ptr _monitorThread; + std::string _cacheDir; + + seallib::Logger* _log; +};