// testDeviceIOWin32.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include #include #include #include #include #include /* CD Every byte == 14bit (EFM) ?? Small Frame == 588bit == 24 byte <== this is the unit of read. Can't read smaller portions. +-----------+------------+--------------+-----------+--------------+-----------+ | Sync code | Subchannel | Main Channel | CIRC code | Main Channel | CIRC code | | | byte | data | | data | | bit | 24+3 | 14+3 | 12x(14+3) | 4x(14+3) | 12x(14+3) | 4x(14+3) | +-----------+------------+--------------+-----------+--------------+-----------+ Frame == 98 Small Frames == 2352 bytes <== this is reachable form soft. +98 byte of subchannel ( 2 sync bytes + 96 bytes of data ) The first 2 small frames containe sync bytes and then the rest of small frames containe data bytes. Session == Lead-in + Program Area + Lead-out Lead-in == TOC in Q-Subchannel Program Area == Logical Tracks (at least containes one logical track) Address format is MSF (Minute/Second/Frame) M=60*S S=75*F 1 Audio Sec = 4(Stereo 16bit)*44100(Hz)=176400 byte = 75 * 2352 byte = 75 Frame 0<= F <= 74 0<= S <= 59 0<= M <= 99 */ enum { ADDR_SEC2FRAME = 75, ADDR_MIN2SEC = 60, CTRL_COPYPROT_MASK = 0x02, // 0010 CTRL_TYPE_MASK = 0x0C, // 1100 CTRL_AUDIO2CH_TRACK = 0x00, // CTRL_DATA_TRACK = 0x04, // CTRL_AUDIO4CH_TRACK = 0x06, // CTRL_RESERVED_TRACK = 0x0C, // CTRL_DATA_INCREMENTAL = 0x01, // CTRL_AUDIO_50_15 = 0x01, // FRAME_DATA = 2352, }; #define MAXIMUM_NUMBER_TRACKS 100 #define NSECTORS 13 #define UNDERSAMPLING 1 #define CB_CDDASECTOR 2368 #define CB_QSUBCHANNEL 16 #define CB_CDROMSECTOR 2048 #define CB_AUDIO (CB_CDDASECTOR-CB_QSUBCHANNEL) /* The code of interest is in the subroutine GetDriveGeometry. The code in main shows how to interpret the results of the call. */ class device { protected: // Handle to the drive to be examined. HANDLE hDevice; DISK_GEOMETRY dg; CDROM_TOC toc; bool m_bLocked; public: device() { hDevice = INVALID_HANDLE_VALUE; m_bLocked = false; } ~device() { if ( hDevice != INVALID_HANDLE_VALUE ) { if ( m_bLocked ) storageMediaUnlock(); close(); } } bool create( const TCHAR* pszDevice ) { hDevice = ::CreateFile(pszDevice, // drive to open GENERIC_READ | GENERIC_WRITE , // no access to the drive FILE_SHARE_READ | // share mode FILE_SHARE_WRITE, NULL, // default security attributes OPEN_EXISTING, // disposition 0, // file attributes NULL); // do not copy file attributes if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive { printErr("CreateFile"); return false; } return true; } bool close() { if ( hDevice != INVALID_HANDLE_VALUE ) { ::CloseHandle(hDevice); hDevice = INVALID_HANDLE_VALUE; } return true; } static void printErr( char* szMsg = "" ) { printf ("%s Error %ld. ", szMsg, GetLastError ()); char szMsgBfr[ 1024 ]; ::FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError (), 0, // Default language szMsgBfr, sizeof( szMsgBfr ), NULL ); szMsgBfr[sizeof( szMsgBfr )-1] = 0; puts ( szMsgBfr ); } bool diskGetDriveGeometry() { DWORD junk; // discard results printf("IOCTL_DISK_GET_DRIVE_GEOMETRY\n"); if ( !DeviceIoControl( hDevice, // device to be queried IOCTL_DISK_GET_DRIVE_GEOMETRY, // operation to perform NULL, 0, // no input buffer &dg, sizeof(dg), // output buffer &junk, // # bytes returned (LPOVERLAPPED) NULL) ) // synchronous I/O { printErr(""); return false; } else { printf("MediaType = %d\n", dg.MediaType); printf("Cylinders = %I64d\n", dg.Cylinders); printf("Tracks/cylinder = %ld\n", (ULONG) dg.TracksPerCylinder); printf("Sectors/track = %ld\n", (ULONG) dg.SectorsPerTrack); printf("Bytes/sector = %ld\n", (ULONG) dg.BytesPerSector); ULONGLONG DiskSize = dg.Cylinders.QuadPart * (ULONG)dg.TracksPerCylinder * (ULONG)dg.SectorsPerTrack * (ULONG)dg.BytesPerSector; printf("Disk size = %I64d (Bytes) = %I64d (Gb)\n", DiskSize, DiskSize / (1024 * 1024 * 1024)); } puts(""); return true; } bool diskGetCacheInformation() { DWORD junk; // discard results DISK_CACHE_INFORMATION dci; printf("IOCTL_DISK_GET_CACHE_INFORMATION\n"); if ( !DeviceIoControl( hDevice, // device to be queried IOCTL_DISK_GET_CACHE_INFORMATION, // operation to perform NULL, 0, // no input buffer &dci, sizeof(dci), // output buffer &junk, // # bytes returned (LPOVERLAPPED) NULL) ) // synchronous I/O { printErr(""); return false; } else { printf("ParametersSavable = %d\n", dci.ParametersSavable); printf("ReadCacheEnabled = %d\n", dci.ReadCacheEnabled); printf("WriteCacheEnabled = %d\n", dci.WriteCacheEnabled); printf("ReadRetentionPriority = %d\n", dci.ReadRetentionPriority); printf("WriteRetentionPriority = %d\n", dci.WriteRetentionPriority); printf("DisablePrefetchTransferLength = %d\n", dci.DisablePrefetchTransferLength); if ( dci.PrefetchScalar ) { printf("ScalarPrefetch.Minimum = %d\n", dci.ScalarPrefetch.Minimum); printf("ScalarPrefetch.Maximum = %d\n", dci.ScalarPrefetch.Maximum); printf("ScalarPrefetch.MaximumBlocks = %d\n", dci.ScalarPrefetch.MaximumBlocks); } else { printf("BlockPrefetch.Minimum = %d\n", dci.BlockPrefetch.Minimum); printf("BlockPrefetch.Maximum = %d\n", dci.BlockPrefetch.Maximum); } } puts(""); return true; } bool diskPerformance() { DWORD junk; // discard results DISK_PERFORMANCE dp; printf("IOCTL_DISK_PERFORMANCE\n"); if ( !DeviceIoControl( hDevice, // device to be queried IOCTL_DISK_PERFORMANCE, // operation to perform NULL, 0, // no input buffer &dp, sizeof(dp), // output buffer &junk, // # bytes returned (LPOVERLAPPED) NULL) ) // synchronous I/O { printErr(""); return false; } else { printf("BytesRead = %I64d\n", dp.BytesRead); printf("BytesWritten = %I64d\n", dp.BytesWritten); printf("ReadTime = %I64d\n", dp.ReadTime); printf("WriteTime = %I64d\n", dp.WriteTime); printf("IdleTime = %I64d\n", dp.IdleTime); printf("ReadCount = %d\n", dp.ReadCount); printf("WriteCount = %d\n", dp.WriteCount); printf("QueueDepth = %d\n", dp.QueueDepth); printf("SplitCount = %d\n", dp.SplitCount); printf("QueryTime = %I64d\n", dp.QueryTime); printf("StorageDeviceNumber = %d\n", dp.StorageDeviceNumber); printf("StorageManagerName = %c%c%c%c%c%c%c%c\n", dp.StorageManagerName[0], dp.StorageManagerName[1], dp.StorageManagerName[2], dp.StorageManagerName[3], dp.StorageManagerName[4], dp.StorageManagerName[5], dp.StorageManagerName[6], dp.StorageManagerName[7]); } puts(""); ////////////////////////////////////////////////////////////////////////////// printf("IOCTL_DISK_PERFORMANCE_OFF\n"); if ( !DeviceIoControl( hDevice, // device to be queried IOCTL_DISK_PERFORMANCE_OFF, // operation to perform NULL, 0, // no input buffer 0, 0, // output buffer &junk, // # bytes returned (LPOVERLAPPED) NULL) ) // synchronous I/O { printErr(""); return false; } puts(""); return true; } bool diskVerify() { DWORD junk; // discard results VERIFY_INFORMATION vi; printf("IOCTL_DISK_VERIFY\n"); vi.StartingOffset.QuadPart = 0; vi.Length = 2048; if ( !DeviceIoControl( hDevice, // device to be queried IOCTL_DISK_VERIFY, // operation to perform &vi, sizeof(vi), // no input buffer 0, 0, // output buffer &junk, // # bytes returned (LPOVERLAPPED) NULL) ) // synchronous I/O { printErr(""); return false; } puts(""); return true; } bool storageMediaLock() { DWORD junk; // discard results PREVENT_MEDIA_REMOVAL pmr; pmr.PreventMediaRemoval = 1; printf("IOCTL_STORAGE_MEDIA_REMOVAL lock\n"); if ( !::DeviceIoControl( hDevice, IOCTL_STORAGE_MEDIA_REMOVAL, &pmr, sizeof( pmr ), 0, 0, &junk, (LPOVERLAPPED)0 ) ) { printErr(""); return false; } m_bLocked = true; return true; } bool storageMediaUnlock() { DWORD junk; // discard results PREVENT_MEDIA_REMOVAL pmr; pmr.PreventMediaRemoval = 0; printf("IOCTL_STORAGE_MEDIA_REMOVAL unlock\n"); if ( !::DeviceIoControl( hDevice, IOCTL_STORAGE_MEDIA_REMOVAL, &pmr, sizeof( pmr ), 0, 0, &junk, (LPOVERLAPPED)0 ) ) { printErr(""); return false; } m_bLocked = false; return true; } bool storageLoadMedia() { DWORD junk; // discard results printf("IOCTL_STORAGE_LOAD_MEDIA\n"); if ( !::DeviceIoControl( hDevice, IOCTL_STORAGE_LOAD_MEDIA, 0, 0, 0, 0, &junk, (LPOVERLAPPED)0 ) ) { printErr(""); return false; } else { // printf(""); } return true; } bool storageCheckVerify() { DWORD junk; // discard results printf("IOCTL_STORAGE_CHECK_VERIFY\n"); if ( !::DeviceIoControl( hDevice, IOCTL_STORAGE_CHECK_VERIFY, 0, 0, 0, 0, &junk, (LPOVERLAPPED)0 ) ) { printErr(""); return false; } else { // printf(""); } return true; } bool storageEjectMedia() { DWORD junk; // discard results printf("IOCTL_STORAGE_EJECT_MEDIA\n"); if ( !::DeviceIoControl( hDevice, IOCTL_STORAGE_EJECT_MEDIA, 0, 0, 0, 0, &junk, (LPOVERLAPPED)0 ) ) { printErr(""); return false; } else { // printf(""); } return true; } bool storageReadCapacity() { // 2003 #if 0 DWORD junk; // discard results STORAGE_READ_CAPACITY src; printf("IOCTL_STORAGE_READ_CAPACITY\n"); if ( !DeviceIoControl( hDevice, // device to be queried IOCTL_STORAGE_READ_CAPACITY, // operation to perform NULL, 0, // no input buffer &src, sizeof(src), // output buffer &junk, // # bytes returned (LPOVERLAPPED) NULL) ) // synchronous I/O { printErr(""); return false; } else { printf("Version = %d\n", src.Version); printf("Size = %d\n", src.Size); printf("BlockLength = %d\n", src.BlockLength); printf("NumberOfBlocks = %I64d\n", dg.NumberOfBlocks); printf("DiskLength = %I64d\n", dg.DiskLength); } puts(""); #endif return true; } bool cdromDiskInfo() { #if 0 DWORD junk; // discard results printf("IOCTL_CDROM_DISC_INFO\n"); CDROM_DISCINFO cdi; if ( !DeviceIoControl( hDevice, // device to be queried IOCTL_CDROM_DISC_INFO, // operation to perform 0, 0, // no input buffer &cdi, sizeof( cdi ), // output buffer &junk, // # bytes returned (LPOVERLAPPED) NULL) ) // synchronous I/O { printErr(""); } else { printf("Reserved = %I64d\n", cdi.Reserved ); printf("FirstTrack = %I64d\n", cdi.FirstTrack ); printf("LastTrack = %I64d\n", cdi.LastTrack ); printf("LastTrack = %I64d\n", cdi.LeadOutTrackAddr ); printf("FirstSession = %I64d\n", cdi.FirstSession ); printf("LastSession = %I64d\n", cdi.LastSession ); printf("ReqSession = %I64d\n", cdi.ReqSession ); printf("RetSession = %I64d\n", cdi.RetSession ); printf("LogicStartAddr = %I64d\n", cdi.LogicStartAddr ); } puts(""); #endif } bool cdromReadTOC() { DWORD junk; // discard results printf("IOCTL_CDROM_READ_TOC\n"); if ( !::DeviceIoControl( hDevice, IOCTL_CDROM_READ_TOC, 0, 0, &toc, sizeof(toc), &junk, (LPOVERLAPPED)0 ) ) { printErr(""); return false; } else { std::cout << "Length = " << (USHORT&)toc.Length << std::endl; std::cout << "FirstTrack = " << int(toc.FirstTrack) << std::endl; std::cout << "LastTrack = " << int(toc.LastTrack) << std::endl; for ( int i = 0; i < (toc.LastTrack - toc.FirstTrack +1); ++i ) { std::cout << "track " << i << " {" << std::endl; if ( toc.TrackData[i].Control & CTRL_COPYPROT_MASK ) std::cout << " No copy protection" << std::endl; else std::cout << " Copy protected" << std::endl; int n = toc.TrackData[i].Control & CTRL_TYPE_MASK; if ( n == CTRL_AUDIO2CH_TRACK ) std::cout << " 2 channel audio track" << std::endl; else if ( n == CTRL_AUDIO4CH_TRACK ) std::cout << " 4 channel audio track" << std::endl; else if ( n == CTRL_DATA_TRACK ) std::cout << " Data track" << std::endl; else std::cout << " Unknown type of track" << std::endl; if ( n == CTRL_DATA_TRACK ) { if ( toc.TrackData[i].Control & CTRL_DATA_INCREMENTAL ) std::cout << " Incremental record" << std::endl; else std::cout << " Continuous record" << std::endl; } else { if ( toc.TrackData[i].Control & CTRL_AUDIO_50_15 ) std::cout << " Predistortion 50/15 mks" << std::endl; else std::cout << " No predistortion" << std::endl; } std::cout << " Adr = " << int(toc.TrackData[i].Adr) << std::endl; std::cout << " TrackNumber = " << int(toc.TrackData[i].TrackNumber) << std::endl; std::cout << " Address[0] = " << int(toc.TrackData[i].Address[0]) << std::endl; std::cout << " Minute = " << int(toc.TrackData[i].Address[1]) << std::endl; std::cout << " Second = " << int(toc.TrackData[i].Address[2]) << std::endl; std::cout << " Frame = " << int(toc.TrackData[i].Address[3]) << std::endl; std::cout << " Start Sector = " << toc.TrackData[i].Address[1] * ADDR_MIN2SEC * ADDR_SEC2FRAME + toc.TrackData[i].Address[2] * ADDR_SEC2FRAME + toc.TrackData[i].Address[3] << std::endl; std::cout << "}" << std::endl; } } return true; } virtual int cdromRawRead( int sector, int num, char* buf, int buf_size ); }; int device::cdromRawRead( int sector, int num, char* buf, int buf_size ) { DWORD nBytsRead = 0; RAW_READ_INFO rri; // rri.TrackMode = CDDA; rri.TrackMode = YellowMode2; rri.SectorCount = num; rri.DiskOffset.QuadPart = sector*CB_CDROMSECTOR; memset ( buf, 0, buf_size ); #if 1 // std::cout << "IOCTL_CDROM_RAW_READ" << std::endl; if ( !::DeviceIoControl( hDevice, IOCTL_CDROM_RAW_READ, &rri, sizeof(rri), buf, buf_size, &nBytsRead, (LPOVERLAPPED)0 ) ) { int i = 0; char tmp[32]; for ( ; i < buf_size && !buf[i]; ++i ); if ( i < buf_size ) _snprintf( tmp, sizeof( tmp), "Sector %d buf!=0", sector ); else _snprintf( tmp, sizeof( tmp), "Sector %d", sector ); printErr( tmp ); return false; } else #endif { #if 0 std::cout << " Read " << nBytsRead << " bytes" << std::endl; const int cCol = 16; for ( int i = 0; i < int(nBytsRead) ; ) { int k = i; for ( int j = 0; j < cCol && k < int(nBytsRead); ++k, ++j ) { std::cout << std::hex << (((unsigned)( buf[k] ) >> 4) & 0xF ) << ((unsigned)( buf[k] ) & 0x0F ) << " "; } for ( int j = 0; j < cCol && i < int(nBytsRead); ++i, ++j ) { if ( 32 < buf[i] && buf[i] < 255 ) std::cout << buf[i]; else std::cout << ' '; } std::cout << std::endl; } #endif } // CB_CDROMSECTOR #if 0 if (m_bTocValid && ((sector + NumSectors) <= GetEndSector(m_TOC.LastTrack))) { RAW_READ_INFO rri; rri.TrackMode = CDDA; rri.SectorCount = (DWORD)NumSectors; rri.DiskOffset.QuadPart = sector*CB_CDROMSECTOR; DWORD charsRead = 0; if (::DeviceIoControl(m_hDrive, IOCTL_CDROM_RAW_READ, &rri, sizeof(rri), Buffer, (DWORD)NumSectors * CB_AUDIO, &charsRead, NULL) != 0) return true; else return false; } else return false; #endif return nBytsRead; } int _tmain(int argc, _TCHAR* argv[]) { //TCHAR szDevice[] = L"\\\\.\\PhysicalDrive0"; //TCHAR szDevice[] = L"\\\\.\\PhysicalDrive2"; TCHAR szDevice[] = L"\\\\.\\E:"; FILE* f = fopen( "dump.txt", "wb" ); device d; if ( !d.create( szDevice ) ) { std::cerr << "Cannot open device." << std::endl; return 1; } if ( !d.storageCheckVerify() ) { std::cerr << "Media is not accessable." << std::endl; return 2; } if ( !d.storageMediaLock() ) { std::cerr << "Cannot lock the media." << std::endl; return 3; } // d.diskGetDriveGeometry(); // d.storageReadCapacity(); // d.diskGetCacheInformation(); // d.diskPerformance(); // d.cdromDiskInfo(); d.cdromReadTOC(); const int nStart = 000; const int nAmount = nStart + 350000; int i = nStart; char buf[ 2*FRAME_DATA ]; for ( ; i < nAmount; ++i ) { int n = d.cdromRawRead( i, 1, buf, sizeof( buf ) ); // fwrite( buf, 1, n, f ); } d.storageMediaUnlock(); d.storageMediaUnlock(); d.storageMediaUnlock(); d.storageMediaUnlock(); d.storageMediaUnlock(); d.storageMediaUnlock(); // d.storageEjectMedia(); d.close(); fclose( f ); return 0; }