mirror of
				https://github.com/pbatard/rufus.git
				synced 2024-08-14 23:57:05 +00:00 
			
		
		
		
	[core] enable UEFI NTFS support
* This allows no-sweat UEFI support of Windows installation ISOs that contain a >4GB file for instance * This is done through UEFI:TOGO (https://github.com/pbatard/uefi-togo) and the efifs NTFS driver (http://efi.akeo.ie) * Closes #414 * This will also be part of our implementation of #126
This commit is contained in:
		
							parent
							
								
									420db67ce1
								
							
						
					
					
						commit
						d81f83c110
					
				
					 11 changed files with 115 additions and 34 deletions
				
			
		|  | @ -4,7 +4,6 @@ This directory contains the Grub 2.0 boot records that are used by Rufus | ||||||
|   commit 72ec399ad8d6348b6c74ea63d80c79784c8b84ae, on a Debian 7.7.0 x64 system. |   commit 72ec399ad8d6348b6c74ea63d80c79784c8b84ae, on a Debian 7.7.0 x64 system. | ||||||
|   This was done following the guide from: |   This was done following the guide from: | ||||||
|   http://pete.akeo.ie/2014/05/compiling-and-installing-grub2-for.html. |   http://pete.akeo.ie/2014/05/compiling-and-installing-grub2-for.html. | ||||||
|   Note that exFAT was not included in core.img in order to keep it under 31.5 KB. |  | ||||||
| 
 | 
 | ||||||
| * boot.img has been modified to nop the jump @ 0x66 as per grub2's setup.c comments: | * boot.img has been modified to nop the jump @ 0x66 as per grub2's setup.c comments: | ||||||
|   /* If DEST_DRIVE is a hard disk, enable the workaround, which is |   /* If DEST_DRIVE is a hard disk, enable the workaround, which is | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								res/uefi/readme.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								res/uefi/readme.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | This directory contains a flat image of the FAT UEFI:TOGO partition added by | ||||||
|  | Rufus for Windows To Go UEFI mode support as well as seamless installation of | ||||||
|  | Windows in UEFI, in the case where the original media contains a >4GB file. | ||||||
|  | 
 | ||||||
|  | This image, which you can mount as FAT filesystem or open in 7-zip, contains | ||||||
|  | the following data: | ||||||
|  | o The NTFS UEFI driver from efifs (https://github.com/pbatard/efifs) which was | ||||||
|  |   compiled, with compression disabled, using Visual Studio 2013 Community Edition. | ||||||
|  |   This is the \EFI\Rufus\ntfs_x64.efi file. | ||||||
|  | o The UEFI:TOGO binary (https://github.com/pbatard/uefi-togo), which was compiled | ||||||
|  |   using Visual Studio 2013 Community Edition. | ||||||
|  |   This is the \EFI\Boot\bootx64.efi file. | ||||||
							
								
								
									
										
											BIN
										
									
								
								res/uefi/uefi-togo.img
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								res/uefi/uefi-togo.img
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										100
									
								
								src/drive.c
									
										
									
									
									
								
							
							
						
						
									
										100
									
								
								src/drive.c
									
										
									
									
									
								
							|  | @ -645,7 +645,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys | ||||||
| { | { | ||||||
| 	// MBR partition types that can be mounted in Windows
 | 	// MBR partition types that can be mounted in Windows
 | ||||||
| 	const uint8_t mbr_mountable[] = { 0x01, 0x04, 0x06, 0x07, 0x0b, 0x0c, 0x0e, 0xef }; | 	const uint8_t mbr_mountable[] = { 0x01, 0x04, 0x06, 0x07, 0x0b, 0x0c, 0x0e, 0xef }; | ||||||
| 	BOOL r, hasRufusExtra = FALSE, ret = FALSE; | 	BOOL r, hasRufusExtra = FALSE, ret = FALSE, isUefiTogo; | ||||||
| 	HANDLE hPhysical; | 	HANDLE hPhysical; | ||||||
| 	DWORD size; | 	DWORD size; | ||||||
| 	BYTE geometry[256], layout[4096], part_type; | 	BYTE geometry[256], layout[4096], part_type; | ||||||
|  | @ -695,6 +695,10 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | #if defined(__GNUC__) | ||||||
|  | // GCC 4.9 bug us about the fact that MS defined an expandable array as array[1]
 | ||||||
|  | #pragma GCC diagnostic ignored "-Warray-bounds" | ||||||
|  | #endif | ||||||
| 	switch (DriveLayout->PartitionStyle) { | 	switch (DriveLayout->PartitionStyle) { | ||||||
| 	case PARTITION_STYLE_MBR: | 	case PARTITION_STYLE_MBR: | ||||||
| 		SelectedDrive.PartitionType = PARTITION_STYLE_MBR; | 		SelectedDrive.PartitionType = PARTITION_STYLE_MBR; | ||||||
|  | @ -709,8 +713,10 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys | ||||||
| 		AnalyzeMBR(hPhysical, "Drive"); | 		AnalyzeMBR(hPhysical, "Drive"); | ||||||
| 		for (i=0; i<DriveLayout->PartitionCount; i++) { | 		for (i=0; i<DriveLayout->PartitionCount; i++) { | ||||||
| 			if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) { | 			if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) { | ||||||
| 				suprintf("Partition %d:\n", i+1); |  | ||||||
| 				part_type = DriveLayout->PartitionEntry[i].Mbr.PartitionType; | 				part_type = DriveLayout->PartitionEntry[i].Mbr.PartitionType; | ||||||
|  | 				isUefiTogo = (i == 1) && (part_type == 0x01) && | ||||||
|  | 					(DriveLayout->PartitionEntry[i].PartitionLength.QuadPart == 131072); | ||||||
|  | 				suprintf("Partition %d%s:\n", i+1, isUefiTogo?" (UEFI:TOGO)":""); | ||||||
| 				for (j=0; j<ARRAYSIZE(mbr_mountable); j++) { | 				for (j=0; j<ARRAYSIZE(mbr_mountable); j++) { | ||||||
| 					if (part_type == mbr_mountable[j]) { | 					if (part_type == mbr_mountable[j]) { | ||||||
| 						ret = TRUE; | 						ret = TRUE; | ||||||
|  | @ -723,7 +729,8 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys | ||||||
| 					DriveLayout->PartitionEntry[i].PartitionLength, DriveLayout->PartitionEntry[i].Mbr.HiddenSectors, | 					DriveLayout->PartitionEntry[i].PartitionLength, DriveLayout->PartitionEntry[i].Mbr.HiddenSectors, | ||||||
| 					DriveLayout->PartitionEntry[i].Mbr.BootIndicator?"Yes":"No", | 					DriveLayout->PartitionEntry[i].Mbr.BootIndicator?"Yes":"No", | ||||||
| 					DriveLayout->PartitionEntry[i].Mbr.RecognizedPartition?"Yes":"No"); | 					DriveLayout->PartitionEntry[i].Mbr.RecognizedPartition?"Yes":"No"); | ||||||
| 				if (part_type == RUFUS_EXTRA_PARTITION_TYPE)	// This is a partition Rufus created => we can safely ignore it
 | 				if ((part_type == RUFUS_EXTRA_PARTITION_TYPE) || (isUefiTogo)) | ||||||
|  | 					// This is a partition Rufus created => we can safely ignore it
 | ||||||
| 					hasRufusExtra = TRUE; | 					hasRufusExtra = TRUE; | ||||||
| 				if (part_type == 0xee)	// Flag a protective MBR for non GPT platforms (XP)
 | 				if (part_type == 0xee)	// Flag a protective MBR for non GPT platforms (XP)
 | ||||||
| 					SelectedDrive.has_protective_mbr = TRUE; | 					SelectedDrive.has_protective_mbr = TRUE; | ||||||
|  | @ -746,6 +753,8 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys | ||||||
| 				GuidToString(&DriveLayout->PartitionEntry[i].Gpt.PartitionId), SizeToHumanReadable(DriveLayout->PartitionEntry[i].PartitionLength.QuadPart, TRUE, FALSE), | 				GuidToString(&DriveLayout->PartitionEntry[i].Gpt.PartitionId), SizeToHumanReadable(DriveLayout->PartitionEntry[i].PartitionLength.QuadPart, TRUE, FALSE), | ||||||
| 				DriveLayout->PartitionEntry[i].PartitionLength, DriveLayout->PartitionEntry[i].StartingOffset.QuadPart / DiskGeometry->Geometry.BytesPerSector, | 				DriveLayout->PartitionEntry[i].PartitionLength, DriveLayout->PartitionEntry[i].StartingOffset.QuadPart / DiskGeometry->Geometry.BytesPerSector, | ||||||
| 				DriveLayout->PartitionEntry[i].Gpt.Attributes); | 				DriveLayout->PartitionEntry[i].Gpt.Attributes); | ||||||
|  | 			if (safe_strcmp(tmp, "UEFI:TOGO") == 0) | ||||||
|  | 				hasRufusExtra = TRUE; | ||||||
| 			if ( (memcmp(&PARTITION_BASIC_DATA_GUID, &DriveLayout->PartitionEntry[i].Gpt.PartitionType, sizeof(GUID)) == 0) && | 			if ( (memcmp(&PARTITION_BASIC_DATA_GUID, &DriveLayout->PartitionEntry[i].Gpt.PartitionType, sizeof(GUID)) == 0) && | ||||||
| 				 (nWindowsVersion >= WINDOWS_VISTA) ) | 				 (nWindowsVersion >= WINDOWS_VISTA) ) | ||||||
| 				ret = TRUE; | 				ret = TRUE; | ||||||
|  | @ -756,6 +765,9 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys | ||||||
| 		suprintf("Partition type: RAW\n"); | 		suprintf("Partition type: RAW\n"); | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
|  | #if defined(__GNUC__) | ||||||
|  | #pragma GCC diagnostic warning "-Warray-bounds" | ||||||
|  | #endif | ||||||
| 	safe_closehandle(hPhysical); | 	safe_closehandle(hPhysical); | ||||||
| 
 | 
 | ||||||
| 	if (hasRufusExtra) | 	if (hasRufusExtra) | ||||||
|  | @ -889,14 +901,15 @@ typedef struct _DRIVE_LAYOUT_INFORMATION_EX4 { | ||||||
|  * copy it got from the last IOCTL, and ignores your changes until you replug the drive |  * copy it got from the last IOCTL, and ignores your changes until you replug the drive | ||||||
|  * or issue an IOCTL_DISK_UPDATE_PROPERTIES. |  * or issue an IOCTL_DISK_UPDATE_PROPERTIES. | ||||||
|  */ |  */ | ||||||
| BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker) | BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker, BOOL add_uefi_togo) | ||||||
| { | { | ||||||
| 	const char* PartitionTypeName[2] = { "MBR", "GPT" }; | 	const char* PartitionTypeName[2] = { "MBR", "GPT" }; | ||||||
|  | 	unsigned char* buffer; | ||||||
| 	CREATE_DISK CreateDisk = {PARTITION_STYLE_RAW, {{0}}}; | 	CREATE_DISK CreateDisk = {PARTITION_STYLE_RAW, {{0}}}; | ||||||
| 	DRIVE_LAYOUT_INFORMATION_EX4 DriveLayoutEx = {0}; | 	DRIVE_LAYOUT_INFORMATION_EX4 DriveLayoutEx = {0}; | ||||||
| 	BOOL r; | 	BOOL r; | ||||||
| 	DWORD size; | 	DWORD size, bufsize; | ||||||
| 	LONGLONG size_in_sectors; | 	LONGLONG size_in_sectors, extra_size_in_tracks = 1; | ||||||
| 
 | 
 | ||||||
| 	PrintStatus(0, TRUE, MSG_238, PartitionTypeName[partition_style]); | 	PrintStatus(0, TRUE, MSG_238, PartitionTypeName[partition_style]); | ||||||
| 
 | 
 | ||||||
|  | @ -908,8 +921,18 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m | ||||||
| 		DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart =  | 		DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart =  | ||||||
| 			SelectedDrive.Geometry.BytesPerSector * SelectedDrive.Geometry.SectorsPerTrack; | 			SelectedDrive.Geometry.BytesPerSector * SelectedDrive.Geometry.SectorsPerTrack; | ||||||
| 	} | 	} | ||||||
| 	// TODO: should we try to align the following to the cluster size as well?
 |  | ||||||
