2021-12-07 22:47:41 +01:00
|
|
|
#include "content/providers/file_provider.hpp"
|
2020-11-11 09:18:35 +01:00
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
#include <ctime>
|
2021-01-03 15:09:12 +01:00
|
|
|
#include <cstring>
|
2020-11-15 16:06:10 +01:00
|
|
|
|
2021-08-29 22:15:18 +02:00
|
|
|
#include <hex/helpers/utils.hpp>
|
2021-09-08 15:18:24 +02:00
|
|
|
#include <hex/helpers/file.hpp>
|
2021-12-07 22:47:41 +01:00
|
|
|
#include <hex/helpers/project_file_handler.hpp>
|
2020-11-15 16:06:10 +01:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
namespace hex::plugin::builtin::prv {
|
|
|
|
|
|
|
|
FileProvider::FileProvider() : Provider() {
|
2020-11-11 09:18:35 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
FileProvider::~FileProvider() {
|
2021-07-27 21:07:36 +02:00
|
|
|
this->close();
|
2020-11-11 09:18:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-09-21 02:29:54 +02:00
|
|
|
bool FileProvider::isAvailable() const {
|
2021-01-03 15:00:16 +01:00
|
|
|
#if defined(OS_WINDOWS)
|
2021-12-12 21:46:48 +01:00
|
|
|
return this->m_file != INVALID_HANDLE_VALUE && this->m_mapping != INVALID_HANDLE_VALUE && this->m_mappedFile != nullptr;
|
2021-01-03 15:00:16 +01:00
|
|
|
#else
|
|
|
|
return this->m_file != -1 && this->m_mappedFile != nullptr;
|
|
|
|
#endif
|
2020-11-11 09:18:35 +01:00
|
|
|
}
|
|
|
|
|
2021-09-21 02:29:54 +02:00
|
|
|
bool FileProvider::isReadable() const {
|
2020-11-11 10:47:02 +01:00
|
|
|
return isAvailable() && this->m_readable;
|
2020-11-11 09:18:35 +01:00
|
|
|
}
|
|
|
|
|
2021-09-21 02:29:54 +02:00
|
|
|
bool FileProvider::isWritable() const {
|
2020-11-11 10:47:02 +01:00
|
|
|
return isAvailable() && this->m_writable;
|
2020-11-11 09:18:35 +01:00
|
|
|
}
|
|
|
|
|
2021-09-21 02:29:54 +02:00
|
|
|
bool FileProvider::isResizable() const {
|
2021-07-27 21:07:36 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-09-21 02:29:54 +02:00
|
|
|
bool FileProvider::isSavable() const {
|
2021-08-21 13:53:50 +02:00
|
|
|
return !this->getPatches().empty();
|
|
|
|
}
|
|
|
|
|
2020-11-11 09:18:35 +01:00
|
|
|
|
2021-03-21 14:50:47 +01:00
|
|
|
void FileProvider::read(u64 offset, void *buffer, size_t size, bool overlays) {
|
2021-12-09 21:10:24 +01:00
|
|
|
if ((offset - this->getBaseAddress()) > (this->getActualSize() - size) || buffer == nullptr || size == 0)
|
2020-11-11 09:18:35 +01:00
|
|
|
return;
|
|
|
|
|
2021-12-09 21:10:24 +01:00
|
|
|
this->readRaw(offset - this->getBaseAddress(), buffer, size);
|
2020-11-27 09:09:48 +01:00
|
|
|
|
2021-01-03 15:00:16 +01:00
|
|
|
for (u64 i = 0; i < size; i++)
|
2021-03-26 21:43:24 +01:00
|
|
|
if (getPatches().contains(offset + i))
|
|
|
|
reinterpret_cast<u8*>(buffer)[i] = getPatches()[offset + PageSize * this->m_currPage + i];
|
2021-03-21 14:50:47 +01:00
|
|
|
|
|
|
|
if (overlays)
|
|
|
|
this->applyOverlays(offset, buffer, size);
|
2020-11-11 09:18:35 +01:00
|
|
|
}
|
|
|
|
|
2020-11-27 13:44:52 +01:00
|
|
|
void FileProvider::write(u64 offset, const void *buffer, size_t size) {
|
2021-12-09 21:10:24 +01:00
|
|
|
if ((offset - this->getBaseAddress()) > (this->getActualSize() - size) || buffer == nullptr || size == 0)
|
2020-11-11 09:18:35 +01:00
|
|
|
return;
|
|
|
|
|
2021-03-26 21:43:24 +01:00
|
|
|
addPatch(offset, buffer, size);
|
2020-11-27 09:09:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileProvider::readRaw(u64 offset, void *buffer, size_t size) {
|
2021-12-09 21:10:24 +01:00
|
|
|
if ((offset + size) > this->getActualSize() || buffer == nullptr || size == 0)
|
2020-11-27 09:09:48 +01:00
|
|
|
return;
|
|
|
|
|
2021-12-23 15:57:22 +01:00
|
|
|
std::memcpy(buffer, reinterpret_cast<u8*>(this->m_mappedFile) + offset, size);
|
2020-11-11 09:18:35 +01:00
|
|
|
}
|
|
|
|
|
2020-11-27 13:44:52 +01:00
|
|
|
void FileProvider::writeRaw(u64 offset, const void *buffer, size_t size) {
|
2021-12-09 21:10:24 +01:00
|
|
|
if ((offset + size) > this->getActualSize() || buffer == nullptr || size == 0)
|
2020-11-27 09:09:48 +01:00
|
|
|
return;
|
|
|
|
|
2021-12-23 15:57:22 +01:00
|
|
|
std::memcpy(reinterpret_cast<u8*>(this->m_mappedFile) + offset, buffer, size);
|
2020-11-27 09:09:48 +01:00
|
|
|
}
|
2021-07-27 21:07:36 +02:00
|
|
|
|
2021-08-21 13:53:50 +02:00
|
|
|
void FileProvider::save() {
|
|
|
|
this->applyPatches();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileProvider::saveAs(const std::string &path) {
|
2021-09-08 15:18:24 +02:00
|
|
|
File file(path, File::Mode::Create);
|
2021-08-21 13:53:50 +02:00
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
if (file.isValid()) {
|
2021-10-07 22:51:16 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
|
|
|
|
|
|
|
std::vector<u8> buffer(std::min<size_t>(0xFF'FFFF, provider->getActualSize()), 0x00);
|
2021-08-21 13:53:50 +02:00
|
|
|
size_t bufferSize = buffer.size();
|
|
|
|
|
|
|
|
for (u64 offset = 0; offset < provider->getActualSize(); offset += bufferSize) {
|
|
|
|
if (bufferSize > provider->getActualSize() - offset)
|
|
|
|
bufferSize = provider->getActualSize() - offset;
|
|
|
|
|
2021-12-09 21:10:24 +01:00
|
|
|
provider->read(offset + this->getBaseAddress(), buffer.data(), bufferSize);
|
2021-09-08 15:18:24 +02:00
|
|
|
file.write(buffer);
|
2021-08-21 13:53:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-27 21:07:36 +02:00
|
|
|
void FileProvider::resize(ssize_t newSize) {
|
2021-07-27 22:46:37 +02:00
|
|
|
this->close();
|
2021-07-27 21:07:36 +02:00
|
|
|
|
|
|
|
#if defined(OS_WINDOWS)
|
|
|
|
std::wstring widePath;
|
|
|
|
{
|
|
|
|
auto length = static_cast<int>(this->m_path.length() + 1);
|
|
|
|
auto wideLength = MultiByteToWideChar(CP_UTF8, 0, this->m_path.data(), length, nullptr, 0);
|
|
|
|
auto buffer = new wchar_t[wideLength];
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, this->m_path.data(), length, buffer, wideLength);
|
|
|
|
widePath = buffer;
|
|
|
|
delete[] buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto handle = ::CreateFileW(widePath.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
|
|
|
|
|
|
if (handle != INVALID_HANDLE_VALUE) {
|
|
|
|
::SetFilePointerEx(handle, LARGE_INTEGER { .QuadPart = newSize }, nullptr, FILE_BEGIN);
|
|
|
|
::SetEndOfFile(handle);
|
|
|
|
::CloseHandle(handle);
|
|
|
|
}
|
|
|
|
#else
|
2021-07-27 21:49:17 +02:00
|
|
|
auto handle = ::open(this->m_path.data(), 0644);
|
2021-07-27 21:07:36 +02:00
|
|
|
|
2021-07-27 22:46:37 +02:00
|
|
|
::ftruncate(handle, newSize - 1);
|
2021-07-27 21:07:36 +02:00
|
|
|
|
2021-07-27 22:46:37 +02:00
|
|
|
::close(handle);
|
2021-07-27 21:07:36 +02:00
|
|
|
#endif
|
|
|
|
|
2021-12-12 00:41:44 +01:00
|
|
|
this->open();
|
2021-07-27 21:07:36 +02:00
|
|
|
}
|
|
|
|
|
2021-09-21 02:29:54 +02:00
|
|
|
size_t FileProvider::getActualSize() const {
|
2021-01-03 15:00:16 +01:00
|
|
|
return this->m_fileSize;
|
2020-11-11 09:18:35 +01:00
|
|
|
}
|
|
|
|
|
2021-09-21 02:29:54 +02:00
|
|
|
std::string FileProvider::getName() const {
|
|
|
|
return std::filesystem::path(this->m_path).filename().string();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::pair<std::string, std::string>> FileProvider::getDataInformation() const {
|
2020-11-15 16:06:10 +01:00
|
|
|
std::vector<std::pair<std::string, std::string>> result;
|
|
|
|
|
2021-02-22 13:07:25 +01:00
|
|
|
result.emplace_back("hex.builtin.provider.file.path"_lang, this->m_path);
|
|
|
|
result.emplace_back("hex.builtin.provider.file.size"_lang, hex::toByteString(this->getActualSize()));
|
2020-11-15 16:06:10 +01:00
|
|
|
|
|
|
|
if (this->m_fileStatsValid) {
|
2021-02-22 13:07:25 +01:00
|
|
|
result.emplace_back("hex.builtin.provider.file.creation"_lang, ctime(&this->m_fileStats.st_ctime));
|
|
|
|
result.emplace_back("hex.builtin.provider.file.access"_lang, ctime(&this->m_fileStats.st_atime));
|
|
|
|
result.emplace_back("hex.builtin.provider.file.modification"_lang, ctime(&this->m_fileStats.st_mtime));
|
2020-11-15 16:06:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-12-12 00:41:44 +01:00
|
|
|
void FileProvider::setPath(const std::string &path) {
|
2021-12-07 22:47:41 +01:00
|
|
|
this->m_path = path;
|
2021-12-12 00:41:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool FileProvider::open() {
|
2021-07-27 21:07:36 +02:00
|
|
|
this->m_fileStatsValid = stat(this->m_path.data(), &this->m_fileStats) == 0;
|
|
|
|
|
|
|
|
this->m_readable = true;
|
|
|
|
this->m_writable = true;
|
|
|
|
|
|
|
|
#if defined(OS_WINDOWS)
|
|
|
|
std::wstring widePath;
|
|
|
|
{
|
|
|
|
auto length = this->m_path.length() + 1;
|
|
|
|
auto wideLength = MultiByteToWideChar(CP_UTF8, 0, this->m_path.data(), length, 0, 0);
|
2021-09-08 15:18:24 +02:00
|
|
|
auto buffer = new wchar_t[wideLength];
|
2021-07-27 21:07:36 +02:00
|
|
|
MultiByteToWideChar(CP_UTF8, 0, this->m_path.data(), length, buffer, wideLength);
|
|
|
|
widePath = buffer;
|
|
|
|
delete[] buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
LARGE_INTEGER fileSize = { 0 };
|
2022-01-09 21:57:43 +01:00
|
|
|
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(widePath.data(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
2021-07-27 21:07:36 +02:00
|
|
|
|
|
|
|
GetFileSizeEx(this->m_file, &fileSize);
|
|
|
|
this->m_fileSize = fileSize.QuadPart;
|
|
|
|
CloseHandle(this->m_file);
|
|
|
|
|
2022-01-09 21:57:43 +01:00
|
|
|
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(widePath.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
2021-07-27 21:07:36 +02:00
|
|
|
if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) {
|
2022-01-09 21:57:43 +01:00
|
|
|
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(widePath.data(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
2021-07-27 21:07:36 +02:00
|
|
|
this->m_writable = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto fileCleanup = SCOPE_GUARD {
|
2022-01-09 21:57:43 +01:00
|
|
|
CloseHandle(this->m_file);
|
|
|
|
|
2021-07-27 21:07:36 +02:00
|
|
|
this->m_readable = false;
|
|
|
|
this->m_file = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) {
|
2021-12-12 00:41:44 +01:00
|
|
|
return false;
|
2021-07-27 21:07:36 +02:00
|
|
|
}
|
|
|
|
|
2021-12-14 20:16:00 +01:00
|
|
|
if (this->m_fileSize > 0) {
|
2021-12-23 15:57:22 +01:00
|
|
|
this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READWRITE, 0, 0, nullptr);
|
2021-12-14 20:16:00 +01:00
|
|
|
if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE) {
|
2022-01-09 21:57:43 +01:00
|
|
|
|
|
|
|
this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
|
|
|
|
|
|
|
if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE)
|
|
|
|
return false;
|
2021-12-14 20:16:00 +01:00
|
|
|
}
|
2021-07-27 21:07:36 +02:00
|
|
|
|
2021-12-14 20:16:00 +01:00
|
|
|
auto mappingCleanup = SCOPE_GUARD {
|
|
|
|
CloseHandle(this->m_mapping);
|
2022-01-09 21:57:43 +01:00
|
|
|
|
|
|
|
this->m_mapping = nullptr;
|
|
|
|
this->m_readable = false;
|
2021-12-14 20:16:00 +01:00
|
|
|
};
|
2021-07-27 21:07:36 +02:00
|
|
|
|
2021-12-14 20:16:00 +01:00
|
|
|
this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_ALL_ACCESS, 0, 0, this->m_fileSize);
|
|
|
|
if (this->m_mappedFile == nullptr) {
|
2022-01-09 21:57:43 +01:00
|
|
|
|
|
|
|
this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_READ, 0, 0, this->m_fileSize);
|
|
|
|
if (this->m_mappedFile == nullptr) {
|
|
|
|
this->m_readable = false;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2021-12-14 20:16:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
mappingCleanup.release();
|
|
|
|
|
|
|
|
ProjectFile::setFilePath(this->m_path);
|
2021-12-15 22:52:35 +01:00
|
|
|
} else if (!this->m_emptyFile) {
|
|
|
|
this->m_emptyFile = true;
|
2021-12-14 20:16:00 +01:00
|
|
|
this->resize(1);
|
2021-12-15 22:52:35 +01:00
|
|
|
} else {
|
|
|
|
return false;
|
2021-07-27 21:07:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fileCleanup.release();
|
|
|
|
|
|
|
|
#else
|
2021-12-12 00:41:44 +01:00
|
|
|
this->m_file = ::open(this->m_path.data(), O_RDWR);
|
2021-07-27 21:07:36 +02:00
|
|
|
if (this->m_file == -1) {
|
2021-07-27 22:46:37 +02:00
|
|
|
this->m_file = ::open(this->m_path.data(), O_RDONLY);
|
2021-07-27 21:07:36 +02:00
|
|
|
this->m_writable = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this->m_file == -1) {
|
|
|
|
this->m_readable = false;
|
2021-12-12 00:41:44 +01:00
|
|
|
return false;
|
2021-07-27 21:07:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
this->m_fileSize = this->m_fileStats.st_size;
|
|
|
|
|
2021-12-22 13:36:26 +01:00
|
|
|
this->m_mappedFile = ::mmap(nullptr, this->m_fileSize, PROT_READ | PROT_WRITE, MAP_SHARED, this->m_file, 0);
|
2021-12-12 00:41:44 +01:00
|
|
|
if (this->m_mappedFile == nullptr) {
|
|
|
|
::close(this->m_file);
|
|
|
|
this->m_file = -1;
|
2021-07-27 21:07:36 +02:00
|
|
|
|
2021-12-12 00:41:44 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return true;
|
2021-07-27 21:07:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileProvider::close() {
|
|
|
|
#if defined(OS_WINDOWS)
|
|
|
|
if (this->m_mappedFile != nullptr)
|
|
|
|
::UnmapViewOfFile(this->m_mappedFile);
|
|
|
|
if (this->m_mapping != nullptr)
|
|
|
|
::CloseHandle(this->m_mapping);
|
|
|
|
if (this->m_file != nullptr)
|
|
|
|
::CloseHandle(this->m_file);
|
|
|
|
#else
|
|
|
|
::munmap(this->m_mappedFile, this->m_fileSize);
|
|
|
|
::close(this->m_file);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-12-22 13:36:26 +01:00
|
|
|
}
|