mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-30 21:05:56 -05:00
fix: Raw Disk Provider not working correctly on Linux and macOS (#1195)
<!-- Please provide as much information as possible about what your PR aims to do. PRs with no description will most likely be closed until more information is provided. If you're planing on changing fundamental behaviour or add big new features, please open a GitHub Issue first before starting to work on it. If it's not something big and you still want to contact us about it, feel free to do so ! --> ### Problem description - Fixed disk provider not working for linux ### Implementation description - Used ioctl instead of fstat - Fixed buffer issues --------- Co-authored-by: WerWolv <werwolv98@gmail.com>
This commit is contained in:
@@ -16,16 +16,25 @@
|
||||
#include <imgui.h>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <winioctl.h>
|
||||
#elif defined(OS_LINUX) || defined(OS_MACOS)
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <winioctl.h>
|
||||
#elif defined(OS_LINUX)
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/fs.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#elif defined(OS_MACOS)
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/disk.h>
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
#define lseek lseek64
|
||||
#define lseek lseek64
|
||||
#endif
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
@@ -35,15 +44,15 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
bool DiskProvider::isAvailable() const {
|
||||
#if defined(OS_WINDOWS)
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
return this->m_diskHandle != INVALID_HANDLE_VALUE;
|
||||
return this->m_diskHandle != INVALID_HANDLE_VALUE;
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
return this->m_diskHandle != -1;
|
||||
return this->m_diskHandle != -1;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DiskProvider::isReadable() const {
|
||||
@@ -67,13 +76,75 @@ namespace hex::plugin::builtin {
|
||||
this->m_path = path;
|
||||
}
|
||||
|
||||
#if defined (OS_LINUX)
|
||||
#ifdef BLKSSZGET
|
||||
int blkdev_get_sector_size(int fd, int *sector_size) {
|
||||
if (ioctl(fd, BLKSSZGET, sector_size) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int blkdev_get_sector_size(int fd, int *sector_size) {
|
||||
(void)fd;
|
||||
*sector_size = DEFAULT_SECTOR_SIZE;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BLKGETSIZE64
|
||||
int blkdev_get_size(int fd, u64 *bytes) {
|
||||
if (ioctl(fd, BLKGETSIZE64, bytes) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int blkdev_get_size(int fd, u64 *bytes) {
|
||||
struct stat st;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -1;
|
||||
|
||||
if (st.st_size == 0) {
|
||||
// try BLKGETSIZE
|
||||
unsigned long long bytes64;
|
||||
if (ioctl(fd, BLKGETSIZE, &bytes64) >= 0) {
|
||||
*bytes = bytes64;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
*bytes = st.st_size;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#elif defined(OS_MACOS)
|
||||
int blkdev_get_sector_size(int fd, int *sector_size) {
|
||||
if (ioctl(fd, DKIOCGETBLOCKSIZE, sector_size) >= 0)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int blkdev_get_size(int fd, u64 *bytes) {
|
||||
int sectorSize = 0;
|
||||
if (blkdev_get_sector_size(fd, §orSize) < 0)
|
||||
return -1;
|
||||
|
||||
if (ioctl(fd, DKIOCGETBLOCKCOUNT, bytes) < 0)
|
||||
return -1;
|
||||
|
||||
*bytes *= sectorSize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool DiskProvider::open() {
|
||||
this->m_readable = true;
|
||||
this->m_writable = true;
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
const auto &path = this->m_path.native();
|
||||
const auto &path = this->m_path.native();
|
||||
|
||||
this->m_diskHandle = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
if (this->m_diskHandle == INVALID_HANDLE_VALUE) {
|
||||
@@ -110,61 +181,59 @@ namespace hex::plugin::builtin {
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
const auto &path = this->m_path.native();
|
||||
const auto &path = this->m_path.native();
|
||||
|
||||
struct stat driveStat;
|
||||
this->m_diskHandle = ::open(path.c_str(), O_RDWR);
|
||||
if (this->m_diskHandle == -1) {
|
||||
this->setErrorMessage(hex::format("hex.builtin.provider.disk.error.read_rw"_lang, path, ::strerror(errno)));
|
||||
log::warn(this->getErrorMessage());
|
||||
this->m_diskHandle = ::open(path.c_str(), O_RDONLY);
|
||||
this->m_writable = false;
|
||||
}
|
||||
|
||||
if (::stat(path.c_str(), &driveStat) == 0)
|
||||
this->m_diskSize = driveStat.st_size;
|
||||
else
|
||||
this->m_diskSize = 0;
|
||||
if (this->m_diskHandle == -1) {
|
||||
this->setErrorMessage(hex::format("hex.builtin.provider.disk.error.read_ro"_lang, path, ::strerror(errno)));
|
||||
log::warn(this->getErrorMessage());
|
||||
this->m_readable = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
this->m_sectorSize = 0;
|
||||
u64 diskSize = 0;
|
||||
blkdev_get_size(this->m_diskHandle, &diskSize);
|
||||
this->m_diskSize = diskSize;
|
||||
blkdev_get_sector_size(this->m_diskHandle, reinterpret_cast<int *>(&this->m_sectorSize));
|
||||
|
||||
this->m_diskHandle = ::open(path.c_str(), O_RDWR);
|
||||
if (this->m_diskHandle == -1) {
|
||||
this->setErrorMessage(hex::format("hex.builtin.provider.disk.error.read_rw"_lang, path, ::strerror(errno)));
|
||||
log::warn(this->getErrorMessage());
|
||||
this->m_diskHandle = ::open(path.c_str(), O_RDONLY);
|
||||
this->m_writable = false;
|
||||
}
|
||||
this->m_sectorBuffer.resize(this->m_sectorSize);
|
||||
|
||||
if (this->m_diskHandle == -1) {
|
||||
this->setErrorMessage(hex::format("hex.builtin.provider.disk.error.read_ro"_lang, path, ::strerror(errno)));
|
||||
log::warn(this->getErrorMessage());
|
||||
this->m_readable = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DiskProvider::close() {
|
||||
#if defined(OS_WINDOWS)
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
if (this->m_diskHandle != INVALID_HANDLE_VALUE)
|
||||
if (this->m_diskHandle != INVALID_HANDLE_VALUE)
|
||||
::CloseHandle(this->m_diskHandle);
|
||||
|
||||
this->m_diskHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
if (this->m_diskHandle != -1)
|
||||
::close(this->m_diskHandle);
|
||||
if (this->m_diskHandle != -1)
|
||||
::close(this->m_diskHandle);
|
||||
|
||||
this->m_diskHandle = -1;
|
||||
this->m_diskHandle = -1;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void DiskProvider::readRaw(u64 offset, void *buffer, size_t size) {
|
||||
#if defined(OS_WINDOWS)
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
DWORD bytesRead = 0;
|
||||
DWORD bytesRead = 0;
|
||||
|
||||
u64 startOffset = offset;
|
||||
|
||||
@@ -185,34 +254,36 @@ namespace hex::plugin::builtin {
|
||||
offset += this->m_sectorSize;
|
||||
}
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
u64 startOffset = offset;
|
||||
|
||||
while (size > 0) {
|
||||
u64 seekPosition = offset - (offset % this->m_sectorSize);
|
||||
|
||||
if (this->m_sectorBufferAddress != seekPosition) {
|
||||
if (this->m_sectorBufferAddress != seekPosition || this->m_sectorBufferAddress == 0) {
|
||||
::lseek(this->m_diskHandle, seekPosition, SEEK_SET);
|
||||
if (::read(this->m_diskHandle, buffer, size) < 0)
|
||||
if (::read(this->m_diskHandle, this->m_sectorBuffer.data(), this->m_sectorBuffer.size()) == -1)
|
||||
break;
|
||||
|
||||
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));
|
||||
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
|
||||
#endif
|
||||
}
|
||||
|
||||
void DiskProvider::writeRaw(u64 offset, const void *buffer, size_t size) {
|
||||
#if defined(OS_WINDOWS)
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
DWORD bytesWritten = 0;
|
||||
DWORD bytesWritten = 0;
|
||||
|
||||
u64 startOffset = offset;
|
||||
|
||||
@@ -237,29 +308,29 @@ namespace hex::plugin::builtin {
|
||||
size -= currSize;
|
||||
}
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
u64 startOffset = offset;
|
||||
u64 startOffset = offset;
|
||||
|
||||
std::vector<u8> modifiedSectorBuffer;
|
||||
modifiedSectorBuffer.resize(this->m_sectorSize);
|
||||
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);
|
||||
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);
|
||||
this->readRaw(sectorBase, modifiedSectorBuffer.data(), modifiedSectorBuffer.size());
|
||||
std::memcpy(modifiedSectorBuffer.data() + ((offset - sectorBase) % this->m_sectorSize), reinterpret_cast<const u8 *>(buffer) + (startOffset - offset), currSize);
|
||||
|
||||
::lseek(this->m_diskHandle, sectorBase, SEEK_SET);
|
||||
if (::write(this->m_diskHandle, modifiedSectorBuffer.data(), modifiedSectorBuffer.size()) < 0)
|
||||
break;
|
||||
::lseek(this->m_diskHandle, sectorBase, SEEK_SET);
|
||||
if (::write(this->m_diskHandle, modifiedSectorBuffer.data(), modifiedSectorBuffer.size()) < 0)
|
||||
break;
|
||||
|
||||
offset += currSize;
|
||||
size -= currSize;
|
||||
}
|
||||
offset += currSize;
|
||||
size -= currSize;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t DiskProvider::getActualSize() const {
|
||||
@@ -272,17 +343,17 @@ namespace hex::plugin::builtin {
|
||||
|
||||
std::vector<DiskProvider::Description> DiskProvider::getDataDescription() const {
|
||||
return {
|
||||
{ "hex.builtin.provider.disk.selected_disk"_lang, wolv::util::toUTF8String(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) }
|
||||
{ "hex.builtin.provider.disk.selected_disk"_lang, wolv::util::toUTF8String(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::reloadDrives() {
|
||||
#if defined(OS_WINDOWS)
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
this->m_availableDrives.clear();
|
||||
this->m_availableDrives.clear();
|
||||
std::bitset<32> drives = ::GetLogicalDrives();
|
||||
for (char i = 0; i < 26; i++) {
|
||||
if (drives[i])
|
||||
@@ -315,13 +386,13 @@ namespace hex::plugin::builtin {
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DiskProvider::drawLoadInterface() {
|
||||
#if defined(OS_WINDOWS)
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
if (this->m_availableDrives.empty())
|
||||
if (this->m_availableDrives.empty())
|
||||
this->reloadDrives();
|
||||
|
||||
if (ImGui::BeginListBox("hex.builtin.provider.disk.selected_disk"_lang)) {
|
||||
@@ -340,12 +411,12 @@ namespace hex::plugin::builtin {
|
||||
this->reloadDrives();
|
||||
}
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
if (ImGui::InputText("hex.builtin.provider.disk.selected_disk"_lang, this->m_pathBuffer.data(), this->m_pathBuffer.size(), ImGuiInputTextFlags_CallbackResize, ImGui::UpdateStringSizeCallback, &this->m_pathBuffer))
|
||||
this->m_path = this->m_pathBuffer;
|
||||
if (ImGui::InputText("hex.builtin.provider.disk.selected_disk"_lang, this->m_pathBuffer.data(), this->m_pathBuffer.size(), ImGuiInputTextFlags_CallbackResize, ImGui::UpdateStringSizeCallback, &this->m_pathBuffer))
|
||||
this->m_path = this->m_pathBuffer;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return !this->m_path.empty();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user