diff --git a/plugins/builtin/source/content/providers/disk_provider.cpp b/plugins/builtin/source/content/providers/disk_provider.cpp index 40a2bd9a3..3168f51cb 100644 --- a/plugins/builtin/source/content/providers/disk_provider.cpp +++ b/plugins/builtin/source/content/providers/disk_provider.cpp @@ -16,16 +16,25 @@ #include #if defined(OS_WINDOWS) - #include -#elif defined(OS_LINUX) || defined(OS_MACOS) - #include - #include - #include - #include +#include +#elif defined(OS_LINUX) +#include +#include +#include +#include +#include +#include +#elif defined(OS_MACOS) +#include +#include +#include +#include +#include +#include #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(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(&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(buffer) + (offset - startOffset), this->m_sectorBuffer.data() + (offset & (this->m_sectorSize - 1)), std::min(this->m_sectorSize, size)); + std::memcpy(reinterpret_cast(buffer) + (offset - startOffset), + this->m_sectorBuffer.data() + (offset & (this->m_sectorSize - 1)), + std::min(this->m_sectorSize, size)); size = std::max(static_cast(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 modifiedSectorBuffer; - modifiedSectorBuffer.resize(this->m_sectorSize); + std::vector 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(buffer) + (startOffset - offset), currSize); + this->readRaw(sectorBase, modifiedSectorBuffer.data(), modifiedSectorBuffer.size()); + std::memcpy(modifiedSectorBuffer.data() + ((offset - sectorBase) % this->m_sectorSize), reinterpret_cast(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::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(); }