mirror of
				https://github.com/pbatard/rufus.git
				synced 2024-08-14 23:57:05 +00:00 
			
		
		
		
	[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
This commit is contained in:
		
							parent
							
								
									d56615cd20
								
							
						
					
					
						commit
						4da36fa321
					
				
					 7 changed files with 434 additions and 189 deletions
				
			
		
							
								
								
									
										399
									
								
								src/drive.c
									
										
									
									
									
								
							
							
						
						
									
										399
									
								
								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<ARRAYSIZE(ignore_device)) && | ||||
| 			(safe_strnicmp(path, ignore_device[j], safe_strlen(ignore_device[j])) != 0); j++); | ||||
| 		if (j < ARRAYSIZE(ignore_device)) { | ||||
| 			uprintf("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, 0, 0); | ||||
| 		if (hDrive == INVALID_HANDLE_VALUE) { | ||||
| 			uprintf("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)) { | ||||
| 			uprintf("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; | ||||
| } | ||||
| 
 | ||||
| /* 
 | ||||
|  * 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; | ||||
| 	} | ||||
|  |  | |||
							
								
								
									
										164
									
								
								src/format.c
									
										
									
									
									
								
							
							
						
						
									
										164
									
								
								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); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										20
									
								
								src/rufus.c
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								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<OP_MAX; i++) { | ||||
| 		if (nb_slots[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')) { | ||||
|  |  | |||
							
								
								
									
										20
									
								
								src/rufus.h
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								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 | ||||
|  |  | |||
							
								
								
									
										10
									
								
								src/rufus.rc
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								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" | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue