From 4da36fa321a8b69df043c9ae9a7319f3f6bbffe9 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 8 Apr 2013 00:10:58 +0100 Subject: [PATCH] [core] low level drive handling redesign * Better split of physical vs logical * Add handling of unmounted volumes by GUID * Force large FAT32 cheat mode * Improve user messages and fix some UI issues --- src/drive.c | 399 +++++++++++++++++++++++++++++++++++-------------- src/format.c | 164 +++++++++++++------- src/rufus.c | 20 ++- src/rufus.h | 20 ++- src/rufus.rc | 10 +- src/stdio.c | 4 + src/syslinux.c | 6 +- 7 files changed, 434 insertions(+), 189 deletions(-) diff --git a/src/drive.c b/src/drive.c index 98a97fed..53a1fa62 100644 --- a/src/drive.c +++ b/src/drive.c @@ -38,106 +38,42 @@ RUFUS_DRIVE_INFO SelectedDrive; extern BOOL enable_fixed_disks; /* - * Open a drive or volume with optional write and lock access - * Returns INVALID_HANDLE_VALUE (/!\ which is DIFFERENT from NULL /!\) on failure. - * This call is quite risky (left unchecked, inadvertently passing 0 as index would - * return a handle to C:, which we might then proceed to unknowingly repartition!), - * so we apply the following mitigation factors: - * - Valid indexes must belong to a specific range [DRIVE_INDEX_MIN; DRIVE_INDEX_MAX] - * - When opening for write access, we lock the volume. If that fails, which would - * typically be the case on C:\ or any other drive in use, we report failure - * - We report the full path of any drive that was successfully opened for write acces + * Working with drive indexes quite risky (left unchecked,inadvertently passing 0 as + * index would return a handle to C:, which we might then proceed to unknowingly + * clear the MBR of!), so we mitigate the risk by forcing our indexes to belong to + * the specific range [DRIVE_INDEX_MIN; DRIVE_INDEX_MAX]. */ -HANDLE GetDriveHandle(DWORD DriveIndex, char* DriveLetter, BOOL bWriteAccess, BOOL bLockDrive) +#define CheckDriveIndex(DriveIndex) do { \ + if ((DriveIndex < DRIVE_INDEX_MIN) || (DriveIndex > DRIVE_INDEX_MAX)) { \ + uprintf("WARNING: Bad index value. Please check the code!\n"); \ + goto out; \ + } \ + DriveIndex -= DRIVE_INDEX_MIN; } while (0) + +/* + * Open a drive or volume with optional write and lock access + * Return INVALID_HANDLE_VALUE (/!\ which is DIFFERENT from NULL /!\) on failure. + */ +static HANDLE GetHandle(char* Path, BOOL bWriteAccess, BOOL bLockDrive) { - BOOL r; DWORD size; HANDLE hDrive = INVALID_HANDLE_VALUE; - STORAGE_DEVICE_NUMBER_REDEF device_number = {0}; - UINT drive_type; - char drives[26*4]; /* "D:\", "E:\", etc. */ - char *drive = drives; - char logical_drive[] = "\\\\.\\#:"; - char physical_drive[24]; - DriveIndex &= DRIVE_INDEX_MASK; - if ((DriveIndex < DRIVE_INDEX_MIN) || (DriveIndex > DRIVE_INDEX_MAX)) { - uprintf("WARNING: Bad index value. Please check the code!\n"); + if (Path == NULL) + goto out; + hDrive = CreateFileA(Path, GENERIC_READ|(bWriteAccess?GENERIC_WRITE:0), + FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); + if (hDrive == INVALID_HANDLE_VALUE) { + uprintf("Could not open drive %s: %s\n", Path, WindowsErrorString()); + goto out; } - DriveIndex -= DRIVE_INDEX_MIN; - // If no drive letter is requested, open a physical drive - if (DriveLetter == NULL) { - safe_sprintf(physical_drive, sizeof(physical_drive), "\\\\.\\PHYSICALDRIVE%d", DriveIndex); - hDrive = CreateFileA(physical_drive, GENERIC_READ|(bWriteAccess?GENERIC_WRITE:0), - FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); - if (hDrive == INVALID_HANDLE_VALUE) { - uprintf("Could not open drive %s: %s\n", physical_drive, WindowsErrorString()); - goto out; - } - if (bWriteAccess) { - uprintf("Caution: Opened %s drive for write access\n", &physical_drive[4]); - } - } else { - *DriveLetter = ' '; - 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; - } - - hDrive = INVALID_HANDLE_VALUE; - for ( ;*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|(bWriteAccess?GENERIC_WRITE:0), - 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); - if ((!r) || (size <= 0)) { - uprintf("IOCTL_STORAGE_GET_DEVICE_NUMBER failed for device %s: %s\n", - logical_drive, WindowsErrorString()); - } else if (device_number.DeviceNumber == DriveIndex) { - break; - } - safe_closehandle(hDrive); - } - if (hDrive == INVALID_HANDLE_VALUE) { - goto out; - } - if (bWriteAccess) { - uprintf("Caution: Opened %s drive for write access\n", &logical_drive[4]); - } - *DriveLetter = *drive?*drive:' '; + if (bWriteAccess) { + uprintf("Caution: Opened drive %s for write access\n", Path); } if ((bLockDrive) && (!DeviceIoControl(hDrive, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &size, NULL))) { - uprintf("Could not get exclusive access to %s %s\n", logical_drive, WindowsErrorString()); + uprintf("Could not get exclusive access to device %s: %s\n", Path, WindowsErrorString()); safe_closehandle(hDrive); goto out; } @@ -146,12 +82,244 @@ out: return hDrive; } +/* + * 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]; + char* r = NULL; + + CheckDriveIndex(DriveIndex); + safe_sprintf(physical_name, sizeof(physical_name), "\\\\.\\PHYSICALDRIVE%d", DriveIndex); + success = TRUE; +out: + return (success)?safe_strdup(physical_name):NULL; +} + +/* + * Return a handle to the physical drive identified by DriveIndex + */ +HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bWriteAccess, BOOL bLockDrive) +{ + HANDLE hPhysical = INVALID_HANDLE_VALUE; + char* PhysicalPath = GetPhysicalName(DriveIndex); + hPhysical = GetHandle(PhysicalPath, bWriteAccess, bLockDrive); + safe_free(PhysicalPath); + return hPhysical; +} + +// 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 +// TODO: a drive may have multiple volumes - should we handle those? +char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash) +{ + 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" }; + + 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) { + uprintf("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) { + uprintf("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, "\\\\?\\", 4) != 0) || (volume_name[len-1] != '\\')) { + uprintf("'%s' is not a GUID volume name\n", volume_name); + continue; + } + + drive_type = GetDriveTypeA(volume_name); + // 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; + + volume_name[len-1] = 0; + + if (QueryDosDeviceA(&volume_name[4], path, sizeof(path)) == 0) { + uprintf("Failed to get device path for GUID volume '%s': %s\n", volume_name, WindowsErrorString()); + continue; + } + + for (j=0; (j= 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; +} + +/* + * Return a handle to the first logical volume on the disk identified by DriveIndex + */ +HANDLE GetLogicalHandle(DWORD DriveIndex, BOOL bWriteAccess, BOOL bLockDrive) +{ + HANDLE hLogical = INVALID_HANDLE_VALUE; + char* LogicalPath = GetLogicalName(DriveIndex, FALSE); + hLogical = GetHandle(LogicalPath, bWriteAccess, bLockDrive); + safe_free(LogicalPath); + return hLogical; +} + +/* + * Returns the first drive letter for a volume located on the drive identified by DriveIndex + * TODO: should we return all the drive letters? + */ +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; +} + +/* + * Return the next unused drive letter from the system + */ +char GetUnusedDriveLetter(void) +{ + DWORD size; + char drive_letter, *drive, drives[26*4]; /* "D:\", "E:\", etc. */ + + 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_letter = 'C'; drive_letter < 'Z'; drive_letter++) { + for (drive = drives ;*drive; drive += safe_strlen(drive)+1) { + if (!isalpha(*drive)) + continue; + if (drive_letter == (char)toupper((int)*drive)) + break; + } + if (!*drive) + break; + } + +out: + return (drive_letter>'Z')?' ':drive_letter; +} + /* * Return the drive letter and volume label + * If the drive doesn't have a volume assigned, space is returned for the letter */ BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label) { - HANDLE hDrive, hPhysical; + HANDLE hPhysical; DWORD size; char AutorunPath[] = "#:\\autorun.inf", *AutorunLabel = NULL; wchar_t wDrivePath[] = L"#:\\"; @@ -160,19 +328,19 @@ BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label) *label = STR_NO_LABEL; - hDrive = GetDriveHandle(DriveIndex, letter, FALSE, FALSE); - if (hDrive == INVALID_HANDLE_VALUE) { - // Assume we have a raw drive without volume assigned if enable_fixed_disk is true - return enable_fixed_disks; + *letter = GetDriveLetter(DriveIndex); + if (*letter == ' ') { + // Drive without volume assigned + // TODO: only with fixed? + return TRUE; } - safe_closehandle(hDrive); AutorunPath[0] = *letter; wDrivePath[0] = *letter; // Try to read an extended label from autorun first. Fallback to regular label if not found. // In the case of card readers with no card, users can get an annoying popup asking them // to insert media. Use IOCTL_STORAGE_CHECK_VERIFY to prevent this - hPhysical = GetDriveHandle(DriveIndex, NULL, FALSE, FALSE); + hPhysical = GetPhysicalHandle(DriveIndex, FALSE, FALSE); if (DeviceIoControl(hPhysical, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, &size, NULL)) AutorunLabel = get_token_data_file("label", AutorunPath); else if (GetLastError() == ERROR_NOT_READY) @@ -196,28 +364,29 @@ BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label) /* * Fill the drive properties (size, FS, etc) */ -BOOL GetDrivePartitionData(DWORD DeviceNumber, char* FileSystemName, DWORD FileSystemNameSize) +BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSystemNameSize) { BOOL r; - HANDLE hDrive; + HANDLE hPhysical; DWORD size; BYTE geometry[128], layout[1024], part_type; void* disk_geometry = (void*)geometry; void* drive_layout = (void*)layout; PDISK_GEOMETRY_EX DiskGeometry = (PDISK_GEOMETRY_EX)disk_geometry; PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)drive_layout; - char DrivePath[] = "#:\\", tmp[256]; + char* volume_name; + char tmp[256]; DWORD i, nb_partitions = 0; - hDrive = GetDriveHandle(DeviceNumber, NULL, FALSE, FALSE); - if (hDrive == INVALID_HANDLE_VALUE) + hPhysical = GetPhysicalHandle(DriveIndex, FALSE, FALSE); + if (hPhysical == INVALID_HANDLE_VALUE) return FALSE; - r = DeviceIoControl(hDrive, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, + r = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, geometry, sizeof(geometry), &size, NULL); if (!r || size <= 0) { - uprintf("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX failed for drive %c: %s\n", DrivePath[0], WindowsErrorString()); - safe_closehandle(hDrive); + uprintf("Could not get geometry for drive #%d: %s\n", DriveIndex, WindowsErrorString()); + safe_closehandle(hPhysical); return FALSE; } SelectedDrive.DiskSize = DiskGeometry->DiskSize.QuadPart; @@ -226,10 +395,10 @@ BOOL GetDrivePartitionData(DWORD DeviceNumber, char* FileSystemName, DWORD FileS uprintf("Cylinders: %lld, TracksPerCylinder: %d, SectorsPerTrack: %d\n", DiskGeometry->Geometry.Cylinders, DiskGeometry->Geometry.TracksPerCylinder, DiskGeometry->Geometry.SectorsPerTrack); - r = DeviceIoControl(hDrive, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, + r = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, layout, sizeof(layout), &size, NULL ); if (!r || size <= 0) { - uprintf("IOCTL_DISK_GET_DRIVE_LAYOUT_EX failed for drive %c: %s\n", DrivePath[0], WindowsErrorString()); + uprintf("Could not get layout for drive #d: %s\n", DriveIndex, WindowsErrorString()); return FALSE; } @@ -281,17 +450,23 @@ BOOL GetDrivePartitionData(DWORD DeviceNumber, char* FileSystemName, DWORD FileS uprintf("Partition type: RAW\n"); break; } - safe_closehandle(hDrive); + safe_closehandle(hPhysical); // Populate the filesystem data - if (!GetVolumeInformationA(DrivePath, NULL, 0, NULL, NULL, NULL, FileSystemName, FileSystemNameSize)) { + volume_name = GetLogicalName(DriveIndex, TRUE); + if ((volume_name == NULL) || (!GetVolumeInformationA(volume_name, NULL, 0, NULL, NULL, NULL, FileSystemName, FileSystemNameSize))) { + uprintf("Did not get volume information for disk 0x%02x\n", DriveIndex); FileSystemName[0] = 0; } + safe_free(volume_name); return TRUE; } -BOOL UnmountDrive(HANDLE hDrive) +/* + * Unmount of volume using the DISMOUNT_VOLUME ioctl + */ +BOOL UnmountVolume(HANDLE hDrive) { DWORD size; @@ -439,7 +614,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m r = DeviceIoControl(hDrive, IOCTL_DISK_CREATE_DISK, (BYTE*)&CreateDisk, size, NULL, 0, &size, NULL ); if (!r) { - uprintf("IOCTL_DISK_CREATE_DISK failed: %s\n", WindowsErrorString()); + uprintf("Could not reset disk: %s\n", WindowsErrorString()); safe_closehandle(hDrive); return FALSE; } @@ -448,7 +623,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m r = DeviceIoControl(hDrive, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, (BYTE*)&DriveLayoutEx, size, NULL, 0, &size, NULL ); if (!r) { - uprintf("IOCTL_DISK_SET_DRIVE_LAYOUT_EX failed: %s\n", WindowsErrorString()); + uprintf("Could not set drive layout: %s\n", WindowsErrorString()); safe_closehandle(hDrive); return FALSE; } diff --git a/src/format.c b/src/format.c index 437515c5..f40432e9 100644 --- a/src/format.c +++ b/src/format.c @@ -54,6 +54,7 @@ static int task_number = 0; /* Number of steps for each FS for FCC_STRUCTURE_PROGRESS */ const int nb_steps[FS_MAX] = { 5, 5, 12, 10 }; static int fs_index = 0; +BOOL force_large_fat32 = FALSE; /* * FormatEx callback. Return FALSE to halt operations @@ -274,6 +275,7 @@ static void ToValidLabel(WCHAR* name, BOOL bFAT) * ----- * 1d02h */ +// TODO: use that for Format "classic" static DWORD GetVolumeID(void) { SYSTEMTIME s; @@ -331,7 +333,6 @@ static DWORD GetFATSizeSectors(DWORD DskSize, DWORD ReservedSecCnt, DWORD SecPer static BOOL FormatFAT32(DWORD DriveIndex) { BOOL r = FALSE; - char DriveLetter; DWORD i; HANDLE hLogicalVolume; DWORD cbRet; @@ -342,7 +343,8 @@ static BOOL FormatFAT32(DWORD DriveIndex) DWORD NumFATs = 2; DWORD BackupBootSect = 6; DWORD VolumeId = 0; // calculated before format - WCHAR wLabel[64], wDriveName[] = L"#:\\"; + char* VolumeName = NULL; + WCHAR wLabel[64], *wVolumeName = NULL; DWORD BurstSize = 128; // Zero in blocks of 64K typically // Calculated later @@ -365,18 +367,17 @@ static BOOL FormatFAT32(DWORD DriveIndex) // Debug temp vars ULONGLONG FatNeeded, ClusterCount; - PrintStatus(0, TRUE, "Formatting..."); - uprintf("Using large FAT32 format method\n"); + PrintStatus(0, TRUE, "Formatting (Large FAT32)..."); VolumeId = GetVolumeID(); // Open the drive (volume should already be locked) - hLogicalVolume = GetDriveHandle(DriveIndex, &DriveLetter, TRUE, FALSE); + hLogicalVolume = GetLogicalHandle(DriveIndex, TRUE, FALSE); if (IS_ERROR(FormatStatus)) goto out; if (hLogicalVolume == INVALID_HANDLE_VALUE) die("Could not access logical volume\n", ERROR_OPEN_FAILED); // Make sure we get exclusive access - if (!UnmountDrive(hLogicalVolume)) + if (!UnmountVolume(hLogicalVolume)) return r; // Work out drive params @@ -526,7 +527,7 @@ static BOOL FormatFAT32(DWORD DriveIndex) } // Now we're commited - print some info first - uprintf("Size : %gGB %u sectors\n", (double) (piDrive.PartitionLength.QuadPart / (1000*1000*1000)), TotalSectors); + uprintf("Size : %s %u sectors\n", SizeToHumanReadable(piDrive.PartitionLength), TotalSectors); uprintf("Cluster size %d bytes, %d Bytes Per Sector\n", SectorsPerCluster*BytesPerSect, BytesPerSect); uprintf("Volume ID is %x:%x\n", VolumeId>>16, VolumeId&0xffff); uprintf("%d Reserved Sectors, %d Sectors per FAT, %d FATs\n", ReservedSectCount, FatSize, NumFATs); @@ -578,18 +579,22 @@ static BOOL FormatFAT32(DWORD DriveIndex) // Set the FAT32 volume label GetWindowTextW(hLabel, wLabel, ARRAYSIZE(wLabel)); ToValidLabel(wLabel, TRUE); - wDriveName[0] = DriveLetter; // Handle must be closed for SetVolumeLabel to work safe_closehandle(hLogicalVolume); - - PrintStatus(0, TRUE, "Setting Label (This can take while)..."); - if (!SetVolumeLabelW(wDriveName, wLabel)) { + PrintStatus(0, TRUE, "Setting Label (This may take while)..."); + VolumeName = GetLogicalName(DriveIndex, TRUE); + wVolumeName = utf8_to_wchar(VolumeName); + if ((wVolumeName == NULL) || (!SetVolumeLabelW(wVolumeName, wLabel))) { uprintf("Could not set label: %s\n", WindowsErrorString()); + // Non fatal error } + uprintf("Format completed.\n"); r = TRUE; out: + safe_free(VolumeName); + safe_free(wVolumeName); safe_closehandle(hLogicalVolume); safe_free(pFAT32BootSect); safe_free(pFAT32FsInfo); @@ -601,18 +606,28 @@ out: /* * Call on fmifs.dll's FormatEx() to format the drive */ -static BOOL FormatDrive(char DriveLetter) +static BOOL FormatDrive(DWORD DriveIndex) { BOOL r = FALSE; PF_DECL(FormatEx); - WCHAR wDriveRoot[] = L"?:\\"; + char* VolumeName = NULL; + WCHAR* wVolumeName = NULL; + char FSType[32], format_status[64]; WCHAR wFSType[32]; WCHAR wLabel[64]; size_t i; char* locale; - wDriveRoot[0] = (WCHAR)DriveLetter; - PrintStatus(0, TRUE, "Formatting..."); + GetWindowTextA(hFileSystem, FSType, ARRAYSIZE(FSType)); + safe_sprintf(format_status, ARRAYSIZE(format_status), "Formatting (%s)...", FSType); + PrintStatus(0, TRUE, format_status); + VolumeName = GetLogicalName(DriveIndex, FALSE); + wVolumeName = utf8_to_wchar(VolumeName); + if (wVolumeName == NULL) { + uprintf("Could not read volume name\n"); + goto out; + } + // LoadLibrary("fmifs.dll") appears to changes the locale, which can lead to // problems with tolower(). Make sure we restore the locale. For more details, // see http://comments.gmane.org/gmane.comp.gnu.mingw.user/39300 @@ -635,7 +650,7 @@ static BOOL FormatDrive(char DriveLetter) format_percent = 0.0f; task_number = 0; fs_index = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem)); - pfFormatEx(wDriveRoot, SelectedDrive.Geometry.MediaType, wFSType, wLabel, + pfFormatEx(wVolumeName, SelectedDrive.Geometry.MediaType, wFSType, wLabel, IsChecked(IDC_QUICKFORMAT), (ULONG)ComboBox_GetItemData(hClusterSize, ComboBox_GetCurSel(hClusterSize)), FormatExCallback); if (!IS_ERROR(FormatStatus)) { @@ -644,6 +659,8 @@ static BOOL FormatDrive(char DriveLetter) } out: + safe_free(VolumeName); + safe_free(wVolumeName); return r; } @@ -737,12 +754,14 @@ static BOOL AnalyzePBR(HANDLE hLogicalVolume) } else if (entire_fat_32_fd_br_matches(&fake_fd)) { uprintf("Drive has a FAT32 FreeDOS partition boot record\n"); } else { - uprintf("Drive has a unknown FAT16 or FAT32 partition boot record\n"); + uprintf("Drive has an unknown FAT16 or FAT32 partition boot record\n"); } } return TRUE; } +// TODO: We may have to clear a few more sectors past the MBR buffer zone +// so that Windows relinquishes access static BOOL ClearMBRGPT(HANDLE hPhysicalDrive, LONGLONG DiskSize, DWORD SectorSize) { BOOL r = FALSE; @@ -1138,15 +1157,24 @@ DWORD WINAPI CloseFormatPromptThread(LPVOID param) { /* * Standalone thread for the formatting operation + * According to http://msdn.microsoft.com/en-us/library/windows/desktop/aa364562.aspx + * To change a volume file system + * Open a volume. + * Lock the volume. + * Format the volume. + * Dismount the volume. + * Unlock the volume. + * Close the volume handle. */ DWORD WINAPI FormatThread(LPVOID param) { int r, pt, bt, fs, dt; - BOOL ret, no_volume = FALSE; - DWORD num = (DWORD)(uintptr_t)param; + BOOL ret; + DWORD DriveIndex = (DWORD)(uintptr_t)param; HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE; HANDLE hLogicalVolume = INVALID_HANDLE_VALUE; SYSTEMTIME lt; + char* guid_volume = NULL; char drive_name[] = "?:\\"; char bb_msg[512]; char logfile[MAX_PATH], *userdir; @@ -1159,34 +1187,41 @@ DWORD WINAPI FormatThread(LPVOID param) pt = GETPARTTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme))); bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme))); - if (num & DRIVE_INDEX_RAW_DRIVE) { - no_volume = TRUE; - uprintf("Using raw drive mode\n"); - } - - hPhysicalDrive = GetDriveHandle(num, NULL, TRUE, TRUE); + PrintStatus(0, TRUE, "Requesting disk access...\n"); + hPhysicalDrive = GetPhysicalHandle(DriveIndex, TRUE, TRUE); if (hPhysicalDrive == INVALID_HANDLE_VALUE) { FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; goto out; } - // At this stage with have both a handle and a lock to the physical drive... - // ... but we can't write sectors that are part of a volume, even if we have - // access to physical, unless we have a lock (which doesn't have to be write) - // Also, having a volume handle allows us to unmount the volume - if (!no_volume) { - hLogicalVolume = GetDriveHandle(num, drive_name, FALSE, TRUE); - if (hLogicalVolume == INVALID_HANDLE_VALUE) { - uprintf("Could not lock volume\n"); - FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; + // At this stage with have both a handle and a lock to the physical drive... + drive_name[0] = GetDriveLetter(DriveIndex); + if (drive_name[0] == ' ') { + uprintf("No drive letter was assigned...\n"); + drive_name[0] = GetUnusedDriveLetter(); + if (drive_name[0] == ' ') { + uprintf("Could not find a suitable drive letter\n"); + FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_ASSIGN_LETTER); goto out; } - UnmountDrive(hLogicalVolume); + } else if (!DeleteVolumeMountPointA(drive_name)) { + uprintf("Failed to delete mountpoint %s: %s\n", drive_name, WindowsErrorString()); + // TODO: generate an error? } + uprintf("Will use '%c': as volume mountpoint\n", drive_name[0]); + hLogicalVolume = GetLogicalHandle(DriveIndex, FALSE, TRUE); + if (hLogicalVolume == INVALID_HANDLE_VALUE) { + uprintf("Could not lock volume\n"); + FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; + goto out; + } + UnmountVolume(hLogicalVolume); + + PrintStatus(0, TRUE, "Analyzing existing boot records...\n"); AnalyzeMBR(hPhysicalDrive); - if (!no_volume) - AnalyzePBR(hLogicalVolume); + AnalyzePBR(hLogicalVolume); + UpdateProgress(OP_ANALYZE_MBR, -1.0f); if (IsChecked(IDC_BADBLOCKS)) { do { @@ -1249,8 +1284,17 @@ DWORD WINAPI FormatThread(LPVOID param) } } // Close the (unmounted) volume before formatting, but keep the lock - if (!no_volume) - safe_closehandle(hLogicalVolume); + // According to MS this relinquishes the lock, so... + PrintStatus(0, TRUE, "Closing existing volume...\n"); + if (!CloseHandle(hLogicalVolume)) { + uprintf("Could not close volume: %s\n", WindowsErrorString()); + FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED; + goto out; + } + hLogicalVolume = INVALID_HANDLE_VALUE; + + // TODO: check for cancel once in a while! + // TODO: our start button should become cancel instead of close // Especially after destructive badblocks test, you must zero the MBR/GPT completely // before repartitioning. Else, all kind of bad things can happen. @@ -1272,28 +1316,24 @@ DWORD WINAPI FormatThread(LPVOID param) // Add a small delay after partitioning to be safe Sleep(200); - if (no_volume) { - hLogicalVolume = GetDriveHandle(num, drive_name, FALSE, TRUE); - if (hLogicalVolume == INVALID_HANDLE_VALUE) { - uprintf("Could not lock volume\n"); - FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; - goto out; - } - UnmountDrive(hLogicalVolume); - safe_closehandle(hLogicalVolume); - } - - // If FAT32 is requested and we have a large drive (>32 GB) use // large FAT32 format, else use MS's FormatEx. - ret = ((fs == FS_FAT32) && (SelectedDrive.DiskSize > LARGE_FAT32_SIZE))? - FormatFAT32(num):FormatDrive(drive_name[0]); + ret = ((fs == FS_FAT32) && ((SelectedDrive.DiskSize > LARGE_FAT32_SIZE) || (force_large_fat32)))? + FormatFAT32(DriveIndex):FormatDrive(DriveIndex); if (!ret) { // Error will be set by FormatDrive() in FormatStatus uprintf("Format error: %s\n", StrError(FormatStatus)); goto out; } + guid_volume = GetLogicalName(DriveIndex, TRUE); + if (guid_volume == NULL) { + uprintf("Could not get GUID volume name\n"); + FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NO_VOLUME_ID; + goto out; + } + uprintf("Found volume GUID %s\n", guid_volume); + if (pt == PARTITION_STYLE_MBR) { PrintStatus(0, TRUE, "Writing master boot record..."); if (!WriteMBR(hPhysicalDrive)) { @@ -1304,6 +1344,12 @@ DWORD WINAPI FormatThread(LPVOID param) UpdateProgress(OP_FIX_MBR, -1.0f); } + if (!SetVolumeMountPointA(drive_name, guid_volume)) { + uprintf("Could not remount %s on %s: %s\n", guid_volume, drive_name, WindowsErrorString()); + FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_MOUNT_VOLUME); + goto out; + } + if (IsChecked(IDC_BOOT)) { if (bt == BT_UEFI) { // For once, no need to do anything - just check our sanity @@ -1315,7 +1361,7 @@ DWORD WINAPI FormatThread(LPVOID param) } else if ((dt == DT_WINME) || (dt == DT_FREEDOS) || ((dt == DT_ISO) && (fs == FS_NTFS))) { // We still have a lock, which we need to modify the volume boot record // => no need to reacquire the lock... - hLogicalVolume = GetDriveHandle(num, drive_name, TRUE, FALSE); + hLogicalVolume = GetLogicalHandle(DriveIndex, TRUE, FALSE); if (hLogicalVolume == INVALID_HANDLE_VALUE) { uprintf("Could not re-mount volume for partition boot record access\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; @@ -1333,7 +1379,7 @@ DWORD WINAPI FormatThread(LPVOID param) safe_unlockclose(hLogicalVolume); } else if ( (dt == DT_SYSLINUX) || ((dt == DT_ISO) && ((fs == FS_FAT16) || (fs == FS_FAT32))) ) { PrintStatus(0, TRUE, "Installing Syslinux..."); - if (!InstallSyslinux(num, drive_name)) { + if (!InstallSyslinux(DriveIndex, drive_name[0])) { FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INSTALL_FAILURE; } } @@ -1368,7 +1414,8 @@ DWORD WINAPI FormatThread(LPVOID param) goto out; } if ((bt == BT_UEFI) && (!iso_report.has_efi) && (iso_report.has_win7_efi)) { - // TODO: progress + // TODO: better progress + // TODO: check ISO with EFI only PrintStatus(0, TRUE, "Win7 EFI boot setup (this may take a while)..."); wim_image[0] = drive_name[0]; efi_dst[0] = drive_name[0]; @@ -1392,7 +1439,7 @@ DWORD WINAPI FormatThread(LPVOID param) } } UpdateProgress(OP_FINALIZE, -1.0f); - PrintStatus(0, TRUE, "Finalizing..."); + PrintStatus(0, TRUE, "Finalizing, please wait..."); if (IsChecked(IDC_SET_ICON)) SetAutorun(drive_name); // Issue another complete remount before we exit, to ensure we're clean @@ -1405,9 +1452,10 @@ DWORD WINAPI FormatThread(LPVOID param) } out: + safe_free(guid_volume); SendMessage(hISOProgressDlg, UM_ISO_EXIT, 0, 0); safe_unlockclose(hLogicalVolume); - safe_unlockclose(hPhysicalDrive); + safe_unlockclose(hPhysicalDrive); // This can take a while PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0); ExitThread(0); } diff --git a/src/rufus.c b/src/rufus.c index c2f018ad..8774adee 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -93,6 +93,7 @@ static BOOL existing_key = FALSE; // For LGP set/restore static BOOL iso_size_check = TRUE; static BOOL log_displayed = FALSE; static BOOL iso_provided = FALSE; +extern BOOL force_large_fat32; static int selection_default; /* @@ -605,7 +606,7 @@ static BOOL GetUSBDevices(DWORD devnum) // We can afford a failure on this call - just replace the name safe_strcpy(buffer, sizeof(buffer), generic_friendly_name); } - uprintf("Found drive '%s'\n", buffer); + uprintf("Found device '%s'\n", buffer); devint_data.cbSize = sizeof(devint_data); hDrive = INVALID_HANDLE_VALUE; @@ -617,6 +618,8 @@ static BOOL GetUSBDevices(DWORD devnum) if (!SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, &_GUID_DEVINTERFACE_DISK, j, &devint_data)) { if(GetLastError() != ERROR_NO_MORE_ITEMS) { uprintf("SetupDiEnumDeviceInterfaces failed: %s\n", WindowsErrorString()); + } else { + uprintf("Device was eliminated because it doesn't report itself as a disk\n"); } break; } @@ -669,7 +672,6 @@ static BOOL GetUSBDevices(DWORD devnum) // Drive letter ' ' is returned for drives that don't have a volume assigned yet if (drive_letter == ' ') { safe_sprintf(entry, sizeof(entry), "%s (Disk %d)", label, device_number.DeviceNumber); - device_number.DeviceNumber |= DRIVE_INDEX_RAW_DRIVE; } else { safe_sprintf(entry, sizeof(entry), "%s (%c:)", label, drive_letter); } @@ -722,6 +724,7 @@ static void InitProgress(void) memset(slot_end, 0, sizeof(slot_end)); previous_end = 0.0f; + nb_slots[OP_ANALYZE_MBR] = 1; nb_slots[OP_ZERO_MBR] = 1; if (IsChecked(IDC_BADBLOCKS)) { nb_slots[OP_BADBLOCKS] = -1; @@ -751,7 +754,7 @@ static void InitProgress(void) || ((fs == FS_FAT32) && (SelectedDrive.DiskSize >= LARGE_FAT32_SIZE)) ) { nb_slots[OP_FORMAT] = -1; } - nb_slots[OP_FINALIZE] = ((dt == DT_ISO) && (fs == FS_NTFS))?2:1; + nb_slots[OP_FINALIZE] = ((dt == DT_ISO) && (fs == FS_NTFS))?3:2; for (i=0; i 0) { @@ -1015,7 +1018,6 @@ DWORD WINAPI ISOScanThread(LPVOID param) safe_free(iso_path); goto out; } - // TODO: 4GB and UEFI = BAD!!! uprintf("ISO label: '%s'\r\n Size: %lld bytes\r\n Has a >4GB file: %s\r\n Uses EFI: %s%s\r\n Uses Bootmgr: %s\r\n Uses WinPE: %s%s\r\n Uses isolinux: %s\n", iso_report.label, iso_report.projected_size, iso_report.has_4GB_file?"Yes":"No", (iso_report.has_efi || iso_report.has_win7_efi)?"Yes":"No", (iso_report.has_win7_efi && (!iso_report.has_efi))?" (win7_x64)":"", iso_report.has_bootmgr?"Yes":"No", @@ -1391,6 +1393,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA user_changed_label = FALSE; return (INT_PTR)TRUE; case DBT_DEVNODES_CHANGED: + // TODO: figure out what the deal is with extra events when FILE_SHARE_WRITE is not enabled // If it's been more than a second since last device refresh, arm a refresh timer if (GetTickCount() > LastRefresh + 1000) { LastRefresh = GetTickCount(); @@ -1673,6 +1676,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_START_THREAD); PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0); } + PrintStatus(0, FALSE, ""); timer = 0; safe_sprintf(szTimer, sizeof(szTimer), "00:00:00"); SendMessageA(GetDlgItem(hMainDialog, IDC_STATUS), SB_SETTEXTA, @@ -1906,6 +1910,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine UpdateWindow(hDlg); // Do our own event processing and process "magic" commands + // TODO: Cheat modes are not handled when the log is at the front - this sucks while(GetMessage(&msg, NULL, 0, 0)) { // The following ensures the processing of the ISO progress window messages if (!IsWindow(hISOProgressDlg) || !IsDialogMessage(hISOProgressDlg, &msg)) { @@ -1917,6 +1922,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine PrintStatus2000("ISO size check", iso_size_check); continue; } + // TODO: move this option to advanced mode // Alt-F => Toggle detection of fixed disks // By default Rufus does not allow formatting USB fixed disk drives, such as USB HDDs // This is a safety feature, to avoid someone unintentionally formatting a backup @@ -1927,6 +1933,12 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine GetUSBDevices(0); continue; } + // Alt-L => Force Large FAT32 format to be used on < 32 GB drives + if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'L')) { + force_large_fat32 = !force_large_fat32; + PrintStatus2000("Force large FAT32 usage", force_large_fat32); + continue; + } // Alt-D => Delete the NoDriveTypeAutorun key on exit (useful if the app crashed) // This key is used to disable Windows popup messages when an USB drive is plugged in. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'D')) { diff --git a/src/rufus.h b/src/rufus.h index 9005a69a..3baea103 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -38,8 +38,6 @@ #define RUFUS_BLOCKING_IO_TITLE APPLICATION_NAME " - Flushing buffers" #define DRIVE_INDEX_MIN 0x00000080 #define DRIVE_INDEX_MAX 0x000000C0 -#define DRIVE_INDEX_MASK 0x0000FFFF -#define DRIVE_INDEX_RAW_DRIVE 0x00010000 // Additional drive properties stored in the drive index #define MAX_DRIVES (DRIVE_INDEX_MAX - DRIVE_INDEX_MIN) #define MAX_TOOLTIPS 32 #define MAX_PROGRESS (0xFFFF-1) // leave room for 1 more for insta-progress workaround @@ -135,6 +133,7 @@ enum timer_type { /* Action type, for progress bar breakdown */ enum action_type { + OP_ANALYZE_MBR, OP_BADBLOCKS, OP_ZERO_MBR, OP_PARTITION, @@ -296,14 +295,19 @@ extern BOOL Question(char* title, char* format, ...); extern BOOL ExtractDOS(const char* path); extern BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan); extern BOOL ExtractISOFile(const char* iso, const char* iso_file, const char* dest_file); -extern BOOL InstallSyslinux(DWORD num, const char* drive_name); +extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter); DWORD WINAPI FormatThread(void* param); +extern char* GetPhysicalName(DWORD DriveIndex); +extern HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bWriteAccess, BOOL bLockDrive); +extern char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash); +extern HANDLE GetLogicalHandle(DWORD DriveIndex, BOOL bWriteAccess, BOOL bLockDrive); +extern char GetDriveLetter(DWORD DriveIndex); +extern char GetUnusedDriveLetter(void); extern BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker); extern const char* GetPartitionType(BYTE Type); -extern BOOL GetDrivePartitionData(DWORD DeviceNumber, char* FileSystemName, DWORD FileSystemNameSize); -extern HANDLE GetDriveHandle(DWORD DriveIndex, char* DriveLetter, BOOL bWriteAccess, BOOL bLockDrive); +extern BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSystemNameSize); extern BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label); -extern BOOL UnmountDrive(HANDLE hDrive); +extern BOOL UnmountVolume(HANDLE hDrive); extern BOOL CreateProgress(void); extern BOOL SetAutorun(const char* path); extern char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_desc); @@ -397,7 +401,9 @@ typedef struct { #define ERROR_ISO_SCAN 0x1207 #define ERROR_ISO_EXTRACT 0x1208 #define ERROR_CANT_REMOUNT_VOLUME 0x1209 -#define ERROR_CANT_PATCH 0x1210 +#define ERROR_CANT_PATCH 0x120A +#define ERROR_CANT_ASSIGN_LETTER 0x120B +#define ERROR_CANT_MOUNT_VOLUME 0x120C /* More niceties */ #ifndef MIN diff --git a/src/rufus.rc b/src/rufus.rc index 861a6f52..f72ea71b 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -30,7 +30,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 206, 316 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_APPWINDOW -CAPTION "Rufus v1.3.3.239" +CAPTION "Rufus v1.3.3.240" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "Start",IDC_START,94,278,50,14 @@ -274,8 +274,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,3,3,239 - PRODUCTVERSION 1,3,3,239 + FILEVERSION 1,3,3,240 + PRODUCTVERSION 1,3,3,240 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -292,13 +292,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "1.3.3.239" + VALUE "FileVersion", "1.3.3.240" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "(c) 2011-2013 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "1.3.3.239" + VALUE "ProductVersion", "1.3.3.240" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index 84bf3d8c..a7bbfca0 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -269,6 +269,10 @@ const char* StrError(DWORD error_code) "mountvol.exe command to make your device accessible again"; case ERROR_CANT_PATCH: return "Unable to patch/setup files for boot"; + case ERROR_CANT_ASSIGN_LETTER: + return "Unable to assign a drive letter"; + case ERROR_CANT_MOUNT_VOLUME: + return "Can't mount GUID volume"; default: uprintf("Unknown error: %08X\n", error_code); SetLastError(error_code); diff --git a/src/syslinux.c b/src/syslinux.c index 1aec0ce5..6bbe1c8f 100644 --- a/src/syslinux.c +++ b/src/syslinux.c @@ -66,7 +66,7 @@ int libfat_readfile(intptr_t pp, void *buf, size_t secsize, * Extract the ldlinux.sys and ldlinux.bss from resources, * then patch and install them */ -BOOL InstallSyslinux(DWORD num, const char* drive_name) +BOOL InstallSyslinux(DWORD drive_index, char drive_letter) { HANDLE f_handle = INVALID_HANDLE_VALUE; HANDLE d_handle = INVALID_HANDLE_VALUE; @@ -84,7 +84,7 @@ BOOL InstallSyslinux(DWORD num, const char* drive_name) int nsectors; int dt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType)); - ldlinux_name[0] = drive_name[0]; + ldlinux_name[0] = drive_letter; /* Initialize the ADV -- this should be smarter */ syslinux_reset_adv(syslinux_adv); @@ -135,7 +135,7 @@ BOOL InstallSyslinux(DWORD num, const char* drive_name) } /* Reopen the volume (we already have a lock) */ - d_handle = GetDriveHandle(num, (char*)drive_name, TRUE, FALSE); + d_handle = GetLogicalHandle(drive_index, TRUE, FALSE); if (d_handle == INVALID_HANDLE_VALUE) { uprintf("Could open volume for syslinux operation\n"); goto out;