1
1
Fork 0
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:
Pete Batard 2013-04-08 00:10:58 +01:00
parent d56615cd20
commit 4da36fa321
7 changed files with 434 additions and 189 deletions

View file

@ -38,106 +38,42 @@ RUFUS_DRIVE_INFO SelectedDrive;
extern BOOL enable_fixed_disks; extern BOOL enable_fixed_disks;
/* /*
* Open a drive or volume with optional write and lock access * Working with drive indexes quite risky (left unchecked,inadvertently passing 0 as
* Returns INVALID_HANDLE_VALUE (/!\ which is DIFFERENT from NULL /!\) on failure. * index would return a handle to C:, which we might then proceed to unknowingly
* This call is quite risky (left unchecked, inadvertently passing 0 as index would * clear the MBR of!), so we mitigate the risk by forcing our indexes to belong to
* return a handle to C:, which we might then proceed to unknowingly repartition!), * the specific range [DRIVE_INDEX_MIN; DRIVE_INDEX_MAX].
* 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
*/ */
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; DWORD size;
HANDLE hDrive = INVALID_HANDLE_VALUE; 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 (Path == NULL)
if ((DriveIndex < DRIVE_INDEX_MIN) || (DriveIndex > DRIVE_INDEX_MAX)) { goto out;
uprintf("WARNING: Bad index value. Please check the code!\n"); 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 (bWriteAccess) {
if (DriveLetter == NULL) { uprintf("Caution: Opened drive %s for write access\n", Path);
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 ((bLockDrive) && (!DeviceIoControl(hDrive, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &size, NULL))) { 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); safe_closehandle(hDrive);
goto out; goto out;
} }
@ -146,12 +82,244 @@ out:
return hDrive; 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 * 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) BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label)
{ {
HANDLE hDrive, hPhysical; HANDLE hPhysical;
DWORD size; DWORD size;
char AutorunPath[] = "#:\\autorun.inf", *AutorunLabel = NULL; char AutorunPath[] = "#:\\autorun.inf", *AutorunLabel = NULL;
wchar_t wDrivePath[] = L"#:\\"; wchar_t wDrivePath[] = L"#:\\";
@ -160,19 +328,19 @@ BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label)
*label = STR_NO_LABEL; *label = STR_NO_LABEL;
hDrive = GetDriveHandle(DriveIndex, letter, FALSE, FALSE); *letter = GetDriveLetter(DriveIndex);
if (hDrive == INVALID_HANDLE_VALUE) { if (*letter == ' ') {
// Assume we have a raw drive without volume assigned if enable_fixed_disk is true // Drive without volume assigned
return enable_fixed_disks; // TODO: only with fixed?
return TRUE;
} }
safe_closehandle(hDrive);
AutorunPath[0] = *letter; AutorunPath[0] = *letter;
wDrivePath[0] = *letter; wDrivePath[0] = *letter;
// Try to read an extended label from autorun first. Fallback to regular label if not found. // 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 // 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 // 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)) if (DeviceIoControl(hPhysical, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, &size, NULL))
AutorunLabel = get_token_data_file("label", AutorunPath); AutorunLabel = get_token_data_file("label", AutorunPath);
else if (GetLastError() == ERROR_NOT_READY) 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) * 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; BOOL r;
HANDLE hDrive; HANDLE hPhysical;
DWORD size; DWORD size;
BYTE geometry[128], layout[1024], part_type; BYTE geometry[128], layout[1024], part_type;
void* disk_geometry = (void*)geometry; void* disk_geometry = (void*)geometry;
void* drive_layout = (void*)layout; void* drive_layout = (void*)layout;
PDISK_GEOMETRY_EX DiskGeometry = (PDISK_GEOMETRY_EX)disk_geometry; PDISK_GEOMETRY_EX DiskGeometry = (PDISK_GEOMETRY_EX)disk_geometry;
PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)drive_layout; 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; DWORD i, nb_partitions = 0;
hDrive = GetDriveHandle(DeviceNumber, NULL, FALSE, FALSE); hPhysical = GetPhysicalHandle(DriveIndex, FALSE, FALSE);
if (hDrive == INVALID_HANDLE_VALUE) if (hPhysical == INVALID_HANDLE_VALUE)
return FALSE; 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); NULL, 0, geometry, sizeof(geometry), &size, NULL);
if (!r || size <= 0) { if (!r || size <= 0) {
uprintf("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX failed for drive %c: %s\n", DrivePath[0], WindowsErrorString()); uprintf("Could not get geometry for drive #%d: %s\n", DriveIndex, WindowsErrorString());
safe_closehandle(hDrive); safe_closehandle(hPhysical);
return FALSE; return FALSE;
} }
SelectedDrive.DiskSize = DiskGeometry->DiskSize.QuadPart; 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", uprintf("Cylinders: %lld, TracksPerCylinder: %d, SectorsPerTrack: %d\n",
DiskGeometry->Geometry.Cylinders, DiskGeometry->Geometry.TracksPerCylinder, DiskGeometry->Geometry.SectorsPerTrack); 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 ); NULL, 0, layout, sizeof(layout), &size, NULL );
if (!r || size <= 0) { 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; return FALSE;
} }
@ -281,17 +450,23 @@ BOOL GetDrivePartitionData(DWORD DeviceNumber, char* FileSystemName, DWORD FileS
uprintf("Partition type: RAW\n"); uprintf("Partition type: RAW\n");
break; break;
} }
safe_closehandle(hDrive); safe_closehandle(hPhysical);
// Populate the filesystem data // 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; FileSystemName[0] = 0;
} }
safe_free(volume_name);
return TRUE; return TRUE;
} }
BOOL UnmountDrive(HANDLE hDrive) /*
* Unmount of volume using the DISMOUNT_VOLUME ioctl
*/
BOOL UnmountVolume(HANDLE hDrive)
{ {
DWORD size; 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, r = DeviceIoControl(hDrive, IOCTL_DISK_CREATE_DISK,
(BYTE*)&CreateDisk, size, NULL, 0, &size, NULL ); (BYTE*)&CreateDisk, size, NULL, 0, &size, NULL );
if (!r) { if (!r) {
uprintf("IOCTL_DISK_CREATE_DISK failed: %s\n", WindowsErrorString()); uprintf("Could not reset disk: %s\n", WindowsErrorString());
safe_closehandle(hDrive); safe_closehandle(hDrive);
return FALSE; 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, 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) {
uprintf("IOCTL_DISK_SET_DRIVE_LAYOUT_EX failed: %s\n", WindowsErrorString()); uprintf("Could not set drive layout: %s\n", WindowsErrorString());
safe_closehandle(hDrive); safe_closehandle(hDrive);
return FALSE; return FALSE;
} }

View file

@ -54,6 +54,7 @@ static int task_number = 0;
/* Number of steps for each FS for FCC_STRUCTURE_PROGRESS */ /* Number of steps for each FS for FCC_STRUCTURE_PROGRESS */
const int nb_steps[FS_MAX] = { 5, 5, 12, 10 }; const int nb_steps[FS_MAX] = { 5, 5, 12, 10 };
static int fs_index = 0; static int fs_index = 0;
BOOL force_large_fat32 = FALSE;
/* /*
* FormatEx callback. Return FALSE to halt operations * FormatEx callback. Return FALSE to halt operations
@ -274,6 +275,7 @@ static void ToValidLabel(WCHAR* name, BOOL bFAT)
* ----- * -----
* 1d02h * 1d02h
*/ */
// TODO: use that for Format "classic"
static DWORD GetVolumeID(void) static DWORD GetVolumeID(void)
{ {
SYSTEMTIME s; SYSTEMTIME s;
@ -331,7 +333,6 @@ static DWORD GetFATSizeSectors(DWORD DskSize, DWORD ReservedSecCnt, DWORD SecPer
static BOOL FormatFAT32(DWORD DriveIndex) static BOOL FormatFAT32(DWORD DriveIndex)
{ {
BOOL r = FALSE; BOOL r = FALSE;
char DriveLetter;
DWORD i; DWORD i;
HANDLE hLogicalVolume; HANDLE hLogicalVolume;
DWORD cbRet; DWORD cbRet;
@ -342,7 +343,8 @@ static BOOL FormatFAT32(DWORD DriveIndex)
DWORD NumFATs = 2; DWORD NumFATs = 2;
DWORD BackupBootSect = 6; DWORD BackupBootSect = 6;
DWORD VolumeId = 0; // calculated before format 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 DWORD BurstSize = 128; // Zero in blocks of 64K typically
// Calculated later // Calculated later
@ -365,18 +367,17 @@ static BOOL FormatFAT32(DWORD DriveIndex)
// Debug temp vars // Debug temp vars
ULONGLONG FatNeeded, ClusterCount; ULONGLONG FatNeeded, ClusterCount;
PrintStatus(0, TRUE, "Formatting..."); PrintStatus(0, TRUE, "Formatting (Large FAT32)...");
uprintf("Using large FAT32 format method\n");
VolumeId = GetVolumeID(); VolumeId = GetVolumeID();
// Open the drive (volume should already be locked) // 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 (IS_ERROR(FormatStatus)) goto out;
if (hLogicalVolume == INVALID_HANDLE_VALUE) if (hLogicalVolume == INVALID_HANDLE_VALUE)
die("Could not access logical volume\n", ERROR_OPEN_FAILED); die("Could not access logical volume\n", ERROR_OPEN_FAILED);
// Make sure we get exclusive access // Make sure we get exclusive access
if (!UnmountDrive(hLogicalVolume)) if (!UnmountVolume(hLogicalVolume))
return r; return r;
// Work out drive params // Work out drive params
@ -526,7 +527,7 @@ static BOOL FormatFAT32(DWORD DriveIndex)
} }
// Now we're commited - print some info first // 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("Cluster size %d bytes, %d Bytes Per Sector\n", SectorsPerCluster*BytesPerSect, BytesPerSect);
uprintf("Volume ID is %x:%x\n", VolumeId>>16, VolumeId&0xffff); 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); 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 // Set the FAT32 volume label
GetWindowTextW(hLabel, wLabel, ARRAYSIZE(wLabel)); GetWindowTextW(hLabel, wLabel, ARRAYSIZE(wLabel));
ToValidLabel(wLabel, TRUE); ToValidLabel(wLabel, TRUE);
wDriveName[0] = DriveLetter;
// Handle must be closed for SetVolumeLabel to work // Handle must be closed for SetVolumeLabel to work
safe_closehandle(hLogicalVolume); safe_closehandle(hLogicalVolume);
PrintStatus(0, TRUE, "Setting Label (This may take while)...");
PrintStatus(0, TRUE, "Setting Label (This can take while)..."); VolumeName = GetLogicalName(DriveIndex, TRUE);
if (!SetVolumeLabelW(wDriveName, wLabel)) { wVolumeName = utf8_to_wchar(VolumeName);
if ((wVolumeName == NULL) || (!SetVolumeLabelW(wVolumeName, wLabel))) {
uprintf("Could not set label: %s\n", WindowsErrorString()); uprintf("Could not set label: %s\n", WindowsErrorString());
// Non fatal error
} }
uprintf("Format completed.\n"); uprintf("Format completed.\n");
r = TRUE; r = TRUE;
out: out:
safe_free(VolumeName);
safe_free(wVolumeName);
safe_closehandle(hLogicalVolume); safe_closehandle(hLogicalVolume);
safe_free(pFAT32BootSect); safe_free(pFAT32BootSect);
safe_free(pFAT32FsInfo); safe_free(pFAT32FsInfo);
@ -601,18 +606,28 @@ out:
/* /*
* Call on fmifs.dll's FormatEx() to format the drive * Call on fmifs.dll's FormatEx() to format the drive
*/ */
static BOOL FormatDrive(char DriveLetter) static BOOL FormatDrive(DWORD DriveIndex)
{ {
BOOL r = FALSE; BOOL r = FALSE;
PF_DECL(FormatEx); PF_DECL(FormatEx);
WCHAR wDriveRoot[] = L"?:\\"; char* VolumeName = NULL;
WCHAR* wVolumeName = NULL;
char FSType[32], format_status[64];
WCHAR wFSType[32]; WCHAR wFSType[32];
WCHAR wLabel[64]; WCHAR wLabel[64];
size_t i; size_t i;
char* locale; char* locale;
wDriveRoot[0] = (WCHAR)DriveLetter; GetWindowTextA(hFileSystem, FSType, ARRAYSIZE(FSType));
PrintStatus(0, TRUE, "Formatting..."); 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 // LoadLibrary("fmifs.dll") appears to changes the locale, which can lead to
// problems with tolower(). Make sure we restore the locale. For more details, // problems with tolower(). Make sure we restore the locale. For more details,
// see http://comments.gmane.org/gmane.comp.gnu.mingw.user/39300 // see http://comments.gmane.org/gmane.comp.gnu.mingw.user/39300
@ -635,7 +650,7 @@ static BOOL FormatDrive(char DriveLetter)
format_percent = 0.0f; format_percent = 0.0f;
task_number = 0; task_number = 0;
fs_index = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem)); 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)), IsChecked(IDC_QUICKFORMAT), (ULONG)ComboBox_GetItemData(hClusterSize, ComboBox_GetCurSel(hClusterSize)),
FormatExCallback); FormatExCallback);
if (!IS_ERROR(FormatStatus)) { if (!IS_ERROR(FormatStatus)) {
@ -644,6 +659,8 @@ static BOOL FormatDrive(char DriveLetter)
} }
out: out:
safe_free(VolumeName);
safe_free(wVolumeName);
return r; return r;
} }
@ -737,12 +754,14 @@ static BOOL AnalyzePBR(HANDLE hLogicalVolume)
} else if (entire_fat_32_fd_br_matches(&fake_fd)) { } else if (entire_fat_32_fd_br_matches(&fake_fd)) {
uprintf("Drive has a FAT32 FreeDOS partition boot record\n"); uprintf("Drive has a FAT32 FreeDOS partition boot record\n");
} else { } 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; 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) static BOOL ClearMBRGPT(HANDLE hPhysicalDrive, LONGLONG DiskSize, DWORD SectorSize)
{ {
BOOL r = FALSE; BOOL r = FALSE;
@ -1138,15 +1157,24 @@ DWORD WINAPI CloseFormatPromptThread(LPVOID param) {
/* /*
* Standalone thread for the formatting operation * 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) DWORD WINAPI FormatThread(LPVOID param)
{ {
int r, pt, bt, fs, dt; int r, pt, bt, fs, dt;
BOOL ret, no_volume = FALSE; BOOL ret;
DWORD num = (DWORD)(uintptr_t)param; DWORD DriveIndex = (DWORD)(uintptr_t)param;
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE; HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
HANDLE hLogicalVolume = INVALID_HANDLE_VALUE; HANDLE hLogicalVolume = INVALID_HANDLE_VALUE;
SYSTEMTIME lt; SYSTEMTIME lt;
char* guid_volume = NULL;
char drive_name[] = "?:\\"; char drive_name[] = "?:\\";
char bb_msg[512]; char bb_msg[512];
char logfile[MAX_PATH], *userdir; char logfile[MAX_PATH], *userdir;
@ -1159,34 +1187,41 @@ DWORD WINAPI FormatThread(LPVOID 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)));
if (num & DRIVE_INDEX_RAW_DRIVE) { PrintStatus(0, TRUE, "Requesting disk access...\n");
no_volume = TRUE; hPhysicalDrive = GetPhysicalHandle(DriveIndex, TRUE, TRUE);
uprintf("Using raw drive mode\n");
}
hPhysicalDrive = GetDriveHandle(num, NULL, TRUE, TRUE);
if (hPhysicalDrive == INVALID_HANDLE_VALUE) { if (hPhysicalDrive == INVALID_HANDLE_VALUE) {
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
goto out; 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 // At this stage with have both a handle and a lock to the physical drive...
// access to physical, unless we have a lock (which doesn't have to be write) drive_name[0] = GetDriveLetter(DriveIndex);
// Also, having a volume handle allows us to unmount the volume if (drive_name[0] == ' ') {
if (!no_volume) { uprintf("No drive letter was assigned...\n");
hLogicalVolume = GetDriveHandle(num, drive_name, FALSE, TRUE); drive_name[0] = GetUnusedDriveLetter();
if (hLogicalVolume == INVALID_HANDLE_VALUE) { if (drive_name[0] == ' ') {
uprintf("Could not lock volume\n"); uprintf("Could not find a suitable drive letter\n");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_ASSIGN_LETTER);
goto out; 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); AnalyzeMBR(hPhysicalDrive);
if (!no_volume) AnalyzePBR(hLogicalVolume);
AnalyzePBR(hLogicalVolume); UpdateProgress(OP_ANALYZE_MBR, -1.0f);
if (IsChecked(IDC_BADBLOCKS)) { if (IsChecked(IDC_BADBLOCKS)) {
do { do {
@ -1249,8 +1284,17 @@ DWORD WINAPI FormatThread(LPVOID param)
} }
} }
// Close the (unmounted) volume before formatting, but keep the lock // Close the (unmounted) volume before formatting, but keep the lock
if (!no_volume) // According to MS this relinquishes the lock, so...
safe_closehandle(hLogicalVolume); 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 // Especially after destructive badblocks test, you must zero the MBR/GPT completely
// before repartitioning. Else, all kind of bad things can happen. // 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 // Add a small delay after partitioning to be safe
Sleep(200); 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 // If FAT32 is requested and we have a large drive (>32 GB) use
// large FAT32 format, else use MS's FormatEx. // large FAT32 format, else use MS's FormatEx.
ret = ((fs == FS_FAT32) && (SelectedDrive.DiskSize > LARGE_FAT32_SIZE))? ret = ((fs == FS_FAT32) && ((SelectedDrive.DiskSize > LARGE_FAT32_SIZE) || (force_large_fat32)))?
FormatFAT32(num):FormatDrive(drive_name[0]); FormatFAT32(DriveIndex):FormatDrive(DriveIndex);
if (!ret) { if (!ret) {
// Error will be set by FormatDrive() in FormatStatus // Error will be set by FormatDrive() in FormatStatus
uprintf("Format error: %s\n", StrError(FormatStatus)); uprintf("Format error: %s\n", StrError(FormatStatus));
goto out; 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) { if (pt == PARTITION_STYLE_MBR) {
PrintStatus(0, TRUE, "Writing master boot record..."); PrintStatus(0, TRUE, "Writing master boot record...");
if (!WriteMBR(hPhysicalDrive)) { if (!WriteMBR(hPhysicalDrive)) {
@ -1304,6 +1344,12 @@ DWORD WINAPI FormatThread(LPVOID param)
UpdateProgress(OP_FIX_MBR, -1.0f); 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 (IsChecked(IDC_BOOT)) {
if (bt == BT_UEFI) { if (bt == BT_UEFI) {
// For once, no need to do anything - just check our sanity // 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))) { } 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 // We still have a lock, which we need to modify the volume boot record
// => no need to reacquire the lock... // => no need to reacquire the lock...
hLogicalVolume = GetDriveHandle(num, drive_name, TRUE, FALSE); hLogicalVolume = GetLogicalHandle(DriveIndex, TRUE, FALSE);
if (hLogicalVolume == INVALID_HANDLE_VALUE) { if (hLogicalVolume == INVALID_HANDLE_VALUE) {
uprintf("Could not re-mount volume for partition boot record access\n"); uprintf("Could not re-mount volume for partition boot record access\n");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
@ -1333,7 +1379,7 @@ DWORD WINAPI FormatThread(LPVOID param)
safe_unlockclose(hLogicalVolume); safe_unlockclose(hLogicalVolume);
} else if ( (dt == DT_SYSLINUX) || ((dt == DT_ISO) && ((fs == FS_FAT16) || (fs == FS_FAT32))) ) { } else if ( (dt == DT_SYSLINUX) || ((dt == DT_ISO) && ((fs == FS_FAT16) || (fs == FS_FAT32))) ) {
PrintStatus(0, TRUE, "Installing Syslinux..."); 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; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INSTALL_FAILURE;
} }
} }
@ -1368,7 +1414,8 @@ DWORD WINAPI FormatThread(LPVOID param)
goto out; goto out;
} }
if ((bt == BT_UEFI) && (!iso_report.has_efi) && (iso_report.has_win7_efi)) { 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)..."); PrintStatus(0, TRUE, "Win7 EFI boot setup (this may take a while)...");
wim_image[0] = drive_name[0]; wim_image[0] = drive_name[0];
efi_dst[0] = drive_name[0]; efi_dst[0] = drive_name[0];
@ -1392,7 +1439,7 @@ DWORD WINAPI FormatThread(LPVOID param)
} }
} }
UpdateProgress(OP_FINALIZE, -1.0f); UpdateProgress(OP_FINALIZE, -1.0f);
PrintStatus(0, TRUE, "Finalizing..."); PrintStatus(0, TRUE, "Finalizing, please wait...");
if (IsChecked(IDC_SET_ICON)) if (IsChecked(IDC_SET_ICON))
SetAutorun(drive_name); SetAutorun(drive_name);
// Issue another complete remount before we exit, to ensure we're clean // Issue another complete remount before we exit, to ensure we're clean
@ -1405,9 +1452,10 @@ DWORD WINAPI FormatThread(LPVOID param)
} }
out: out:
safe_free(guid_volume);
SendMessage(hISOProgressDlg, UM_ISO_EXIT, 0, 0); SendMessage(hISOProgressDlg, UM_ISO_EXIT, 0, 0);
safe_unlockclose(hLogicalVolume); safe_unlockclose(hLogicalVolume);
safe_unlockclose(hPhysicalDrive); safe_unlockclose(hPhysicalDrive); // This can take a while
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0); PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
ExitThread(0); ExitThread(0);
} }

View file

@ -93,6 +93,7 @@ static BOOL existing_key = FALSE; // For LGP set/restore
static BOOL iso_size_check = TRUE; static BOOL iso_size_check = TRUE;
static BOOL log_displayed = FALSE; static BOOL log_displayed = FALSE;
static BOOL iso_provided = FALSE; static BOOL iso_provided = FALSE;
extern BOOL force_large_fat32;
static int selection_default; 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 // We can afford a failure on this call - just replace the name
safe_strcpy(buffer, sizeof(buffer), generic_friendly_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); devint_data.cbSize = sizeof(devint_data);
hDrive = INVALID_HANDLE_VALUE; 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 (!SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, &_GUID_DEVINTERFACE_DISK, j, &devint_data)) {
if(GetLastError() != ERROR_NO_MORE_ITEMS) { if(GetLastError() != ERROR_NO_MORE_ITEMS) {
uprintf("SetupDiEnumDeviceInterfaces failed: %s\n", WindowsErrorString()); uprintf("SetupDiEnumDeviceInterfaces failed: %s\n", WindowsErrorString());
} else {
uprintf("Device was eliminated because it doesn't report itself as a disk\n");
} }
break; break;
} }
@ -669,7 +672,6 @@ static BOOL GetUSBDevices(DWORD devnum)
// Drive letter ' ' is returned for drives that don't have a volume assigned yet // Drive letter ' ' is returned for drives that don't have a volume assigned yet
if (drive_letter == ' ') { if (drive_letter == ' ') {
safe_sprintf(entry, sizeof(entry), "%s (Disk %d)", label, device_number.DeviceNumber); safe_sprintf(entry, sizeof(entry), "%s (Disk %d)", label, device_number.DeviceNumber);
device_number.DeviceNumber |= DRIVE_INDEX_RAW_DRIVE;
} else { } else {
safe_sprintf(entry, sizeof(entry), "%s (%c:)", label, drive_letter); 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)); memset(slot_end, 0, sizeof(slot_end));
previous_end = 0.0f; previous_end = 0.0f;
nb_slots[OP_ANALYZE_MBR] = 1;
nb_slots[OP_ZERO_MBR] = 1; nb_slots[OP_ZERO_MBR] = 1;
if (IsChecked(IDC_BADBLOCKS)) { if (IsChecked(IDC_BADBLOCKS)) {
nb_slots[OP_BADBLOCKS] = -1; nb_slots[OP_BADBLOCKS] = -1;
@ -751,7 +754,7 @@ static void InitProgress(void)
|| ((fs == FS_FAT32) && (SelectedDrive.DiskSize >= LARGE_FAT32_SIZE)) ) { || ((fs == FS_FAT32) && (SelectedDrive.DiskSize >= LARGE_FAT32_SIZE)) ) {
nb_slots[OP_FORMAT] = -1; 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++) { for (i=0; i<OP_MAX; i++) {
if (nb_slots[i] > 0) { if (nb_slots[i] > 0) {
@ -1015,7 +1018,6 @@ DWORD WINAPI ISOScanThread(LPVOID param)
safe_free(iso_path); safe_free(iso_path);
goto out; 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", 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.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", (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; user_changed_label = FALSE;
return (INT_PTR)TRUE; return (INT_PTR)TRUE;
case DBT_DEVNODES_CHANGED: 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 it's been more than a second since last device refresh, arm a refresh timer
if (GetTickCount() > LastRefresh + 1000) { if (GetTickCount() > LastRefresh + 1000) {
LastRefresh = GetTickCount(); 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); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_START_THREAD);
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0); PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
} }
PrintStatus(0, FALSE, "");
timer = 0; timer = 0;
safe_sprintf(szTimer, sizeof(szTimer), "00:00:00"); safe_sprintf(szTimer, sizeof(szTimer), "00:00:00");
SendMessageA(GetDlgItem(hMainDialog, IDC_STATUS), SB_SETTEXTA, SendMessageA(GetDlgItem(hMainDialog, IDC_STATUS), SB_SETTEXTA,
@ -1906,6 +1910,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
UpdateWindow(hDlg); UpdateWindow(hDlg);
// Do our own event processing and process "magic" commands // 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)) { while(GetMessage(&msg, NULL, 0, 0)) {
// The following ensures the processing of the ISO progress window messages // The following ensures the processing of the ISO progress window messages
if (!IsWindow(hISOProgressDlg) || !IsDialogMessage(hISOProgressDlg, &msg)) { 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); PrintStatus2000("ISO size check", iso_size_check);
continue; continue;
} }
// TODO: move this option to advanced mode
// Alt-F => Toggle detection of fixed disks // Alt-F => Toggle detection of fixed disks
// By default Rufus does not allow formatting USB fixed disk drives, such as USB HDDs // 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 // 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); GetUSBDevices(0);
continue; 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) // 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. // This key is used to disable Windows popup messages when an USB drive is plugged in.
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'D')) { if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'D')) {

View file

@ -38,8 +38,6 @@
#define RUFUS_BLOCKING_IO_TITLE APPLICATION_NAME " - Flushing buffers" #define RUFUS_BLOCKING_IO_TITLE APPLICATION_NAME " - Flushing buffers"
#define DRIVE_INDEX_MIN 0x00000080 #define DRIVE_INDEX_MIN 0x00000080
#define DRIVE_INDEX_MAX 0x000000C0 #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_DRIVES (DRIVE_INDEX_MAX - DRIVE_INDEX_MIN)
#define MAX_TOOLTIPS 32 #define MAX_TOOLTIPS 32
#define MAX_PROGRESS (0xFFFF-1) // leave room for 1 more for insta-progress workaround #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 */ /* Action type, for progress bar breakdown */
enum action_type { enum action_type {
OP_ANALYZE_MBR,
OP_BADBLOCKS, OP_BADBLOCKS,
OP_ZERO_MBR, OP_ZERO_MBR,
OP_PARTITION, OP_PARTITION,
@ -296,14 +295,19 @@ extern BOOL Question(char* title, char* format, ...);
extern BOOL ExtractDOS(const char* path); extern BOOL ExtractDOS(const char* path);
extern BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan); 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 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); 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 BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker);
extern const char* GetPartitionType(BYTE Type); extern const char* GetPartitionType(BYTE Type);
extern BOOL GetDrivePartitionData(DWORD DeviceNumber, char* FileSystemName, DWORD FileSystemNameSize); extern BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSystemNameSize);
extern HANDLE GetDriveHandle(DWORD DriveIndex, char* DriveLetter, BOOL bWriteAccess, BOOL bLockDrive);
extern BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label); 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 CreateProgress(void);
extern BOOL SetAutorun(const char* path); extern BOOL SetAutorun(const char* path);
extern char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_desc); 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_SCAN 0x1207
#define ERROR_ISO_EXTRACT 0x1208 #define ERROR_ISO_EXTRACT 0x1208
#define ERROR_CANT_REMOUNT_VOLUME 0x1209 #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 */ /* More niceties */
#ifndef MIN #ifndef MIN

