mirror of
https://github.com/pbatard/rufus.git
synced 2025-05-19 01:15:12 -04:00
[core] drive handling improvements
* Use IOCTL_DISK_UPDATE_PROPERTIES after partitioning * Use IOCTL_DISK_DELETE_DRIVE_LAYOUT to invalidate partitions before formatting * Fix handling of unpartitioned drives * Increase delay after partitioning * All of the above should help with the infamous #122 * Also fix display of error messages in ms-sys' file.c as well as stdio.c * Also add commandline option -f to list fixed drives
This commit is contained in:
parent
fe3b1eb6f6
commit
cd5665881c
7 changed files with 163 additions and 72 deletions
92
src/format.c
92
src/format.c
|
@ -372,12 +372,14 @@ static BOOL FormatFAT32(DWORD DriveIndex)
|
|||
// Open the drive (volume should already be locked)
|
||||
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);
|
||||
if ((hLogicalVolume == INVALID_HANDLE_VALUE) || (hLogicalVolume == NULL))
|
||||
die("Invalid logical volume handle\n", ERROR_INVALID_HANDLE);
|
||||
|
||||
// Make sure we get exclusive access
|
||||
if (!UnmountVolume(hLogicalVolume))
|
||||
return r;
|
||||
if (!UnmountVolume(hLogicalVolume)) {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Work out drive params
|
||||
if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dgDrive,
|
||||
|
@ -1088,19 +1090,45 @@ out:
|
|||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mount the volume identified by drive_guid to mountpoint drive_name
|
||||
*/
|
||||
static BOOL MountVolume(char* drive_name, char *drive_guid)
|
||||
{
|
||||
char mounted_guid[50];
|
||||
|
||||
if (!SetVolumeMountPointA(drive_name, drive_guid)) {
|
||||
// If the OS was faster than us at remounting the drive, this operation can fail
|
||||
// with ERROR_DIR_NOT_EMPTY. If that's the case, just check that mountpoints match
|
||||
if (GetLastError() == ERROR_DIR_NOT_EMPTY) {
|
||||
if (!GetVolumeNameForVolumeMountPointA(drive_name, mounted_guid, sizeof(mounted_guid))) {
|
||||
uprintf("%s already mounted, but volume GUID could not be checked\n", drive_name);
|
||||
return FALSE;
|
||||
}
|
||||
if (safe_strcmp(drive_guid, mounted_guid) != 0) {
|
||||
uprintf("%s already mounted, but volume GUID doesn't match:\r\n expected %s, got %s\n",
|
||||
drive_name, drive_guid, mounted_guid);
|
||||
return FALSE;
|
||||
}
|
||||
uprintf("%s was already mounted as %s\n", drive_guid, drive_name);
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Issue a complete remount of the volume
|
||||
*/
|
||||
static BOOL RemountVolume(char drive_letter)
|
||||
static BOOL RemountVolume(char* drive_name)
|
||||
{
|
||||
char drive_guid[50];
|
||||
char drive_name[] = "?:\\";
|
||||
|
||||
drive_name[0] = drive_letter;
|
||||
if (GetVolumeNameForVolumeMountPointA(drive_name, drive_guid, sizeof(drive_guid))) {
|
||||
if (DeleteVolumeMountPointA(drive_name)) {
|
||||
Sleep(200);
|
||||
if (SetVolumeMountPointA(drive_name, drive_guid)) {
|
||||
if (MountVolume(drive_name, drive_guid)) {
|
||||
uprintf("Successfully remounted %s on %s\n", &drive_guid[4], drive_name);
|
||||
} else {
|
||||
uprintf("Failed to remount %s on %s\n", &drive_guid[4], drive_name);
|
||||
|
@ -1212,22 +1240,39 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
uprintf("Failed to delete mountpoint %s: %s\n", drive_name, WindowsErrorString());
|
||||
// Try to continue. We will bail out if this causes an issue.
|
||||
}
|
||||
uprintf("Will use '%c': as volume mountpoint\n", drive_name[0]);
|
||||
uprintf("Will use '%c:' as volume mountpoint\n", drive_name[0]);
|
||||
|
||||
// ...but we need a lock to the logical drive to be able to write anything to it
|
||||
// TODO: Use a retry loop for the lock
|
||||
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;
|
||||
} else if (hLogicalVolume == NULL) {
|
||||
// NULL is returned for cases where the drive is not yet partitioned
|
||||
uprintf("Drive does not appear to be partitioned\n");
|
||||
} else {
|
||||
if (!UnmountVolume(hLogicalVolume))
|
||||
uprintf("Trying to continue regardless...\n");
|
||||
}
|
||||
UnmountVolume(hLogicalVolume);
|
||||
if (FormatStatus) goto out; // Check for user cancel
|
||||
|
||||
PrintStatus(0, TRUE, "Analyzing existing boot records...\n");
|
||||
AnalyzeMBR(hPhysicalDrive);
|
||||
AnalyzePBR(hLogicalVolume);
|
||||
if (hLogicalVolume != NULL) {
|
||||
AnalyzePBR(hLogicalVolume);
|
||||
}
|
||||
UpdateProgress(OP_ANALYZE_MBR, -1.0f);
|
||||
|
||||
// Zap any existing partitions. This should help to prevent access errors
|
||||
// TODO: With this, we should be able to avoid having to deal with the logical volume above
|
||||
if (!DeletePartitions(hPhysicalDrive)) {
|
||||
uprintf("Could not reset partitions\n");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (IsChecked(IDC_BADBLOCKS)) {
|
||||
do {
|
||||
// create a log file for bad blocks report. Since %USERPROFILE% may
|
||||
|
@ -1290,11 +1335,13 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
}
|
||||
// Close the (unmounted) volume before formatting, but keep the lock
|
||||
// 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;
|
||||
if (hLogicalVolume != NULL) {
|
||||
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;
|
||||
|
||||
|
@ -1318,8 +1365,9 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
}
|
||||
UpdateProgress(OP_PARTITION, -1.0f);
|
||||
|
||||
// Add a small delay after partitioning to be safe
|
||||
Sleep(200);
|
||||
// Add a delay after partitioning to be safe
|
||||
// TODO: Use a retry loop and test the lock
|
||||
Sleep(2000);
|
||||
|
||||
// If FAT32 is requested and we have a large drive (>32 GB) use
|
||||
// large FAT32 format, else use MS's FormatEx.
|
||||
|
@ -1350,7 +1398,7 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
}
|
||||
if (FormatStatus) goto out; // Check for user cancel
|
||||
|
||||
if (!SetVolumeMountPointA(drive_name, guid_volume)) {
|
||||
if (!MountVolume(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;
|
||||
|
@ -1368,7 +1416,7 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
// We still have a lock, which we need to modify the volume boot record
|
||||
// => no need to reacquire the lock...
|
||||
hLogicalVolume = GetLogicalHandle(DriveIndex, TRUE, FALSE);
|
||||
if (hLogicalVolume == INVALID_HANDLE_VALUE) {
|
||||
if ((hLogicalVolume == INVALID_HANDLE_VALUE) || (hLogicalVolume == NULL)) {
|
||||
uprintf("Could not re-mount volume for partition boot record access\n");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
||||
goto out;
|
||||
|
@ -1397,7 +1445,7 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
// We issue a complete remount of the filesystem at on account of:
|
||||
// - Ensuring the file explorer properly detects that the volume was updated
|
||||
// - Ensuring that an NTFS system will be reparsed so that it becomes bootable
|
||||
if (!RemountVolume(drive_name[0]))
|
||||
if (!RemountVolume(drive_name))
|
||||
goto out;
|
||||
if (FormatStatus) goto out; // Check for user cancel
|
||||
|
||||
|
@ -1449,7 +1497,7 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
if (IsChecked(IDC_SET_ICON))
|
||||
SetAutorun(drive_name);
|
||||
// Issue another complete remount before we exit, to ensure we're clean
|
||||
RemountVolume(drive_name[0]);
|
||||
RemountVolume(drive_name);
|
||||
// NTFS fixup (WinPE/AIK images don't seem to boot without an extra checkdisk)
|
||||
if ((dt == DT_ISO) && (fs == FS_NTFS)) {
|
||||
CheckDisk(drive_name[0]);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue