From cda40547fe35b28321f7a00b53cc18eb9cf77cba Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Tue, 23 May 2017 12:23:07 +0200 Subject: Windows: query extra host drive information using IOCTL_STORAGE_QUERY_PROPERTY (StorageAdapterProperty) in both driver and user mode applications. --- src/Common/Apidrvr.h | 3 ++ src/Common/Dlgcode.c | 114 ++++++++++++++++++++++++++++++++++++++++++-------- src/Driver/Ntdriver.h | 3 ++ src/Driver/Ntvol.c | 33 +++++++++++++++ 4 files changed, 136 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/Common/Apidrvr.h b/src/Common/Apidrvr.h index 28202e61..adffacc2 100644 --- a/src/Common/Apidrvr.h +++ b/src/Common/Apidrvr.h @@ -172,6 +172,9 @@ typedef struct BOOL bIsNTFS; // output only BOOL bDriverSetLabel; BOOL bCachePim; + ULONG MaximumTransferLength; + ULONG MaximumPhysicalPages; + ULONG AlignmentMask; } MOUNT_STRUCT; typedef struct diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c index d09e0044..97c55da4 100644 --- a/src/Common/Dlgcode.c +++ b/src/Common/Dlgcode.c @@ -7228,36 +7228,97 @@ void BroadcastDeviceChange (WPARAM message, int nDosDriveNo, DWORD driveMap) IgnoreWmDeviceChange = FALSE; } -BOOL GetPhysicalDriveAlignment(UINT nDriveNumber, STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR* pDesc) +static BOOL GetDeviceStorageProperty (HANDLE hDevice, STORAGE_PROPERTY_ID propertyId, DWORD dwDescSize, void* pDesc) { DWORD dwRet = NO_ERROR; if (!pDesc) return FALSE; - // Format physical drive path (may be '\\.\PhysicalDrive0', '\\.\PhysicalDrive1' and so on). - TCHAR strDrivePath[512]; - StringCbPrintf(strDrivePath, sizeof(strDrivePath), _T("\\\\.\\PhysicalDrive%u"), nDriveNumber); - - // Get a handle to physical drive - HANDLE hDevice = ::CreateFile(strDrivePath, 0, FILE_SHARE_READ, - NULL, OPEN_EXISTING, 0, NULL); - - if(INVALID_HANDLE_VALUE == hDevice) - return FALSE; + ZeroMemory (pDesc, dwDescSize); // Set the input data structure STORAGE_PROPERTY_QUERY storagePropertyQuery; ZeroMemory(&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY)); - storagePropertyQuery.PropertyId = StorageAccessAlignmentProperty; + storagePropertyQuery.PropertyId = propertyId; storagePropertyQuery.QueryType = PropertyStandardQuery; // Get the necessary output buffer size + STORAGE_DESCRIPTOR_HEADER descHeader = {0}; DWORD dwBytesReturned = 0; BOOL bRet = ::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY), - pDesc, sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR), + &descHeader, sizeof(STORAGE_DESCRIPTOR_HEADER), &dwBytesReturned, NULL); + if (bRet) + { + if (dwBytesReturned == sizeof(STORAGE_DESCRIPTOR_HEADER)) + { + unsigned char* outputBuffer = (unsigned char*) TCalloc (descHeader.Size); + bRet = ::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, + &storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY), + outputBuffer, descHeader.Size, + &dwBytesReturned, NULL); + if (bRet) + { + if (dwBytesReturned >= dwDescSize) + { + memcpy (pDesc, outputBuffer, dwDescSize); + ((STORAGE_DESCRIPTOR_HEADER*)pDesc)->Version = dwDescSize; + ((STORAGE_DESCRIPTOR_HEADER*)pDesc)->Size = dwDescSize; + } + else + { + bRet = FALSE; + dwRet = ERROR_UNHANDLED_ERROR; + } + } + else + dwRet = ::GetLastError(); + TCfree (outputBuffer); + } + else + { + bRet = FALSE; + dwRet = ERROR_UNHANDLED_ERROR; + } + } + else + dwRet = ::GetLastError(); + ::CloseHandle(hDevice); + + if (!bRet) + { + SetLastError (dwRet); + return FALSE; + } + else + return TRUE; +} + +BOOL GetPhysicalDriveStorageInformation(UINT nDriveNumber, STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR* pAlignmentDesc, STORAGE_ADAPTER_DESCRIPTOR* pAdapterDesc) +{ + DWORD dwRet = NO_ERROR; + + if (!pAlignmentDesc || pAdapterDesc) + { + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; + } + + // Format physical drive path (may be '\\.\PhysicalDrive0', '\\.\PhysicalDrive1' and so on). + TCHAR strDrivePath[512]; + StringCbPrintf(strDrivePath, sizeof(strDrivePath), _T("\\\\.\\PhysicalDrive%u"), nDriveNumber); + + // Get a handle to physical drive + HANDLE hDevice = ::CreateFile(strDrivePath, 0, FILE_SHARE_READ, + NULL, OPEN_EXISTING, 0, NULL); + + if(INVALID_HANDLE_VALUE == hDevice) + return FALSE; + + BOOL bRet = (GetDeviceStorageProperty (hDevice, StorageAccessAlignmentProperty, sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR), pAlignmentDesc) + || GetDeviceStorageProperty (hDevice, StorageAdapterProperty, sizeof (STORAGE_ADAPTER_DESCRIPTOR), pAdapterDesc))? TRUE : FALSE; dwRet = ::GetLastError(); ::CloseHandle(hDevice); @@ -7621,6 +7682,13 @@ retry: if (!bDevice) { + // put default values + mount.BytesPerSector = 512; + mount.BytesPerPhysicalSector = 512; + mount.MaximumTransferLength = 65536; + mount.MaximumPhysicalPages = 17; + mount.AlignmentMask = 0; + // UNC path if (path.find (L"\\\\") == 0) { @@ -7655,11 +7723,23 @@ retry: { if (extents.NumberOfDiskExtents > 0) { - STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR desc; - if (GetPhysicalDriveAlignment (extents.Extents[0].DiskNumber, &desc)) + STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR accessDesc; + STORAGE_ADAPTER_DESCRIPTOR adapterDesc; + + if (GetPhysicalDriveStorageInformation (extents.Extents[0].DiskNumber, &accessDesc, &adapterDesc)) { - mount.BytesPerSector = desc.BytesPerLogicalSector; - mount.BytesPerPhysicalSector = desc.BytesPerPhysicalSector; + if (accessDesc.Size >= sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR)) + { + mount.BytesPerSector = accessDesc.BytesPerLogicalSector; + mount.BytesPerPhysicalSector = accessDesc.BytesPerPhysicalSector; + } + + if (adapterDesc.Size >= sizeof (STORAGE_ADAPTER_DESCRIPTOR)) + { + mount.MaximumTransferLength = adapterDesc.MaximumTransferLength; + mount.MaximumPhysicalPages = adapterDesc.MaximumPhysicalPages; + mount.AlignmentMask = adapterDesc.AlignmentMask; + } } } } diff --git a/src/Driver/Ntdriver.h b/src/Driver/Ntdriver.h index 5b52ab04..09a29542 100644 --- a/src/Driver/Ntdriver.h +++ b/src/Driver/Ntdriver.h @@ -63,6 +63,9 @@ typedef struct EXTENSION uint32 HostBytesPerSector; uint32 HostBytesPerPhysicalSector; + ULONG HostMaximumTransferLength; + ULONG HostMaximumPhysicalPages; + ULONG HostAlignmentMask; KEVENT keVolumeEvent; /* Event structure used when setting up a device */ diff --git a/src/Driver/Ntvol.c b/src/Driver/Ntvol.c index 8fda0bd9..8be0393a 100644 --- a/src/Driver/Ntvol.c +++ b/src/Driver/Ntvol.c @@ -63,6 +63,11 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject, Extension->hDeviceFile = NULL; Extension->bTimeStampValid = FALSE; + /* default value for storage alignment */ + Extension->HostMaximumTransferLength = 65536; + Extension->HostMaximumPhysicalPages = 17; + Extension->HostAlignmentMask = 0; + RtlInitUnicodeString (&FullFileName, pwszMountVolume); InitializeObjectAttributes (&oaFileAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | (forceAccessCheck ? OBJ_FORCE_ACCESS_CHECK : 0) | OBJ_KERNEL_HANDLE, NULL, NULL); KeInitializeEvent (&Extension->keVolumeEvent, NotificationEvent, FALSE); @@ -129,6 +134,31 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject, TCfree (outputBuffer); } + + storagePropertyQuery.PropertyId = StorageAdapterProperty; + if (NT_SUCCESS (TCSendHostDeviceIoControlRequestEx (DeviceObject, Extension, IOCTL_STORAGE_QUERY_PROPERTY, + (char*) &storagePropertyQuery, sizeof(storagePropertyQuery), + (char *) &storageHeader, sizeof (storageHeader)))) + { + byte* outputBuffer = TCalloc (storageHeader.Size); + if (!outputBuffer) + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + goto error; + } + + if (NT_SUCCESS (TCSendHostDeviceIoControlRequestEx (DeviceObject, Extension, IOCTL_STORAGE_QUERY_PROPERTY, + (char*) &storagePropertyQuery, sizeof(storagePropertyQuery), + outputBuffer, storageHeader.Size))) + { + PSTORAGE_ADAPTER_DESCRIPTOR pStorageDescriptor = (PSTORAGE_ADAPTER_DESCRIPTOR) outputBuffer; + Extension->HostMaximumTransferLength = pStorageDescriptor->MaximumTransferLength; + Extension->HostMaximumPhysicalPages = pStorageDescriptor->MaximumPhysicalPages; + Extension->HostAlignmentMask = pStorageDescriptor->AlignmentMask; + } + + TCfree (outputBuffer); + } } // Drive geometry is used only when IOCTL_DISK_GET_PARTITION_INFO fails @@ -179,6 +209,9 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject, Extension->HostBytesPerSector = mount->BytesPerSector; Extension->HostBytesPerPhysicalSector = mount->BytesPerPhysicalSector; + Extension->HostMaximumTransferLength = mount->MaximumTransferLength; + Extension->HostMaximumPhysicalPages = mount->MaximumPhysicalPages; + Extension->HostAlignmentMask = mount->AlignmentMask; if (Extension->HostBytesPerSector != TC_SECTOR_SIZE_FILE_HOSTED_VOLUME) disableBuffering = FALSE; -- cgit v1.2.3