View file

@ -30,7 +30,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 206, 316 IDD_DIALOG DIALOGEX 12, 12, 206, 316
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW EXSTYLE WS_EX_APPWINDOW
CAPTION "Rufus v1.3.3.239" CAPTION "Rufus v1.3.3.240"
FONT 8, "MS Shell Dlg", 400, 0, 0x1 FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,278,50,14 DEFPUSHBUTTON "Start",IDC_START,94,278,50,14
@ -274,8 +274,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,3,3,239 FILEVERSION 1,3,3,240
PRODUCTVERSION 1,3,3,239 PRODUCTVERSION 1,3,3,240
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -292,13 +292,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.3.3.239" VALUE "FileVersion", "1.3.3.240"
VALUE "InternalName", "Rufus" VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "(c) 2011-2013 Pete Batard (GPL v3)" VALUE "LegalCopyright", "(c) 2011-2013 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.3.3.239" VALUE "ProductVersion", "1.3.3.240"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -269,6 +269,10 @@ const char* StrError(DWORD error_code)
"mountvol.exe command to make your device accessible again"; "mountvol.exe command to make your device accessible again";
case ERROR_CANT_PATCH: case ERROR_CANT_PATCH:
return "Unable to patch/setup files for boot"; 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: default:
uprintf("Unknown error: %08X\n", error_code); uprintf("Unknown error: %08X\n", error_code);
SetLastError(error_code); SetLastError(error_code);

View file

@ -66,7 +66,7 @@ int libfat_readfile(intptr_t pp, void *buf, size_t secsize,
* Extract the ldlinux.sys and ldlinux.bss from resources, * Extract the ldlinux.sys and ldlinux.bss from resources,
* then patch and install them * 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 f_handle = INVALID_HANDLE_VALUE;
HANDLE d_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 nsectors;
int dt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType)); 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 */ /* Initialize the ADV -- this should be smarter */
syslinux_reset_adv(syslinux_adv); 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) */ /* 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) { if (d_handle == INVALID_HANDLE_VALUE) {
uprintf("Could open volume for syslinux operation\n"); uprintf("Could open volume for syslinux operation\n");
goto out; goto out;