| 	size_in_sectors = (SelectedDrive.DiskSize - DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart) / SelectedDrive.Geometry.BytesPerSector; | 	size_in_sectors = (SelectedDrive.DiskSize - DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart) / SelectedDrive.Geometry.BytesPerSector; | ||||||
|  | 	// Align on track boundary if the extra part option is checked
 | ||||||
|  | 	if ((partition_style == PARTITION_STYLE_MBR) && ((IsChecked(IDC_EXTRA_PARTITION)) || (add_uefi_togo))) { | ||||||
|  | 		if (add_uefi_togo)	// Already set to 1 track in non To_Go mode
 | ||||||
|  | 			extra_size_in_tracks = (MIN_EXTRA_PART_SIZE + SelectedDrive.Geometry.SectorsPerTrack - 1) / | ||||||
|  | 				SelectedDrive.Geometry.SectorsPerTrack; | ||||||
|  | 		uprintf("Reserving %d tracks for extra partition", extra_size_in_tracks); | ||||||
|  | 		size_in_sectors = ((size_in_sectors / SelectedDrive.Geometry.SectorsPerTrack) - extra_size_in_tracks) * | ||||||
|  | 			SelectedDrive.Geometry.SectorsPerTrack; | ||||||
|  | 		if (size_in_sectors <= 0) | ||||||
|  | 			return FALSE; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	switch (partition_style) { | 	switch (partition_style) { | ||||||
| 	case PARTITION_STYLE_MBR: | 	case PARTITION_STYLE_MBR: | ||||||
|  | @ -927,13 +950,6 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m | ||||||
| 		// TODO: CHS fixup (32 sectors/track) through a cheat mode, if requested
 | 		// TODO: CHS fixup (32 sectors/track) through a cheat mode, if requested
 | ||||||
| 		// NB: disk geometry is computed by BIOS & co. by finding a match between LBA and CHS value of first partition
 | 		// NB: disk geometry is computed by BIOS & co. by finding a match between LBA and CHS value of first partition
 | ||||||
| 		//     ms-sys's write_partition_number_of_heads() and write_partition_start_sector_number() can be used if needed
 | 		//     ms-sys's write_partition_number_of_heads() and write_partition_start_sector_number() can be used if needed
 | ||||||
| 
 |  | ||||||
| 		// Align on sector boundary if the extra part option is checked
 |  | ||||||
| 		if (IsChecked(IDC_EXTRA_PARTITION)) { |  | ||||||
| 			size_in_sectors = ((size_in_sectors / SelectedDrive.Geometry.SectorsPerTrack)-1) * SelectedDrive.Geometry.SectorsPerTrack; |  | ||||||
| 			if (size_in_sectors <= 0) |  | ||||||
| 				return FALSE; |  | ||||||
| 		} |  | ||||||
| 		break; | 		break; | ||||||
| 	case PARTITION_STYLE_GPT: | 	case PARTITION_STYLE_GPT: | ||||||
| 		// TODO: (?) As per MSDN: "When specifying a GUID partition table (GPT) as the PARTITION_STYLE of the CREATE_DISK
 | 		// TODO: (?) As per MSDN: "When specifying a GUID partition table (GPT) as the PARTITION_STYLE of the CREATE_DISK
 | ||||||
|  | @ -945,7 +961,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m | ||||||
| 		CreateDisk.Gpt.MaxPartitionCount = MAX_GPT_PARTITIONS; | 		CreateDisk.Gpt.MaxPartitionCount = MAX_GPT_PARTITIONS; | ||||||
| 
 | 
 | ||||||
| 		DriveLayoutEx.PartitionStyle = PARTITION_STYLE_GPT; | 		DriveLayoutEx.PartitionStyle = PARTITION_STYLE_GPT; | ||||||
| 		DriveLayoutEx.PartitionCount = 1; | 		DriveLayoutEx.PartitionCount = (add_uefi_togo)?2:1; | ||||||
| 		// At the very least, a GPT disk has 34 reserved sectors at the beginning and 33 at the end.
 | 		// At the very least, a GPT disk has 34 reserved sectors at the beginning and 33 at the end.
 | ||||||
| 		DriveLayoutEx.Type.Gpt.StartingUsableOffset.QuadPart = 34 * SelectedDrive.Geometry.BytesPerSector; | 		DriveLayoutEx.Type.Gpt.StartingUsableOffset.QuadPart = 34 * SelectedDrive.Geometry.BytesPerSector; | ||||||
| 		DriveLayoutEx.Type.Gpt.UsableLength.QuadPart = SelectedDrive.DiskSize - (34+33) * SelectedDrive.Geometry.BytesPerSector; | 		DriveLayoutEx.Type.Gpt.UsableLength.QuadPart = SelectedDrive.DiskSize - (34+33) * SelectedDrive.Geometry.BytesPerSector; | ||||||
|  | @ -984,18 +1000,24 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m | ||||||
| 			uprintf("Unsupported file system\n"); | 			uprintf("Unsupported file system\n"); | ||||||
| 			return FALSE; | 			return FALSE; | ||||||
| 		} | 		} | ||||||
| 		// Create an extra partition on request - can improve BIOS detection as HDD for older BIOSes
 | 		// Create an extra partition on request
 | ||||||
| 		if (IsChecked(IDC_EXTRA_PARTITION)) { | 		if (IsChecked(IDC_EXTRA_PARTITION) || (add_uefi_togo)) { | ||||||
| 			DriveLayoutEx.PartitionEntry[1].PartitionStyle = PARTITION_STYLE_MBR; | 			DriveLayoutEx.PartitionEntry[1].PartitionStyle = PARTITION_STYLE_MBR; | ||||||
| 			// Should end on a sector boundary
 | 			// Should end on a track boundary
 | ||||||
| 			DriveLayoutEx.PartitionEntry[1].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart + | 			DriveLayoutEx.PartitionEntry[1].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart + | ||||||
| 				DriveLayoutEx.PartitionEntry[0].PartitionLength.QuadPart; | 				DriveLayoutEx.PartitionEntry[0].PartitionLength.QuadPart; | ||||||
| 			DriveLayoutEx.PartitionEntry[1].PartitionLength.QuadPart = SelectedDrive.Geometry.SectorsPerTrack*SelectedDrive.Geometry.BytesPerSector; | 			if (add_uefi_togo) { | ||||||
|  | 				DriveLayoutEx.PartitionEntry[1].PartitionLength.QuadPart = | ||||||
|  | 					GetResourceSize(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_TOGO), _RT_RCDATA, "uefi-togo.img"); | ||||||
|  | 			} else { | ||||||
|  | 				DriveLayoutEx.PartitionEntry[1].PartitionLength.QuadPart = extra_size_in_tracks * | ||||||
|  | 					SelectedDrive.Geometry.SectorsPerTrack * SelectedDrive.Geometry.BytesPerSector; | ||||||
|  | 			} | ||||||
| 			DriveLayoutEx.PartitionEntry[1].PartitionNumber = 2; | 			DriveLayoutEx.PartitionEntry[1].PartitionNumber = 2; | ||||||
| 			DriveLayoutEx.PartitionEntry[1].RewritePartition = TRUE; | 			DriveLayoutEx.PartitionEntry[1].RewritePartition = TRUE; | ||||||
| 			DriveLayoutEx.PartitionEntry[1].Mbr.BootIndicator = FALSE; | 			DriveLayoutEx.PartitionEntry[1].Mbr.BootIndicator = FALSE; | ||||||
| 			DriveLayoutEx.PartitionEntry[1].Mbr.HiddenSectors = SelectedDrive.Geometry.SectorsPerTrack*SelectedDrive.Geometry.BytesPerSector; | 			DriveLayoutEx.PartitionEntry[1].Mbr.HiddenSectors = SelectedDrive.Geometry.SectorsPerTrack*SelectedDrive.Geometry.BytesPerSector; | ||||||
| 			DriveLayoutEx.PartitionEntry[1].Mbr.PartitionType = RUFUS_EXTRA_PARTITION_TYPE; | 			DriveLayoutEx.PartitionEntry[1].Mbr.PartitionType = (add_uefi_togo)?0x01:RUFUS_EXTRA_PARTITION_TYPE; | ||||||
| 		} | 		} | ||||||
| 		// For the remaining partitions, PartitionStyle & PartitionType have already
 | 		// For the remaining partitions, PartitionStyle & PartitionType have already
 | ||||||
