diff --git a/src/drive.c b/src/drive.c index f613d157..c6b74dee 100644 --- a/src/drive.c +++ b/src/drive.c @@ -37,14 +37,16 @@ #include "ntfs.h" #include "localization.h" +#if !defined(PARTITION_BASIC_DATA_GUID) +const GUID PARTITION_BASIC_DATA_GUID = + { 0xebd0a0a2, 0xb9e5, 0x4433, {0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7} }; +#endif + /* * Globals */ RUFUS_DRIVE_INFO SelectedDrive; -// TODO: add a DetectSectorSize()? -// http://msdn.microsoft.com/en-us/library/ff800831.aspx - /* * 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 @@ -78,7 +80,7 @@ static HANDLE GetHandle(char* Path, BOOL bWriteAccess, BOOL bLockDrive) } if (bWriteAccess) { - uprintf("Caution: Opened drive %s for write access\n", Path); + uprintf("Opened drive %s for write access\n", Path); } if (bLockDrive) { @@ -136,7 +138,6 @@ HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bWriteAccess, BOOL bLockDrive) * The returned string is allocated and must be freed * TODO: a drive may have multiple volumes - should we handle those? */ -#define suprintf(...) if (!bSilent) uprintf(__VA_ARGS__) char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent) { BOOL success = FALSE; @@ -585,10 +586,13 @@ BOOL AnalyzePBR(HANDLE hLogicalVolume) /* * Fill the drive properties (size, FS, etc) + * Returns TRUE if the drive has a partition that can be mounted in Windows, FALSE otherwise */ -int GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSystemNameSize) +BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSystemNameSize, BOOL bSilent) { - BOOL r, hasRufusExtra = FALSE; + // MBR partition types that can be mounted in Windows + const uint8_t mbr_mountable[] = { 0x01, 0x04, 0x06, 0x07, 0x0b, 0x0c, 0x0e, 0xef }; + BOOL r, hasRufusExtra = FALSE, ret = FALSE; HANDLE hPhysical; DWORD size; BYTE geometry[256], layout[4096], part_type; @@ -596,13 +600,14 @@ int GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSyst PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)(void*)layout; char* volume_name; char tmp[256]; - DWORD i, nb_partitions = 0; + DWORD i, j; + SelectedDrive.nPartitions = 0; // Populate the filesystem data FileSystemName[0] = 0; volume_name = GetLogicalName(DriveIndex, TRUE, FALSE); if ((volume_name == NULL) || (!GetVolumeInformationA(volume_name, NULL, 0, NULL, NULL, NULL, FileSystemName, FileSystemNameSize))) { - uprintf("No volume information for drive 0x%02x\n", DriveIndex); + suprintf("No volume information for drive 0x%02x\n", DriveIndex); } safe_free(volume_name); @@ -613,26 +618,26 @@ int GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSyst r = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, geometry, sizeof(geometry), &size, NULL); if (!r || size <= 0) { - uprintf("Could not get geometry for drive 0x%02x: %s\n", DriveIndex, WindowsErrorString()); + suprintf("Could not get geometry for drive 0x%02x: %s\n", DriveIndex, WindowsErrorString()); safe_closehandle(hPhysical); return 0; } if (DiskGeometry->Geometry.BytesPerSector < 512) { - uprintf("WARNING: Drive 0x%02x reports a sector size of %d - Correcting to 512 bytes.\n", + suprintf("WARNING: Drive 0x%02x reports a sector size of %d - Correcting to 512 bytes.\n", DriveIndex, DiskGeometry->Geometry.BytesPerSector); DiskGeometry->Geometry.BytesPerSector = 512; } SelectedDrive.DiskSize = DiskGeometry->DiskSize.QuadPart; memcpy(&SelectedDrive.Geometry, &DiskGeometry->Geometry, sizeof(DISK_GEOMETRY)); - uprintf("Disk type: %s, Sector Size: %d bytes\n", (DiskGeometry->Geometry.MediaType == FixedMedia)?"Fixed":"Removable", + suprintf("Disk type: %s, Sector Size: %d bytes\n", (DiskGeometry->Geometry.MediaType == FixedMedia)?"Fixed":"Removable", DiskGeometry->Geometry.BytesPerSector); - uprintf("Cylinders: %lld, TracksPerCylinder: %d, SectorsPerTrack: %d\n", + suprintf("Cylinders: %lld, TracksPerCylinder: %d, SectorsPerTrack: %d\n", DiskGeometry->Geometry.Cylinders, DiskGeometry->Geometry.TracksPerCylinder, DiskGeometry->Geometry.SectorsPerTrack); r = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, layout, sizeof(layout), &size, NULL ); if (!r || size <= 0) { - uprintf("Could not get layout for drive 0x%02x: %s\n", DriveIndex, WindowsErrorString()); + suprintf("Could not get layout for drive 0x%02x: %s\n", DriveIndex, WindowsErrorString()); safe_closehandle(hPhysical); return 0; } @@ -642,18 +647,24 @@ int GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSyst SelectedDrive.PartitionType = PARTITION_STYLE_MBR; for (i=0; iPartitionCount; i++) { if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) { - nb_partitions++; + SelectedDrive.nPartitions++; } } - uprintf("Partition type: MBR, NB Partitions: %d\n", nb_partitions); + suprintf("Partition type: MBR, NB Partitions: %d\n", SelectedDrive.nPartitions); SelectedDrive.has_mbr_uefi_marker = (DriveLayout->Mbr.Signature == MBR_UEFI_MARKER); - uprintf("Disk ID: 0x%08X %s\n", DriveLayout->Mbr.Signature, SelectedDrive.has_mbr_uefi_marker?"(UEFI target)":""); + suprintf("Disk ID: 0x%08X %s\n", DriveLayout->Mbr.Signature, SelectedDrive.has_mbr_uefi_marker?"(UEFI target)":""); AnalyzeMBR(hPhysical, "Drive"); for (i=0; iPartitionCount; i++) { if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) { - uprintf("Partition %d:\n", i+1); + suprintf("Partition %d:\n", i+1); part_type = DriveLayout->PartitionEntry[i].Mbr.PartitionType; - uprintf(" Type: %s (0x%02x)\r\n Size: %s (%lld bytes)\r\n Start Sector: %d, Boot: %s, Recognized: %s\n", + for (j=0; jPartitionEntry[i].PartitionLength.QuadPart, TRUE, FALSE), DriveLayout->PartitionEntry[i].PartitionLength, DriveLayout->PartitionEntry[i].Mbr.HiddenSectors, @@ -668,32 +679,35 @@ int GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSyst break; case PARTITION_STYLE_GPT: SelectedDrive.PartitionType = PARTITION_STYLE_GPT; - uprintf("Partition type: GPT, NB Partitions: %d\n", DriveLayout->PartitionCount); - uprintf("Disk GUID: %s\n", GuidToString(&DriveLayout->Gpt.DiskId)); - uprintf("Max parts: %d, Start Offset: %lld, Usable = %lld bytes\n", + suprintf("Partition type: GPT, NB Partitions: %d\n", DriveLayout->PartitionCount); + suprintf("Disk GUID: %s\n", GuidToString(&DriveLayout->Gpt.DiskId)); + suprintf("Max parts: %d, Start Offset: %lld, Usable = %lld bytes\n", DriveLayout->Gpt.MaxPartitionCount, DriveLayout->Gpt.StartingUsableOffset.QuadPart, DriveLayout->Gpt.UsableLength.QuadPart); for (i=0; iPartitionCount; i++) { - nb_partitions++; + SelectedDrive.nPartitions++; tmp[0] = 0; wchar_to_utf8_no_alloc(DriveLayout->PartitionEntry[i].Gpt.Name, tmp, sizeof(tmp)); - uprintf("Partition %d:\r\n Type: %s\r\n Name: '%s'\n", DriveLayout->PartitionEntry[i].PartitionNumber, + suprintf("Partition %d:\r\n Type: %s\r\n Name: '%s'\n", DriveLayout->PartitionEntry[i].PartitionNumber, GuidToString(&DriveLayout->PartitionEntry[i].Gpt.PartitionType), tmp); - uprintf(" ID: %s\r\n Size: %s (%lld bytes)\r\n Start Sector: %lld, Attributes: 0x%016llX\n", + suprintf(" ID: %s\r\n Size: %s (%lld bytes)\r\n Start Sector: %lld, Attributes: 0x%016llX\n", 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].Gpt.Attributes); + if ( (memcmp(&PARTITION_BASIC_DATA_GUID, &DriveLayout->PartitionEntry[i].Gpt.PartitionType, sizeof(GUID)) == 0) && + (nWindowsVersion >= WINDOWS_VISTA) ) + ret = TRUE; } break; default: SelectedDrive.PartitionType = PARTITION_STYLE_MBR; - uprintf("Partition type: RAW\n"); + suprintf("Partition type: RAW\n"); break; } safe_closehandle(hPhysical); if (hasRufusExtra) - nb_partitions--; - return (int)nb_partitions; + SelectedDrive.nPartitions--; + return ret; } /* @@ -822,9 +836,6 @@ typedef struct _DRIVE_LAYOUT_INFORMATION_EX4 { * copy it got from the last IOCTL, and ignores your changes until you replug the drive * or issue an IOCTL_DISK_UPDATE_PROPERTIES. */ -#if !defined(PARTITION_BASIC_DATA_GUID) -const GUID PARTITION_BASIC_DATA_GUID = { 0xebd0a0a2, 0xb9e5, 0x4433, {0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7} }; -#endif BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker) { const char* PartitionTypeName[2] = { "MBR", "GPT" }; @@ -963,10 +974,8 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m safe_closehandle(hDrive); return FALSE; } - // Diskpart does call the following IOCTL this after updating the partition table, so we do too - r = DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &size, NULL ); - if (!r) { - uprintf("Could not refresh drive layout: %s\n", WindowsErrorString()); + + if (!RefreshDriveLayout(hDrive)) { safe_closehandle(hDrive); return FALSE; } @@ -974,6 +983,18 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m return TRUE; } +BOOL RefreshDriveLayout(HANDLE hDrive) +{ + BOOL r; + DWORD size; + + // Diskpart does call the following IOCTL this after updating the partition table, so we do too + r = DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &size, NULL ); + if (!r) + uprintf("Could not refresh drive layout: %s\n", WindowsErrorString()); + return r; +} + /* Delete the disk partition table */ BOOL DeletePartitions(HANDLE hDrive) { diff --git a/src/drive.h b/src/drive.h index aac6ff11..26c2748d 100644 --- a/src/drive.h +++ b/src/drive.h @@ -51,10 +51,11 @@ uint64_t GetDriveSize(DWORD DriveIndex); BOOL IsMediaPresent(DWORD DriveIndex); BOOL AnalyzeMBR(HANDLE hPhysicalDrive, const char* TargetName); BOOL AnalyzePBR(HANDLE hLogicalVolume); -int GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSystemNameSize); +BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSystemNameSize, BOOL bSilent); BOOL UnmountVolume(HANDLE hDrive); BOOL MountVolume(char* drive_name, char *drive_guid); BOOL RemountVolume(char* drive_name); BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker); BOOL DeletePartitions(HANDLE hDrive); +BOOL RefreshDriveLayout(HANDLE hDrive); const char* GetPartitionType(BYTE Type); diff --git a/src/format.c b/src/format.c index 6151df4a..b4bbdddf 100644 --- a/src/format.c +++ b/src/format.c @@ -1358,8 +1358,18 @@ DWORD WINAPI FormatThread(void* param) } } + // Especially after destructive badblocks test, you must zero the MBR/GPT completely + // before repartitioning. Else, all kind of bad things happen. + if (!ClearMBRGPT(hPhysicalDrive, SelectedDrive.DiskSize, 512, use_large_fat32)) { + uprintf("unable to zero MBR/GPT\n"); + if (!IS_ERROR(FormatStatus)) + FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; + goto out; + } + // Write an image file if (dt == DT_IMG) { + char fs_type[32]; // We poked the MBR and other stuff, so we need to rewind li.QuadPart = 0; if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN)) @@ -1421,10 +1431,32 @@ DWORD WINAPI FormatThread(void* param) } if (i >= WRITE_RETRIES) goto out; } + + // If the image contains a partition we might be able to access, try to re-mount it + RefreshDriveLayout(hPhysicalDrive); + safe_unlockclose(hPhysicalDrive); + safe_unlockclose(hLogicalVolume); + Sleep(200); + WaitForLogical(DriveIndex); + if (GetDrivePartitionData(SelectedDrive.DeviceNumber, fs_type, sizeof(fs_type), TRUE)) { + guid_volume = GetLogicalName(DriveIndex, TRUE, TRUE); + if ((guid_volume != NULL) && (MountVolume(drive_name, guid_volume))) + uprintf("Remounted %s on %s\n", guid_volume, drive_name); + } + uprintf("Done"); goto out; } + UpdateProgress(OP_ZERO_MBR, -1.0f); + CHECK_FOR_USER_CANCEL; + + if (!CreatePartition(hPhysicalDrive, pt, fs, (pt==PARTITION_STYLE_MBR)&&(bt==BT_UEFI))) { + FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE; + goto out; + } + UpdateProgress(OP_PARTITION, -1.0f); + // Close the (unmounted) volume before formatting if ((hLogicalVolume != NULL) && (hLogicalVolume != INVALID_HANDLE_VALUE)) { PrintStatus(0, TRUE, MSG_227); @@ -1436,23 +1468,6 @@ DWORD WINAPI FormatThread(void* param) } hLogicalVolume = INVALID_HANDLE_VALUE; - // Especially after destructive badblocks test, you must zero the MBR/GPT completely - // before repartitioning. Else, all kind of bad things happen. - if (!ClearMBRGPT(hPhysicalDrive, SelectedDrive.DiskSize, 512, use_large_fat32)) { - uprintf("unable to zero MBR/GPT\n"); - if (!IS_ERROR(FormatStatus)) - FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; - goto out; - } - UpdateProgress(OP_ZERO_MBR, -1.0f); - CHECK_FOR_USER_CANCEL; - - if (!CreatePartition(hPhysicalDrive, pt, fs, (pt==PARTITION_STYLE_MBR)&&(bt==BT_UEFI))) { - FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE; - goto out; - } - UpdateProgress(OP_PARTITION, -1.0f); - // Wait for the logical drive we just created to appear uprintf("Waiting for logical drive to reappear...\n"); Sleep(200); diff --git a/src/rufus.c b/src/rufus.c index 86be935b..b6e18330 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -380,7 +380,7 @@ static BOOL SetDriveInfo(int ComboIndex) memset(&SelectedDrive, 0, sizeof(SelectedDrive)); SelectedDrive.DeviceNumber = (DWORD)ComboBox_GetItemData(hDeviceList, ComboIndex); - SelectedDrive.nPartitions = GetDrivePartitionData(SelectedDrive.DeviceNumber, fs_type, sizeof(fs_type)); + GetDrivePartitionData(SelectedDrive.DeviceNumber, fs_type, sizeof(fs_type), FALSE); if (!DefineClusterSizes()) { uprintf("No file system is selectable for this drive\n"); diff --git a/src/rufus.h b/src/rufus.h index 05dd9419..d251f1b3 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -104,6 +104,7 @@ extern void _uprintf(const char *format, ...); #define uprintf(...) _uprintf(__VA_ARGS__) #define vuprintf(...) if (verbose) _uprintf(__VA_ARGS__) #define vvuprintf(...) if (verbose > 1) _uprintf(__VA_ARGS__) +#define suprintf(...) if (!bSilent) _uprintf(__VA_ARGS__) #ifdef _DEBUG #define duprintf(...) _uprintf(__VA_ARGS__) #else @@ -114,6 +115,7 @@ extern void _uprintf(const char *format, ...); #define vuprintf(...) #define vvuprintf(...) #define duprintf(...) +#define suprintf(...) #endif /* Custom Windows messages */ diff --git a/src/rufus.rc b/src/rufus.rc index 6abfe410..bf20e0b7 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 206, 329 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Rufus 1.4.10.510" +CAPTION "Rufus 1.4.10.511" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "Start",IDC_START,94,291,50,14 @@ -165,7 +165,7 @@ END RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL -CAPTION "Rufus 1.4.10.510" +CAPTION "Rufus 1.4.10.511" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "Start",IDC_START,94,291,50,14 @@ -428,8 +428,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,4,10,510 - PRODUCTVERSION 1,4,10,510 + FILEVERSION 1,4,10,511 + PRODUCTVERSION 1,4,10,511 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -446,13 +446,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "1.4.10.510" + VALUE "FileVersion", "1.4.10.511" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "1.4.10.510" + VALUE "ProductVersion", "1.4.10.511" END END BLOCK "VarFileInfo"