Узнать размер диска..

Тема в разделе "WASM.WIN32", создана пользователем test555, 5 апр 2009.

  1. test555

    test555 New Member

    Публикаций:
    0
    Регистрация:
    7 дек 2007
    Сообщения:
    241
    Помогите пожалуйста узнать размер физического носителя.

    Код (Text):
    1. function GetdiskSize(h:THANDLE):int64;
    2.   const
    3.     IOCTL_DISK_GET_DRIVE_GEOMETRY = $70000;
    4.  
    5.   type
    6.     TDiskGeometry = packed record
    7.       Cylinders: Int64;          
    8.       MediaType: DWORD;        
    9.       TracksPerCylinder: DWORD;  
    10.       SectorsPerTrack: DWORD;    
    11.       BytesPerSector: DWORD;      
    12.     end;
    13. var DiskGeometry:TDiskGeometry;  junk:dword;
    14.  
    15. begin
    16. result:=(-1);
    17. if  DeviceIoControl(h,IOCTL_DISK_GET_DRIVE_GEOMETRY,nil,0,
    18.     @DiskGeometry,SizeOf(TDiskGeometry),junk,nil) and (junk = SizeOf(TDiskGeometry)) then
    19.     begin
    20.   with  DiskGeometry do
    21.     Result:=Cylinders * TracksPerCylinder * SectorsPerTrack * BytesPerSector;
    22.  
    23.     writeln('Cylinders ', DiskGeometry.Cylinders);
    24.     writeln('TracksPerCylinder ', DiskGeometry.TracksPerCylinder);
    25.     writeln('SectorsPerTrack ', DiskGeometry.SectorsPerTrack);
    26.     writeln('BytesPerSector ',DiskGeometry.BytesPerSector);
    27.       end;
    28. end;
    Код (Text):
    1.  hDisk:=CreateFile(PChar('\\.\PhysicalDrive0') ),
    2.                             GENERIC_WRITE or GENERIC_READ,
    3.                             FILE_SHARE_READ or FILE_SHARE_WRITE,
    4.                             nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
    Открываю устройство как диск, потом вызываю указанную выше функцию. Возвращяет он мне близкое к настоящему, но не точное значение.

    Cylinders 77825
    TracksPerCylinder 255
    SectorsPerTrack 63
    BytesPerSector 512
    640132416000


    Это близко, т.к. винт на 640 Гб.

    Я открываю winHex этот диск, показывается следующая информаци:
    Емкость: 640 133 946 880
    Number of cylinders 12289
    Number of heads 255
    Number of track 63
    Bytes per sectors 512


    Того у меня разница получается на 1 530 880 байт.
    Винхексу я больше верю, т.к. он и показывает эту физическую область, и ее можно отредактировать, переоткрыть и данные будут.

    Я так и не понял, как винхекс считает размер диска.

    Обычные АПИ функции типа GetFileSize(Ex) не помогают..

    Что делать? Нужно корректно определить размер физического носителя.

    Игра с АПи SetFilePointer не помогла. Хотел сдвинуть ее на последнюю позицию и прочесть позицию.. Не получается.. (работает если сдвигать сначала на значение, меньшее емкости.. Тогда все корректно). Если же сдвинуть сначала на размер более емкости винта, то он так и показывает эту позицию большую...Пробовал сдвигать на -4096 от конца, ничего.. Если от начала сдвинуть вперед, то корректно показывает позицию. Гетластеррор показывает 1 (если с конца двигать). ХЗ что делать.

    Промониторил как работает винхекс (написал драйвер-перехватчик . После открытия устройства от шлет им DeviceIoControl:
    SCSI_PASS_THROUGH_DIRECT
    SCSI_PASS_THROUGH

    структуры.. Так вот, почитал описание.. (думал что там будет типа поля "размер диска".. Ну так вот, ничего подобного не нашел)... Могу посмотреть полностью структуру ДО и ПОСЛЕ вызова функции, но это мне пока мало чем помогло..


    Всем спасибо.

    Нужно конкретно физического устройства..
     
  2. ams007

    ams007 New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2007
    Сообщения:
    86
    IOCTL_SCSI_PASS_THROUGH_DIRECT
    и IOCTL_SCSI_PASS_THROUGH содержат в себе SCSI-команды, тебя интересует
    SCSIOP_READ_CAPACITY. Заполняй правильно один из этих ирпов с этой командой.

    Получишь размер физического диска в секторах и размер сектора в эндиан - формате.
    Был примерчик для заполнения SCSIOP_INQUIRY на работе. Там самая шляпа с ModeSense.
    Удачи!
    ЗЫ: да, и не все виртуальные устройства тебе на эту команду честно ответят!
     
  3. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    GetDiskFreeSpace(...,...,...,...,TotalNumberOfClusters);
    TotalNumberOfClusters
    Points to variable for the total number of clusters on the disk.
     
  4. test555

    test555 New Member

    Публикаций:
    0
    Регистрация:
    7 дек 2007
    Сообщения:
    241
    max7C4, Нужно конкретно физического устройства.. А не раздела.
    Перед тем как запостить - испробовал функцию. Не пашет с '\\.\PhysicalDrive0'....
     
  5. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    test555
    Сорри. Задумался пока Ваш пост до конца дочитал.
     
  6. test555

    test555 New Member

    Публикаций:
    0
    Регистрация:
    7 дек 2007
    Сообщения:
    241
    ams007, пока что-то не могу разобраться где содержиться SCSI команда.
    Судя по ДДК
    Код (Text):
    1. typedef struct _SCSI_PASS_THROUGH_DIRECT {
    2.     USHORT Length;
    3.     UCHAR ScsiStatus;
    4.     UCHAR PathId;
    5.     UCHAR TargetId;
    6.     UCHAR Lun;
    7.     UCHAR CdbLength;
    8.     UCHAR SenseInfoLength;
    9.     UCHAR DataIn;
    10.     ULONG DataTransferLength;
    11.     ULONG TimeOutValue;
    12.     PVOID DataBuffer;
    13.     ULONG SenseInfoOffset;
    14.     UCHAR Cdb[16];
    15. }SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
    Есть некий буфер, на который указывает DataBuffer и есть блок Cdb из 16 байт. Вот думал что я этом блоке будут и команды и данные, но нет..
    Перед вызовом оригинальное функции и после - все байты в этом блоке равны нулю..
    Не знаю пока что делать с DataBuffer...

    Может подсказочку небольшую?
     
  7. test555

    test555 New Member

    Публикаций:
    0
    Регистрация:
    7 дек 2007
    Сообщения:
    241
    Вопрос решен. Пока копался в исходниках ДДК storage\class\disk\disk.c, нашел что есть структура
    Код (Text):
    1. typedef struct _DISK_GEOMETRY_EX {
    2.         DISK_GEOMETRY Geometry;                                 // Standard disk geometry: may be faked by driver.
    3.         LARGE_INTEGER DiskSize;                                 // Must always be correct
    4.         UCHAR Data[1];                                                  // Partition, Detect info
    5. } DISK_GEOMETRY_EX, *PDISK_GEOMETRY_EX;
    Которая и выдает настоящий размер диска..
    Кормим запросом IOCTL_DISK_GET_DRIVE_GEOMETRY_Ex...
     
  8. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    test555
    Зря веришь вин-хексу. Перемнож цифры и сравни. :derisive:

    Коректный размер в CHS может быть только до дисков размером менее 16 514 064 байт согласно спецификации ATA\ATAPI-5 в последующих стандартах от CHS отказались. BIOS продержался немногим долее. Он сам начал транслировать CHS в LBA. Но регистры вдруг закончились и это произошло на 8ГБ.
    BIOS исходит из того что 512 байт на кластер. Один байт под головки максимум 255 головок.
    Секторов на дорожки максимум 63 (6 бит) . Число цилиндров максимум 1024 (8бит от одного регистра и те 2 что остались от другого)
    1024*63*255*512=8 422 686 720

    Что касается ошибки то просто Cylinders+1 это от биоса осталось.
     
  9. test555

    test555 New Member

    Публикаций:
    0
    Регистрация:
    7 дек 2007
    Сообщения:
    241
    Pavia, не понял, если перемножать число цилиндров, секторов и дорожек, то получается меньше чем винхекс, в придачу ты говоришь что это справедливо только для для малых винтов.
     
  10. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    Перемножаем цифры от винхекса получаем 101 080 465 920 Кужа делись еще 530 ГБайт ?
     
  11. test555

    test555 New Member

    Публикаций:
    0
    Регистрация:
    7 дек 2007
    Сообщения:
    241
    Я не знаю откуда винхекс брал эти параметры, т.к. когда моя программа считала
    Код (Text):
    1. Cylinders 77825
    2. TracksPerCylinder 255
    3. SectorsPerTrack 63
    4. BytesPerSector 512
    То получалось чуть другое значение от того что показывал винхекс... А полный размер он показывает такой же, как и дает DISK_GEOMETRY_EX...

    Вот.
     
  12. ams007

    ams007 New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2007
    Сообщения:
    86
    Cdb содержит сказевую команду, Cdb[0] - опкод.

    завтра пример кину, просто нет у меня дома ни ддк, ни студии, ни мсдн, а было это давно...

    ЗЫ: я верю только в SCSI-команды, т.к. в конечном счете все дисковые устройства работают через них (disk.sys вниз шлет только их...) :)
     
  13. ams007

    ams007 New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2007
    Сообщения:
    86
    Код (Text):
    1. #include "stdafx.h"
    2. #include <Windows.h>
    3. #include <WinIoCtl.h>
    4. #include <stdlib.h>
    5. #include <conio.h>
    6. #include <memory.h>
    7. #include <ntddscsi.h>
    8.  
    9.  
    10.  
    11. // размер буфера sense info - как правило 0xa,0xb
    12. #define  SENSE_B_SIZE       0xb
    13. // размер буфера данных - вроде как МАХ значение 0x100
    14. #define  TRANSFER_B_SIZE    0x100
    15.  
    16. #pragma pack(push,1)
    17.  
    18. typedef union _ULONG_BT {
    19.     UCHAR   m_cBytes[4];
    20.     ULONG   m_dwAsULONG;
    21. } ULONG_BT, *PULONG_BT;
    22.  
    23. typedef union _USHORT_BT {
    24.     UCHAR   m_cBytes[2];
    25.     USHORT  m_wAsUSHORT;
    26. } USHORT_BT, *PUSHORT_BT;
    27.  
    28. // из scsi.h или ntddscsi.h
    29. typedef struct _SENSE_DATA {
    30.     UCHAR ErrorCode:7;
    31.     UCHAR Valid:1;
    32.     UCHAR SegmentNumber;
    33.     UCHAR SenseKey:4;
    34.     UCHAR Reserved:1;
    35.     UCHAR IncorrectLength:1;
    36.     UCHAR EndOfMedia:1;
    37.     UCHAR FileMark:1;
    38.     UCHAR Information[4];
    39.     UCHAR AdditionalSenseLength;
    40.     UCHAR CommandSpecificInformation[4];
    41.     UCHAR AdditionalSenseCode;
    42.     UCHAR AdditionalSenseCodeQualifier;
    43.     UCHAR FieldReplaceableUnitCode;
    44.     UCHAR SenseKeySpecific[3];
    45. } SENSE_DATA, *PSENSE_DATA;
    46.  
    47. // из scsi.h или ntddscsi.h
    48. typedef struct _READ_CAPACITY_DATA {
    49.     ULONG LogicalBlockAddress;
    50.     ULONG BytesPerBlock;
    51. } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
    52.  
    53. #pragma pack(pop)
    54.  
    55.  
    56. HANDLE
    57. OpenDevice(
    58.         IN PWCHAR pName)
    59. {
    60.     return CreateFile(
    61.         pName,
    62.         GENERIC_READ |GENERIC_WRITE,
    63.         FILE_SHARE_READ|FILE_SHARE_WRITE,
    64.         NULL,
    65.         OPEN_EXISTING,
    66.         0x0,
    67.         NULL);
    68. }
    69.  
    70. LPTSTR
    71. GetStrLastError()
    72. {
    73.     LPVOID lpMsgBuf;
    74.     FormatMessage(
    75.         FORMAT_MESSAGE_ALLOCATE_BUFFER |
    76.         FORMAT_MESSAGE_FROM_SYSTEM |
    77.         FORMAT_MESSAGE_IGNORE_INSERTS,
    78.         NULL,
    79.         GetLastError(),
    80.         0, // Default language
    81.         (LPTSTR) &lpMsgBuf,
    82.         0,
    83.         NULL
    84.         );
    85.  
    86.     CharToOem((LPCWSTR)lpMsgBuf,(LPSTR)lpMsgBuf);
    87.     return (LPTSTR)lpMsgBuf;
    88. }
    89.  
    90. // крутит вертит из литл эндиан формата
    91. __inline USHORT
    92. CrvdScsiInvWORD(
    93.     IN USHORT   wValue)
    94. {
    95.     USHORT_BT Value;
    96.     USHORT_BT Result;
    97.  
    98.     Value.m_wAsUSHORT = wValue;
    99.  
    100.     Result.m_cBytes[0] = Value.m_cBytes[1];
    101.     Result.m_cBytes[1] = Value.m_cBytes[0];
    102.  
    103.     return Result.m_wAsUSHORT;
    104. }
    105.  
    106. // крутит вертит из биг эндиан формата
    107. __inline ULONG
    108. CrvdScsiInvDWORD(
    109.     IN ULONG    dwValue)
    110. {
    111.     ULONG_BT Value;
    112.     ULONG_BT Result;
    113.  
    114.     Value.m_dwAsULONG = dwValue;
    115.  
    116.     Result.m_cBytes[0] = Value.m_cBytes[3];
    117.     Result.m_cBytes[1] = Value.m_cBytes[2];
    118.     Result.m_cBytes[2] = Value.m_cBytes[1];
    119.     Result.m_cBytes[3] = Value.m_cBytes[0];
    120.  
    121.     return Result.m_dwAsULONG;
    122. }
    123.  
    124. int _tmain(int argc, _TCHAR* argv[])
    125. {
    126.     HANDLE              hDevice;
    127.     PSENSE_DATA         pSenseBuffer;
    128.     PSCSI_PASS_THROUGH  pPass;
    129.  
    130.     PREAD_CAPACITY_DATA pData;
    131.  
    132.     PUCHAR      pInputBuffer;
    133.     ULONG       dwInputBufferSize;
    134.     ULONG       dwBytesReturned;
    135.     BOOL        fSuccess;
    136.  
    137.     ULONG       dwSectorSize;
    138.     ULONG       dwSectorsAmount;
    139.  
    140.     // только для Х :))))
    141.     hDevice = OpenDevice(L"\\\\.\\X:");
    142.     if( INVALID_HANDLE_VALUE == hDevice )
    143.     {
    144.         wprintf(L"Error open device,  %s",GetStrLastError());
    145.         return 2;
    146.     }
    147.  
    148.     dwInputBufferSize = sizeof(SCSI_PASS_THROUGH) + SENSE_B_SIZE + TRANSFER_B_SIZE;
    149.    
    150.     pInputBuffer = (PUCHAR)malloc(dwInputBufferSize);
    151.  
    152.     memset(pInputBuffer,0,dwInputBufferSize);
    153.  
    154.     pPass = (PSCSI_PASS_THROUGH)pInputBuffer;
    155.  
    156.     pPass->Length = sizeof(SCSI_PASS_THROUGH);
    157.     pPass->CdbLength = 6;
    158.  
    159.     pPass->SenseInfoLength      = SENSE_B_SIZE;
    160.     pPass->SenseInfoOffset      = sizeof(SCSI_PASS_THROUGH);
    161.    
    162.     pPass->DataTransferLength   = TRANSFER_B_SIZE;
    163.     pPass->DataBufferOffset     = sizeof(SCSI_PASS_THROUGH) + SENSE_B_SIZE;
    164.  
    165.     pPass->TimeOutValue = 15;
    166.     pPass->DataIn = SCSI_IOCTL_DATA_IN;
    167.  
    168.     pPass->Cdb[0] = 0x25; // SCSIOP_READ_CAPACITY
    169.    
    170.     fSuccess = DeviceIoControl(
    171.         hDevice,
    172.         IOCTL_SCSI_PASS_THROUGH,
    173.         pInputBuffer,
    174.         dwInputBufferSize,
    175.         pInputBuffer,
    176.         dwInputBufferSize,
    177.         &dwBytesReturned,
    178.         NULL);
    179.  
    180.     if ( FALSE == fSuccess )
    181.     {
    182.         printf("Error send cmd, error code = %d",GetLastError());
    183.         return 2;
    184.     }
    185.  
    186.     pPass = (PSCSI_PASS_THROUGH)pInputBuffer;
    187.  
    188.     pData = (PREAD_CAPACITY_DATA)(pInputBuffer + sizeof(SCSI_PASS_THROUGH) + SENSE_B_SIZE);
    189.     pSenseBuffer = (PSENSE_DATA)(pInputBuffer + sizeof(SCSI_PASS_THROUGH));
    190.  
    191.  
    192.     dwSectorsAmount = CrvdScsiInvDWORD(pData->LogicalBlockAddress);
    193.     dwSectorsAmount += 1;
    194.  
    195.     dwSectorSize = CrvdScsiInvDWORD(pData->BytesPerBlock);
    196.  
    197.     printf(" Sector size == %d, Sectors amount == %d", dwSectorSize, dwSectorsAmount);
    198.  
    199.     free(pInputBuffer);
    200.     CloseHandle(hDevice);
    201.     return 0;
    202. }
    pData->LogicalBlockAddress содержит адрес последнего сектора на диске в эндиан формате, т.е. размер в секторах на 1цу больше.

    pData->BytesPerBlock содержит размер сектора в том же формате.

    pSenseBuffer содержит расширенную инф-ю об ошибке. Если там все нули, то гуд.

    Пример для 3кольца. Структуры из ддк, кроме USHORT_BT, ULONG_BT, но там есль вроде и аналоги. Также вроде есль макросы, которые делают то же самое, что и CrvdScsiInvDWORD(), CrvdScsiInvWORD().

    ЗЫ: SCSI рулит! :)
     
  14. test555

    test555 New Member

    Публикаций:
    0
    Регистрация:
    7 дек 2007
    Сообщения:
    241
    все спасибо в общем ))