| 		// been zeroed => already set to MBR/unused
 | 		// been zeroed => already set to MBR/unused
 | ||||||
|  | @ -1003,12 +1025,48 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m | ||||||
| 	case PARTITION_STYLE_GPT: | 	case PARTITION_STYLE_GPT: | ||||||
| 		DriveLayoutEx.PartitionEntry[0].Gpt.PartitionType = PARTITION_BASIC_DATA_GUID; | 		DriveLayoutEx.PartitionEntry[0].Gpt.PartitionType = PARTITION_BASIC_DATA_GUID; | ||||||
| 		wcscpy(DriveLayoutEx.PartitionEntry[0].Gpt.Name, L"Microsoft Basic Data"); | 		wcscpy(DriveLayoutEx.PartitionEntry[0].Gpt.Name, L"Microsoft Basic Data"); | ||||||
|  | 		if (add_uefi_togo) { | ||||||
|  | 			DriveLayoutEx.PartitionEntry[1].Gpt.PartitionType = PARTITION_BASIC_DATA_GUID; | ||||||
|  | 			wcscpy(DriveLayoutEx.PartitionEntry[1].Gpt.Name, L"UEFI:TOGO"); | ||||||
|  | 			DriveLayoutEx.PartitionEntry[1].PartitionNumber = 2; | ||||||
|  | 			DriveLayoutEx.PartitionEntry[1].RewritePartition = TRUE; | ||||||
|  | 			DriveLayoutEx.PartitionEntry[1].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart + | ||||||
|  | 				DriveLayoutEx.PartitionEntry[0].PartitionLength.QuadPart; | ||||||
|  | 			DriveLayoutEx.PartitionEntry[1].PartitionLength.QuadPart = | ||||||
|  | 				GetResourceSize(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_TOGO), _RT_RCDATA, "uefi-togo.img"); | ||||||
|  | 		} | ||||||
| 		IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[0].Gpt.PartitionId)); | 		IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[0].Gpt.PartitionId)); | ||||||
|  | 		IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[1].Gpt.PartitionId)); | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// We need to write the extra partition before we refresh the disk
 | ||||||
|  | 	if (add_uefi_togo) { | ||||||
|  | 		uprintf("Writing UEFI:TOGO partition..."); | ||||||
|  | 		if (!SetFilePointerEx(hDrive, DriveLayoutEx.PartitionEntry[1].StartingOffset, NULL, FILE_BEGIN)) { | ||||||
|  | 			uprintf("Unable to set position"); | ||||||
|  | 			safe_closehandle(hDrive); | ||||||
|  | 			return FALSE; | ||||||
|  | 		} | ||||||
|  | 		buffer = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_TOGO), _RT_RCDATA, "uefi-togo.img", &bufsize, FALSE); | ||||||
|  | 		if (buffer == NULL) { | ||||||
|  | 			uprintf("Could not access uefi-togo.img"); | ||||||
|  | 			safe_closehandle(hDrive); | ||||||
|  | 			return FALSE; | ||||||
|  | 		} | ||||||
|  | 		r = WriteFile(hDrive, buffer, bufsize, &size, NULL); | ||||||
|  | 		if ((!r) || (size != bufsize)) { | ||||||
|  | 			if (!r) | ||||||
|  | 				uprintf("Write error: %s", WindowsErrorString()); | ||||||
|  | 			else | ||||||
|  | 				uprintf("Write error: Wrote %d bytes, expected %d bytes\n", size, bufsize); | ||||||
|  | 			safe_closehandle(hDrive); | ||||||
|  | 			return FALSE; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// If you don't call IOCTL_DISK_CREATE_DISK, the next call will fail
 | 	// If you don't call IOCTL_DISK_CREATE_DISK, the next call will fail
 | ||||||
| 	size = sizeof(CreateDisk); | 	size = sizeof(CreateDisk); | ||||||
| 	r = DeviceIoControl(hDrive, IOCTL_DISK_CREATE_DISK, | 	r = DeviceIoControl(hDrive, IOCTL_DISK_CREATE_DISK, | ||||||
|  | @ -1019,7 +1077,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m | ||||||
| 		return FALSE; | 		return FALSE; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	size = sizeof(DriveLayoutEx) - ((partition_style == PARTITION_STYLE_GPT)?(3*sizeof(PARTITION_INFORMATION_EX)):0); | 	size = sizeof(DriveLayoutEx) - ((partition_style == PARTITION_STYLE_GPT)?((add_uefi_togo?2:3)*sizeof(PARTITION_INFORMATION_EX)):0); | ||||||
| 	r = DeviceIoControl(hDrive, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, | 	r = DeviceIoControl(hDrive, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, | ||||||
| 			(BYTE*)&DriveLayoutEx, size, NULL, 0, &size, NULL ); | 			(BYTE*)&DriveLayoutEx, size, NULL, 0, &size, NULL ); | ||||||
| 	if (!r) { | 	if (!r) { | ||||||
|  |  | ||||||
|  | @ -63,7 +63,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys | ||||||
| BOOL UnmountVolume(HANDLE hDrive); | BOOL UnmountVolume(HANDLE hDrive); | ||||||
| BOOL MountVolume(char* drive_name, char *drive_guid); | BOOL MountVolume(char* drive_name, char *drive_guid); | ||||||
| BOOL RemountVolume(char* drive_name); | BOOL RemountVolume(char* drive_name); | ||||||
| BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker); | BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker, BOOL add_uefi_togo); | ||||||
| BOOL DeletePartitions(HANDLE hDrive); | BOOL DeletePartitions(HANDLE hDrive); | ||||||
| BOOL RefreshDriveLayout(HANDLE hDrive); | BOOL RefreshDriveLayout(HANDLE hDrive); | ||||||
| const char* GetPartitionType(BYTE Type); | const char* GetPartitionType(BYTE Type); | ||||||
|  |  | ||||||
|  | @ -1271,7 +1271,7 @@ DWORD WINAPI CloseFormatPromptThread(LPVOID param) { | ||||||
| DWORD WINAPI FormatThread(void* param) | DWORD WINAPI FormatThread(void* param) | ||||||
| { | { | ||||||
| 	int i, r, pt, bt, fs, dt; | 	int i, r, pt, bt, fs, dt; | ||||||
| 	BOOL s, ret, use_large_fat32; | 	BOOL s, ret, use_large_fat32, add_uefi_togo; | ||||||
| 	const DWORD SectorSize = SelectedDrive.Geometry.BytesPerSector; | 	const DWORD SectorSize = SelectedDrive.Geometry.BytesPerSector; | ||||||
| 	DWORD rSize, wSize, BufSize, LastRefresh = 0, DriveIndex = (DWORD)(uintptr_t)param; | 	DWORD rSize, wSize, BufSize, LastRefresh = 0, DriveIndex = (DWORD)(uintptr_t)param; | ||||||
| 	HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE; | 	HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE; | ||||||
|  | @ -1301,6 +1301,7 @@ DWORD WINAPI FormatThread(void* param) | ||||||
| 	pt = GETPARTTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme))); | 	pt = GETPARTTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme))); | ||||||
| 	bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme))); | 	bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme))); | ||||||
| 	use_large_fat32 = (fs == FS_FAT32) && ((SelectedDrive.DiskSize > LARGE_FAT32_SIZE) || (force_large_fat32)); | 	use_large_fat32 = (fs == FS_FAT32) && ((SelectedDrive.DiskSize > LARGE_FAT32_SIZE) || (force_large_fat32)); | ||||||
|  | 	add_uefi_togo = (fs == FS_NTFS) && (dt == DT_ISO) && (IS_EFI(iso_report)) && (bt == BT_UEFI); | ||||||
| 
 | 
 | ||||||
| 	PrintStatus(0, TRUE, MSG_225); | 	PrintStatus(0, TRUE, MSG_225); | ||||||
| 	hPhysicalDrive = GetPhysicalHandle(DriveIndex, TRUE, TRUE); | 	hPhysicalDrive = GetPhysicalHandle(DriveIndex, TRUE, TRUE); | ||||||
|  | @ -1531,7 +1532,7 @@ DWORD WINAPI FormatThread(void* param) | ||||||
| 	UpdateProgress(OP_ZERO_MBR, -1.0f); | 	UpdateProgress(OP_ZERO_MBR, -1.0f); | ||||||
| 	CHECK_FOR_USER_CANCEL; | 	CHECK_FOR_USER_CANCEL; | ||||||
| 
 | 
 | ||||||
| 	if (!CreatePartition(hPhysicalDrive, pt, fs, (pt==PARTITION_STYLE_MBR)&&(bt==BT_UEFI))) { | 	if (!CreatePartition(hPhysicalDrive, pt, fs, (pt==PARTITION_STYLE_MBR) && (bt==BT_UEFI), add_uefi_togo)) { | ||||||
| 		FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE; | 		FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE; | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -73,6 +73,7 @@ | ||||||
| #define IDR_GR_GRUB2_CORE_IMG           451 | #define IDR_GR_GRUB2_CORE_IMG           451 | ||||||
| #define IDR_LC_RUFUS_LOC                500 | #define IDR_LC_RUFUS_LOC                500 | ||||||
| #define IDR_XT_HOGGER                   501 | #define IDR_XT_HOGGER                   501 | ||||||
|  | #define IDR_UEFI_TOGO                   502 | ||||||
| #define IDC_DEVICE                      1001 | #define IDC_DEVICE                      1001 | ||||||
| #define IDC_FILESYSTEM                  1002 | #define IDC_FILESYSTEM                  1002 | ||||||
| #define IDC_START                       1003 | #define IDC_START                       1003 | ||||||
|  |  | ||||||
|  | @ -460,7 +460,8 @@ static void SetFSFromISO(void) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Syslinux and EFI have precedence over bootmgr (unless the user selected BIOS as target type)
 | 	// Syslinux and EFI have precedence over bootmgr (unless the user selected BIOS as target type)
 | ||||||
| 	if ((HAS_SYSLINUX(iso_report)) || (IS_REACTOS(iso_report)) || (iso_report.has_kolibrios) || ( (IS_EFI(iso_report)) && (bt == BT_UEFI))) { | 	if ((HAS_SYSLINUX(iso_report)) || (IS_REACTOS(iso_report)) || (iso_report.has_kolibrios) || | ||||||
|  | 		((IS_EFI(iso_report)) && (bt == BT_UEFI) && (!iso_report.has_4GB_file))) { | ||||||
| 		if (fs_mask & (1<<FS_FAT32)) { | 		if (fs_mask & (1<<FS_FAT32)) { | ||||||
| 			selected_fs = FS_FAT32; | 			selected_fs = FS_FAT32; | ||||||
| 		} else if ((fs_mask & (1<<FS_FAT16)) && (!iso_report.has_kolibrios)) { | 		} else if ((fs_mask & (1<<FS_FAT16)) && (!iso_report.has_kolibrios)) { | ||||||
|  |  | ||||||
|  | @ -42,6 +42,7 @@ | ||||||
| #define DRIVE_ACCESS_RETRIES        60			// How many times we should retry
 | #define DRIVE_ACCESS_RETRIES        60			// How many times we should retry
 | ||||||
| #define DRIVE_INDEX_MIN             0x00000080 | #define DRIVE_INDEX_MIN             0x00000080 | ||||||
| #define DRIVE_INDEX_MAX             0x000000C0 | #define DRIVE_INDEX_MAX             0x000000C0 | ||||||
|  | #define MIN_EXTRA_PART_SIZE         2048		// Minimum size of the extra partition, in sectors
 | ||||||
| #define MAX_DRIVES                  (DRIVE_INDEX_MAX - DRIVE_INDEX_MIN) | #define MAX_DRIVES                  (DRIVE_INDEX_MAX - DRIVE_INDEX_MIN) | ||||||
| #define MAX_TOOLTIPS                128 | #define MAX_TOOLTIPS                128 | ||||||
| #define MAX_SIZE_SUFFIXES           6			// bytes, KB, MB, GB, TB, PB
 | #define MAX_SIZE_SUFFIXES           6			// bytes, KB, MB, GB, TB, PB
 | ||||||
|  | @ -384,6 +385,7 @@ extern BOOL SetAutorun(const char* path); | ||||||
| extern char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options); | extern char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options); | ||||||
| extern BOOL FileIO(BOOL save, char* path, char** buffer, DWORD* size); | extern BOOL FileIO(BOOL save, char* path, char** buffer, DWORD* size); | ||||||
| extern unsigned char* GetResource(HMODULE module, char* name, char* type, const char* desc, DWORD* len, BOOL duplicate); | extern unsigned char* GetResource(HMODULE module, char* name, char* type, const char* desc, DWORD* len, BOOL duplicate); | ||||||
|  | extern DWORD GetResourceSize(HMODULE module, char* name, char* type, const char* desc); | ||||||
| extern BOOL GetUSBDevices(DWORD devnum); | extern BOOL GetUSBDevices(DWORD devnum); | ||||||
| extern BOOL SetLGP(BOOL bRestore, BOOL* bExistingKey, const char* szPath, const char* szPolicy, DWORD dwValue); | extern BOOL SetLGP(BOOL bRestore, BOOL* bExistingKey, const char* szPath, const char* szPolicy, DWORD dwValue); | ||||||
| extern LONG GetEntryWidth(HWND hDropDown, const char* entry); | extern LONG GetEntryWidth(HWND hDropDown, const char* entry); | ||||||
|  |  | ||||||
							
								
								
									
										18
									
								
								src/rufus.rc
									
										
									
									
									
								
							
							
						
						
									
										18
									
								
								src/rufus.rc
									
										
									
									
									
								
							|  | @ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL | ||||||
| 
 | 
 | ||||||
| IDD_DIALOG DIALOGEX 12, 12, 242, 329 | IDD_DIALOG DIALOGEX 12, 12, 242, 329 | ||||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | ||||||
| CAPTION "Rufus 1.5.0.559" | CAPTION "Rufus 1.5.0.560" | ||||||
| FONT 8, "Segoe UI", 400, 0, 0x1 | FONT 8, "Segoe UI", 400, 0, 0x1 | ||||||
| BEGIN | BEGIN | ||||||
|     DEFPUSHBUTTON   "Start",IDC_START,127,291,50,14 |     DEFPUSHBUTTON   "Start",IDC_START,127,291,50,14 | ||||||
|  | @ -164,7 +164,7 @@ END | ||||||
| 
 | 
 | ||||||
| IDD_DIALOG_XP DIALOGEX 12, 12, 242, 329 | IDD_DIALOG_XP DIALOGEX 12, 12, 242, 329 | ||||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | ||||||
| CAPTION "Rufus 1.5.0.559" | CAPTION "Rufus 1.5.0.560" | ||||||
| FONT 8, "MS Shell Dlg", 400, 0, 0x1 | FONT 8, "MS Shell Dlg", 400, 0, 0x1 | ||||||
| BEGIN | BEGIN | ||||||
|     DEFPUSHBUTTON   "Start",IDC_START,127,291,50,14 |     DEFPUSHBUTTON   "Start",IDC_START,127,291,50,14 | ||||||
|  | @ -297,7 +297,7 @@ END | ||||||
| IDD_DIALOG_RTL DIALOGEX 12, 12, 242, 329 | IDD_DIALOG_RTL DIALOGEX 12, 12, 242, 329 | ||||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | ||||||
| EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL | EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL | ||||||
| CAPTION "Rufus 1.5.0.559" | CAPTION "Rufus 1.5.0.560" | ||||||
| FONT 8, "Segoe UI", 400, 0, 0x1 | FONT 8, "Segoe UI", 400, 0, 0x1 | ||||||
| BEGIN | BEGIN | ||||||
|     DEFPUSHBUTTON   "Start",IDC_START,127,291,50,14 |     DEFPUSHBUTTON   "Start",IDC_START,127,291,50,14 | ||||||
|  | @ -437,7 +437,7 @@ END | ||||||
| IDD_DIALOG_RTL_XP DIALOGEX 12, 12, 242, 329 | IDD_DIALOG_RTL_XP DIALOGEX 12, 12, 242, 329 | ||||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | ||||||
| EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL | EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL | ||||||
| CAPTION "Rufus 1.5.0.559" | CAPTION "Rufus 1.5.0.560" | ||||||
| FONT 8, "MS Shell Dlg", 400, 0, 0x1 | FONT 8, "MS Shell Dlg", 400, 0, 0x1 | ||||||
| BEGIN | BEGIN | ||||||
|     DEFPUSHBUTTON   "Start",IDC_START,127,291,50,14 |     DEFPUSHBUTTON   "Start",IDC_START,127,291,50,14 | ||||||
|  | @ -641,6 +641,7 @@ BEGIN | ||||||
|     "IDR_FD_EGA17_CPX        RCDATA                  ""../res/freedos/ega17.cpx""\r\n" |     "IDR_FD_EGA17_CPX        RCDATA                  ""../res/freedos/ega17.cpx""\r\n" | ||||||
|     "IDR_FD_EGA18_CPX        RCDATA                  ""../res/freedos/ega18.cpx""\r\n" |     "IDR_FD_EGA18_CPX        RCDATA                  ""../res/freedos/ega18.cpx""\r\n" | ||||||
|     "IDR_XT_HOGGER           RCDATA                  ""../res/hogger/hogger.exe""\r\n" |     "IDR_XT_HOGGER           RCDATA                  ""../res/hogger/hogger.exe""\r\n" | ||||||
|  |     "IDR_UEFI_TOGO           RCDATA                  ""../res/uefi/uefi-togo.img""\r\n" | ||||||
|     "\r\n" |     "\r\n" | ||||||
|     "// Must reference a manifest for visual styles and elevation\r\n" |     "// Must reference a manifest for visual styles and elevation\r\n" | ||||||
|     "// Oh, and it must happen at the end, or MinGW will ignore it!\r\n" |     "// Oh, and it must happen at the end, or MinGW will ignore it!\r\n" | ||||||
|  | @ -702,8 +703,8 @@ END | ||||||
| // | // | ||||||
| 
 | 
 | ||||||
| VS_VERSION_INFO VERSIONINFO | VS_VERSION_INFO VERSIONINFO | ||||||
|  FILEVERSION 1,5,0,559 |  FILEVERSION 1,5,0,560 | ||||||
|  PRODUCTVERSION 1,5,0,559 |  PRODUCTVERSION 1,5,0,560 | ||||||
|  FILEFLAGSMASK 0x3fL |  FILEFLAGSMASK 0x3fL | ||||||
| #ifdef _DEBUG | #ifdef _DEBUG | ||||||
|  FILEFLAGS 0x1L |  FILEFLAGS 0x1L | ||||||
|  | @ -720,13 +721,13 @@ BEGIN | ||||||
|         BEGIN |         BEGIN | ||||||
|             VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" |             VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" | ||||||
|             VALUE "FileDescription", "Rufus" |             VALUE "FileDescription", "Rufus" | ||||||
|             VALUE "FileVersion", "1.5.0.559" |             VALUE "FileVersion", "1.5.0.560" | ||||||
|             VALUE "InternalName", "Rufus" |             VALUE "InternalName", "Rufus" | ||||||
|             VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)" |             VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)" | ||||||
|             VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" |             VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" | ||||||
|             VALUE "OriginalFilename", "rufus.exe" |             VALUE "OriginalFilename", "rufus.exe" | ||||||
|             VALUE "ProductName", "Rufus" |             VALUE "ProductName", "Rufus" | ||||||
|             VALUE "ProductVersion", "1.5.0.559" |             VALUE "ProductVersion", "1.5.0.560" | ||||||
|         END |         END | ||||||
|     END |     END | ||||||
|     BLOCK "VarFileInfo" |     BLOCK "VarFileInfo" | ||||||
|  | @ -797,6 +798,7 @@ IDR_FD_EGA16_CPX        RCDATA                  "../res/freedos/ega16.cpx" | ||||||
| IDR_FD_EGA17_CPX        RCDATA                  "../res/freedos/ega17.cpx" | IDR_FD_EGA17_CPX        RCDATA                  "../res/freedos/ega17.cpx" | ||||||
| IDR_FD_EGA18_CPX        RCDATA                  "../res/freedos/ega18.cpx" | IDR_FD_EGA18_CPX        RCDATA                  "../res/freedos/ega18.cpx" | ||||||
| IDR_XT_HOGGER           RCDATA                  "../res/hogger/hogger.exe" | IDR_XT_HOGGER           RCDATA                  "../res/hogger/hogger.exe" | ||||||
|  | IDR_UEFI_TOGO           RCDATA                  "../res/uefi/uefi-togo.img" | ||||||
| 
 | 
 | ||||||
| // Must reference a manifest for visual styles and elevation | // Must reference a manifest for visual styles and elevation | ||||||
| // Oh, and it must happen at the end, or MinGW will ignore it! | // Oh, and it must happen at the end, or MinGW will ignore it! | ||||||
|  |  | ||||||
|  | @ -522,6 +522,11 @@ out: | ||||||
| 	return p; | 	return p; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | DWORD GetResourceSize(HMODULE module, char* name, char* type, const char* desc) | ||||||
|  | { | ||||||
|  | 	DWORD len = 0; | ||||||
|  | 	return (GetResource(module, name, type, desc, &len, FALSE) == NULL)?0:len; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Set or restore a Local Group Policy DWORD key indexed by szPath/SzPolicy |  * Set or restore a Local Group Policy DWORD key indexed by szPath/SzPolicy | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue