mirror of
				https://github.com/pbatard/rufus.git
				synced 2024-08-14 23:57:05 +00:00 
			
		
		
		
	[core] use offset rather than index to identify a partition
* Also fix potential bcdboot invocation failure by introducing a new AltGetLogicalName() call. * Also use the AltMount calls for ext# formatting
This commit is contained in:
		
							parent
							
								
									1fa0aaf325
								
							
						
					
					
						commit
						94e2015edf
					
				
					 4 changed files with 133 additions and 112 deletions
				
			
		
							
								
								
									
										156
									
								
								src/drive.c
									
										
									
									
									
								
							
							
						
						
									
										156
									
								
								src/drive.c
									
										
									
									
									
								
							|  | @ -86,7 +86,7 @@ PF_TYPE_DECL(NTAPI, NTSTATUS, NtQueryVolumeInformationFile, (HANDLE, PIO_STATUS_ | |||
|  */ | ||||
| RUFUS_DRIVE_INFO SelectedDrive; | ||||
| BOOL installed_uefi_ntfs; | ||||
| DWORD partition_index[3]; | ||||
| uint64_t partition_offset[3]; | ||||
| uint64_t persistence_size = 0; | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -245,22 +245,18 @@ out: | |||
| /*
 | ||||
|  * Return the path to access a partition on a specific disk, or NULL on error. | ||||
|  * The string is allocated and must be freed (to ensure concurrent access) | ||||
|  * If PartitionOffset is 0, the offset is ignored and the first partition found is returned. | ||||
|  */ | ||||
| char* GetPartitionName(DWORD DriveIndex, DWORD PartitionIndex) | ||||
| char* GetPartitionName(DWORD DriveIndex, uint64_t PartitionOffset) | ||||
| { | ||||
| 	BOOL success = FALSE; | ||||
| 	char partition_name[32]; | ||||
| 	DWORD i = MAX_PARTITIONS + 1; | ||||
| 
 | ||||
| 	CheckDriveIndex(DriveIndex); | ||||
| 	if (PartitionIndex >= MAX_PARTITIONS) | ||||
| 		goto out; | ||||
| 	if (PartitionIndex == 0) | ||||
| 		PartitionIndex = 1; | ||||
| 	 | ||||
| 	static_sprintf(partition_name, "\\Device\\Harddisk%lu\\Partition%lu", DriveIndex, PartitionIndex); | ||||
| 	success = TRUE; | ||||
| 	for (i = 1; (i <= MAX_PARTITIONS) && (PartitionOffset != 0) && (SelectedDrive.PartitionOffset[i - 1] != PartitionOffset); i++); | ||||
| 	static_sprintf(partition_name, "\\Device\\Harddisk%lu\\Partition%lu", DriveIndex, i); | ||||
| out: | ||||
| 	return (success) ? safe_strdup(partition_name) : NULL; | ||||
| 	return (i <= MAX_PARTITIONS) ? safe_strdup(partition_name) : NULL; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -278,11 +274,10 @@ HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bLockDrive, BOOL bWriteAccess, B | |||
| /*
 | ||||
|  * Return the GUID volume name for the disk and partition specified, or NULL if not found. | ||||
|  * See http://msdn.microsoft.com/en-us/library/cc542456.aspx
 | ||||
|  * PartitionIndex starts at 1 (for the first partition). If PartitionIndex is zero, then | ||||
|  * the first partition found by this function (which *MAY NOT* be the actual first partition) | ||||
|  * is returned. The returned string is allocated and must be freed. | ||||
|  * If PartitionOffset is 0, the offset is ignored and the first partition found is returned. | ||||
|  * The returned string is allocated and must be freed. | ||||
|  */ | ||||
| char* GetLogicalName(DWORD DriveIndex, DWORD PartitionIndex, BOOL bKeepTrailingBackslash, BOOL bSilent) | ||||
| char* GetLogicalName(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bKeepTrailingBackslash, BOOL bSilent) | ||||
| { | ||||
| 	static const char* ignore_device[] = { "\\Device\\CdRom", "\\Device\\Floppy" }; | ||||
| 	static const char* volume_start = "\\\\?\\"; | ||||
|  | @ -294,13 +289,11 @@ char* GetLogicalName(DWORD DriveIndex, DWORD PartitionIndex, BOOL bKeepTrailingB | |||
| 	UINT drive_type; | ||||
| 	StrArray found_name; | ||||
| 	uint64_t found_offset[MAX_PARTITIONS] = { 0 }; | ||||
| 	uint32_t i, j, k; | ||||
| 	uint32_t i, j; | ||||
| 	size_t len; | ||||
| 
 | ||||
| 	StrArrayCreate(&found_name, MAX_PARTITIONS); | ||||
| 	CheckDriveIndex(DriveIndex); | ||||
| 	if (PartitionIndex > MAX_PARTITIONS) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	for (i = 0; hDrive == INVALID_HANDLE_VALUE; i++) { | ||||
| 		if (i == 0) { | ||||
|  | @ -391,33 +384,14 @@ char* GetLogicalName(DWORD DriveIndex, DWORD PartitionIndex, BOOL bKeepTrailingB | |||
| 	if (found_name.Index == 0) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	// Now process all the volumes we found, and find the one that matches our partition index
 | ||||
| 	if (PartitionIndex == 0) { | ||||
| 		i = 0; | ||||
| 	} else for (i = 0, k = 0; i < found_name.Index; i++) { | ||||
| 		for (j = 0; j < found_name.Index; j++) { | ||||
| 			if (found_offset[i] > found_offset[j]) | ||||
| 				k++; | ||||
| 		} | ||||
| 		if (k == ((int)PartitionIndex) - 1) | ||||
| 			break; | ||||
| 	} | ||||
| 	if (i < found_name.Index) { | ||||
| 	// Now process all the volumes we found, and try to match one with our partition offset
 | ||||
| 	for (i = 0; (i < found_name.Index) && (PartitionOffset != 0) && (PartitionOffset != found_offset[i]); i++); | ||||
| 
 | ||||
| 	if (i < found_name.Index) | ||||
| 		ret = safe_strdup(found_name.String[i]); | ||||
| 	} else { | ||||
| 		// Some volumes, such as ESPs, are not listed by Windows, be it with VDS or other APIs.
 | ||||
| 		// For these, we return the "\\?\GLOBALROOT\Device\HarddiskVolume#" identifier that
 | ||||
| 		// matches our "Harddisk#Partition#", as reported by QueryDosDevice().
 | ||||
| 		static_sprintf(path, "Harddisk%luPartition%lu", DriveIndex, PartitionIndex); | ||||
| 		static_strcpy(volume_name, groot_name); | ||||
| 		if (!QueryDosDeviceA(path, &volume_name[groot_len], (DWORD)(MAX_PATH - groot_len)) || (strlen(volume_name) < 20)) { | ||||
| 			uprintf("Could not find the DOS volume name for '%s': %s", path, WindowsErrorString()); | ||||
| 		} else { | ||||
| 			if (bKeepTrailingBackslash) | ||||
| 				static_strcat(volume_name, "\\"); | ||||
| 			ret = safe_strdup(volume_name); | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 		// NB: We need to re-add DRIVE_INDEX_MIN for this call since CheckDriveIndex() substracted it
 | ||||
| 		ret = AltGetLogicalName(DriveIndex + DRIVE_INDEX_MIN, PartitionOffset, bKeepTrailingBackslash, bSilent); | ||||
| 
 | ||||
| out: | ||||
| 	if (hVolume != INVALID_HANDLE_VALUE) | ||||
|  | @ -426,6 +400,40 @@ out: | |||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Alternative version of the above, needed because some volumes, such as ESPs, are not listed | ||||
|  * by Windows, be it with VDS or other APIs. | ||||
|  * For these, we return the "\\?\GLOBALROOT\Device\HarddiskVolume#" identifier that matches | ||||
|  * our "Harddisk#Partition#", as reported by QueryDosDevice(). | ||||
|  * The returned string is allocated and must be freed. | ||||
| */ | ||||
| char* AltGetLogicalName(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bKeepTrailingBackslash, BOOL bSilent) | ||||
| { | ||||
| 	DWORD i; | ||||
| 	char *ret = NULL, volume_name[MAX_PATH], path[MAX_PATH]; | ||||
| 
 | ||||
| 	CheckDriveIndex(DriveIndex); | ||||
| 
 | ||||
| 	// Match the offset to a partition index
 | ||||
| 	for (i = 0; (i < MAX_PARTITIONS) && (PartitionOffset != 0) && (PartitionOffset != SelectedDrive.PartitionOffset[i]); i++); | ||||
| 	if (i >= MAX_PARTITIONS) { | ||||
| 		suprintf("Error: Could not find a partition at offset %lld on this disk", PartitionOffset); | ||||
| 		goto out; | ||||
| 	} | ||||
| 	static_sprintf(path, "Harddisk%luPartition%lu", DriveIndex, i + 1); | ||||
| 	static_strcpy(volume_name, groot_name); | ||||
| 	if (!QueryDosDeviceA(path, &volume_name[groot_len], (DWORD)(MAX_PATH - groot_len)) || (strlen(volume_name) < 20)) { | ||||
| 		suprintf("Could not find the DOS volume name for '%s': %s", path, WindowsErrorString()); | ||||
| 	} else { | ||||
| 		if (bKeepTrailingBackslash) | ||||
| 			static_strcat(volume_name, "\\"); | ||||
| 		ret = safe_strdup(volume_name); | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Call on VDS to refresh the drive layout | ||||
|  */ | ||||
|  | @ -720,7 +728,7 @@ out: | |||
| 
 | ||||
| 
 | ||||
| /* Wait for a logical drive to reappear - Used when a drive has just been repartitioned */ | ||||
| BOOL WaitForLogical(DWORD DriveIndex, DWORD PartitionIndex) | ||||
| BOOL WaitForLogical(DWORD DriveIndex, uint64_t PartitionOffset) | ||||
| { | ||||
| 	uint64_t EndTime; | ||||
| 	char* LogicalPath = NULL; | ||||
|  | @ -729,7 +737,7 @@ BOOL WaitForLogical(DWORD DriveIndex, DWORD PartitionIndex) | |||
| 	// make sure we don't spend more than DRIVE_ACCESS_TIMEOUT in wait.
 | ||||
| 	EndTime = GetTickCount64() + DRIVE_ACCESS_TIMEOUT; | ||||
| 	do { | ||||
| 		LogicalPath = GetLogicalName(DriveIndex, PartitionIndex, FALSE, TRUE); | ||||
| 		LogicalPath = GetLogicalName(DriveIndex, PartitionOffset, FALSE, TRUE); | ||||
| 		// Need to filter out GlobalRoot devices as we don't want to wait on those
 | ||||
| 		if ((LogicalPath != NULL) && (strncmp(LogicalPath, groot_name, groot_len) != 0)) { | ||||
| 			free(LogicalPath); | ||||
|  | @ -749,10 +757,10 @@ BOOL WaitForLogical(DWORD DriveIndex, DWORD PartitionIndex) | |||
|  * Returns INVALID_HANDLE_VALUE on error or NULL if no logical path exists (typical | ||||
|  * of unpartitioned drives) | ||||
|  */ | ||||
| HANDLE GetLogicalHandle(DWORD DriveIndex, DWORD PartitionIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare) | ||||
| HANDLE GetLogicalHandle(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare) | ||||
| { | ||||
| 	HANDLE hLogical = INVALID_HANDLE_VALUE; | ||||
| 	char* LogicalPath = GetLogicalName(DriveIndex, PartitionIndex, FALSE, FALSE); | ||||
| 	char* LogicalPath = GetLogicalName(DriveIndex, PartitionOffset, FALSE, FALSE); | ||||
| 
 | ||||
| 	if (LogicalPath == NULL) { | ||||
| 		uprintf("No logical drive found (unpartitioned?)"); | ||||
|  | @ -767,10 +775,10 @@ HANDLE GetLogicalHandle(DWORD DriveIndex, DWORD PartitionIndex, BOOL bLockDrive, | |||
| /*
 | ||||
|  * Similar to the above, but use the partition name instead | ||||
|  */ | ||||
| HANDLE GetPartitionHandle(DWORD DriveIndex, DWORD PartitionIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare) | ||||
| HANDLE GetPartitionHandle(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare) | ||||
| { | ||||
| 	HANDLE handle = INVALID_HANDLE_VALUE; | ||||
| 	char* volume_name = GetPartitionName(DriveIndex, PartitionIndex); | ||||
| 	char* volume_name = GetPartitionName(DriveIndex, PartitionOffset); | ||||
| 
 | ||||
| 	if (volume_name == NULL) { | ||||
| 		uprintf("Could not get partition volume name"); | ||||
|  | @ -1158,6 +1166,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys | |||
| 		return FALSE; | ||||
| 
 | ||||
| 	SelectedDrive.nPartitions = 0; | ||||
| 	memset(SelectedDrive.PartitionOffset, 0, sizeof(SelectedDrive.PartitionOffset)); | ||||
| 	// Populate the filesystem data
 | ||||
| 	FileSystemName[0] = 0; | ||||
| 	volume_name = GetLogicalName(DriveIndex, 0, TRUE, FALSE); | ||||
|  | @ -1246,6 +1255,8 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys | |||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 				if (i < MAX_PARTITIONS) | ||||
| 					SelectedDrive.PartitionOffset[i] = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart; | ||||
| 				// NB: MinGW's gcc 4.9.2 broke "%lld" printout on XP so we use the inttypes.h "PRI##" qualifiers
 | ||||
| 				suprintf("  Type: %s (0x%02x)\r\n  Size: %s (%" PRIi64 " bytes)\r\n  Start Sector: %" PRIi64 ", Boot: %s", | ||||
| 					((part_type==0x07||super_floppy_disk)&&(FileSystemName[0]!=0))?FileSystemName:GetPartitionType(part_type), super_floppy_disk?0:part_type, | ||||
|  | @ -1271,6 +1282,8 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys | |||
| 		suprintf("Max parts: %d, Start Offset: %" PRIi64 ", Usable = %" PRIi64 " bytes", | ||||
| 			DriveLayout->Gpt.MaxPartitionCount, DriveLayout->Gpt.StartingUsableOffset.QuadPart, DriveLayout->Gpt.UsableLength.QuadPart); | ||||
| 		for (i=0; i<DriveLayout->PartitionCount; i++) { | ||||
| 			if (i < MAX_PARTITIONS) | ||||
| 				SelectedDrive.PartitionOffset[i] = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart; | ||||
| 			SelectedDrive.nPartitions++; | ||||
| 			isUefiNtfs = (wcscmp(DriveLayout->PartitionEntry[i].Gpt.Name, L"UEFI:NTFS") == 0); | ||||
| 			suprintf("Partition %d%s:\r\n  Type: %s\r\n  Name: '%S'", i+1, isUefiNtfs ? " (UEFI:NTFS)" : "", | ||||
|  | @ -1401,33 +1414,33 @@ BOOL MountVolume(char* drive_name, char *volume_name) | |||
| /*
 | ||||
|  * Alternate version of MountVolume required for ESP's, since Windows (including VDS) does | ||||
|  * *NOT* provide any means of mounting these volume but through DefineDosDevice(). Also | ||||
|  * note the bcdboot is very finicky about what it may or may not handle, even if the | ||||
|  * note that bcdboot is very finicky about what it may or may not handle, even if the | ||||
|  * mount was successful (e.g. '\Device\HarddiskVolume###' vs 'Device\HarddiskVolume###'). | ||||
|  * Returned string is static (no concurrency) and should not be freed. | ||||
|  * Returned string is static (no concurrency) and must not be freed. | ||||
|  */ | ||||
| char* AltMountVolume(DWORD DriveIndex, DWORD PartitionIndex) | ||||
| char* AltMountVolume(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bSilent) | ||||
| { | ||||
| 	char* ret = NULL, *volume_name = NULL; | ||||
| 	static char mounted_drive[] = "?:"; | ||||
| 
 | ||||
| 	mounted_drive[0] = GetUnusedDriveLetter(); | ||||
| 	if (mounted_drive[0] == 0) { | ||||
| 		uprintf("Could not find an unused drive letter"); | ||||
| 		suprintf("Could not find an unused drive letter"); | ||||
| 		goto out; | ||||
| 	} | ||||
| 	volume_name = GetLogicalName(DriveIndex, PartitionIndex, FALSE, TRUE); | ||||
| 	// Can't use a regular volume GUID for ESPs...
 | ||||
| 	volume_name = AltGetLogicalName(DriveIndex, PartitionOffset, FALSE, TRUE); | ||||
| 	if ((volume_name == NULL) || (strncmp(volume_name, groot_name, groot_len) != 0)) { | ||||
| 		uprintf("Unexpected volume name: '%s'", volume_name); | ||||
| 		suprintf("Unexpected volume name: '%s'", volume_name); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	// bcdboot sure won't like it if you forget the starting '\'
 | ||||
| 	suprintf("Mounting '%s' as '%s'", &volume_name[14], mounted_drive); | ||||
| 	// bcdboot doesn't like it if you forget the starting '\'
 | ||||
| 	if (!DefineDosDeviceA(DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM, mounted_drive, &volume_name[14])) { | ||||
| 		uprintf("Could not mount '%s' to '%s': %s", &volume_name[14], mounted_drive, WindowsErrorString()); | ||||
| 		suprintf("Mount operation failed: %s", WindowsErrorString()); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	uprintf("Successfully mounted '%s' (Partition %d) as '%s'", &volume_name[14], PartitionIndex, mounted_drive); | ||||
| 	ret = mounted_drive; | ||||
| 
 | ||||
| out: | ||||
|  | @ -1438,15 +1451,15 @@ out: | |||
| /*
 | ||||
|  * Unmount a volume that was mounted by AltmountVolume() | ||||
|  */ | ||||
| BOOL AltUnmountVolume(const char* drive_name) | ||||
| BOOL AltUnmountVolume(const char* drive_name, BOOL bSilent) | ||||
| { | ||||
| 	if (drive_name == NULL) | ||||
| 		return FALSE; | ||||
| 	if (!DefineDosDeviceA(DDD_REMOVE_DEFINITION | DDD_NO_BROADCAST_SYSTEM, drive_name, NULL)) { | ||||
| 		uprintf("Could not unmount '%s': %s", drive_name, WindowsErrorString()); | ||||
| 		suprintf("Could not unmount '%s': %s", drive_name, WindowsErrorString()); | ||||
| 		return FALSE; | ||||
| 	} | ||||
| 	uprintf("Successfully unmounted '%s'", drive_name); | ||||
| 	suprintf("Successfully unmounted '%s'", drive_name); | ||||
| 	return TRUE; | ||||
| } | ||||
| 
 | ||||
|  | @ -1536,7 +1549,8 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m | |||
| 		if (uefi_ntfs_size == 0) | ||||
| 			return FALSE; | ||||
| 	} | ||||
| 	memset(partition_index, 0, sizeof(partition_index)); | ||||
| 	memset(partition_offset, 0, sizeof(partition_offset)); | ||||
| 	memset(SelectedDrive.PartitionOffset, 0, sizeof(SelectedDrive.PartitionOffset)); | ||||
| 
 | ||||
| 	// Compute the start offset of our first partition
 | ||||
| 	if ((partition_style == PARTITION_STYLE_GPT) || (!IsChecked(IDC_OLD_BIOS_FIXES))) { | ||||
|  | @ -1560,6 +1574,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m | |||
| 		// Zero the first sectors from this partition to avoid file system caching issues
 | ||||
| 		if (!ClearPartition(hDrive, DriveLayoutEx.PartitionEntry[pn].StartingOffset, size_to_clear)) | ||||
| 			uprintf("Could not zero %S: %s", extra_part_name, WindowsErrorString()); | ||||
| 		SelectedDrive.PartitionOffset[pn] = DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart; | ||||
| 		pn++; | ||||
| 		DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[pn-1].StartingOffset.QuadPart + | ||||
| 				DriveLayoutEx.PartitionEntry[pn-1].PartitionLength.QuadPart; | ||||
|  | @ -1641,15 +1656,12 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m | |||
| 		IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId)); | ||||
| 		wcsncpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, main_part_name, ARRAYSIZE(DriveLayoutEx.PartitionEntry[pn].Gpt.Name)); | ||||
| 	} | ||||
| 	SelectedDrive.PartitionOffset[pn] = DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart; | ||||
| 	partition_offset[PI_MAIN] = SelectedDrive.PartitionOffset[pn]; | ||||
| 	pn++; | ||||
| 	partition_index[PI_MAIN] = pn; | ||||
| 
 | ||||
| 	// Set the optional extra partition
 | ||||
| 	if (extra_partitions) { | ||||
| 		if (extra_partitions & XP_CASPER) | ||||
| 			partition_index[PI_CASPER] = pn + 1; | ||||
| 		else if (extra_partitions & XP_ESP) | ||||
| 			partition_index[PI_ESP] = pn + 1; | ||||
| 		// Should end on a track boundary
 | ||||
| 		DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[pn-1].StartingOffset.QuadPart + | ||||
| 			DriveLayoutEx.PartitionEntry[pn-1].PartitionLength.QuadPart; | ||||
|  | @ -1657,6 +1669,12 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m | |||
| 			extra_part_size_in_tracks * bytes_per_track; | ||||
| 		uprintf("● Creating %S Partition (offset: %lld, size: %s)", extra_part_name, DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart, | ||||
| 			SizeToHumanReadable(DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart, TRUE, FALSE)); | ||||
| 		SelectedDrive.PartitionOffset[pn] = DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart; | ||||
| 		if (extra_partitions & XP_CASPER) | ||||
| 			partition_offset[PI_CASPER] = SelectedDrive.PartitionOffset[pn]; | ||||
| 		else if (extra_partitions & XP_ESP) | ||||
| 			partition_offset[PI_ESP] = SelectedDrive.PartitionOffset[pn]; | ||||
| 
 | ||||
| 		if (partition_style == PARTITION_STYLE_GPT) { | ||||
| 			DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = (extra_partitions & XP_ESP) ? PARTITION_SYSTEM_GUID : PARTITION_BASIC_DATA_GUID; | ||||
| 			IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId)); | ||||
|  |  | |||
							
								
								
									
										20
									
								
								src/drive.h
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								src/drive.h
									
										
									
									
									
								
							|  | @ -350,6 +350,7 @@ typedef struct { | |||
| 	MEDIA_TYPE MediaType; | ||||
| 	int PartitionStyle; | ||||
| 	int nPartitions;	// number of partitions we actually care about
 | ||||
| 	uint64_t PartitionOffset[MAX_PARTITIONS]; | ||||
| 	int FSType; | ||||
| 	char proposed_label[16]; | ||||
| 	BOOL has_protective_mbr; | ||||
|  | @ -360,18 +361,19 @@ typedef struct { | |||
| 	} ClusterSize[FS_MAX]; | ||||
| } RUFUS_DRIVE_INFO; | ||||
| extern RUFUS_DRIVE_INFO SelectedDrive; | ||||
| extern DWORD partition_index[3]; | ||||
| extern uint64_t partition_offset[3]; | ||||
| 
 | ||||
| BOOL SetAutoMount(BOOL enable); | ||||
| BOOL GetAutoMount(BOOL* enabled); | ||||
| char* GetPhysicalName(DWORD DriveIndex); | ||||
| char* GetPartitionName(DWORD DriveIndex, DWORD PartitionIndex); | ||||
| char* GetPartitionName(DWORD DriveIndex, uint64_t PartitionOffset); | ||||
| BOOL DeletePartitions(DWORD DriveIndex); | ||||
| HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare); | ||||
| char* GetLogicalName(DWORD DriveIndex, DWORD PartitionIndex, BOOL bKeepTrailingBackslash, BOOL bSilent); | ||||
| BOOL WaitForLogical(DWORD DriveIndex, DWORD PartitionIndex); | ||||
| HANDLE GetLogicalHandle(DWORD DriveIndex, DWORD PartitionIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare); | ||||
| HANDLE GetPartitionHandle(DWORD DriveIndex, DWORD PartitionIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare); | ||||
| char* GetLogicalName(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bKeepTrailingBackslash, BOOL bSilent); | ||||
| char* AltGetLogicalName(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bKeepTrailingBackslash, BOOL bSilent); | ||||
| BOOL WaitForLogical(DWORD DriveIndex, uint64_t PartitionOffset); | ||||
| HANDLE GetLogicalHandle(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare); | ||||
| HANDLE GetPartitionHandle(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare); | ||||
| int GetDriveNumber(HANDLE hDrive, char* path); | ||||
| BOOL GetDriveLetters(DWORD DriveIndex, char* drive_letters); | ||||
| UINT GetDriveTypeFromIndex(DWORD DriveIndex); | ||||
|  | @ -384,14 +386,14 @@ BOOL AnalyzePBR(HANDLE hLogicalVolume); | |||
| BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSystemNameSize, BOOL bSilent); | ||||
| BOOL UnmountVolume(HANDLE hDrive); | ||||
| BOOL MountVolume(char* drive_name, char *drive_guid); | ||||
| BOOL AltUnmountVolume(const char* drive_name); | ||||
| char* AltMountVolume(DWORD DriveIndex, DWORD PartitionIndex); | ||||
| BOOL AltUnmountVolume(const char* drive_name, BOOL bSilent); | ||||
| char* AltMountVolume(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bSilent); | ||||
| BOOL RemountVolume(char* drive_name); | ||||
| BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker, uint8_t extra_partitions); | ||||
| BOOL InitializeDisk(HANDLE hDrive); | ||||
| BOOL RefreshDriveLayout(HANDLE hDrive); | ||||
| const char* GetPartitionType(BYTE Type); | ||||
| const char* GetExtFsLabel(DWORD DriveIndex, DWORD PartitionIndex); | ||||
| const char* GetExtFsLabel(DWORD DriveIndex, uint64_t PartitionOffset); | ||||
| BOOL GetDevices(DWORD devnum); | ||||
| BOOL CyclePort(int index); | ||||
| int CycleDevice(int index); | ||||
|  |  | |||
							
								
								
									
										59
									
								
								src/format.c
									
										
									
									
									
								
							
							
						
						
									
										59
									
								
								src/format.c
									
										
									
									
									
								
							|  | @ -373,7 +373,7 @@ static DWORD GetFATSizeSectors(DWORD DskSize, DWORD ReservedSecCnt, DWORD SecPer | |||
|  * Large FAT32 volume formatting from fat32format by Tom Thornhill | ||||
|  * http://www.ridgecrop.demon.co.uk/index.htm?fat32format.htm
 | ||||
|  */ | ||||
| static BOOL FormatFAT32(DWORD DriveIndex, DWORD PartitionIndex, DWORD ClusterSize, LPCSTR FSName, LPCSTR Label, DWORD Flags) | ||||
| static BOOL FormatFAT32(DWORD DriveIndex, uint64_t PartitionOffset, DWORD ClusterSize, LPCSTR FSName, LPCSTR Label, DWORD Flags) | ||||
| { | ||||
| 	BOOL r = FALSE; | ||||
| 	DWORD i; | ||||
|  | @ -420,7 +420,7 @@ static BOOL FormatFAT32(DWORD DriveIndex, DWORD PartitionIndex, DWORD ClusterSiz | |||
| 	VolumeId = GetVolumeID(); | ||||
| 
 | ||||
| 	// Open the drive and lock it
 | ||||
| 	hLogicalVolume = GetLogicalHandle(DriveIndex, PartitionIndex, TRUE, TRUE, FALSE); | ||||
| 	hLogicalVolume = GetLogicalHandle(DriveIndex, PartitionOffset, TRUE, TRUE, FALSE); | ||||
| 	if (IS_ERROR(FormatStatus)) | ||||
| 		goto out; | ||||
| 	if ((hLogicalVolume == INVALID_HANDLE_VALUE) || (hLogicalVolume == NULL)) | ||||
|  | @ -651,7 +651,7 @@ static BOOL FormatFAT32(DWORD DriveIndex, DWORD PartitionIndex, DWORD ClusterSiz | |||
| 	PrintInfoDebug(0, MSG_221); | ||||
| 	// Handle must be closed for SetVolumeLabel to work
 | ||||
| 	safe_closehandle(hLogicalVolume); | ||||
| 	VolumeName = GetLogicalName(DriveIndex, PartitionIndex, TRUE, TRUE); | ||||
| 	VolumeName = GetLogicalName(DriveIndex, PartitionOffset, TRUE, TRUE); | ||||
| 	if ((VolumeName == NULL) || (!SetVolumeLabelA(VolumeName, Label))) { | ||||
| 		uprintf("Could not set label: %s", WindowsErrorString()); | ||||
| 		// Non fatal error
 | ||||
|  | @ -819,14 +819,16 @@ errcode_t ext2fs_print_progress(int64_t cur_value, int64_t max_value) | |||
| 	return IS_ERROR(FormatStatus) ? EXT2_ET_CANCEL_REQUESTED : 0; | ||||
| } | ||||
| 
 | ||||
| const char* GetExtFsLabel(DWORD DriveIndex, DWORD PartitionIndex) | ||||
| const char* GetExtFsLabel(DWORD DriveIndex, uint64_t PartitionOffset) | ||||
| { | ||||
| 	static char label[EXT2_LABEL_LEN + 1]; | ||||
| 	errcode_t r; | ||||
| 	ext2_filsys ext2fs = NULL; | ||||
| 	io_manager manager = nt_io_manager(); | ||||
| 	char* volume_name = GetPartitionName(DriveIndex, PartitionIndex); | ||||
| 	char* volume_name = AltMountVolume(DriveIndex, PartitionOffset, TRUE); | ||||
| 
 | ||||
| 	if (volume_name == NULL) | ||||
| 		return NULL; | ||||
| 	r = ext2fs_open(volume_name, EXT2_FLAG_SKIP_MMP, 0, 0, manager, &ext2fs); | ||||
| 	if (r == 0) { | ||||
| 		strncpy(label, ext2fs->super->s_volume_name, EXT2_LABEL_LEN); | ||||
|  | @ -834,11 +836,11 @@ const char* GetExtFsLabel(DWORD DriveIndex, DWORD PartitionIndex) | |||
| 	} | ||||
| 	if (ext2fs != NULL) | ||||
| 		ext2fs_close(ext2fs); | ||||
| 	free(volume_name); | ||||
| 	AltUnmountVolume(volume_name, TRUE); | ||||
| 	return (r == 0) ? label : NULL; | ||||
| } | ||||
| 
 | ||||
| BOOL FormatExtFs(DWORD DriveIndex, DWORD PartitionIndex, DWORD BlockSize, LPCSTR FSName, LPCSTR Label, DWORD Flags) | ||||
| BOOL FormatExtFs(DWORD DriveIndex, uint64_t PartitionOffset, DWORD BlockSize, LPCSTR FSName, LPCSTR Label, DWORD Flags) | ||||
| { | ||||
| 	// Mostly taken from mke2fs.conf
 | ||||
| 	const float reserve_ratio = 0.05f; | ||||
|  | @ -877,7 +879,7 @@ BOOL FormatExtFs(DWORD DriveIndex, DWORD PartitionIndex, DWORD BlockSize, LPCSTR | |||
| 	} | ||||
| 	CloseHandle(h); | ||||
| #else | ||||
| 	volume_name = GetPartitionName(DriveIndex, PartitionIndex); | ||||
| 	volume_name = AltMountVolume(DriveIndex, PartitionOffset, FALSE); | ||||
| #endif | ||||
| 	if ((volume_name == NULL) | (strlen(FSName) != 4) || (strncmp(FSName, "ext", 3) != 0)) { | ||||
| 		FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_INVALID_PARAMETER; | ||||
|  | @ -1097,14 +1099,14 @@ BOOL FormatExtFs(DWORD DriveIndex, DWORD PartitionIndex, DWORD BlockSize, LPCSTR | |||
| out: | ||||
| 	ext2fs_free(ext2fs); | ||||
| 	free(buf); | ||||
| 	free(volume_name); | ||||
| 	AltUnmountVolume(volume_name, FALSE); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Call on VDS to format a partition | ||||
|  */ | ||||
| static BOOL FormatDriveVds(DWORD DriveIndex, DWORD PartitionIndex, DWORD ClusterSize, LPCSTR FSName, LPCSTR Label, DWORD Flags) | ||||
| static BOOL FormatDriveVds(DWORD DriveIndex, uint64_t PartitionOffset, DWORD ClusterSize, LPCSTR FSName, LPCSTR Label, DWORD Flags) | ||||
| { | ||||
| 	BOOL r = FALSE, bFoundVolume = FALSE; | ||||
| 	HRESULT hr; | ||||
|  | @ -1122,7 +1124,7 @@ static BOOL FormatDriveVds(DWORD DriveIndex, DWORD PartitionIndex, DWORD Cluster | |||
| 		PrintInfoDebug(0, MSG_222, FSName); | ||||
| 	} | ||||
| 	LastRefresh = 0; | ||||
| 	VolumeName = GetLogicalName(DriveIndex, PartitionIndex, TRUE, TRUE); | ||||
| 	VolumeName = GetLogicalName(DriveIndex, PartitionOffset, TRUE, TRUE); | ||||
| 	wVolumeName = utf8_to_wchar(VolumeName); | ||||
| 	if (wVolumeName == NULL) { | ||||
| 		uprintf("Could not read volume name"); | ||||
|  | @ -1350,7 +1352,7 @@ out: | |||
| /*
 | ||||
|  * Call on fmifs.dll's FormatEx() to format the drive | ||||
|  */ | ||||
| static BOOL FormatDrive(DWORD DriveIndex, DWORD PartitionIndex, DWORD ClusterSize, LPCSTR FSName, LPCSTR Label, DWORD Flags) | ||||
| static BOOL FormatDrive(DWORD DriveIndex, uint64_t PartitionOffset, DWORD ClusterSize, LPCSTR FSName, LPCSTR Label, DWORD Flags) | ||||
| { | ||||
| 	BOOL r = FALSE; | ||||
| 	PF_DECL(FormatEx); | ||||
|  | @ -1364,10 +1366,10 @@ static BOOL FormatDrive(DWORD DriveIndex, DWORD PartitionIndex, DWORD ClusterSiz | |||
| 	} else { | ||||
| 		PrintInfoDebug(0, MSG_222, FSName); | ||||
| 	} | ||||
| 	VolumeName = GetLogicalName(DriveIndex, PartitionIndex, TRUE, TRUE); | ||||
| 	VolumeName = GetLogicalName(DriveIndex, PartitionOffset, TRUE, TRUE); | ||||
| 	wVolumeName = utf8_to_wchar(VolumeName); | ||||
| 	if (wVolumeName == NULL) { | ||||
| 		uprintf("Could not read volume name\n"); | ||||
| 		uprintf("Could not read volume name"); | ||||
| 		FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | @ -1429,9 +1431,9 @@ out: | |||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| static BOOL FormatPartition(DWORD DriveIndex, DWORD PartitionIndex, DWORD UnitAllocationSize, USHORT FSType, LPCSTR Label, DWORD Flags) | ||||
| static BOOL FormatPartition(DWORD DriveIndex, uint64_t PartitionOffset, DWORD UnitAllocationSize, USHORT FSType, LPCSTR Label, DWORD Flags) | ||||
| { | ||||
| 	if ((DriveIndex < 0x80) || (DriveIndex > 0x100) || (PartitionIndex >= MAX_PARTITIONS) || (FSType >= FS_MAX) || | ||||
| 	if ((DriveIndex < 0x80) || (DriveIndex > 0x100) || (FSType >= FS_MAX) || | ||||
| 		// The following validates that UnitAllocationSize is a power of 2
 | ||||
| 		((UnitAllocationSize != 0) && (UnitAllocationSize & (UnitAllocationSize - 1)))) { | ||||
| 		ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_INVALID_PARAMETER; | ||||
|  | @ -1439,13 +1441,13 @@ static BOOL FormatPartition(DWORD DriveIndex, DWORD PartitionIndex, DWORD UnitAl | |||
| 	} | ||||
| 	actual_fs_type = FSType; | ||||
| 	if ((FSType == FS_FAT32) && ((SelectedDrive.DiskSize > LARGE_FAT32_SIZE) || (force_large_fat32) || (Flags & FP_LARGE_FAT32))) | ||||
| 		return FormatFAT32(DriveIndex, PartitionIndex, UnitAllocationSize, FileSystemLabel[FSType], Label, Flags); | ||||
| 		return FormatFAT32(DriveIndex, PartitionOffset, UnitAllocationSize, FileSystemLabel[FSType], Label, Flags); | ||||
| 	else if (FSType >= FS_EXT2) | ||||
| 		return FormatExtFs(DriveIndex, PartitionIndex, UnitAllocationSize, FileSystemLabel[FSType], Label, Flags); | ||||
| 		return FormatExtFs(DriveIndex, PartitionOffset, UnitAllocationSize, FileSystemLabel[FSType], Label, Flags); | ||||
| 	else if (use_vds) | ||||
| 		return FormatDriveVds(DriveIndex, PartitionIndex, UnitAllocationSize, FileSystemLabel[FSType], Label, Flags); | ||||
| 		return FormatDriveVds(DriveIndex, PartitionOffset, UnitAllocationSize, FileSystemLabel[FSType], Label, Flags); | ||||
| 	else | ||||
| 		return FormatDrive(DriveIndex, PartitionIndex, UnitAllocationSize, FileSystemLabel[FSType], Label, Flags); | ||||
| 		return FormatDrive(DriveIndex, PartitionOffset, UnitAllocationSize, FileSystemLabel[FSType], Label, Flags); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -2159,7 +2161,7 @@ static BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp) | |||
| 		// VDS cannot list ESP volumes (talk about allegedly improving on the old disk and volume APIs, only to
 | ||||
| 		// completely neuter it) and IVdsDiskPartitionMF::FormatPartitionEx(), which is what you are supposed to
 | ||||
| 		// use for ESPs, explicitly states: "This method cannot be used to format removable media."
 | ||||
| 		if (!FormatPartition(DriveIndex, partition_index[PI_ESP], cluster_size, FS_FAT32, "", | ||||
| 		if (!FormatPartition(DriveIndex, partition_offset[PI_ESP], cluster_size, FS_FAT32, "", | ||||
| 			FP_QUICK | FP_FORCE | FP_LARGE_FAT32 | FP_NO_BOOT)) { | ||||
| 			uprintf("Could not format EFI System Partition"); | ||||
| 			return FALSE; | ||||
|  | @ -2169,7 +2171,7 @@ static BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp) | |||
| 
 | ||||
| 	if (use_esp) { | ||||
| 		// Need to have the ESP mounted to invoke bcdboot
 | ||||
| 		ms_efi = AltMountVolume(DriveIndex, partition_index[PI_ESP]); | ||||
| 		ms_efi = AltMountVolume(DriveIndex, partition_offset[PI_ESP], FALSE); | ||||
| 		if (ms_efi == NULL) { | ||||
| 			FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_ASSIGN_LETTER); | ||||
| 			return FALSE; | ||||
|  | @ -2192,7 +2194,7 @@ static BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp) | |||
| 
 | ||||
| 	if (use_esp) { | ||||
| 		Sleep(200); | ||||
| 		AltUnmountVolume(ms_efi); | ||||
| 		AltUnmountVolume(ms_efi, FALSE); | ||||
| 	} | ||||
| 	PrintInfo(0, MSG_267, 99.9f); | ||||
| 	UpdateProgress(OP_DOS, 99.9f); | ||||
|  | @ -2679,7 +2681,7 @@ DWORD WINAPI FormatThread(void* param) | |||
| 	// Wait for the logical drive we just created to appear
 | ||||
| 	uprintf("Waiting for logical drive to reappear..."); | ||||
| 	Sleep(200); | ||||
| 	if (!WaitForLogical(DriveIndex, partition_index[PI_MAIN])) { | ||||
| 	if (!WaitForLogical(DriveIndex, partition_offset[PI_MAIN])) { | ||||
| 		uprintf("Logical drive was not found - aborting"); | ||||
| 		FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_NO_VOLUME_ID; | ||||
| 		goto out; | ||||
|  | @ -2693,7 +2695,7 @@ DWORD WINAPI FormatThread(void* param) | |||
| 		if ((ext_version < 2) || (ext_version > 4)) | ||||
| 			ext_version = 3; | ||||
| 		uprintf("Using %s-like method to enable persistence", img_report.uses_casper ? "Ubuntu" : "Debian"); | ||||
| 		if (!FormatPartition(DriveIndex, partition_index[PI_CASPER], 0, FS_EXT2 + (ext_version - 2), | ||||
| 		if (!FormatPartition(DriveIndex, partition_offset[PI_CASPER], 0, FS_EXT2 + (ext_version - 2), | ||||
| 			img_report.uses_casper ? "casper-rw" : "persistence", | ||||
| 			(img_report.uses_casper ? 0 : FP_CREATE_PERSISTENCE_CONF) | | ||||
| 			(IsChecked(IDC_QUICK_FORMAT) ? FP_QUICK : 0))) { | ||||
|  | @ -2716,7 +2718,7 @@ DWORD WINAPI FormatThread(void* param) | |||
| 	if ((fs_type == FS_NTFS) && (enable_ntfs_compression)) | ||||
| 		Flags |= FP_COMPRESSION; | ||||
| 
 | ||||
| 	ret = FormatPartition(DriveIndex, partition_index[PI_MAIN], ClusterSize, fs_type, label, Flags); | ||||
| 	ret = FormatPartition(DriveIndex, partition_offset[PI_MAIN], ClusterSize, fs_type, label, Flags); | ||||
| 	if (!ret) { | ||||
| 		// Error will be set by FormatPartition() in FormatStatus
 | ||||
| 		uprintf("Format error: %s", StrError(FormatStatus, TRUE)); | ||||
|  | @ -2747,7 +2749,7 @@ DWORD WINAPI FormatThread(void* param) | |||
| 	// Try to continue
 | ||||
| 	CHECK_FOR_USER_CANCEL; | ||||
| 
 | ||||
| 	volume_name = GetLogicalName(DriveIndex, partition_index[PI_MAIN], TRUE, TRUE); | ||||
| 	volume_name = GetLogicalName(DriveIndex, partition_offset[PI_MAIN], TRUE, TRUE); | ||||
| 	if (volume_name == NULL) { | ||||
| 		uprintf("Could not get volume name"); | ||||
| 		FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NO_VOLUME_ID; | ||||
|  | @ -2800,8 +2802,7 @@ DWORD WINAPI FormatThread(void* param) | |||
| 		} else { | ||||
| 			// We still have a lock, which we need to modify the volume boot record
 | ||||
| 			// => no need to reacquire the lock...
 | ||||
| 			// TODO: Shouldn't PI always be 1 here?
 | ||||
| 			hLogicalVolume = GetLogicalHandle(DriveIndex, partition_index[PI_MAIN], FALSE, TRUE, FALSE); | ||||
| 			hLogicalVolume = GetLogicalHandle(DriveIndex, partition_offset[PI_MAIN], FALSE, TRUE, FALSE); | ||||
| 			if ((hLogicalVolume == INVALID_HANDLE_VALUE) || (hLogicalVolume == NULL)) { | ||||
| 				uprintf("Could not re-mount volume for partition boot record access"); | ||||
| 				FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; | ||||
|  |  | |||
							
								
								
									
										10
									
								
								src/rufus.rc
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								src/rufus.rc
									
										
									
									
									
								
							|  | @ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL | |||
| IDD_DIALOG DIALOGEX 12, 12, 232, 326 | ||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | ||||
| EXSTYLE WS_EX_ACCEPTFILES | ||||
| CAPTION "Rufus 3.7.1561" | ||||
| CAPTION "Rufus 3.7.1562" | ||||
| FONT 9, "Segoe UI Symbol", 400, 0, 0x0 | ||||
| BEGIN | ||||
|     LTEXT           "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP | ||||
|  | @ -394,8 +394,8 @@ END | |||
| // | ||||
| 
 | ||||
| VS_VERSION_INFO VERSIONINFO | ||||
|  FILEVERSION 3,7,1561,0 | ||||
|  PRODUCTVERSION 3,7,1561,0 | ||||
|  FILEVERSION 3,7,1562,0 | ||||
|  PRODUCTVERSION 3,7,1562,0 | ||||
|  FILEFLAGSMASK 0x3fL | ||||
| #ifdef _DEBUG | ||||
|  FILEFLAGS 0x1L | ||||
|  | @ -413,13 +413,13 @@ BEGIN | |||
|             VALUE "Comments", "https://akeo.ie" | ||||
|             VALUE "CompanyName", "Akeo Consulting" | ||||
|             VALUE "FileDescription", "Rufus" | ||||
|             VALUE "FileVersion", "3.7.1561" | ||||
|             VALUE "FileVersion", "3.7.1562" | ||||
|             VALUE "InternalName", "Rufus" | ||||
|             VALUE "LegalCopyright", "© 2011-2019 Pete Batard (GPL v3)" | ||||
|             VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html" | ||||
|             VALUE "OriginalFilename", "rufus-3.7.exe" | ||||
|             VALUE "ProductName", "Rufus" | ||||
|             VALUE "ProductVersion", "3.7.1561" | ||||
|             VALUE "ProductVersion", "3.7.1562" | ||||
|         END | ||||
|     END | ||||
|     BLOCK "VarFileInfo" | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue