mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[core] low level drive handling redesign
* Better split of physical vs logical * Add handling of unmounted volumes by GUID * Force large FAT32 cheat mode * Improve user messages and fix some UI issues
This commit is contained in:
parent
d56615cd20
commit
4da36fa321
7 changed files with 434 additions and 189 deletions
399
src/drive.c
399
src/drive.c
|
@ -38,106 +38,42 @@ RUFUS_DRIVE_INFO SelectedDrive;
|
|||
extern BOOL enable_fixed_disks;
|
||||
|
||||
/*
|
||||
* Open a drive or volume with optional write and lock access
|
||||
* Returns INVALID_HANDLE_VALUE (/!\ which is DIFFERENT from NULL /!\) on failure.
|
||||
* This call is quite risky (left unchecked, inadvertently passing 0 as index would
|
||||
* return a handle to C:, which we might then proceed to unknowingly repartition!),
|
||||
* so we apply the following mitigation factors:
|
||||
* - Valid indexes must belong to a specific range [DRIVE_INDEX_MIN; DRIVE_INDEX_MAX]
|
||||
* - When opening for write access, we lock the volume. If that fails, which would
|
||||
* typically be the case on C:\ or any other drive in use, we report failure
|
||||
* - We report the full path of any drive that was successfully opened for write acces
|
||||
* Working with drive indexes quite risky (left unchecked,inadvertently passing 0 as
|
||||
* index would return a handle to C:, which we might then proceed to unknowingly
|
||||
* clear the MBR of!), so we mitigate the risk by forcing our indexes to belong to
|
||||
* the specific range [DRIVE_INDEX_MIN; DRIVE_INDEX_MAX].
|
||||
*/
|
||||
HANDLE GetDriveHandle(DWORD DriveIndex, char* DriveLetter, BOOL bWriteAccess, BOOL bLockDrive)
|
||||
#define CheckDriveIndex(DriveIndex) do { \
|
||||
if ((DriveIndex < DRIVE_INDEX_MIN) || (DriveIndex > DRIVE_INDEX_MAX)) { \
|
||||
uprintf("WARNING: Bad index value. Please check the code!\n"); \
|
||||
goto out; \
|
||||
} \
|
||||
DriveIndex -= DRIVE_INDEX_MIN; } while (0)
|
||||
|
||||
/*
|
||||
* Open a drive or volume with optional write and lock access
|
||||
* Return INVALID_HANDLE_VALUE (/!\ which is DIFFERENT from NULL /!\) on failure.
|
||||
*/
|
||||
static HANDLE GetHandle(char* Path, BOOL bWriteAccess, BOOL bLockDrive)
|
||||
{
|
||||
BOOL r;
|
||||
DWORD size;
|
||||
HANDLE hDrive = INVALID_HANDLE_VALUE;
|
||||
STORAGE_DEVICE_NUMBER_REDEF device_number = {0};
|
||||
UINT drive_type;
|
||||
char drives[26*4]; /* "D:\", "E:\", etc. */
|
||||
char *drive = drives;
|
||||
char logical_drive[] = "\\\\.\\#:";
|
||||
char physical_drive[24];
|
||||
|
||||
DriveIndex &= DRIVE_INDEX_MASK;
|
||||
if ((DriveIndex < DRIVE_INDEX_MIN) || (DriveIndex > DRIVE_INDEX_MAX)) {
|
||||
uprintf("WARNING: Bad index value. Please check the code!\n");
|
||||
if (Path == NULL)
|
||||
goto out;
|
||||
hDrive = CreateFileA(Path, GENERIC_READ|(bWriteAccess?GENERIC_WRITE:0),
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
|
||||
if (hDrive == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Could not open drive %s: %s\n", Path, WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
DriveIndex -= DRIVE_INDEX_MIN;
|
||||
|
||||
// If no drive letter is requested, open a physical drive
|
||||
if (DriveLetter == NULL) {
|
||||
safe_sprintf(physical_drive, sizeof(physical_drive), "\\\\.\\PHYSICALDRIVE%d", DriveIndex);
|
||||
hDrive = CreateFileA(physical_drive, GENERIC_READ|(bWriteAccess?GENERIC_WRITE:0),
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
|
||||
if (hDrive == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Could not open drive %s: %s\n", physical_drive, WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
if (bWriteAccess) {
|
||||
uprintf("Caution: Opened %s drive for write access\n", &physical_drive[4]);
|
||||
}
|
||||
} else {
|
||||
*DriveLetter = ' ';
|
||||
size = GetLogicalDriveStringsA(sizeof(drives), drives);
|
||||
if (size == 0) {
|
||||
uprintf("GetLogicalDriveStrings failed: %s\n", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
if (size > sizeof(drives)) {
|
||||
uprintf("GetLogicalDriveStrings: buffer too small (required %d vs %d)\n", size, sizeof(drives));
|
||||
goto out;
|
||||
}
|
||||
|
||||
hDrive = INVALID_HANDLE_VALUE;
|
||||
for ( ;*drive; drive += safe_strlen(drive)+1) {
|
||||
if (!isalpha(*drive))
|
||||
continue;
|
||||
*drive = (char)toupper((int)*drive);
|
||||
if (*drive < 'C') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* IOCTL_STORAGE_GET_DEVICE_NUMBER's STORAGE_DEVICE_NUMBER.DeviceNumber is
|
||||
not unique! An HDD, a DVD and probably other drives can have the same
|
||||
value there => Use GetDriveType() to filter out unwanted devices.
|
||||
See https://github.com/pbatard/rufus/issues/32 for details. */
|
||||
drive_type = GetDriveTypeA(drive);
|
||||
// NB: the HP utility allows drive_type == DRIVE_FIXED, which we don't allow by default
|
||||
// Using Alt-F in Rufus does enable listing, but this mode is unsupported.
|
||||
if ((drive_type != DRIVE_REMOVABLE) && ((!enable_fixed_disks) || (drive_type != DRIVE_FIXED)))
|
||||
continue;
|
||||
|
||||
safe_sprintf(logical_drive, sizeof(logical_drive), "\\\\.\\%c:", drive[0]);
|
||||
hDrive = CreateFileA(logical_drive, GENERIC_READ|(bWriteAccess?GENERIC_WRITE:0),
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
|
||||
if (hDrive == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Warning: could not open drive %c: %s\n", drive[0], WindowsErrorString());
|
||||
continue;
|
||||
}
|
||||
|
||||
r = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL,
|
||||
0, &device_number, sizeof(device_number), &size, NULL);
|
||||
if ((!r) || (size <= 0)) {
|
||||
uprintf("IOCTL_STORAGE_GET_DEVICE_NUMBER failed for device %s: %s\n",
|
||||
logical_drive, WindowsErrorString());
|
||||
} else if (device_number.DeviceNumber == DriveIndex) {
|
||||
break;
|
||||
}
|
||||
safe_closehandle(hDrive);
|
||||
}
|
||||
if (hDrive == INVALID_HANDLE_VALUE) {
|
||||
goto out;
|
||||
}
|
||||
if (bWriteAccess) {
|
||||
uprintf("Caution: Opened %s drive for write access\n", &logical_drive[4]);
|
||||
}
|
||||
*DriveLetter = *drive?*drive:' ';
|
||||
if (bWriteAccess) {
|
||||
uprintf("Caution: Opened drive %s for write access\n", Path);
|
||||
}
|
||||
|
||||
if ((bLockDrive) && (!DeviceIoControl(hDrive, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &size, NULL))) {
|
||||
uprintf("Could not get exclusive access to %s %s\n", logical_drive, WindowsErrorString());
|
||||
uprintf("Could not get exclusive access to device %s: %s\n", Path, WindowsErrorString());
|
||||
safe_closehandle(hDrive);
|
||||
goto out;
|
||||
}
|
||||
|
@ -146,12 +82,244 @@ out:
|
|||
return hDrive;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the path to access the physical drive, or NULL on error.
|
||||
* The string is allocated and must be freed (to ensure concurrent access)
|
||||
*/
|
||||
char* GetPhysicalName(DWORD DriveIndex)
|
||||
{
|
||||
BOOL success = FALSE;
|
||||
char physical_name[24];
|
||||
char* r = NULL;
|
||||
|
||||
CheckDriveIndex(DriveIndex);
|
||||
safe_sprintf(physical_name, sizeof(physical_name), "\\\\.\\PHYSICALDRIVE%d", DriveIndex);
|
||||
success = TRUE;
|
||||
out:
|
||||
return (success)?safe_strdup(physical_name):NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a handle to the physical drive identified by DriveIndex
|
||||
*/
|
||||
HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bWriteAccess, BOOL bLockDrive)
|
||||
{
|
||||
HANDLE hPhysical = INVALID_HANDLE_VALUE;
|
||||
char* PhysicalPath = GetPhysicalName(DriveIndex);
|
||||
hPhysical = GetHandle(PhysicalPath, bWriteAccess, bLockDrive);
|
||||
safe_free(PhysicalPath);
|
||||
return hPhysical;
|
||||
}
|
||||
|
||||
// Return the first GUID volume name for the associated drive or NULL if not found
|
||||
// See http://msdn.microsoft.com/en-us/library/cc542456.aspx
|
||||
// The returned string is allocated and must be freed
|
||||
// TODO: a drive may have multiple volumes - should we handle those?
|
||||
char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash)
|
||||
{
|
||||
BOOL success = FALSE;
|
||||
char volume_name[MAX_PATH];
|
||||
HANDLE hDrive = INVALID_HANDLE_VALUE, hVolume = INVALID_HANDLE_VALUE;
|
||||
size_t len;
|
||||
char path[MAX_PATH];
|
||||
VOLUME_DISK_EXTENTS DiskExtents;
|
||||
DWORD size;
|
||||
UINT drive_type;
|
||||
int i, j;
|
||||
static const char* ignore_device[] = { "\\Device\\CdRom", "\\Device\\Floppy" };
|
||||
|
||||
CheckDriveIndex(DriveIndex);
|
||||
|
||||
for (i=0; hDrive == INVALID_HANDLE_VALUE; i++) {
|
||||
if (i == 0) {
|
||||
hVolume = FindFirstVolumeA(volume_name, sizeof(volume_name));
|
||||
if (hVolume == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Could not access first GUID volume: %s\n", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if (!FindNextVolumeA(hVolume, volume_name, sizeof(volume_name))) {
|
||||
if (GetLastError() != ERROR_NO_MORE_FILES) {
|
||||
uprintf("Could not access next GUID volume: %s\n", WindowsErrorString());
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity checks
|
||||
len = safe_strlen(volume_name);
|
||||
if ((len <= 1) || (safe_strnicmp(volume_name, "\\\\?\\", 4) != 0) || (volume_name[len-1] != '\\')) {
|
||||
uprintf("'%s' is not a GUID volume name\n", volume_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
drive_type = GetDriveTypeA(volume_name);
|
||||
// NB: the HP utility allows drive_type == DRIVE_FIXED, which we don't allow by default
|
||||
// Using Alt-F in Rufus does enable listing, but this mode is unsupported.
|
||||
if ((drive_type != DRIVE_REMOVABLE) && ((!enable_fixed_disks) || (drive_type != DRIVE_FIXED)))
|
||||
continue;
|
||||
|
||||
volume_name[len-1] = 0;
|
||||
|
||||
if (QueryDosDeviceA(&volume_name[4], path, sizeof(path)) == 0) {
|
||||
uprintf("Failed to get device path for GUID volume '%s': %s\n", volume_name, WindowsErrorString());
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j=0; (j<ARRAYSIZE(ignore_device)) &&
|
||||
(safe_strnicmp(path, ignore_device[j], safe_strlen(ignore_device[j])) != 0); j++);
|
||||
if (j < ARRAYSIZE(ignore_device)) {
|
||||
uprintf("Skipping GUID volume for '%s'\n", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we can't have FILE_SHARE_WRITE, forget it
|
||||
hDrive = CreateFileA(volume_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
|
||||
if (hDrive == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Could not open GUID volume '%s': %s\n", volume_name, WindowsErrorString());
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((!DeviceIoControl(hDrive, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0,
|
||||
&DiskExtents, sizeof(DiskExtents), &size, NULL)) || (size <= 0)) {
|
||||
uprintf("Could not get Disk Extents: %s\n", WindowsErrorString());
|
||||
safe_closehandle(hDrive);
|
||||
continue;
|
||||
}
|
||||
safe_closehandle(hDrive);
|
||||
if ((DiskExtents.NumberOfDiskExtents >= 1) && (DiskExtents.Extents[0].DiskNumber == DriveIndex)) {
|
||||
if (bKeepTrailingBackslash)
|
||||
volume_name[len-1] = '\\';
|
||||
success = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (hVolume != INVALID_HANDLE_VALUE)
|
||||
FindVolumeClose(hVolume);
|
||||
return (success)?safe_strdup(volume_name):NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a handle to the first logical volume on the disk identified by DriveIndex
|
||||
*/
|
||||
HANDLE GetLogicalHandle(DWORD DriveIndex, BOOL bWriteAccess, BOOL bLockDrive)
|
||||
{
|
||||
HANDLE hLogical = INVALID_HANDLE_VALUE;
|
||||
char* LogicalPath = GetLogicalName(DriveIndex, FALSE);
|
||||
hLogical = GetHandle(LogicalPath, bWriteAccess, bLockDrive);
|
||||
safe_free(LogicalPath);
|
||||
return hLogical;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the first drive letter for a volume located on the drive identified by DriveIndex
|
||||
* TODO: should we return all the drive letters?
|
||||
*/
|
||||
char GetDriveLetter(DWORD DriveIndex)
|
||||
{
|
||||
DWORD size;
|
||||
BOOL r;
|
||||
STORAGE_DEVICE_NUMBER_REDEF device_number = {0};
|
||||
UINT drive_type;
|
||||
HANDLE hDrive = INVALID_HANDLE_VALUE;
|
||||
char *drive, drives[26*4]; /* "D:\", "E:\", etc. */
|
||||
char logical_drive[] = "\\\\.\\#:";
|
||||
char drive_letter = ' ';
|
||||
CheckDriveIndex(DriveIndex);
|
||||
|
||||
size = GetLogicalDriveStringsA(sizeof(drives), drives);
|
||||
if (size == 0) {
|
||||
uprintf("GetLogicalDriveStrings failed: %s\n", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
if (size > sizeof(drives)) {
|
||||
uprintf("GetLogicalDriveStrings: buffer too small (required %d vs %d)\n", size, sizeof(drives));
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (drive = drives ;*drive; drive += safe_strlen(drive)+1) {
|
||||
if (!isalpha(*drive))
|
||||
continue;
|
||||
*drive = (char)toupper((int)*drive);
|
||||
if (*drive < 'C') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* IOCTL_STORAGE_GET_DEVICE_NUMBER's STORAGE_DEVICE_NUMBER.DeviceNumber is
|
||||
not unique! An HDD, a DVD and probably other drives can have the same
|
||||
value there => Use GetDriveType() to filter out unwanted devices.
|
||||
See https://github.com/pbatard/rufus/issues/32 for details. */
|
||||
drive_type = GetDriveTypeA(drive);
|
||||
// NB: the HP utility allows drive_type == DRIVE_FIXED, which we don't allow by default
|
||||
// Using Alt-F in Rufus does enable listing, but this mode is unsupported.
|
||||
if ((drive_type != DRIVE_REMOVABLE) && ((!enable_fixed_disks) || (drive_type != DRIVE_FIXED)))
|
||||
continue;
|
||||
|
||||
safe_sprintf(logical_drive, sizeof(logical_drive), "\\\\.\\%c:", drive[0]);
|
||||
hDrive = CreateFileA(logical_drive, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
|
||||
if (hDrive == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Warning: could not open drive %c: %s\n", drive[0], WindowsErrorString());
|
||||
continue;
|
||||
}
|
||||
|
||||
r = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL,
|
||||
0, &device_number, sizeof(device_number), &size, NULL);
|
||||
safe_closehandle(hDrive);
|
||||
if ((!r) || (size <= 0)) {
|
||||
uprintf("Could not get device number for device %s: %s\n",
|
||||
logical_drive, WindowsErrorString());
|
||||
} else if (device_number.DeviceNumber == DriveIndex) {
|
||||
drive_letter = *drive;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return drive_letter;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next unused drive letter from the system
|
||||
*/
|
||||
char GetUnusedDriveLetter(void)
|
||||
{
|
||||
DWORD size;
|
||||
char drive_letter, *drive, drives[26*4]; /* "D:\", "E:\", etc. */
|
||||
|
||||
size = GetLogicalDriveStringsA(sizeof(drives), drives);
|
||||
if (size == 0) {
|
||||
uprintf("GetLogicalDriveStrings failed: %s\n", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
if (size > sizeof(drives)) {
|
||||
uprintf("GetLogicalDriveStrings: buffer too small (required %d vs %d)\n", size, sizeof(drives));
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (drive_letter = 'C'; drive_letter < 'Z'; drive_letter++) {
|
||||
for (drive = drives ;*drive; drive += safe_strlen(drive)+1) {
|
||||
if (!isalpha(*drive))
|
||||
continue;
|
||||
if (drive_letter == (char)toupper((int)*drive))
|
||||
break;
|
||||
}
|
||||
if (!*drive)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return (drive_letter>'Z')?' ':drive_letter;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the drive letter and volume label
|
||||
* If the drive doesn't have a volume assigned, space is returned for the letter
|
||||
*/
|
||||
BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label)
|
||||
{
|
||||
HANDLE hDrive, hPhysical;
|
||||
HANDLE hPhysical;
|
||||
DWORD size;
|
||||
char AutorunPath[] = "#:\\autorun.inf", *AutorunLabel = NULL;
|
||||
wchar_t wDrivePath[] = L"#:\\";
|
||||
|
@ -160,19 +328,19 @@ BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label)
|
|||
|
||||
*label = STR_NO_LABEL;
|
||||
|
||||
hDrive = GetDriveHandle(DriveIndex, letter, FALSE, FALSE);
|
||||
if (hDrive == INVALID_HANDLE_VALUE) {
|
||||
// Assume we have a raw drive without volume assigned if enable_fixed_disk is true
|
||||
return enable_fixed_disks;
|
||||
*letter = GetDriveLetter(DriveIndex);
|
||||
if (*letter == ' ') {
|
||||
// Drive without volume assigned
|
||||
// TODO: only with fixed?
|
||||
return TRUE;
|
||||
}
|
||||
safe_closehandle(hDrive);
|
||||
AutorunPath[0] = *letter;
|
||||
wDrivePath[0] = *letter;
|
||||
|
||||
// Try to read an extended label from autorun first. Fallback to regular label if not found.
|
||||
// In the case of card readers with no card, users can get an annoying popup asking them
|
||||
// to insert media. Use IOCTL_STORAGE_CHECK_VERIFY to prevent this
|
||||
hPhysical = GetDriveHandle(DriveIndex, NULL, FALSE, FALSE);
|
||||
hPhysical = GetPhysicalHandle(DriveIndex, FALSE, FALSE);
|
||||
if (DeviceIoControl(hPhysical, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, &size, NULL))
|
||||
AutorunLabel = get_token_data_file("label", AutorunPath);
|
||||
else if (GetLastError() == ERROR_NOT_READY)
|
||||
|
@ -196,28 +364,29 @@ BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label)
|
|||
/*
|
||||
* Fill the drive properties (size, FS, etc)
|
||||
*/
|
||||
BOOL GetDrivePartitionData(DWORD DeviceNumber, char* FileSystemName, DWORD FileSystemNameSize)
|
||||
BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSystemNameSize)
|
||||
{
|
||||
BOOL r;
|
||||
HANDLE hDrive;
|
||||
HANDLE hPhysical;
|
||||
DWORD size;
|
||||
BYTE geometry[128], layout[1024], part_type;
|
||||
void* disk_geometry = (void*)geometry;
|
||||
void* drive_layout = (void*)layout;
|
||||
PDISK_GEOMETRY_EX DiskGeometry = (PDISK_GEOMETRY_EX)disk_geometry;
|
||||
PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)drive_layout;
|
||||
char DrivePath[] = "#:\\", tmp[256];
|
||||
char* volume_name;
|
||||
char tmp[256];
|
||||
DWORD i, nb_partitions = 0;
|
||||
|
||||
hDrive = GetDriveHandle(DeviceNumber, NULL, FALSE, FALSE);
|
||||
if (hDrive == INVALID_HANDLE_VALUE)
|
||||
hPhysical = GetPhysicalHandle(DriveIndex, FALSE, FALSE);
|
||||
if (hPhysical == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
r = DeviceIoControl(hDrive, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
|
||||
r = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
|
||||
NULL, 0, geometry, sizeof(geometry), &size, NULL);
|
||||
if (!r || size <= 0) {
|
||||
uprintf("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX failed for drive %c: %s\n", DrivePath[0], WindowsErrorString());
|
||||
safe_closehandle(hDrive);
|
||||
uprintf("Could not get geometry for drive #%d: %s\n", DriveIndex, WindowsErrorString());
|
||||
safe_closehandle(hPhysical);
|
||||
return FALSE;
|
||||
}
|
||||
SelectedDrive.DiskSize = DiskGeometry->DiskSize.QuadPart;
|
||||
|
@ -226,10 +395,10 @@ BOOL GetDrivePartitionData(DWORD DeviceNumber, char* FileSystemName, DWORD FileS
|
|||
uprintf("Cylinders: %lld, TracksPerCylinder: %d, SectorsPerTrack: %d\n",
|
||||
DiskGeometry->Geometry.Cylinders, DiskGeometry->Geometry.TracksPerCylinder, DiskGeometry->Geometry.SectorsPerTrack);
|
||||
|
||||
r = DeviceIoControl(hDrive, IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
|
||||
r = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
|
||||
NULL, 0, layout, sizeof(layout), &size, NULL );
|
||||
if (!r || size <= 0) {
|
||||
uprintf("IOCTL_DISK_GET_DRIVE_LAYOUT_EX failed for drive %c: %s\n", DrivePath[0], WindowsErrorString());
|
||||
uprintf("Could not get layout for drive #d: %s\n", DriveIndex, WindowsErrorString());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -281,17 +450,23 @@ BOOL GetDrivePartitionData(DWORD DeviceNumber, char* FileSystemName, DWORD FileS
|
|||
uprintf("Partition type: RAW\n");
|
||||
break;
|
||||
}
|
||||
safe_closehandle(hDrive);
|
||||
safe_closehandle(hPhysical);
|
||||
|
||||
// Populate the filesystem data
|
||||
if (!GetVolumeInformationA(DrivePath, NULL, 0, NULL, NULL, NULL, FileSystemName, FileSystemNameSize)) {
|
||||
volume_name = GetLogicalName(DriveIndex, TRUE);
|
||||
if ((volume_name == NULL) || (!GetVolumeInformationA(volume_name, NULL, 0, NULL, NULL, NULL, FileSystemName, FileSystemNameSize))) {
|
||||
uprintf("Did not get volume information for disk 0x%02x\n", DriveIndex);
|
||||
FileSystemName[0] = 0;
|
||||
}
|
||||
safe_free(volume_name);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL UnmountDrive(HANDLE hDrive)
|
||||
/*
|
||||
* Unmount of volume using the DISMOUNT_VOLUME ioctl
|
||||
*/
|
||||
BOOL UnmountVolume(HANDLE hDrive)
|
||||
{
|
||||
DWORD size;
|
||||
|
||||
|
@ -439,7 +614,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
|
|||
r = DeviceIoControl(hDrive, IOCTL_DISK_CREATE_DISK,
|
||||
(BYTE*)&CreateDisk, size, NULL, 0, &size, NULL );
|
||||
if (!r) {
|
||||
uprintf("IOCTL_DISK_CREATE_DISK failed: %s\n", WindowsErrorString());
|
||||
uprintf("Could not reset disk: %s\n", WindowsErrorString());
|
||||
safe_closehandle(hDrive);
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -448,7 +623,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
|
|||
r = DeviceIoControl(hDrive, IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
|
||||
(BYTE*)&DriveLayoutEx, size, NULL, 0, &size, NULL );
|
||||
if (!r) {
|
||||
uprintf("IOCTL_DISK_SET_DRIVE_LAYOUT_EX failed: %s\n", WindowsErrorString());
|
||||
uprintf("Could not set drive layout: %s\n", WindowsErrorString());
|
||||
safe_closehandle(hDrive);
|
||||
return FALSE;
|
||||
}
|
||||
|
|
164
src/format.c
164
src/format.c
|
@ -54,6 +54,7 @@ static int task_number = 0;
|
|||
/* Number of steps for each FS for FCC_STRUCTURE_PROGRESS */
|
||||
const int nb_steps[FS_MAX] = { 5, 5, 12, 10 };
|
||||
static int fs_index = 0;
|
||||
BOOL force_large_fat32 = FALSE;
|
||||
|
||||
/*
|
||||
* FormatEx callback. Return FALSE to halt operations
|
||||
|
@ -274,6 +275,7 @@ static void ToValidLabel(WCHAR* name, BOOL bFAT)
|
|||
* -----
|
||||
* 1d02h
|
||||
*/
|
||||
// TODO: use that for Format "classic"
|
||||
static DWORD GetVolumeID(void)
|
||||
{
|
||||
SYSTEMTIME s;
|
||||
|
@ -331,7 +333,6 @@ static DWORD GetFATSizeSectors(DWORD DskSize, DWORD ReservedSecCnt, DWORD SecPer
|
|||
static BOOL FormatFAT32(DWORD DriveIndex)
|
||||
{
|
||||
BOOL r = FALSE;
|
||||
char DriveLetter;
|
||||
DWORD i;
|
||||
HANDLE hLogicalVolume;
|
||||
DWORD cbRet;
|
||||
|
@ -342,7 +343,8 @@ static BOOL FormatFAT32(DWORD DriveIndex)
|
|||
DWORD NumFATs = 2;
|
||||
DWORD BackupBootSect = 6;
|
||||
DWORD VolumeId = 0; // calculated before format
|
||||
WCHAR wLabel[64], wDriveName[] = L"#:\\";
|
||||
char* VolumeName = NULL;
|
||||
WCHAR wLabel[64], *wVolumeName = NULL;
|
||||
DWORD BurstSize = 128; // Zero in blocks of 64K typically
|
||||
|
||||
// Calculated later
|
||||
|
@ -365,18 +367,17 @@ static BOOL FormatFAT32(DWORD DriveIndex)
|
|||
// Debug temp vars
|
||||
ULONGLONG FatNeeded, ClusterCount;
|
||||
|
||||
PrintStatus(0, TRUE, "Formatting...");
|
||||
uprintf("Using large FAT32 format method\n");
|
||||
PrintStatus(0, TRUE, "Formatting (Large FAT32)...");
|
||||
VolumeId = GetVolumeID();
|
||||
|
||||
// Open the drive (volume should already be locked)
|
||||
hLogicalVolume = GetDriveHandle(DriveIndex, &DriveLetter, TRUE, FALSE);
|
||||
hLogicalVolume = GetLogicalHandle(DriveIndex, TRUE, FALSE);
|
||||
if (IS_ERROR(FormatStatus)) goto out;
|
||||
if (hLogicalVolume == INVALID_HANDLE_VALUE)
|
||||
die("Could not access logical volume\n", ERROR_OPEN_FAILED);
|
||||
|
||||
// Make sure we get exclusive access
|
||||
if (!UnmountDrive(hLogicalVolume))
|
||||
if (!UnmountVolume(hLogicalVolume))
|
||||
return r;
|
||||
|
||||
// Work out drive params
|
||||
|
@ -526,7 +527,7 @@ static BOOL FormatFAT32(DWORD DriveIndex)
|
|||
}
|
||||
|
||||
// Now we're commited - print some info first
|
||||
uprintf("Size : %gGB %u sectors\n", (double) (piDrive.PartitionLength.QuadPart / (1000*1000*1000)), TotalSectors);
|
||||
uprintf("Size : %s %u sectors\n", SizeToHumanReadable(piDrive.PartitionLength), TotalSectors);
|
||||
uprintf("Cluster size %d bytes, %d Bytes Per Sector\n", SectorsPerCluster*BytesPerSect, BytesPerSect);
|
||||
uprintf("Volume ID is %x:%x\n", VolumeId>>16, VolumeId&0xffff);
|
||||
uprintf("%d Reserved Sectors, %d Sectors per FAT, %d FATs\n", ReservedSectCount, FatSize, NumFATs);
|
||||
|
@ -578,18 +579,22 @@ static BOOL FormatFAT32(DWORD DriveIndex)
|
|||
// Set the FAT32 volume label
|
||||
GetWindowTextW(hLabel, wLabel, ARRAYSIZE(wLabel));
|
||||
ToValidLabel(wLabel, TRUE);
|
||||
wDriveName[0] = DriveLetter;
|
||||
// Handle must be closed for SetVolumeLabel to work
|
||||
safe_closehandle(hLogicalVolume);
|
||||
|
||||
PrintStatus(0, TRUE, "Setting Label (This can take while)...");
|
||||
if (!SetVolumeLabelW(wDriveName, wLabel)) {
|
||||
PrintStatus(0, TRUE, "Setting Label (This may take while)...");
|
||||
VolumeName = GetLogicalName(DriveIndex, TRUE);
|
||||
wVolumeName = utf8_to_wchar(VolumeName);
|
||||
if ((wVolumeName == NULL) || (!SetVolumeLabelW(wVolumeName, wLabel))) {
|
||||
uprintf("Could not set label: %s\n", WindowsErrorString());
|
||||
// Non fatal error
|
||||
}
|
||||
|
||||
uprintf("Format completed.\n");
|
||||
r = TRUE;
|
||||
|
||||
out:
|
||||
safe_free(VolumeName);
|
||||
safe_free(wVolumeName);
|
||||
safe_closehandle(hLogicalVolume);
|
||||
safe_free(pFAT32BootSect);
|
||||
safe_free(pFAT32FsInfo);
|
||||
|
@ -601,18 +606,28 @@ out:
|
|||
/*
|
||||
* Call on fmifs.dll's FormatEx() to format the drive
|
||||
*/
|
||||
static BOOL FormatDrive(char DriveLetter)
|
||||
static BOOL FormatDrive(DWORD DriveIndex)
|
||||
{
|
||||
BOOL r = FALSE;
|
||||
PF_DECL(FormatEx);
|
||||
WCHAR wDriveRoot[] = L"?:\\";
|
||||
char* VolumeName = NULL;
|
||||
WCHAR* wVolumeName = NULL;
|
||||
char FSType[32], format_status[64];
|
||||
WCHAR wFSType[32];
|
||||
WCHAR wLabel[64];
|
||||
size_t i;
|
||||
char* locale;
|
||||
|
||||
wDriveRoot[0] = (WCHAR)DriveLetter;
|
||||
PrintStatus(0, TRUE, "Formatting...");
|
||||
GetWindowTextA(hFileSystem, FSType, ARRAYSIZE(FSType));
|
||||
safe_sprintf(format_status, ARRAYSIZE(format_status), "Formatting (%s)...", FSType);
|
||||
PrintStatus(0, TRUE, format_status);
|
||||
VolumeName = GetLogicalName(DriveIndex, FALSE);
|
||||
wVolumeName = utf8_to_wchar(VolumeName);
|
||||
if (wVolumeName == NULL) {
|
||||
uprintf("Could not read volume name\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
// LoadLibrary("fmifs.dll") appears to changes the locale, which can lead to
|
||||
// problems with tolower(). Make sure we restore the locale. For more details,
|
||||
// see http://comments.gmane.org/gmane.comp.gnu.mingw.user/39300
|
||||
|
@ -635,7 +650,7 @@ static BOOL FormatDrive(char DriveLetter)
|
|||
format_percent = 0.0f;
|
||||
task_number = 0;
|
||||
fs_index = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
|
||||
pfFormatEx(wDriveRoot, SelectedDrive.Geometry.MediaType, wFSType, wLabel,
|
||||
pfFormatEx(wVolumeName, SelectedDrive.Geometry.MediaType, wFSType, wLabel,
|
||||
IsChecked(IDC_QUICKFORMAT), (ULONG)ComboBox_GetItemData(hClusterSize, ComboBox_GetCurSel(hClusterSize)),
|
||||
FormatExCallback);
|
||||
if (!IS_ERROR(FormatStatus)) {
|
||||
|
@ -644,6 +659,8 @@ static BOOL FormatDrive(char DriveLetter)
|
|||
}
|
||||
|
||||
out:
|
||||
safe_free(VolumeName);
|
||||
safe_free(wVolumeName);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -737,12 +754,14 @@ static BOOL AnalyzePBR(HANDLE hLogicalVolume)
|
|||
} else if (entire_fat_32_fd_br_matches(&fake_fd)) {
|
||||
uprintf("Drive has a FAT32 FreeDOS partition boot record\n");
|
||||
} else {
|
||||
uprintf("Drive has a unknown FAT16 or FAT32 partition boot record\n");
|
||||
uprintf("Drive has an unknown FAT16 or FAT32 partition boot record\n");
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// TODO: We may have to clear a few more sectors past the MBR buffer zone
|
||||
// so that Windows relinquishes access
|
||||
static BOOL ClearMBRGPT(HANDLE hPhysicalDrive, LONGLONG DiskSize, DWORD SectorSize)
|
||||
{
|
||||
BOOL r = FALSE;
|
||||
|
@ -1138,15 +1157,24 @@ DWORD WINAPI CloseFormatPromptThread(LPVOID param) {
|
|||
|
||||
/*
|
||||
* Standalone thread for the formatting operation
|
||||
* According to http://msdn.microsoft.com/en-us/library/windows/desktop/aa364562.aspx
|
||||
* To change a volume file system
|
||||
* Open a volume.
|
||||
* Lock the volume.
|
||||
* Format the volume.
|
||||
* Dismount the volume.
|
||||
* Unlock the volume.
|
||||
* Close the volume handle.
|
||||
*/
|
||||
DWORD WINAPI FormatThread(LPVOID param)
|
||||
{
|
||||
int r, pt, bt, fs, dt;
|
||||
BOOL ret, no_volume = FALSE;
|
||||
DWORD num = (DWORD)(uintptr_t)param;
|
||||
BOOL ret;
|
||||
DWORD DriveIndex = (DWORD)(uintptr_t)param;
|
||||
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
|
||||
HANDLE hLogicalVolume = INVALID_HANDLE_VALUE;
|
||||
SYSTEMTIME lt;
|
||||
char* guid_volume = NULL;
|
||||
char drive_name[] = "?:\\";
|
||||
char bb_msg[512];
|
||||
char logfile[MAX_PATH], *userdir;
|
||||
|
@ -1159,34 +1187,41 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
pt = GETPARTTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
|
||||
bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
|
||||
|
||||
if (num & DRIVE_INDEX_RAW_DRIVE) {
|
||||
no_volume = TRUE;
|
||||
uprintf("Using raw drive mode\n");
|
||||
}
|
||||
|
||||
hPhysicalDrive = GetDriveHandle(num, NULL, TRUE, TRUE);
|
||||
PrintStatus(0, TRUE, "Requesting disk access...\n");
|
||||
hPhysicalDrive = GetPhysicalHandle(DriveIndex, TRUE, TRUE);
|
||||
if (hPhysicalDrive == INVALID_HANDLE_VALUE) {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
||||
goto out;
|
||||
}
|
||||
// At this stage with have both a handle and a lock to the physical drive...
|
||||
|
||||
// ... but we can't write sectors that are part of a volume, even if we have
|
||||
// access to physical, unless we have a lock (which doesn't have to be write)
|
||||
// Also, having a volume handle allows us to unmount the volume
|
||||
if (!no_volume) {
|
||||
hLogicalVolume = GetDriveHandle(num, drive_name, FALSE, TRUE);
|
||||
if (hLogicalVolume == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Could not lock volume\n");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
||||
// At this stage with have both a handle and a lock to the physical drive...
|
||||
drive_name[0] = GetDriveLetter(DriveIndex);
|
||||
if (drive_name[0] == ' ') {
|
||||
uprintf("No drive letter was assigned...\n");
|
||||
drive_name[0] = GetUnusedDriveLetter();
|
||||
if (drive_name[0] == ' ') {
|
||||
uprintf("Could not find a suitable drive letter\n");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_ASSIGN_LETTER);
|
||||
goto out;
|
||||
}
|
||||
UnmountDrive(hLogicalVolume);
|
||||
} else if (!DeleteVolumeMountPointA(drive_name)) {
|
||||
uprintf("Failed to delete mountpoint %s: %s\n", drive_name, WindowsErrorString());
|
||||
// TODO: generate an error?
|
||||
}
|
||||
uprintf("Will use '%c': as volume mountpoint\n", drive_name[0]);
|
||||
|
||||
hLogicalVolume = GetLogicalHandle(DriveIndex, FALSE, TRUE);
|
||||
if (hLogicalVolume == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Could not lock volume\n");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
||||
goto out;
|
||||
}
|
||||
UnmountVolume(hLogicalVolume);
|
||||
|
||||
PrintStatus(0, TRUE, "Analyzing existing boot records...\n");
|
||||
AnalyzeMBR(hPhysicalDrive);
|
||||
if (!no_volume)
|
||||
AnalyzePBR(hLogicalVolume);
|
||||
AnalyzePBR(hLogicalVolume);
|
||||
UpdateProgress(OP_ANALYZE_MBR, -1.0f);
|
||||
|
||||
if (IsChecked(IDC_BADBLOCKS)) {
|
||||
do {
|
||||
|
@ -1249,8 +1284,17 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
}
|
||||
}
|
||||
// Close the (unmounted) volume before formatting, but keep the lock
|
||||
if (!no_volume)
|
||||
safe_closehandle(hLogicalVolume);
|
||||
// According to MS this relinquishes the lock, so...
|
||||
PrintStatus(0, TRUE, "Closing existing volume...\n");
|
||||
if (!CloseHandle(hLogicalVolume)) {
|
||||
uprintf("Could not close volume: %s\n", WindowsErrorString());
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED;
|
||||
goto out;
|
||||
}
|
||||
hLogicalVolume = INVALID_HANDLE_VALUE;
|
||||
|
||||
// TODO: check for cancel once in a while!
|
||||
// TODO: our start button should become cancel instead of close
|
||||
|
||||
// Especially after destructive badblocks test, you must zero the MBR/GPT completely
|
||||
// before repartitioning. Else, all kind of bad things can happen.
|
||||
|
@ -1272,28 +1316,24 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
// Add a small delay after partitioning to be safe
|
||||
Sleep(200);
|
||||
|
||||
if (no_volume) {
|
||||
hLogicalVolume = GetDriveHandle(num, drive_name, FALSE, TRUE);
|
||||
if (hLogicalVolume == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Could not lock volume\n");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
||||
goto out;
|
||||
}
|
||||
UnmountDrive(hLogicalVolume);
|
||||
safe_closehandle(hLogicalVolume);
|
||||
}
|
||||
|
||||
|
||||
// If FAT32 is requested and we have a large drive (>32 GB) use
|
||||
// large FAT32 format, else use MS's FormatEx.
|
||||
ret = ((fs == FS_FAT32) && (SelectedDrive.DiskSize > LARGE_FAT32_SIZE))?
|
||||
FormatFAT32(num):FormatDrive(drive_name[0]);
|
||||
ret = ((fs == FS_FAT32) && ((SelectedDrive.DiskSize > LARGE_FAT32_SIZE) || (force_large_fat32)))?
|
||||
FormatFAT32(DriveIndex):FormatDrive(DriveIndex);
|
||||
if (!ret) {
|
||||
// Error will be set by FormatDrive() in FormatStatus
|
||||
uprintf("Format error: %s\n", StrError(FormatStatus));
|
||||
goto out;
|
||||
}
|
||||
|
||||
guid_volume = GetLogicalName(DriveIndex, TRUE);
|
||||
if (guid_volume == NULL) {
|
||||
uprintf("Could not get GUID volume name\n");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NO_VOLUME_ID;
|
||||
goto out;
|
||||
}
|
||||
uprintf("Found volume GUID %s\n", guid_volume);
|
||||
|
||||
if (pt == PARTITION_STYLE_MBR) {
|
||||
PrintStatus(0, TRUE, "Writing master boot record...");
|
||||
if (!WriteMBR(hPhysicalDrive)) {
|
||||
|
@ -1304,6 +1344,12 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
UpdateProgress(OP_FIX_MBR, -1.0f);
|
||||
}
|
||||
|
||||
if (!SetVolumeMountPointA(drive_name, guid_volume)) {
|
||||
uprintf("Could not remount %s on %s: %s\n", guid_volume, drive_name, WindowsErrorString());
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_MOUNT_VOLUME);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (IsChecked(IDC_BOOT)) {
|
||||
if (bt == BT_UEFI) {
|
||||
// For once, no need to do anything - just check our sanity
|
||||
|
@ -1315,7 +1361,7 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
} else if ((dt == DT_WINME) || (dt == DT_FREEDOS) || ((dt == DT_ISO) && (fs == FS_NTFS))) {
|
||||
// We still have a lock, which we need to modify the volume boot record
|
||||
// => no need to reacquire the lock...
|
||||
hLogicalVolume = GetDriveHandle(num, drive_name, TRUE, FALSE);
|
||||
hLogicalVolume = GetLogicalHandle(DriveIndex, TRUE, FALSE);
|
||||
if (hLogicalVolume == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Could not re-mount volume for partition boot record access\n");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
||||
|
@ -1333,7 +1379,7 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
safe_unlockclose(hLogicalVolume);
|
||||
} else if ( (dt == DT_SYSLINUX) || ((dt == DT_ISO) && ((fs == FS_FAT16) || (fs == FS_FAT32))) ) {
|
||||
PrintStatus(0, TRUE, "Installing Syslinux...");
|
||||
if (!InstallSyslinux(num, drive_name)) {
|
||||
if (!InstallSyslinux(DriveIndex, drive_name[0])) {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
}
|
||||
|
@ -1368,7 +1414,8 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
goto out;
|
||||
}
|
||||
if ((bt == BT_UEFI) && (!iso_report.has_efi) && (iso_report.has_win7_efi)) {
|
||||
// TODO: progress
|
||||
// TODO: better progress
|
||||
// TODO: check ISO with EFI only
|
||||
PrintStatus(0, TRUE, "Win7 EFI boot setup (this may take a while)...");
|
||||
wim_image[0] = drive_name[0];
|
||||
efi_dst[0] = drive_name[0];
|
||||
|
@ -1392,7 +1439,7 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
}
|
||||
}
|
||||
UpdateProgress(OP_FINALIZE, -1.0f);
|
||||
PrintStatus(0, TRUE, "Finalizing...");
|
||||
PrintStatus(0, TRUE, "Finalizing, please wait...");
|
||||
if (IsChecked(IDC_SET_ICON))
|
||||
SetAutorun(drive_name);
|
||||
// Issue another complete remount before we exit, to ensure we're clean
|
||||
|
@ -1405,9 +1452,10 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
}
|
||||
|
||||
out:
|
||||
safe_free(guid_volume);
|
||||
SendMessage(hISOProgressDlg, UM_ISO_EXIT, 0, 0);
|
||||
safe_unlockclose(hLogicalVolume);
|
||||
safe_unlockclose(hPhysicalDrive);
|
||||
safe_unlockclose(hPhysicalDrive); // This can take a while
|
||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
|
||||
ExitThread(0);
|
||||
}
|
||||
|
|
20
src/rufus.c
20
src/rufus.c
|
@ -93,6 +93,7 @@ static BOOL existing_key = FALSE; // For LGP set/restore
|
|||
static BOOL iso_size_check = TRUE;
|
||||
static BOOL log_displayed = FALSE;
|
||||
static BOOL iso_provided = FALSE;
|
||||
extern BOOL force_large_fat32;
|
||||
static int selection_default;
|
||||
|
||||
/*
|
||||
|
@ -605,7 +606,7 @@ static BOOL GetUSBDevices(DWORD devnum)
|
|||
// We can afford a failure on this call - just replace the name
|
||||
safe_strcpy(buffer, sizeof(buffer), generic_friendly_name);
|
||||
}
|
||||
uprintf("Found drive '%s'\n", buffer);
|
||||
uprintf("Found device '%s'\n", buffer);
|
||||
|
||||
devint_data.cbSize = sizeof(devint_data);
|
||||
hDrive = INVALID_HANDLE_VALUE;
|
||||
|
@ -617,6 +618,8 @@ static BOOL GetUSBDevices(DWORD devnum)
|
|||
if (!SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, &_GUID_DEVINTERFACE_DISK, j, &devint_data)) {
|
||||
if(GetLastError() != ERROR_NO_MORE_ITEMS) {
|
||||
uprintf("SetupDiEnumDeviceInterfaces failed: %s\n", WindowsErrorString());
|
||||
} else {
|
||||
uprintf("Device was eliminated because it doesn't report itself as a disk\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -669,7 +672,6 @@ static BOOL GetUSBDevices(DWORD devnum)
|
|||
// Drive letter ' ' is returned for drives that don't have a volume assigned yet
|
||||
if (drive_letter == ' ') {
|
||||
safe_sprintf(entry, sizeof(entry), "%s (Disk %d)", label, device_number.DeviceNumber);
|
||||
device_number.DeviceNumber |= DRIVE_INDEX_RAW_DRIVE;
|
||||
} else {
|
||||
safe_sprintf(entry, sizeof(entry), "%s (%c:)", label, drive_letter);
|
||||
}
|
||||
|
@ -722,6 +724,7 @@ static void InitProgress(void)
|
|||
memset(slot_end, 0, sizeof(slot_end));
|
||||
previous_end = 0.0f;
|
||||
|
||||
nb_slots[OP_ANALYZE_MBR] = 1;
|
||||
nb_slots[OP_ZERO_MBR] = 1;
|
||||
if (IsChecked(IDC_BADBLOCKS)) {
|
||||
nb_slots[OP_BADBLOCKS] = -1;
|
||||
|
@ -751,7 +754,7 @@ static void InitProgress(void)
|
|||
|| ((fs == FS_FAT32) && (SelectedDrive.DiskSize >= LARGE_FAT32_SIZE)) ) {
|
||||
nb_slots[OP_FORMAT] = -1;
|
||||
}
|
||||
nb_slots[OP_FINALIZE] = ((dt == DT_ISO) && (fs == FS_NTFS))?2:1;
|
||||
nb_slots[OP_FINALIZE] = ((dt == DT_ISO) && (fs == FS_NTFS))?3:2;
|
||||
|
||||
for (i=0; i<OP_MAX; i++) {
|
||||
if (nb_slots[i] > 0) {
|
||||
|
@ -1015,7 +1018,6 @@ DWORD WINAPI ISOScanThread(LPVOID param)
|
|||
safe_free(iso_path);
|
||||
goto out;
|
||||
}
|
||||
// TODO: 4GB and UEFI = BAD!!!
|
||||
uprintf("ISO label: '%s'\r\n Size: %lld bytes\r\n Has a >4GB file: %s\r\n Uses EFI: %s%s\r\n Uses Bootmgr: %s\r\n Uses WinPE: %s%s\r\n Uses isolinux: %s\n",
|
||||
iso_report.label, iso_report.projected_size, iso_report.has_4GB_file?"Yes":"No", (iso_report.has_efi || iso_report.has_win7_efi)?"Yes":"No",
|
||||
(iso_report.has_win7_efi && (!iso_report.has_efi))?" (win7_x64)":"", iso_report.has_bootmgr?"Yes":"No",
|
||||
|
@ -1391,6 +1393,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
user_changed_label = FALSE;
|
||||
return (INT_PTR)TRUE;
|
||||
case DBT_DEVNODES_CHANGED:
|
||||
// TODO: figure out what the deal is with extra events when FILE_SHARE_WRITE is not enabled
|
||||
// If it's been more than a second since last device refresh, arm a refresh timer
|
||||
if (GetTickCount() > LastRefresh + 1000) {
|
||||
LastRefresh = GetTickCount();
|
||||
|
@ -1673,6 +1676,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_START_THREAD);
|
||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
|
||||
}
|
||||
PrintStatus(0, FALSE, "");
|
||||
timer = 0;
|
||||
safe_sprintf(szTimer, sizeof(szTimer), "00:00:00");
|
||||
SendMessageA(GetDlgItem(hMainDialog, IDC_STATUS), SB_SETTEXTA,
|
||||
|
@ -1906,6 +1910,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
UpdateWindow(hDlg);
|
||||
|
||||
// Do our own event processing and process "magic" commands
|
||||
// TODO: Cheat modes are not handled when the log is at the front - this sucks
|
||||
while(GetMessage(&msg, NULL, 0, 0)) {
|
||||
// The following ensures the processing of the ISO progress window messages
|
||||
if (!IsWindow(hISOProgressDlg) || !IsDialogMessage(hISOProgressDlg, &msg)) {
|
||||
|
@ -1917,6 +1922,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
PrintStatus2000("ISO size check", iso_size_check);
|
||||
continue;
|
||||
}
|
||||
// TODO: move this option to advanced mode
|
||||
// Alt-F => Toggle detection of fixed disks
|
||||
// By default Rufus does not allow formatting USB fixed disk drives, such as USB HDDs
|
||||
// This is a safety feature, to avoid someone unintentionally formatting a backup
|
||||
|
@ -1927,6 +1933,12 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
GetUSBDevices(0);
|
||||
continue;
|
||||
}
|
||||
// Alt-L => Force Large FAT32 format to be used on < 32 GB drives
|
||||
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'L')) {
|
||||
force_large_fat32 = !force_large_fat32;
|
||||
PrintStatus2000("Force large FAT32 usage", force_large_fat32);
|
||||
continue;
|
||||
}
|
||||
// Alt-D => Delete the NoDriveTypeAutorun key on exit (useful if the app crashed)
|
||||
// This key is used to disable Windows popup messages when an USB drive is plugged in.
|
||||
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'D')) {
|
||||
|
|
20
src/rufus.h
20
src/rufus.h
|
@ -38,8 +38,6 @@
|
|||
#define RUFUS_BLOCKING_IO_TITLE APPLICATION_NAME " - Flushing buffers"
|
||||
#define DRIVE_INDEX_MIN 0x00000080
|
||||
#define DRIVE_INDEX_MAX 0x000000C0
|
||||
#define DRIVE_INDEX_MASK 0x0000FFFF
|
||||
#define DRIVE_INDEX_RAW_DRIVE 0x00010000 // Additional drive properties stored in the drive index
|
||||
#define MAX_DRIVES (DRIVE_INDEX_MAX - DRIVE_INDEX_MIN)
|
||||
#define MAX_TOOLTIPS 32
|
||||
#define MAX_PROGRESS (0xFFFF-1) // leave room for 1 more for insta-progress workaround
|
||||
|
@ -135,6 +133,7 @@ enum timer_type {
|
|||
|
||||
/* Action type, for progress bar breakdown */
|
||||
enum action_type {
|
||||
OP_ANALYZE_MBR,
|
||||
OP_BADBLOCKS,
|
||||
OP_ZERO_MBR,
|
||||
OP_PARTITION,
|
||||
|
@ -296,14 +295,19 @@ extern BOOL Question(char* title, char* format, ...);
|
|||
extern BOOL ExtractDOS(const char* path);
|
||||
extern BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan);
|
||||
extern BOOL ExtractISOFile(const char* iso, const char* iso_file, const char* dest_file);
|
||||
extern BOOL InstallSyslinux(DWORD num, const char* drive_name);
|
||||
extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter);
|
||||
DWORD WINAPI FormatThread(void* param);
|
||||
extern char* GetPhysicalName(DWORD DriveIndex);
|
||||
extern HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bWriteAccess, BOOL bLockDrive);
|
||||
extern char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash);
|
||||
extern HANDLE GetLogicalHandle(DWORD DriveIndex, BOOL bWriteAccess, BOOL bLockDrive);
|
||||
extern char GetDriveLetter(DWORD DriveIndex);
|
||||
extern char GetUnusedDriveLetter(void);
|
||||
extern BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker);
|
||||
extern const char* GetPartitionType(BYTE Type);
|
||||
extern BOOL GetDrivePartitionData(DWORD DeviceNumber, char* FileSystemName, DWORD FileSystemNameSize);
|
||||
extern HANDLE GetDriveHandle(DWORD DriveIndex, char* DriveLetter, BOOL bWriteAccess, BOOL bLockDrive);
|
||||
extern BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSystemNameSize);
|
||||
extern BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label);
|
||||
extern BOOL UnmountDrive(HANDLE hDrive);
|
||||
extern BOOL UnmountVolume(HANDLE hDrive);
|
||||
extern BOOL CreateProgress(void);
|
||||
extern BOOL SetAutorun(const char* path);
|
||||
extern char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_desc);
|
||||
|
@ -397,7 +401,9 @@ typedef struct {
|
|||
#define ERROR_ISO_SCAN 0x1207
|
||||
#define ERROR_ISO_EXTRACT 0x1208
|
||||
#define ERROR_CANT_REMOUNT_VOLUME 0x1209
|
||||
#define ERROR_CANT_PATCH 0x1210
|
||||
#define ERROR_CANT_PATCH 0x120A
|
||||
#define ERROR_CANT_ASSIGN_LETTER 0x120B
|
||||
#define ERROR_CANT_MOUNT_VOLUME 0x120C
|
||||
|
||||
/* More niceties */
|
||||
#ifndef MIN
|
||||
|
|
10
src/rufus.rc
10
src/rufus.rc
|
@ -30,7 +30,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
|
|||
IDD_DIALOG DIALOGEX 12, 12, 206, 316
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
EXSTYLE WS_EX_APPWINDOW
|
||||
CAPTION "Rufus v1.3.3.239"
|
||||
CAPTION "Rufus v1.3.3.240"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "Start",IDC_START,94,278,50,14
|
||||
|
@ -274,8 +274,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,3,3,239
|
||||
PRODUCTVERSION 1,3,3,239
|
||||
FILEVERSION 1,3,3,240
|
||||
PRODUCTVERSION 1,3,3,240
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -292,13 +292,13 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
|
||||
VALUE "FileDescription", "Rufus"
|
||||
VALUE "FileVersion", "1.3.3.239"
|
||||
VALUE "FileVersion", "1.3.3.240"
|
||||
VALUE "InternalName", "Rufus"
|
||||
VALUE "LegalCopyright", "(c) 2011-2013 Pete Batard (GPL v3)"
|
||||
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
|
||||
VALUE "OriginalFilename", "rufus.exe"
|
||||
VALUE "ProductName", "Rufus"
|
||||
VALUE "ProductVersion", "1.3.3.239"
|
||||
VALUE "ProductVersion", "1.3.3.240"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
|
@ -269,6 +269,10 @@ const char* StrError(DWORD error_code)
|
|||
"mountvol.exe command to make your device accessible again";
|
||||
case ERROR_CANT_PATCH:
|
||||
return "Unable to patch/setup files for boot";
|
||||
case ERROR_CANT_ASSIGN_LETTER:
|
||||
return "Unable to assign a drive letter";
|
||||
case ERROR_CANT_MOUNT_VOLUME:
|
||||
return "Can't mount GUID volume";
|
||||
default:
|
||||
uprintf("Unknown error: %08X\n", error_code);
|
||||
SetLastError(error_code);
|
||||
|
|
|
@ -66,7 +66,7 @@ int libfat_readfile(intptr_t pp, void *buf, size_t secsize,
|
|||
* Extract the ldlinux.sys and ldlinux.bss from resources,
|
||||
* then patch and install them
|
||||
*/
|
||||
BOOL InstallSyslinux(DWORD num, const char* drive_name)
|
||||
BOOL InstallSyslinux(DWORD drive_index, char drive_letter)
|
||||
{
|
||||
HANDLE f_handle = INVALID_HANDLE_VALUE;
|
||||
HANDLE d_handle = INVALID_HANDLE_VALUE;
|
||||
|
@ -84,7 +84,7 @@ BOOL InstallSyslinux(DWORD num, const char* drive_name)
|
|||
int nsectors;
|
||||
int dt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType));
|
||||
|
||||
ldlinux_name[0] = drive_name[0];
|
||||
ldlinux_name[0] = drive_letter;
|
||||
|
||||
/* Initialize the ADV -- this should be smarter */
|
||||
syslinux_reset_adv(syslinux_adv);
|
||||
|
@ -135,7 +135,7 @@ BOOL InstallSyslinux(DWORD num, const char* drive_name)
|
|||
}
|
||||
|
||||
/* Reopen the volume (we already have a lock) */
|
||||
d_handle = GetDriveHandle(num, (char*)drive_name, TRUE, FALSE);
|
||||
d_handle = GetLogicalHandle(drive_index, TRUE, FALSE);
|
||||
if (d_handle == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Could open volume for syslinux operation\n");
|
||||
goto out;
|
||||
|
|
Loading…
Reference in a new issue