/* * Return the path to access the physical drive, or NULL on error. * The string is allocated and must be freed (to ensure concurrent access) */ char* GetPhysicalName(DWORD DriveIndex) { BOOL success = FALSE; char physical_name[24]; CheckDriveIndex(DriveIndex); safe_sprintf(physical_name, sizeof(physical_name), "\\\\.\\PHYSICALDRIVE%d", DriveIndex); success = TRUE; out: return (success)?safe_strdup(physical_name):NULL; }
/* * Returns the drive letters for all volumes located on the drive identified by DriveIndex, * as well as the drive type. This is used as base for the 2 function calls that follow. */ static BOOL _GetDriveLettersAndType(DWORD DriveIndex, char* drive_letters, UINT* drive_type) { DWORD size; BOOL r = FALSE; HANDLE hDrive = INVALID_HANDLE_VALUE; UINT _drive_type; int i = 0, drive_number; char *drive, drives[26*4 + 1]; /* "D:\", "E:\", etc., plus one NUL */ char logical_drive[] = "\\\\.\\#:"; if (drive_letters != NULL) drive_letters[0] = 0; if (drive_type != NULL) *drive_type = DRIVE_UNKNOWN; CheckDriveIndex(DriveIndex); // This call is weird... The buffer needs to have an extra NUL, but you're // supposed to provide the size without the extra NUL. And the returned size // does not include the NUL either *EXCEPT* if your buffer is too small... // But then again, this doesn't hold true if you have a 105 byte buffer and // pass a 4*26=104 size, as the the call will return 105 (i.e. *FAILURE*) // instead of 104 as it should => screw Microsoft: We'll include the NUL // always, as each drive string is at least 4 chars long anyway. size = GetLogicalDriveStringsA(sizeof(drives), drives); if (size == 0) { uprintf("GetLogicalDriveStrings failed: %s\n", WindowsErrorString()); goto out; } if (size > sizeof(drives)) { uprintf("GetLogicalDriveStrings: Buffer too small (required %d vs. %d)\n", size, sizeof(drives)); goto out; } r = TRUE; // Required to detect drives that don't have volumes assigned for (drive = drives ;*drive; drive += safe_strlen(drive)+1) { if (!isalpha(*drive)) continue; *drive = (char)toupper((int)*drive); if (*drive < 'C') { continue; } // IOCTL_STORAGE_GET_DEVICE_NUMBER's STORAGE_DEVICE_NUMBER.DeviceNumber is // not unique! An HDD, a DVD and probably other drives can have the same // value there => Use GetDriveType() to filter out unwanted devices. // See https://github.com/pbatard/rufus/issues/32#issuecomment-3785956 _drive_type = GetDriveTypeA(drive); if ((_drive_type != DRIVE_REMOVABLE) && (_drive_type != DRIVE_FIXED)) continue; safe_sprintf(logical_drive, sizeof(logical_drive), "\\\\.\\%c:", drive[0]); hDrive = CreateFileA(logical_drive, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hDrive == INVALID_HANDLE_VALUE) { // uprintf("Warning: could not open drive %c: %s\n", drive[0], WindowsErrorString()); continue; } drive_number = GetDriveNumber(hDrive, logical_drive); safe_closehandle(hDrive); if (drive_number == DriveIndex) { r = TRUE; if (drive_letters != NULL) drive_letters[i++] = *drive; // The drive type should be the same for all volumes, so we can overwrite if (drive_type != NULL) *drive_type = _drive_type; } } out: if (drive_letters != NULL) drive_letters[i] = 0; return r; }
/* * Return the first GUID volume name for the associated drive or NULL if not found * See http://msdn.microsoft.com/en-us/library/cc542456.aspx * The returned string is allocated and must be freed */ char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent) { BOOL success = FALSE; char volume_name[MAX_PATH]; HANDLE hDrive = INVALID_HANDLE_VALUE, hVolume = INVALID_HANDLE_VALUE; size_t len; char path[MAX_PATH]; VOLUME_DISK_EXTENTS DiskExtents; DWORD size; UINT drive_type; int i, j; static const char* ignore_device[] = { "\\Device\\CdRom", "\\Device\\Floppy" }; static const char* volume_start = "\\\\?\\"; CheckDriveIndex(DriveIndex); for (i=0; hDrive == INVALID_HANDLE_VALUE; i++) { if (i == 0) { hVolume = FindFirstVolumeA(volume_name, sizeof(volume_name)); if (hVolume == INVALID_HANDLE_VALUE) { suprintf("Could not access first GUID volume: %s\n", WindowsErrorString()); goto out; } } else { if (!FindNextVolumeA(hVolume, volume_name, sizeof(volume_name))) { if (GetLastError() != ERROR_NO_MORE_FILES) { suprintf("Could not access next GUID volume: %s\n", WindowsErrorString()); } goto out; } } // Sanity checks len = safe_strlen(volume_name); if ((len <= 1) || (safe_strnicmp(volume_name, volume_start, 4) != 0) || (volume_name[len-1] != '\\')) { suprintf("'%s' is not a GUID volume name\n", volume_name); continue; } drive_type = GetDriveTypeA(volume_name); if ((drive_type != DRIVE_REMOVABLE) && (drive_type != DRIVE_FIXED)) continue; volume_name[len-1] = 0; if (QueryDosDeviceA(&volume_name[4], path, sizeof(path)) == 0) { suprintf("Failed to get device path for GUID volume '%s': %s\n", volume_name, WindowsErrorString()); continue; } for (j=0; (j<ARRAYSIZE(ignore_device)) && (_strnicmp(path, ignore_device[j], safe_strlen(ignore_device[j])) != 0); j++); if (j < ARRAYSIZE(ignore_device)) { suprintf("Skipping GUID volume for '%s'\n", path); continue; } // If we can't have FILE_SHARE_WRITE, forget it hDrive = CreateFileA(volume_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hDrive == INVALID_HANDLE_VALUE) { suprintf("Could not open GUID volume '%s': %s\n", volume_name, WindowsErrorString()); continue; } if ((!DeviceIoControl(hDrive, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, &DiskExtents, sizeof(DiskExtents), &size, NULL)) || (size <= 0)) { suprintf("Could not get Disk Extents: %s\n", WindowsErrorString()); safe_closehandle(hDrive); continue; } safe_closehandle(hDrive); if ((DiskExtents.NumberOfDiskExtents >= 1) && (DiskExtents.Extents[0].DiskNumber == DriveIndex)) { if (bKeepTrailingBackslash) volume_name[len-1] = '\\'; success = TRUE; break; } } out: if (hVolume != INVALID_HANDLE_VALUE) FindVolumeClose(hVolume); return (success)?safe_strdup(volume_name):NULL; }
/* * Returns the drive letters for all volumes located on the drive identified by DriveIndex, * as well as the drive type. This is used as base for the 2 function calls that follow. */ static BOOL _GetDriveLettersAndType(DWORD DriveIndex, char* drive_letters, UINT* drive_type) { DWORD size; BOOL r = FALSE; HANDLE hDrive = INVALID_HANDLE_VALUE; UINT _drive_type; int i = 0, drive_number; char *drive, drives[26*4]; /* "D:\", "E:\", etc. */ char logical_drive[] = "\\\\.\\#:"; if (drive_letters != NULL) drive_letters[0] = 0; if (drive_type != NULL) *drive_type = DRIVE_UNKNOWN; CheckDriveIndex(DriveIndex); size = GetLogicalDriveStringsA(sizeof(drives), drives); if (size == 0) { uprintf("GetLogicalDriveStrings failed: %s\n", WindowsErrorString()); goto out; } if (size > sizeof(drives)) { uprintf("GetLogicalDriveStrings: buffer too small (required %d vs %d)\n", size, sizeof(drives)); goto out; } r = TRUE; // Required to detect drives that don't have volumes assigned for (drive = drives ;*drive; drive += safe_strlen(drive)+1) { if (!isalpha(*drive)) continue; *drive = (char)toupper((int)*drive); if (*drive < 'C') { continue; } /* IOCTL_STORAGE_GET_DEVICE_NUMBER's STORAGE_DEVICE_NUMBER.DeviceNumber is not unique! An HDD, a DVD and probably other drives can have the same value there => Use GetDriveType() to filter out unwanted devices. See https://github.com/pbatard/rufus/issues/32 for details. */ _drive_type = GetDriveTypeA(drive); if ((_drive_type != DRIVE_REMOVABLE) && (_drive_type != DRIVE_FIXED)) continue; safe_sprintf(logical_drive, sizeof(logical_drive), "\\\\.\\%c:", drive[0]); hDrive = CreateFileA(logical_drive, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDrive == INVALID_HANDLE_VALUE) { uprintf("Warning: could not open drive %c: %s\n", drive[0], WindowsErrorString()); continue; } drive_number = GetDriveNumber(hDrive, logical_drive); safe_closehandle(hDrive); if (drive_number == DriveIndex) { r = TRUE; if (drive_letters != NULL) drive_letters[i++] = *drive; // The drive type should be the same for all volumes, so we can overwrite if (drive_type != NULL) *drive_type = _drive_type; } } out: if (drive_letters != NULL) drive_letters[i] = 0; return r; }
/* * Returns the first drive letter for a volume located on the drive identified by DriveIndex, * as well as the drive type. This is used as base for the 2 function calls that follow. */ static BOOL _GetDriveLetterAndType(DWORD DriveIndex, char* drive_letter, UINT* drive_type) { DWORD size; BOOL r = FALSE; STORAGE_DEVICE_NUMBER_REDEF device_number = {0}; HANDLE hDrive = INVALID_HANDLE_VALUE; UINT _drive_type; char *drive, drives[26*4]; /* "D:\", "E:\", etc. */ char logical_drive[] = "\\\\.\\#:"; if (drive_letter != NULL) *drive_letter = ' '; if (drive_type != NULL) *drive_type = DRIVE_UNKNOWN; CheckDriveIndex(DriveIndex); size = GetLogicalDriveStringsA(sizeof(drives), drives); if (size == 0) { uprintf("GetLogicalDriveStrings failed: %s\n", WindowsErrorString()); goto out; } if (size > sizeof(drives)) { uprintf("GetLogicalDriveStrings: buffer too small (required %d vs %d)\n", size, sizeof(drives)); goto out; } r = TRUE; for (drive = drives ;*drive; drive += safe_strlen(drive)+1) { if (!isalpha(*drive)) continue; *drive = (char)toupper((int)*drive); if (*drive < 'C') { continue; } /* IOCTL_STORAGE_GET_DEVICE_NUMBER's STORAGE_DEVICE_NUMBER.DeviceNumber is not unique! An HDD, a DVD and probably other drives can have the same value there => Use GetDriveType() to filter out unwanted devices. See https://github.com/pbatard/rufus/issues/32 for details. */ _drive_type = GetDriveTypeA(drive); if ((_drive_type != DRIVE_REMOVABLE) && (_drive_type != DRIVE_FIXED)) continue; safe_sprintf(logical_drive, sizeof(logical_drive), "\\\\.\\%c:", drive[0]); hDrive = CreateFileA(logical_drive, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDrive == INVALID_HANDLE_VALUE) { uprintf("Warning: could not open drive %c: %s\n", drive[0], WindowsErrorString()); continue; } r = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &device_number, sizeof(device_number), &size, NULL) && (size > 0); safe_closehandle(hDrive); if (!r) { uprintf("Could not get device number for device %s: %s\n", logical_drive, WindowsErrorString()); } else if (device_number.DeviceNumber == DriveIndex) { if (drive_letter != NULL) *drive_letter = *drive; if (drive_type != NULL) *drive_type = _drive_type; break; } } out: return r; }
/* * Returns the first drive letter for a volume located on the drive identified by DriveIndex */ char GetDriveLetter(DWORD DriveIndex) { DWORD size; BOOL r; STORAGE_DEVICE_NUMBER_REDEF device_number = {0}; UINT drive_type; HANDLE hDrive = INVALID_HANDLE_VALUE; char *drive, drives[26*4]; /* "D:\", "E:\", etc. */ char logical_drive[] = "\\\\.\\#:"; char drive_letter = ' '; CheckDriveIndex(DriveIndex); size = GetLogicalDriveStringsA(sizeof(drives), drives); if (size == 0) { uprintf("GetLogicalDriveStrings failed: %s\n", WindowsErrorString()); goto out; } if (size > sizeof(drives)) { uprintf("GetLogicalDriveStrings: buffer too small (required %d vs %d)\n", size, sizeof(drives)); goto out; } for (drive = drives ;*drive; drive += safe_strlen(drive)+1) { if (!isalpha(*drive)) continue; *drive = (char)toupper((int)*drive); if (*drive < 'C') { continue; } /* IOCTL_STORAGE_GET_DEVICE_NUMBER's STORAGE_DEVICE_NUMBER.DeviceNumber is not unique! An HDD, a DVD and probably other drives can have the same value there => Use GetDriveType() to filter out unwanted devices. See https://github.com/pbatard/rufus/issues/32 for details. */ drive_type = GetDriveTypeA(drive); // NB: the HP utility allows drive_type == DRIVE_FIXED, which we don't allow by default // Using Alt-F in Rufus does enable listing, but this mode is unsupported. if ((drive_type != DRIVE_REMOVABLE) && ((!enable_fixed_disks) || (drive_type != DRIVE_FIXED))) continue; safe_sprintf(logical_drive, sizeof(logical_drive), "\\\\.\\%c:", drive[0]); hDrive = CreateFileA(logical_drive, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); if (hDrive == INVALID_HANDLE_VALUE) { uprintf("Warning: could not open drive %c: %s\n", drive[0], WindowsErrorString()); continue; } r = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &device_number, sizeof(device_number), &size, NULL); safe_closehandle(hDrive); if ((!r) || (size <= 0)) { uprintf("Could not get device number for device %s: %s\n", logical_drive, WindowsErrorString()); } else if (device_number.DeviceNumber == DriveIndex) { drive_letter = *drive; break; } } out: return drive_letter; }