133 lines
3.5 KiB
C++
133 lines
3.5 KiB
C++
#include <std_include.hpp>
|
|
#include "loader/component_loader.hpp"
|
|
#include "game/game.hpp"
|
|
#include "game/dvars.hpp"
|
|
|
|
#include <utils/hook.hpp>
|
|
#include <utils/string.hpp>
|
|
|
|
#include "filesystem.hpp"
|
|
#include "game_module.hpp"
|
|
|
|
namespace filesystem {
|
|
namespace {
|
|
const char* sys_default_install_path_stub() {
|
|
static auto current_path = std::filesystem::current_path().string();
|
|
return current_path.c_str();
|
|
}
|
|
} // namespace
|
|
|
|
bool file_wrapper_rotate(const char* ospath) {
|
|
constexpr auto MAX_BACKUPS = 20;
|
|
|
|
char renamed_path[game::MAX_OSPATH]{};
|
|
struct _stat64i32 stat_buf;
|
|
|
|
auto oldest_index = -1;
|
|
auto current_index = 0;
|
|
time_t oldest_time = 0;
|
|
|
|
// Check if the original file exists
|
|
if (_stat64i32(ospath, &stat_buf)) {
|
|
return true; // Return true if the file does not exist (no file to rotate)
|
|
}
|
|
|
|
for (; current_index < MAX_BACKUPS; ++current_index) {
|
|
(void)sprintf_s(renamed_path, "%s.%03i", ospath, current_index);
|
|
|
|
if (_stat64i32(renamed_path, &stat_buf)) {
|
|
break; // Stop if an available slot is found
|
|
}
|
|
|
|
if (oldest_index == -1 || stat_buf.st_mtime < oldest_time) {
|
|
oldest_time = stat_buf.st_mtime;
|
|
oldest_index = current_index;
|
|
}
|
|
}
|
|
|
|
if (current_index == MAX_BACKUPS) {
|
|
(void)sprintf_s(renamed_path, "%s.%03i", ospath, oldest_index);
|
|
(void)std::remove(renamed_path); // Remove the oldest backup file
|
|
} else {
|
|
(void)sprintf_s(renamed_path, "%s.%03i", ospath, current_index);
|
|
}
|
|
|
|
// Rename the original file to the selected backup slot
|
|
return std::rename(ospath, renamed_path) == 0;
|
|
}
|
|
|
|
bool file_rotate(const char* filename) {
|
|
char ospath[game::MAX_OSPATH]{};
|
|
|
|
const auto* basepath = (*dvars::fs_homepath)->current.string;
|
|
game::FS_BuildOSPath(basepath, reinterpret_cast<char*>(0x1956038), filename,
|
|
ospath);
|
|
return file_wrapper_rotate(ospath);
|
|
}
|
|
|
|
std::vector<std::string> vectored_file_list(const std::string& path,
|
|
const std::string& extension) {
|
|
std::vector<std::string> file_list;
|
|
|
|
auto num_files = 0;
|
|
const auto** files = game::FS_ListFiles(path.c_str(), extension.c_str(),
|
|
game::FS_LIST_ALL, &num_files, 10);
|
|
|
|
if (files) {
|
|
for (auto i = 0; i < num_files; ++i) {
|
|
if (files[i]) {
|
|
file_list.emplace_back(files[i]);
|
|
}
|
|
}
|
|
|
|
game::FS_FreeFileList(files, 10);
|
|
}
|
|
|
|
return file_list;
|
|
}
|
|
|
|
std::string get_binary_directory() {
|
|
const auto dir = game_module::get_host_module().get_folder();
|
|
return utils::string::replace(dir, "/", "\\");
|
|
}
|
|
|
|
file::file(std::string name, game::FsThread thread) : name_(std::move(name)) {
|
|
assert(!this->name_.empty());
|
|
|
|
auto handle = 0;
|
|
const auto len =
|
|
game::FS_FOpenFileReadForThread(name_.c_str(), &handle, thread);
|
|
|
|
if (!handle) {
|
|
this->valid_ = false;
|
|
return;
|
|
}
|
|
|
|
auto* buf = static_cast<char*>(game::Hunk_AllocateTempMemory(len + 1));
|
|
game::FS_Read(buf, len, handle);
|
|
buf[len] = '\0';
|
|
|
|
game::FS_FCloseFile(handle);
|
|
|
|
this->valid_ = true;
|
|
this->buffer_.append(buf, len);
|
|
}
|
|
|
|
bool file::exists() const { return this->valid_; }
|
|
|
|
const std::string& file::get_buffer() const { return this->buffer_; }
|
|
|
|
const std::string& file::get_name() const { return this->name_; }
|
|
|
|
class component final : public component_interface {
|
|
public:
|
|
void post_load() override {
|
|
utils::hook(0x465B90, sys_default_install_path_stub, HOOK_CALL)
|
|
.install() // hook*
|
|
->quick(); // Sys_CreateFile
|
|
}
|
|
};
|
|
} // namespace filesystem
|
|
|
|
REGISTER_COMPONENT(filesystem::component)
|