00 Window I/O 관련
원문 : http://kkamagui.springnote.com/pages/340860
들어가기 전에...
- 이 글은 kkamagui에 의해 작성된 글입니다.
- 마음껏 인용하시거나 사용하셔도 됩니다. 단 출처(http://kkamagui.tistory.com, http://kkamagui.springnote.com)는 밝혀 주십시오.
- 기타 사항은 mint64os at gmail.com 이나 http://kkamagui.tistory.com으로 보내주시면 반영하겠습니다.
- OS 제작에 대한 상세한 내용은 책 "64비트 멀티코어 OS 구조와 원리"를 참고하기 바랍니다.
1.윈도우에서 Physical Drive 직접 읽고 쓰기
- 드라이브 열기
- HANDLE OpenDrive( int iPhysicalDriveNumber )
{
HANDLE hDevice;
char vcDriveName[ 30 ]; -
-
-
// HDD를 실수로 지우는걸 방지하기 위함
if( iPhysicalDriveNumber == 0 )
{
return INVALID_HANDLE_VALUE;
} -
// Physical Drive를 연다.
sprintf( vcDriveName, "\\\\.\\PhysicalDrive%d", iPhysicalDriveNumber );
hDevice = CreateFile( vcDriveName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
return hDevice;
}
- 드라이브 읽기
- BOOL ReadSector( HANDLE hDevice, DWORD dwSectorOffset, BYTE* pbBuffer,
int iSectorCount )
{
DWORD dwLow;
DWORD dwHigh;
DWORD dwRet;
DWORD dwRead;
DWORD dwErrorCode; - // 움직일 위치는 byte 단위로 되어야 한다.
// 결국 dwSectorOffset에 512를 곱해줘야 한다.
dwLow = ( dwSectorOffset << 9 );
dwHigh = ( dwSectorOffset >> 23 ); - // File Pointer를 이동한다.
dwRet = SetFilePointer( hDevice, dwLow, &dwHigh, FILE_BEGIN );
if( dwRet == INVALID_SET_FILE_POINTER )
{
return FALSE;
} - // Sector를 읽는다.
if( ReadFile( hDevice, pbBuffer, iSectorCount * SECTORSIZE, &dwRead,
NULL ) == FALSE )
{
dwErrorCode = GetLastError();
return FALSE;
} - return TRUE;
}
- 드라이브 쓰기
- BOOL WriteSector( HANDLE hDevice, DWORD dwSectorOffset, BYTE* pbBuffer,
int iSectorCount )
{
DWORD dwLow;
DWORD dwHigh;
DWORD dwRet;
DWORD dwWrite;
DWORD dwErrorCode; - // 움직일 위치는 byte 단위로 되어야 한다.
// 결국 dwSectorOffset에 512를 곱해줘야 한다.
dwLow = ( dwSectorOffset << 9 );
dwHigh = ( dwSectorOffset >> 23 ); - // File Pointer를 이동한다.
dwRet = SetFilePointer( hDevice, dwLow, &dwHigh, FILE_BEGIN );
if( dwRet == INVALID_SET_FILE_POINTER )
{
return FALSE;
} - // Sector를 쓴다.
if( WriteFile( hDevice, pbBuffer, iSectorCount * SECTORSIZE, &dwWrite,
NULL ) == FALSE )
{
dwErrorCode = GetLastError();
return FALSE;
} - gs_dwTotalWriteSectorCount += iSectorCount;
return TRUE;
}
- 드라이브 닫기
- void CloseDrive( HANDLE hDevice )
{
CloseHandle( hDevice );
}
2.Drive의 Geometry 읽기
Geometry정보에는 CHS 값이 들어있기 때문에 유용하게 쓸 수 있다.
- BOOL GetDriveGeometry( int iPhysicalDriveNumber, GEOMETRY* pstGeometry )
{
HANDLE hDevice;
BOOL bRet;
DWORD dwOutBytes;
char vcDriveName[ 30 ];
DISK_GEOMETRY stWindowGeometry; - // Physical Drive Number를 저장한다.
sprintf( vcDriveName, "\\\\.\\PhysicalDrive%d", iPhysicalDriveNumber ); - hDevice = CreateFile( vcDriveName, 0, FILE_SHARE_READ |
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); - if( hDevice == INVALID_HANDLE_VALUE )
{
return FALSE;
} - bRet = DeviceIoControl( hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL, 0, &stWindowGeometry, sizeof( DISK_GEOMETRY ), &dwOutBytes,
NULL ); - CloseHandle( hDevice );
- // 지금은 윈도우 Geometry와 같은 Geometry를 사용한다.
memcpy( pstGeometry, &stWindowGeometry, sizeof( DISK_GEOMETRY ) ); - return bRet;
}
3.Drive Descriptor 얻기
Descriptor에 보면 해당 드라이브의 제품명과 리비전 번호 같은 걸 알 수 있다.
- BOOL GetDeviceDescriptor( char* pcDevice, PSTORAGE_DEVICE_DESCRIPTOR pstDesc )
{
HANDLE hDevice;
STORAGE_PROPERTY_QUERY stQuery;
DWORD dwOut;
BOOL bRet; - memset( pstDesc, 0, sizeof(STORAGE_DEVICE_DESCRIPTOR) );
- // Device를 Open한다.
hDevice = CreateFile( pcDevice, GENERIC_READ, FILE_SHARE_READ |
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
if( hDevice == INVALID_HANDLE_VALUE )
{
return FALSE;
} - pstDesc->Size = sizeof( STORAGE_DEVICE_DESCRIPTOR );
- // Device Io Control을 호출한다.
stQuery.PropertyId = StorageDeviceProperty;
stQuery.QueryType = PropertyStandardQuery; - bRet = DeviceIoControl( hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
&stQuery, sizeof( STORAGE_PROPERTY_QUERY ),
pstDesc, pstDesc->Size, &dwOut, NULL);
if( bRet == FALSE )
{
return FALSE;
} - CloseHandle( hDevice );
return TRUE;
}
4.Drive 문자로 Physical Index 얻기
드라이브 문자로 Physical Index를 얻는 방법은 VOLUME 정보를 이용하면 된다.
- int GetPhysicalDriveNumber( char cDriveName )
{
HANDLE hDevice;
DWORD dwOut;
BOOL bRet;
char vcDriveName[ 40 ];
VOLUME_DISK_EXTENTS* pstVolumeData;
int iDiskNumber; - // 메모리를 할당한다.
pstVolumeData = ( VOLUME_DISK_EXTENTS* ) malloc( VOLUMEDISKSIZE );
if( pstVolumeData == NULL )
{
return -1;
} - // 해당 Drive의 정보를 얻는다.
sprintf( vcDriveName, "\\\\?\\%c:", cDriveName );
// Device를 Open한다.
hDevice = CreateFile( vcDriveName, GENERIC_READ, FILE_SHARE_READ |
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
if( hDevice == INVALID_HANDLE_VALUE )
{
return -1;
} - // Device Io Control을 호출한다.
bRet = DeviceIoControl( hDevice, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
NULL, 0, pstVolumeData, VOLUMEDISKSIZE, &dwOut, NULL );
if( bRet == FALSE )
{
free( pstVolumeData );
return -1;
}
CloseHandle( hDevice ); - // Disk 정보가 1보다 작으면 실패
if( pstVolumeData->NumberOfDiskExtents < 1 )
{
free( pstVolumeData );
return -1;
} - iDiskNumber = pstVolumeData->Extents[ 0 ].DiskNumber;
free( pstVolumeData ); - return iDiskNumber;
}
5.Logical Drive와 Physical Drive 간의 매치방법
1. 일단 Logical Drive를 검색한다.
-> GetDriveType() 함수를 이용
2. 해당 Drvie를 열어서 Volume 정보를 얻음
-> "\\?\c" 와 같은 형태로 CreateFile() 호출
-> IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS를 날려서 Physical Drive 정보를 얻음
-> 리더기에 데이터가 연결되어있지 않으면 DeviceIoControl에서 문제 발생
이 글은 스프링노트에서 작성되었습니다.
'Windows System Application' 카테고리의 다른 글
00 윈도우 DLL 분석 (1) | 2007.11.14 |
---|---|
01 FAT 파일 시스템(File System) (4) | 2007.11.14 |
[USB] 컥.. 이런... HID로 만들면 Report를 통해서 데이터를 주고 받을 수 있구나.. @0@ (0) | 2007.05.25 |
[USB] 오오~ 세상 참 좋구나~ >ㅁ<)/~ (0) | 2007.04.25 |
[USB] Vendor Command를 보내는 관련 링크 (0) | 2007.04.24 |