#include "IoCtl.hpp" #include "../Utils.hpp" #ifdef _WIN32 #define _NTSCSI_USER_MODE_ 1 #include #include #include #include #include #include #include #include #include #endif #include #include #include namespace Li::Scsi { IoCtl::IoCtl(std::string drive) { this->dvdCssHandle = dvdcss_open(drive.c_str()); this->osFileHandle = dvdcss_get_raw_fd(this->dvdCssHandle); } IoCtl::~IoCtl() { dvdcss_close(this->dvdCssHandle); this->dvdCssHandle = NULL; this->osFileHandle = NULL; } std::vector* IoCtl::GetSupportedReadSpeeds() { std::vector* speeds = new std::vector(); #ifdef _WIN32 CDROM_PERFORMANCE_REQUEST perfRequest; memset(&perfRequest, 0x00, sizeof(CDROM_PERFORMANCE_REQUEST)); perfRequest.RequestType = CdromPerformanceRequest; perfRequest.PerformanceType = CdromReadPerformance; perfRequest.Exceptions = CdromNominalPerformance; perfRequest.Tolerance = Cdrom10Nominal20Exceptions; perfRequest.StaringLba = 0; uint64_t sz = sizeof(CDROM_PERFORMANCE_HEADER) * 0x1000; byte* buffer = new byte[sz]; memset(buffer, 0x00, sz); CDROM_PERFORMANCE_HEADER* perfHeader = (CDROM_PERFORMANCE_HEADER*)buffer; DWORD unused; BOOL success = DeviceIoControl((HANDLE)this->osFileHandle, IOCTL_CDROM_GET_PERFORMANCE, &perfRequest, sizeof(CDROM_PERFORMANCE_REQUEST), perfHeader, sz, &unused, nullptr); if (!success) { Utils::ShowErrorMessage("Error getting supported read speeds: " + std::to_string(GetLastError())); return speeds; } uint64_t dataLen = _byteswap_ulong(*(uint32_t*)perfHeader->DataLength); uint64_t count = dataLen / sizeof(CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR); CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR* pptr = (CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR*)perfHeader->Data; for (uint64_t i = 0; i < count; i++) { CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR perfDesc = pptr[i]; uint32_t startPerf = _byteswap_ulong(*(uint32_t*)perfDesc.StartPerformance); uint32_t endPerf = _byteswap_ulong(*(uint32_t*)perfDesc.EndPerformance); bool startAlreadyInList = false; bool endAlreadyInList = false; for (uint32_t speed : *speeds) { if (speed == startPerf) { startAlreadyInList = true; } if (speed == startPerf) { endAlreadyInList = true; } } if(!startAlreadyInList) speeds->push_back(startPerf); if(!endAlreadyInList) speeds->push_back(endPerf); } delete buffer; #else #error no way to get all supported read speeds on this platform #endif return speeds; } uint32_t IoCtl::GetTotalSectors() { #ifdef _WIN32 DISK_GEOMETRY_EX geometry; memset(&geometry, 0x00, sizeof(DISK_GEOMETRY_EX)); DWORD unused; BOOL success = DeviceIoControl((HANDLE)this->osFileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, nullptr, 0, &geometry, sizeof(DISK_GEOMETRY_EX), &unused, nullptr); if (!success) { Utils::ShowErrorMessage("Error getting geometry: " + std::to_string(GetLastError())); } uint64_t totalSz = geometry.DiskSize.QuadPart; if ((totalSz % DVDCSS_BLOCK_SIZE) != 0) totalSz += (DVDCSS_BLOCK_SIZE - (totalSz % DVDCSS_BLOCK_SIZE)); return (uint32_t)(totalSz / DVDCSS_BLOCK_SIZE); #else #error no way to get total sector count of disc on this platform .. #endif } bool IoCtl::AllowReadingPastDisc() { #ifdef _WIN32 // On windows, you cannot read anything outside the last session of the disc, unless you enable this // this means you cannot read the Lead-Out, *or* double densitity DVDs DWORD unused; BOOL success = DeviceIoControl((HANDLE)this->osFileHandle, FSCTL_ALLOW_EXTENDED_DASD_IO, nullptr, 0, nullptr, 0, &unused, nullptr); if (!success) { Utils::ShowErrorMessage("Error enabling DASD I/O: " + std::to_string(GetLastError())); } return success; #else #error no way to disable bounds checks (DASHD) i/o on this platform (maybe not required?) #endif } Li::Gui::DvdSpin::CdType IoCtl::GetMediaType() { #ifdef _WIN32 DWORD unused; GET_CONFIGURATION_IOCTL_INPUT configInput; memset(&configInput, 0, sizeof(GET_CONFIGURATION_IOCTL_INPUT)); configInput.Feature = FeatureProfileList; configInput.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT; GET_CONFIGURATION_HEADER hdr; memset(&hdr, 0, sizeof(GET_CONFIGURATION_HEADER)); BOOL success = DeviceIoControl((HANDLE)this->osFileHandle, IOCTL_CDROM_GET_CONFIGURATION, &configInput, sizeof(GET_CONFIGURATION_IOCTL_INPUT), &hdr, sizeof(GET_CONFIGURATION_HEADER), &unused, nullptr); if (!success) { Utils::ShowErrorMessage("Error getting configuration: " + std::to_string(GetLastError())); } else { FEATURE_PROFILE_TYPE currentProfile = (FEATURE_PROFILE_TYPE)(_byteswap_ushort(*(uint16_t*)hdr.CurrentProfile)); if (currentProfile == ProfileDvdRom || currentProfile == ProfileDvdRecordable || currentProfile == ProfileDvdRam || currentProfile == ProfileDvdRewritable || currentProfile == ProfileDvdRWSequential || currentProfile == ProfileDvdDashRDualLayer || currentProfile == ProfileDvdDashRLayerJump || currentProfile == ProfileDvdPlusRW || currentProfile == ProfileDvdPlusR || currentProfile == ProfileDvdPlusRWDualLayer || currentProfile == ProfileDvdPlusRDualLayer ) { return Li::Gui::DvdSpin::CdType::DIGITAL_VERSITLE_DISC; } else if ( currentProfile == ProfileCdrom || currentProfile == ProfileCdRecordable || currentProfile == ProfileCdRewritable || currentProfile == ProfileDDCdrom || currentProfile == ProfileDDCdRecordable || currentProfile == ProfileDDCdRewritable) { return Li::Gui::DvdSpin::CdType::COMPACT_DISC; } else if ( currentProfile == ProfileBDRom || currentProfile == ProfileBDRSequentialWritable || currentProfile == ProfileBDRRandomWritable || currentProfile == ProfileBDRewritable) { return Li::Gui::DvdSpin::CdType::BLU_RAY; } else if ( currentProfile == ProfileHDDVDRom || currentProfile == ProfileHDDVDRecordable || currentProfile == ProfileHDDVDRam || currentProfile == ProfileHDDVDRewritable || currentProfile == ProfileHDDVDRDualLayer || currentProfile == ProfileHDDVDRWDualLayer) { return Li::Gui::DvdSpin::CdType::HIGH_DEFINITION_DIGITAL_VERSITLE_DISC; } } return Li::Gui::DvdSpin::CdType::UNKNOWN_DISC; #else #error no way to check media type #endif } /*bool IoCtl::UnmountVolume() { #ifdef _WIN32 DWORD unused; BOOL success = DeviceIoControl((HANDLE)this->osFileHandle, FSCTL_LOCK_VOLUME, nullptr, 0, nullptr, 0, &unused, nullptr); if (!success) { Utils::ShowErrorMessage("Error unmounting drive: " + std::to_string(GetLastError())); } return success; #else #error no way to unmount drive on this platform #endif } bool IoCtl::MountVolume() { #ifdef _WIN32 DWORD unused; BOOL success = DeviceIoControl((HANDLE)this->osFileHandle, FSCTL_UNLOCK_VOLUME, nullptr, 0, nullptr, 0, &unused, nullptr); if (!success) { Utils::ShowErrorMessage("Error mounting drive: " + std::to_string(GetLastError())); } return success; #else #error no way to mount drive on this platform #endif } bool IoCtl::ExclusiveLockDrive() { #ifdef _WIN32 this->UnmountVolume(); DWORD unused; CDROM_EXCLUSIVE_LOCK exclusiveLockRequest; memset(&exclusiveLockRequest, 0x00, sizeof(CDROM_EXCLUSIVE_LOCK)); exclusiveLockRequest.Access.RequestType = ExclusiveAccessLockDevice; exclusiveLockRequest.Access.Flags = CDROM_LOCK_IGNORE_VOLUME; int err = GetLastError(); strncpy((char*)(exclusiveLockRequest.CallerName), "LiDeeVeeDeeDumperProgramThing", CDROM_EXCLUSIVE_CALLER_LENGTH - 1); BOOL success = DeviceIoControl((HANDLE)this->osFileHandle, IOCTL_CDROM_EXCLUSIVE_ACCESS, &exclusiveLockRequest, sizeof(CDROM_EXCLUSIVE_LOCK), nullptr, 0, &unused, nullptr); if (!success) { //Utils::ShowErrorMessage("Error Locking the drive: " + std::to_string(GetLastError())); } return success; #else #error no way to exclusive lock drive on this platform. #endif } bool IoCtl::ExclusiveUnlockDrive() { #ifdef _WIN32 DWORD unused; CDROM_EXCLUSIVE_ACCESS exclusiveUnlockRequest; memset(&exclusiveUnlockRequest, 0x00, sizeof(CDROM_EXCLUSIVE_ACCESS)); exclusiveUnlockRequest.RequestType = ExclusiveAccessUnlockDevice; int err = GetLastError(); BOOL success = DeviceIoControl((HANDLE)this->osFileHandle, IOCTL_CDROM_EXCLUSIVE_ACCESS, &exclusiveUnlockRequest, sizeof(CDROM_EXCLUSIVE_LOCK), nullptr, 0, &unused, nullptr); if (!success) { //Utils::ShowErrorMessage("Error Unlocking the drive: " + std::to_string(GetLastError())); } this->MountVolume(); return success; #else #error no way to exclusive unlock drive on this platform. #endif }*/ bool IoCtl::SetDriveSpeed(int readSpeed, int writeSpeed) { #ifdef _WIN32 DWORD unused; CDROM_SET_SPEED cdromSetSpeed; memset(&cdromSetSpeed, 0x00, sizeof(CDROM_SET_SPEED)); cdromSetSpeed.RequestType = CdromSetSpeed; cdromSetSpeed.ReadSpeed = (uint16_t)readSpeed; cdromSetSpeed.WriteSpeed = (uint16_t)writeSpeed; cdromSetSpeed.RotationControl = CdromDefaultRotation; BOOL success = DeviceIoControl((HANDLE)this->osFileHandle, IOCTL_CDROM_SET_SPEED, &cdromSetSpeed, sizeof(CDROM_SET_SPEED), nullptr, 0, &unused, nullptr); if (!success) { Utils::ShowErrorMessage("Error setting speed: " + std::to_string(GetLastError())); } return success; #else #error no way to set drive speed folder on this platform. #endif } dvdcss_t IoCtl::GetDvdCssHandle() { return this->dvdCssHandle; } }