1
1
Fork 0
mirror of https://github.com/pbatard/rufus.git synced 2024-08-14 23:57:05 +00:00

[core] improved error and cancellation handling

* return standard Windows error codes where possible
* add custom error codes that follow the Windows error format
* automatically close cancel MessageBox if the process completes
This commit is contained in:
Pete Batard 2011-11-28 12:37:58 +00:00
parent 23b1f55338
commit d6c66e0d09
2 changed files with 51 additions and 44 deletions

84
rufus.c
View file

@ -84,7 +84,7 @@ struct {
static HWND hDeviceList, hCapacity, hFileSystem, hLabel; static HWND hDeviceList, hCapacity, hFileSystem, hLabel;
static HWND hDeviceTooltip = NULL, hFSTooltip = NULL; static HWND hDeviceTooltip = NULL, hFSTooltip = NULL;
static StrArray DriveID, DriveLabel; static StrArray DriveID, DriveLabel;
static DWORD FormatErr; static DWORD FormatStatus;
#ifdef RUFUS_DEBUG #ifdef RUFUS_DEBUG
void _uprintf(const char *format, ...) void _uprintf(const char *format, ...)
@ -209,7 +209,7 @@ static BOOL GetDriveHandle(DWORD DriveIndex, HANDLE* hDrive, char* DriveLetter,
safe_closehandle(*hDrive); safe_closehandle(*hDrive);
return FALSE; return FALSE;
} }
uprintf("Warning: Opening %s drive for write access\n", drive_name); uprintf("Caution: Opened %s drive for write access\n", drive_name);
} }
break; break;
} }
@ -217,7 +217,7 @@ static BOOL GetDriveHandle(DWORD DriveIndex, HANDLE* hDrive, char* DriveLetter,
} }
if (DriveLetter != NULL) { if (DriveLetter != NULL) {
*DriveLetter = *drive?*drive:' '; // TODO: handle NUL char upstream *DriveLetter = *drive?*drive:' ';
} }
return (*hDrive != INVALID_HANDLE_VALUE); return (*hDrive != INVALID_HANDLE_VALUE);
@ -293,6 +293,7 @@ static BOOL GetDriveInfo(void)
if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) { if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) {
uprintf("Partition #%d:\n", ++nb_partitions); uprintf("Partition #%d:\n", ++nb_partitions);
if (hFSTooltip == NULL) { if (hFSTooltip == NULL) {
// TODO: provide all partitions FS on tooltip, not just the one
safe_sprintf(tmp, sizeof(tmp), "Current file system: %s (0x%02x)", safe_sprintf(tmp, sizeof(tmp), "Current file system: %s (0x%02x)",
GetPartitionType(DriveLayout->PartitionEntry[i].Mbr.PartitionType), GetPartitionType(DriveLayout->PartitionEntry[i].Mbr.PartitionType),
DriveLayout->PartitionEntry[i].Mbr.PartitionType); DriveLayout->PartitionEntry[i].Mbr.PartitionType);
@ -508,7 +509,8 @@ static BOOLEAN __stdcall FormatExCallback(FILE_SYSTEM_CALLBACK_COMMAND Command,
DWORD* percent; DWORD* percent;
int task_number = 0; int task_number = 0;
if (FormatErr != 0) return FALSE; if (IS_ERROR(FormatStatus))
return FALSE;
switch(Command) { switch(Command) {
case FCC_PROGRESS: case FCC_PROGRESS:
@ -517,65 +519,60 @@ static BOOLEAN __stdcall FormatExCallback(FILE_SYSTEM_CALLBACK_COMMAND Command,
uprintf("%d percent completed.\n", *percent); uprintf("%d percent completed.\n", *percent);
break; break;
case FCC_STRUCTURE_PROGRESS: // No progress on quick format case FCC_STRUCTURE_PROGRESS: // No progress on quick format
uprintf("format task %d/n completed.\n", ++task_number); uprintf("Format task %d/? completed.\n", ++task_number);
break; break;
case FCC_DONE: case FCC_DONE:
if(*(BOOLEAN*)Data == FALSE) { if(*(BOOLEAN*)Data == FALSE) {
uprintf("Error while formatting.\n"); uprintf("Error while formatting.\n");
FormatErr = FCC_DONE; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE;
} }
break; break;
case FCC_INCOMPATIBLE_FILE_SYSTEM: case FCC_INCOMPATIBLE_FILE_SYSTEM:
uprintf("Incompatible File System\n"); uprintf("Incompatible File System\n");
FormatErr = Command; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INCOMPATIBLE_FS;
break; break;
case FCC_ACCESS_DENIED: case FCC_ACCESS_DENIED:
uprintf("Access denied\n"); uprintf("Access denied\n");
FormatErr = Command; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED;
break; break;
case FCC_MEDIA_WRITE_PROTECTED: case FCC_MEDIA_WRITE_PROTECTED:
uprintf("Media is write protected\n"); uprintf("Media is write protected\n");
FormatErr = Command; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_PROTECT;
break; break;
case FCC_VOLUME_IN_USE: case FCC_VOLUME_IN_USE:
uprintf("Volume is in use\n"); uprintf("Volume is in use\n");
FormatErr = Command; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_DEVICE_IN_USE;
break; break;
case FCC_CANT_QUICK_FORMAT: case FCC_CANT_QUICK_FORMAT:
uprintf("Cannot quick format this volume\n"); uprintf("Cannot quick format this volume\n");
FormatErr = Command; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANT_QUICK_FORMAT;
break; break;
case FCC_BAD_LABEL: case FCC_BAD_LABEL:
uprintf("Bad label\n"); uprintf("Bad label\n");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INVALID_LABEL;
break; break;
case FCC_OUTPUT: case FCC_OUTPUT:
uprintf("%s\n", ((PTEXTOUTPUT)Data)->Output); uprintf("%s\n", ((PTEXTOUTPUT)Data)->Output);
break; break;
case FCC_CLUSTER_SIZE_TOO_SMALL:
uprintf("Allocation unit size is too small\n");
FormatErr = Command;
break;
case FCC_CLUSTER_SIZE_TOO_BIG: case FCC_CLUSTER_SIZE_TOO_BIG:
uprintf("Allocation unit size is too big\n"); case FCC_CLUSTER_SIZE_TOO_SMALL:
FormatErr = Command; uprintf("Allocation unit size is too %s\n", FCC_CLUSTER_SIZE_TOO_BIG?"big":"small");
break; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INVALID_CLUSTER_SIZE;
case FCC_VOLUME_TOO_SMALL:
uprintf("Volume is too small\n");
FormatErr = Command;
break; break;
case FCC_VOLUME_TOO_BIG: case FCC_VOLUME_TOO_BIG:
uprintf("Volume is too big\n"); case FCC_VOLUME_TOO_SMALL:
FormatErr = Command; uprintf("Volume is too %s\n", FCC_VOLUME_TOO_BIG?"big":"small");
break; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INVALID_VOLUME_SIZE;
case FCC_NO_MEDIA_IN_DRIVE: case FCC_NO_MEDIA_IN_DRIVE:
uprintf("No media\n"); uprintf("No media in drive\n");
FormatErr = Command; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NO_MEDIA_IN_DRIVE;
break; break;
default: default:
uprintf("FormatExCallback: received unhandled command %X\n", Command); uprintf("FormatExCallback: received unhandled command %X\n", Command);
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_SUPPORTED;
break; break;
} }
return (FormatErr == 0); return (!IS_ERROR(FormatStatus));
} }
/* /*
@ -594,17 +591,14 @@ static BOOL FormatDrive(char DriveLetter)
PF_INIT_OR_OUT(FormatEx, fmifs); PF_INIT_OR_OUT(FormatEx, fmifs);
// TODO: properly set MediaType // TODO: properly set MediaType
FormatErr = 0;
GetWindowTextW(hFileSystem, wFSType, ARRAYSIZE(wFSType)); GetWindowTextW(hFileSystem, wFSType, ARRAYSIZE(wFSType));
GetWindowTextW(hLabel, wLabel, ARRAYSIZE(wLabel)); GetWindowTextW(hLabel, wLabel, ARRAYSIZE(wLabel));
// TODO set sector size // TODO set sector size
pfFormatEx(wDriveRoot, RemovableMedia, wFSType, wLabel, pfFormatEx(wDriveRoot, RemovableMedia, wFSType, wLabel,
IsChecked(IDC_QUICKFORMAT), 4096, FormatExCallback); IsChecked(IDC_QUICKFORMAT), 4096, FormatExCallback);
if (FormatErr == 0) { if (!IS_ERROR(FormatStatus)) {
uprintf("Format completed.\n"); uprintf("Format completed.\n");
r = TRUE; r = TRUE;
} else {
uprintf("Format error: 0x%02x\n", FormatErr);
} }
out: out:
@ -623,14 +617,14 @@ static void __cdecl FormatThread(void* param)
int i; int i;
if (!GetDriveHandle(num, &hDrive, NULL, TRUE)) { if (!GetDriveHandle(num, &hDrive, NULL, TRUE)) {
// TODO: use FormatErr to report an error FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
goto out; goto out;
} }
r = CreatePartition(hDrive); r = CreatePartition(hDrive);
safe_closehandle(hDrive); safe_closehandle(hDrive);
if (!r) { if (!r) {
// TODO: use FormatErr to report an error FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE;
goto out; goto out;
} }
@ -643,12 +637,14 @@ static void __cdecl FormatThread(void* param)
} }
if (i >= 10) { if (i >= 10) {
uprintf("Unable to reopen drive post partitioning\n"); uprintf("Unable to reopen drive post partitioning\n");
// TODO: use FormatErr to report an error FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
goto out; goto out;
} }
safe_closehandle(hDrive); safe_closehandle(hDrive);
if (!FormatDrive(drive_name[0])) { if (!FormatDrive(drive_name[0])) {
// Error will be set by FormatDrive() in FormatStatus
uprintf("Format error: 0x%08X\n", FormatStatus);
goto out; goto out;
} }
@ -855,13 +851,12 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
case IDOK: // close application case IDOK: // close application
case IDCANCEL: case IDCANCEL:
if (format_thid != -1L) { if (format_thid != -1L) {
// TODO: destroy MessageBox if operation completed while waiting
if (MessageBoxA(hMainDialog, "Cancelling may leave the device in an UNUSABLE state.\r\n" if (MessageBoxA(hMainDialog, "Cancelling may leave the device in an UNUSABLE state.\r\n"
"If you are sure you want to cancel, click YES. Otherwise, click NO.", "If you are sure you want to cancel, click YES. Otherwise, click NO.",
"Do you want to cancel?", MB_YESNO|MB_ICONWARNING) == IDYES) { RUFUS_CANCELBOX_TITLE, MB_YESNO|MB_ICONWARNING) == IDYES) {
// Operation may have completed // Operation may have completed in the meantime
if (format_thid != -1L) { if (format_thid != -1L) {
FormatErr = -1; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED;
StatusPrintf("Cancelling - please wait..."); StatusPrintf("Cancelling - please wait...");
} }
} }
@ -886,7 +881,6 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
} }
break; break;
case IDC_START: case IDC_START:
// TODO: disable all controls and replace Close with Cancel
if (format_thid != -1L) { if (format_thid != -1L) {
return (INT_PTR)TRUE; return (INT_PTR)TRUE;
} }
@ -904,10 +898,12 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
SendMessage(hProgress, PBM_SETMARQUEE, TRUE, 0); SendMessage(hProgress, PBM_SETMARQUEE, TRUE, 0);
} }
DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex); DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex);
FormatStatus = 0;
format_thid = _beginthread(FormatThread, 0, (void*)(uintptr_t)DeviceNum); format_thid = _beginthread(FormatThread, 0, (void*)(uintptr_t)DeviceNum);
if (format_thid == -1L) { if (format_thid == -1L) {
// TODO: handle error
uprintf("Unable to start formatting thread"); uprintf("Unable to start formatting thread");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANT_START_THREAD;
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
} }
} }
} }
@ -930,6 +926,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
case UM_FORMAT_COMPLETED: case UM_FORMAT_COMPLETED:
format_thid = -1L; format_thid = -1L;
// Close the cancel MessageBox if active
SendMessage(FindWindowA(MAKEINTRESOURCEA(32770), RUFUS_CANCELBOX_TITLE), WM_COMMAND, IDNO, 0);
if (IsChecked(IDC_QUICKFORMAT)) { if (IsChecked(IDC_QUICKFORMAT)) {
SendMessage(hProgress, PBM_SETMARQUEE, FALSE, 0); SendMessage(hProgress, PBM_SETMARQUEE, FALSE, 0);
SetWindowLongPtr(hProgress, GWL_STYLE, ProgressStyle); SetWindowLongPtr(hProgress, GWL_STYLE, ProgressStyle);
@ -938,9 +936,9 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
SendMessage(hProgress, PBM_SETPOS, 101, 0); SendMessage(hProgress, PBM_SETPOS, 101, 0);
SendMessage(hProgress, PBM_SETRANGE, 0, 100<<16); SendMessage(hProgress, PBM_SETRANGE, 0, 100<<16);
} }
SendMessage(hProgress, PBM_SETPOS, FormatErr?0:100, 0); SendMessage(hProgress, PBM_SETPOS, FormatStatus?0:100, 0);
// TODO: report cancelled status StatusPrintf(!IS_ERROR(FormatStatus)?"DONE":
StatusPrintf(FormatErr?"FAILED":"DONE"); ((SCODE_CODE(FormatStatus)==ERROR_CANCELLED)?"Cancelled":"FAILED"));
EnableControls(TRUE); EnableControls(TRUE);
return (INT_PTR)TRUE; return (INT_PTR)TRUE;
} }

11
rufus.h
View file

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <winioctl.h> // for MEDIA_TYPE #include <winioctl.h> // for MEDIA_TYPE
#pragma once #pragma once
@ -23,6 +23,7 @@
#define APP_VERSION "Rufus v1.0.0.1" #define APP_VERSION "Rufus v1.0.0.1"
#define STR_NO_LABEL "NO_LABEL" #define STR_NO_LABEL "NO_LABEL"
#define RUFUS_CANCELBOX_TITLE "Rufus - Cancellation"
#define DRIVE_INDEX_MIN 0x80 #define DRIVE_INDEX_MIN 0x80
#define DRIVE_INDEX_MAX 0xC0 #define DRIVE_INDEX_MAX 0xC0
#define MAX_DRIVES 16 #define MAX_DRIVES 16
@ -213,3 +214,11 @@ typedef BOOLEAN (WINAPI* EnableVolumeCompression_t)(
WCHAR* DriveRoot, WCHAR* DriveRoot,
ULONG CompressionFlags // FILE_SYSTEM_PROP_FLAG ULONG CompressionFlags // FILE_SYSTEM_PROP_FLAG
); );
/* Custom application errors */
#define FAC(f) (f<<16)
#define ERROR_INCOMPATIBLE_FS (APPLICATION_ERROR_MASK|0x1201)
#define ERROR_CANT_QUICK_FORMAT (APPLICATION_ERROR_MASK|0x1202)
#define ERROR_INVALID_CLUSTER_SIZE (APPLICATION_ERROR_MASK|0x1203)
#define ERROR_INVALID_VOLUME_SIZE (APPLICATION_ERROR_MASK|0x1204)
#define ERROR_CANT_START_THREAD (APPLICATION_ERROR_MASK|0x1205)