provider: Added raw disk provider
This commit is contained in:
parent
3e736b36b6
commit
8a36897fd9
@ -18,6 +18,7 @@ add_library(${PROJECT_NAME} SHARED
|
||||
|
||||
source/content/providers/file_provider.cpp
|
||||
source/content/providers/gdb_provider.cpp
|
||||
source/content/providers/disk_provider.cpp
|
||||
|
||||
source/content/views/view_hexeditor.cpp
|
||||
source/content/views/view_pattern_editor.cpp
|
||||
|
62
plugins/builtin/include/content/providers/disk_provider.hpp
Normal file
62
plugins/builtin/include/content/providers/disk_provider.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include "content/providers/file_provider.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
|
||||
class DiskProvider : public hex::prv::Provider {
|
||||
public:
|
||||
DiskProvider();
|
||||
~DiskProvider() override;
|
||||
|
||||
[[nodiscard]] bool isAvailable() const override;
|
||||
[[nodiscard]] bool isReadable() const override;
|
||||
[[nodiscard]] bool isWritable() const override;
|
||||
[[nodiscard]] bool isResizable() const override;
|
||||
[[nodiscard]] bool isSavable() const override;
|
||||
|
||||
void readRaw(u64 offset, void *buffer, size_t size) override;
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override;
|
||||
[[nodiscard]] size_t getActualSize() const override;
|
||||
|
||||
void setPath(const std::string &path);
|
||||
|
||||
[[nodiscard]] bool open() override;
|
||||
void close() override;
|
||||
|
||||
[[nodiscard]] virtual std::string getName() const;
|
||||
[[nodiscard]] virtual std::vector<std::pair<std::string, std::string>> getDataInformation() const;
|
||||
|
||||
[[nodiscard]] bool hasLoadInterface() const override { return true; }
|
||||
void drawLoadInterface() override;
|
||||
protected:
|
||||
std::set<std::string> m_availableDrives;
|
||||
std::string m_path;
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
HANDLE m_diskHandle = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
int m_diskHandle = -1;
|
||||
#endif
|
||||
|
||||
size_t m_diskSize;
|
||||
size_t m_sectorSize;
|
||||
|
||||
u64 m_sectorBufferAddress;
|
||||
std::vector<u8> m_sectorBuffer;
|
||||
|
||||
bool m_readable = false;
|
||||
bool m_writable = false;
|
||||
};
|
||||
|
||||
}
|
@ -3,11 +3,13 @@
|
||||
|
||||
#include "content/providers/gdb_provider.hpp"
|
||||
#include "content/providers/file_provider.hpp"
|
||||
#include "content/providers/disk_provider.hpp"
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void registerProviders() {
|
||||
ContentRegistry::Provider::add("hex.builtin.provider.gdb");
|
||||
ContentRegistry::Provider::add("hex.builtin.provider.disk");
|
||||
|
||||
(void) EventManager::subscribe<RequestCreateProvider>([](const std::string &unlocalizedName, hex::prv::Provider **provider){
|
||||
if (unlocalizedName != "hex.builtin.provider.file") return;
|
||||
@ -30,6 +32,17 @@ namespace hex::plugin::builtin {
|
||||
if (provider != nullptr)
|
||||
*provider = newProvider;
|
||||
});
|
||||
|
||||
(void) EventManager::subscribe<RequestCreateProvider>([](const std::string &unlocalizedName, hex::prv::Provider **provider){
|
||||
if (unlocalizedName != "hex.builtin.provider.disk") return;
|
||||
|
||||
auto newProvider = new prv::DiskProvider();
|
||||
|
||||
hex::ImHexApi::Provider::add(newProvider);
|
||||
|
||||
if (provider != nullptr)
|
||||
*provider = newProvider;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
308
plugins/builtin/source/content/providers/disk_provider.cpp
Normal file
308
plugins/builtin/source/content/providers/disk_provider.cpp
Normal file
@ -0,0 +1,308 @@
|
||||
#include "content/providers/disk_provider.hpp"
|
||||
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
#include <bitset>
|
||||
#include <filesystem>
|
||||
|
||||
#if defined (OS_LINUX) || defined (OS_MACOS)
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
|
||||
DiskProvider::DiskProvider() : Provider() {
|
||||
|
||||
}
|
||||
|
||||
DiskProvider::~DiskProvider() {
|
||||
this->close();
|
||||
}
|
||||
|
||||
bool DiskProvider::isAvailable() const {
|
||||
#if defined (OS_WINDOWS)
|
||||
return this->m_diskHandle != INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
return this->m_diskHandle != -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DiskProvider::isReadable() const {
|
||||
return this->m_readable;
|
||||
}
|
||||
|
||||
bool DiskProvider::isWritable() const {
|
||||
return this->m_writable;
|
||||
}
|
||||
|
||||
bool DiskProvider::isResizable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DiskProvider::isSavable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void DiskProvider::setPath(const std::string &path) {
|
||||
this->m_path = path;
|
||||
}
|
||||
|
||||
bool DiskProvider::open() {
|
||||
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);
|
||||
auto buffer = new wchar_t[wideLength];
|
||||
MultiByteToWideChar(CP_UTF8, 0, this->m_path.data(), length, buffer, wideLength);
|
||||
widePath = buffer;
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
this->m_diskHandle = reinterpret_cast<HANDLE>(CreateFileW(widePath.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
if (this->m_diskHandle == INVALID_HANDLE_VALUE) {
|
||||
this->m_diskHandle = reinterpret_cast<HANDLE>(CreateFileW(widePath.data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
this->m_writable = false;
|
||||
|
||||
if (this->m_diskHandle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
DISK_GEOMETRY_EX diskGeometry = { 0 };
|
||||
DWORD bytesRead = 0;
|
||||
if (DeviceIoControl(
|
||||
this->m_diskHandle,
|
||||
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
|
||||
nullptr, 0,
|
||||
&diskGeometry, sizeof(DISK_GEOMETRY_EX),
|
||||
&bytesRead,
|
||||
nullptr))
|
||||
{
|
||||
this->m_diskSize = diskGeometry.DiskSize.QuadPart;
|
||||
this->m_sectorSize = diskGeometry.Geometry.BytesPerSector;
|
||||
this->m_sectorBuffer.resize(this->m_sectorSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->m_diskHandle == nullptr || this->m_diskHandle == INVALID_HANDLE_VALUE) {
|
||||
this->m_readable = false;
|
||||
this->m_diskHandle = nullptr;
|
||||
CloseHandle(this->m_diskHandle);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
struct stat driveStat;
|
||||
|
||||
::stat(this->m_path.data(), &driveStat) == 0;
|
||||
this->m_diskSize = driveStat.st_size;
|
||||
this->m_sectorSize = 0;
|
||||
|
||||
this->m_diskHandle = ::open(this->m_path.data(), O_RDWR);
|
||||
if (this->m_diskHandle == -1) {
|
||||
this->m_diskHandle = ::open(this->m_path.data(), O_RDONLY);
|
||||
this->m_writable = false;
|
||||
}
|
||||
|
||||
if (this->m_diskHandle == -1) {
|
||||
this->m_readable = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DiskProvider::close() {
|
||||
#if defined (OS_WINDOWS)
|
||||
if (this->m_diskHandle != INVALID_HANDLE_VALUE)
|
||||
::CloseHandle(this->m_diskHandle);
|
||||
|
||||
this->m_diskHandle = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
if (this->m_diskHandle != -1)
|
||||
::close(this->m_diskHandle);
|
||||
|
||||
this->m_diskHandle = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DiskProvider::readRaw(u64 offset, void *buffer, size_t size) {
|
||||
#if defined (OS_WINDOWS)
|
||||
DWORD bytesRead = 0;
|
||||
|
||||
u64 startOffset = offset;
|
||||
|
||||
while (size > 0) {
|
||||
LARGE_INTEGER seekPosition;
|
||||
seekPosition.LowPart = (offset & 0xFFFF'FFFF) - (offset % this->m_sectorSize);
|
||||
seekPosition.HighPart = offset >> 32;
|
||||
|
||||
if (this->m_sectorBufferAddress != seekPosition.QuadPart) {
|
||||
::SetFilePointer(this->m_diskHandle, seekPosition.LowPart, &seekPosition.HighPart, FILE_BEGIN);
|
||||
::ReadFile(this->m_diskHandle, this->m_sectorBuffer.data(), this->m_sectorBuffer.size(), &bytesRead, nullptr);
|
||||
this->m_sectorBufferAddress = seekPosition.QuadPart;
|
||||
}
|
||||
|
||||
std::memcpy(reinterpret_cast<u8*>(buffer) + (offset - startOffset), this->m_sectorBuffer.data() + (offset & (this->m_sectorSize - 1)), std::min(this->m_sectorSize, size));
|
||||
|
||||
size = std::max<ssize_t>(static_cast<ssize_t>(size) - this->m_sectorSize, 0);
|
||||
offset += this->m_sectorSize;
|
||||
}
|
||||
#else
|
||||
u64 startOffset = offset;
|
||||
|
||||
while (size > 0) {
|
||||
u64 seekPosition = offset - (offset % this->m_sectorSize);
|
||||
|
||||
if (this->m_sectorBufferAddress != seekPosition) {
|
||||
::lseek64(this->m_diskHandle, seekPosition, SEEK_SET);
|
||||
::read(this->m_diskHandle, buffer, size);
|
||||
this->m_sectorBufferAddress = seekPosition;
|
||||
}
|
||||
|
||||
std::memcpy(reinterpret_cast<u8*>(buffer) + (offset - startOffset), this->m_sectorBuffer.data() + (offset & (this->m_sectorSize - 1)), std::min(this->m_sectorSize, size));
|
||||
|
||||
size = std::max<ssize_t>(static_cast<ssize_t>(size) - this->m_sectorSize, 0);
|
||||
offset += this->m_sectorSize;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DiskProvider::writeRaw(u64 offset, const void *buffer, size_t size) {
|
||||
#if defined (OS_WINDOWS)
|
||||
DWORD bytesWritten = 0;
|
||||
|
||||
u64 startOffset = offset;
|
||||
|
||||
std::vector<u8> modifiedSectorBuffer;
|
||||
modifiedSectorBuffer.resize(this->m_sectorSize);
|
||||
|
||||
while (size > 0) {
|
||||
u64 sectorBase = offset - (offset % this->m_sectorSize);
|
||||
size_t currSize = std::min(size, this->m_sectorSize);
|
||||
|
||||
this->readRaw(sectorBase, modifiedSectorBuffer.data(), modifiedSectorBuffer.size());
|
||||
std::memcpy(modifiedSectorBuffer.data() + ((offset - sectorBase) % this->m_sectorSize), reinterpret_cast<const u8*>(buffer) + (startOffset - offset), currSize);
|
||||
|
||||
LARGE_INTEGER seekPosition;
|
||||
seekPosition.LowPart = (offset & 0xFFFF'FFFF) - (offset % this->m_sectorSize);
|
||||
seekPosition.HighPart = offset >> 32;
|
||||
|
||||
::SetFilePointer(this->m_diskHandle, seekPosition.LowPart, &seekPosition.HighPart, FILE_BEGIN);
|
||||
::WriteFile(this->m_diskHandle, modifiedSectorBuffer.data(), modifiedSectorBuffer.size(), &bytesWritten, nullptr);
|
||||
|
||||
offset += currSize;
|
||||
size -= currSize;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
u64 startOffset = offset;
|
||||
|
||||
std::vector<u8> modifiedSectorBuffer;
|
||||
modifiedSectorBuffer.resize(this->m_sectorSize);
|
||||
|
||||
while (size > 0) {
|
||||
u64 sectorBase = offset - (offset % this->m_sectorSize);
|
||||
size_t currSize = std::min(size, this->m_sectorSize);
|
||||
|
||||
this->readRaw(sectorBase, modifiedSectorBuffer.data(), modifiedSectorBuffer.size());
|
||||
std::memcpy(modifiedSectorBuffer.data() + ((offset - sectorBase) % this->m_sectorSize), reinterpret_cast<const u8*>(buffer) + (startOffset - offset), currSize);
|
||||
|
||||
::lseek64(this->m_diskHandle, sectorBase, SEEK_SET);
|
||||
::write(this->m_diskHandle, modifiedSectorBuffer.data(), modifiedSectorBuffer.size());
|
||||
|
||||
offset += currSize;
|
||||
size -= currSize;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t DiskProvider::getActualSize() const {
|
||||
return this->m_diskSize;
|
||||
}
|
||||
|
||||
std::string DiskProvider::getName() const {
|
||||
return this->m_path;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> DiskProvider::getDataInformation() const {
|
||||
return {
|
||||
{ "hex.builtin.provider.disk.selected_disk"_lang, this->m_path },
|
||||
{ "hex.builtin.provider.disk.disk_size"_lang, hex::toByteString(this->m_diskSize) },
|
||||
{ "hex.builtin.provider.disk.sector_size"_lang, hex::toByteString(this->m_sectorSize) }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DiskProvider::drawLoadInterface() {
|
||||
#if defined (OS_WINDOWS)
|
||||
if (ImGui::BeginListBox("hex.builtin.provider.disk.selected_disk"_lang)) {
|
||||
|
||||
for (const auto &drive : this->m_availableDrives) {
|
||||
if (ImGui::Selectable(drive.c_str(), this->m_path == drive))
|
||||
this->m_path = drive;
|
||||
}
|
||||
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("hex.builtin.provider.disk.reload"_lang)) {
|
||||
this->m_availableDrives.clear();
|
||||
std::bitset<32> drives = ::GetLogicalDrives();
|
||||
for (char i = 0; i < 26; i++) {
|
||||
if (drives[i])
|
||||
this->m_availableDrives.insert(hex::format(R"(\\.\{:c}:)", 'A' + i));
|
||||
}
|
||||
|
||||
auto logicalDrives = this->m_availableDrives;
|
||||
for (const auto &drive : logicalDrives) {
|
||||
auto handle = reinterpret_cast<HANDLE>(::CreateFile(drive.data(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr));
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) continue;
|
||||
|
||||
VOLUME_DISK_EXTENTS diskExtents = { 0 };
|
||||
DWORD bytesRead = 0;
|
||||
auto result = ::DeviceIoControl(
|
||||
handle,
|
||||
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
|
||||
nullptr,
|
||||
0,
|
||||
&diskExtents,
|
||||
sizeof(VOLUME_DISK_EXTENTS),
|
||||
&bytesRead,
|
||||
nullptr);
|
||||
|
||||
if (result) {
|
||||
auto diskPath = hex::format(R"(\\.\PhysicalDrive{})", diskExtents.Extents[0].DiskNumber);
|
||||
this->m_availableDrives.insert(diskPath);
|
||||
}
|
||||
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
ImGui::InputText("hex.builtin.provider.disk.selected_disk"_lang, this->m_path.data(), this->m_path.capacity(), ImGuiInputTextFlags_CallbackResize, ImGui::UpdateStringSizeCallback, &this->m_path);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
@ -679,6 +679,11 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.provider.gdb", "GDB Server Provider" },
|
||||
{ "hex.builtin.provider.gdb.name", "GDB Server <{0}:{1}>" },
|
||||
{ "hex.builtin.provider.gdb.server", "Server" },
|
||||
{ "hex.builtin.provider.disk", "Datenträger Provider" },
|
||||
{ "hex.builtin.provider.disk.selected_disk", "Datenträger" },
|
||||
{ "hex.builtin.provider.disk.disk_size", "Datenträgergrösse" },
|
||||
{ "hex.builtin.provider.disk.sector_size", "Sektorgrösse" },
|
||||
{ "hex.builtin.provider.disk.reload", "Neu laden" },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -682,6 +682,11 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.provider.gdb", "GDB Server Provider" },
|
||||
{ "hex.builtin.provider.gdb.name", "GDB Server <{0}:{1}>" },
|
||||
{ "hex.builtin.provider.gdb.server", "Server" },
|
||||
{ "hex.builtin.provider.disk", "Raw Disk Provider" },
|
||||
{ "hex.builtin.provider.disk.selected_disk", "Disk" },
|
||||
{ "hex.builtin.provider.disk.disk_size", "Disk Size" },
|
||||
{ "hex.builtin.provider.disk.sector_size", "Sector Size" },
|
||||
{ "hex.builtin.provider.disk.reload", "Reload" },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -676,6 +676,11 @@ namespace hex::plugin::builtin {
|
||||
//{ "hex.builtin.provider.gdb", "GDB Server Provider" },
|
||||
//{ "hex.builtin.provider.gdb.name", "GDB Server <{0}:{1}>" },
|
||||
//{ "hex.builtin.provider.gdb.server", "Server" },
|
||||
//{ "hex.builtin.provider.disk", "Raw Disk Provider" },
|
||||
//{ "hex.builtin.provider.disk.selected_disk", "Disk" },
|
||||
//{ "hex.builtin.provider.disk.disk_size", "Disk Size" },
|
||||
//{ "hex.builtin.provider.disk.sector_size", "Sector Size" },
|
||||
//{ "hex.builtin.provider.disk.reload", "Reload" },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -678,6 +678,11 @@ namespace hex::plugin::builtin {
|
||||
//{ "hex.builtin.provider.gdb", "GDB Server Provider" },
|
||||
//{ "hex.builtin.provider.gdb.name", "GDB Server <{0}:{1}>" },
|
||||
//{ "hex.builtin.provider.gdb.server", "Server" },
|
||||
//{ "hex.builtin.provider.disk", "Raw Disk Provider" },
|
||||
//{ "hex.builtin.provider.disk.selected_disk", "Disk" },
|
||||
//{ "hex.builtin.provider.disk.disk_size", "Disk Size" },
|
||||
//{ "hex.builtin.provider.disk.sector_size", "Sector Size" },
|
||||
//{ "hex.builtin.provider.disk.reload", "Reload" },
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user