From: Carl Hetherington Date: Sun, 8 Mar 2020 22:14:02 +0000 (+0100) Subject: Various Windows drive scanning hacks. X-Git-Url: https://main.carlh.net/gitweb/?a=commitdiff_plain;h=5e09d91f2e7eae52e8ff30babd4c72f521ecb608;p=dcpomatic.git Various Windows drive scanning hacks. --- diff --git a/src/lib/cross_windows.cc b/src/lib/cross_windows.cc index 9c6fab577..5d2cf5372 100644 --- a/src/lib/cross_windows.cc +++ b/src/lib/cross_windows.cc @@ -271,15 +271,21 @@ thread_id () return (uint64_t) GetCurrentThreadId (); } -int -avio_open_boost (AVIOContext** s, boost::filesystem::path file, int flags) +static string +wchar_to_utf8 (wchar_t const * s) { - int const length = (file.string().length() + 1) * 2; + int const length = (wcslen(s) + 1) * 2; char* utf8 = new char[length]; - WideCharToMultiByte (CP_UTF8, 0, file.c_str(), -1, utf8, length, 0, 0); - int const r = avio_open (s, utf8, flags); + WideCharToMultiByte (CP_UTF8, 0, s, -1, utf8, length, 0, 0); + string u (utf8); delete[] utf8; - return r; + return u; +} + +int +avio_open_boost (AVIOContext** s, boost::filesystem::path file, int flags) +{ + return avio_open (s, wchar_to_utf8(file.c_str()).c_str(), flags); } void @@ -323,114 +329,148 @@ running_32_on_64 () return p; } +static optional +get_friendly_name (HDEVINFO device_info, SP_DEVINFO_DATA* device_info_data) +{ + wchar_t buffer[MAX_PATH]; + ZeroMemory (&buffer, sizeof(buffer)); + bool r = SetupDiGetDeviceRegistryPropertyW ( + device_info, device_info_data, SPDRP_FRIENDLYNAME, 0, reinterpret_cast(buffer), sizeof(buffer), 0 + ); + if (!r) { + return optional(); + } + return wchar_to_utf8 (buffer); +} + +static const GUID GUID_DEVICE_INTERFACE_DISK = { + 0x53F56307L, 0xB6BF, 0x11D0, { 0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B } +}; + +static optional +get_device_number (HDEVINFO device_info, SP_DEVINFO_DATA* device_info_data) +{ + /* Find the Windows path to the device */ + + SP_DEVICE_INTERFACE_DATA device_interface_data; + device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + BOOL r = SetupDiEnumDeviceInterfaces (device_info, device_info_data, &GUID_DEVICE_INTERFACE_DISK, 0, &device_interface_data); + if (!r) { + LOG_DIST("SetupDiEnumDeviceInterfaces failed (%1)", GetLastError()); + return optional(); + } + + /* Find out how much space we need for our SP_DEVICE_INTERFACE_DETAIL_DATA_W */ + DWORD size; + r = SetupDiGetDeviceInterfaceDetailW(device_info, &device_interface_data, 0, 0, &size, 0); + PSP_DEVICE_INTERFACE_DETAIL_DATA_W device_detail_data = static_cast (malloc(size)); + if (!device_detail_data) { + LOG_DIST_NC("malloc failed"); + return optional(); + } + + device_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); + + /* And get the path */ + r = SetupDiGetDeviceInterfaceDetailW (device_info, &device_interface_data, device_detail_data, size, &size, 0); + if (!r) { + LOG_DIST_NC("SetupDiGetDeviceInterfaceDetailW failed"); + free (device_detail_data); + return optional(); + } + + /* Open it. We would not be allowed GENERIC_READ access here but specifying 0 for + dwDesiredAccess allows us to query some metadata. + */ + HANDLE device = CreateFileW ( + device_detail_data->DevicePath, 0, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, 0, 0 + ); + + free (device_detail_data); + + if (device == INVALID_HANDLE_VALUE) { + LOG_DIST("CreateFileW failed with %1", GetLastError()); + return optional(); + } + + /* Get the device number */ + STORAGE_DEVICE_NUMBER device_number; + r = DeviceIoControl ( + device, IOCTL_STORAGE_GET_DEVICE_NUMBER, 0, 0, + &device_number, sizeof(device_number), &size, 0 + ); + + CloseHandle (device); + + if (!r) { + return optional(); + } + + return device_number.DeviceNumber; +} + vector get_drives () { vector drives; - const GUID GUID_DEVICE_INTERFACE_DISK = { - 0x53F56307L, 0xB6BF, 0x11D0, { 0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B } - }; - + /* Get a `device information set' containing information about all disks */ HDEVINFO device_info = SetupDiGetClassDevsA (&GUID_DEVICE_INTERFACE_DISK, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (device_info == INVALID_HANDLE_VALUE) { - LOG_DIST_NC("SetupDiClassDevsA failed"); + LOG_DIST_NC ("SetupDiClassDevsA failed"); return drives; } int i = 0; while (true) { + /* Find out about the next disk */ SP_DEVINFO_DATA device_info_data; device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); if (!SetupDiEnumDeviceInfo(device_info, i, &device_info_data)) { - LOG_DIST ("SetupDiEnumDeviceInfo failed (%1)", GetLastError()); - return drives; + DWORD e = GetLastError(); + if (e != ERROR_NO_MORE_ITEMS) { + LOG_DIST ("SetupDiEnumDeviceInfo failed (%1)", GetLastError()); + } + break; } ++i; - wchar_t friendly_name_buffer[MAX_PATH]; - ZeroMemory (&friendly_name_buffer, sizeof(friendly_name_buffer)); - - bool r = SetupDiGetDeviceRegistryPropertyW ( - device_info, &device_info_data, SPDRP_FRIENDLYNAME, 0, reinterpret_cast(friendly_name_buffer), sizeof(friendly_name_buffer), 0 - ); - - if (r) { - int const length = (wcslen(friendly_name_buffer) + 1) * 2; - char* utf8 = new char[length]; - /* XXX: this is used in a few places in this file; should be abstracted out */ - WideCharToMultiByte (CP_UTF8, 0, friendly_name_buffer, -1, utf8, length, 0, 0); - /* XXX: utf8 contains a user-readable name */ - delete[] utf8; + optional const friendly_name = get_friendly_name (device_info, &device_info_data); + optional device_number = get_device_number (device_info, &device_info_data); + if (!device_number) { + continue; } - int j = 0; - while (true) { - SP_DEVICE_INTERFACE_DATA device_interface_data; - device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); - - bool r = SetupDiEnumDeviceInterfaces (device_info, &device_info_data, &GUID_DEVICE_INTERFACE_DISK, j, &device_interface_data); - if (!r) { - DWORD e = GetLastError(); - if (e == ERROR_NO_MORE_ITEMS) { - break; - } else { - LOG_DIST("SetupDiEnumDeviceInterfaces failed (%1)", e); - return drives; - } - } + string const physical_drive = String::compose("\\\\.\\PHYSICALDRIVE%1", *device_number); - DWORD size; - r = SetupDiGetDeviceInterfaceDetailW(device_info, &device_interface_data, 0, 0, &size, 0); - PSP_DEVICE_INTERFACE_DETAIL_DATA_W device_detail_data = static_cast (malloc(size)); - if (!device_detail_data) { - LOG_DIST_NC("malloc failed"); - return drives; - } - - device_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); - - r = SetupDiGetDeviceInterfaceDetailW (device_info, &device_interface_data, device_detail_data, size, &size, 0); - if (!r) { - LOG_DIST_NC("SetupDiGetDeviceInterfaceDetailW failed"); - return vector(); - } - - HANDLE device = CreateFileW ( - device_detail_data->DevicePath, 0, + HANDLE device = CreateFileA ( + physical_drive.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 - ); - - if (device == INVALID_HANDLE_VALUE) { - LOG_DIST_NC("CreateFileW failed"); - return drives; - } - - VOLUME_DISK_EXTENTS disk_extents; - r = DeviceIoControl ( - device, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, 0, 0, - &disk_extents, sizeof(VOLUME_DISK_EXTENTS), &size, 0 + OPEN_EXISTING, 0, 0 ); - if (r && disk_extents.NumberOfDiskExtents > 0) { - LOG_DIST("GET_VOLUME_DISK_EXTENTS gives %1", disk_extents.Extents[0].DiskNumber); - /* Disk number for \\.\PHYSICALDRIVEx is disk disk_extents.Extents[0].DiskNumber */ - } + if (device == INVALID_HANDLE_VALUE) { + LOG_DIST_NC("Could not open PHYSICALDRIVE"); + } - STORAGE_DEVICE_NUMBER device_number; - r = DeviceIoControl ( - device, IOCTL_STORAGE_GET_DEVICE_NUMBER, 0, 0, - &device_number, sizeof(device_number), &size, 0 + DISK_GEOMETRY geom; + DWORD returned; + BOOL r = DeviceIoControl ( + device, IOCTL_DISK_GET_DRIVE_GEOMETRY, 0, 0, + &geom, sizeof(geom), &returned, 0 ); - if (r) { - LOG_DIST("GET_DEVICE_NUMBER gives %1", device_number.DeviceNumber); - /* Disk number for \\.\PHYSICALDRIVEx is device_number.DeviceNumber */ - } - - ++j; + if (r) { + uint64_t const disk_size = geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector; + drives.push_back (Drive(physical_drive, disk_size, false, friendly_name, optional())); + } else { + LOG_DIST("Error %1", GetLastError()); } + + CloseHandle (device); } return drives;