From 192c3d6cc8c44a8294357325a4376001e2a940a1 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 6 Dec 2011 23:35:55 +0000 Subject: [PATCH] [bb] progress bar and cancellation support --- configure | 2 + configure.ac | 2 + rufus.rc | 0 src/badblocks.c | 114 ++++++++++++++++++++++++------------------------ src/badblocks.h | 4 +- src/format.c | 17 +++++--- src/rufus.c | 4 ++ src/rufus.h | 2 +- src/rufus.rc | 12 ++--- src/stdio.c | 4 +- 10 files changed, 89 insertions(+), 72 deletions(-) delete mode 100644 rufus.rc diff --git a/configure b/configure index 7c30c72a6a5..d8f9fbd76ed 100644 --- a/configure +++ b/configure @@ -3360,6 +3360,8 @@ $as_echo "#define _GNU_SOURCE /**/" >>confdefs.h # AC_MSG_ERROR([unsupported development environment]) #esac +# Clang needs an explicit WIN32_WINNT defined else it produces warnings +# in msapi_utf8.h - including winver.h only doesn't work AM_CFLAGS="${AM_CFLAGS} -DWINVER=0x501 -D_WIN32_WINNT=0x501 -D_WIN32_IE=0x501" AM_LDFLAGS="${AM_LDFLAGS} -Wl,-no-undefined" diff --git a/configure.ac b/configure.ac index a1e36ec6d55..10c213fe159 100644 --- a/configure.ac +++ b/configure.ac @@ -31,6 +31,8 @@ AC_DEFINE([_GNU_SOURCE], [], [Use GNU extensions]) # AC_MSG_ERROR([unsupported development environment]) #esac +# Clang needs an explicit WIN32_WINNT defined else it produces warnings +# in msapi_utf8.h - including winver.h only doesn't work AM_CFLAGS="${AM_CFLAGS} -DWINVER=0x501 -D_WIN32_WINNT=0x501 -D_WIN32_IE=0x501" AM_LDFLAGS="${AM_LDFLAGS} -Wl,-no-undefined" diff --git a/rufus.rc b/rufus.rc deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/badblocks.c b/src/badblocks.c index e26519fd808..21ad900e3ff 100644 --- a/src/badblocks.c +++ b/src/badblocks.c @@ -272,10 +272,11 @@ static void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter) /* * from e2fsprogs/misc/badblocks.c */ -static int v_flag = 2; /* verbose */ +static int v_flag = 1; /* verbose */ static int s_flag = 1; /* show progress of test */ static int t_flag = 0; /* number of test patterns */ static unsigned int *t_patts = NULL; /* test patterns */ +static int cancel_ops = 0; /* abort current operation */ /* Abort test if more than this number of bad blocks has been encountered */ static unsigned int max_bb = EXT2_BAD_BLOCKS_THRESHOLD; static DWORD time_start; @@ -354,23 +355,32 @@ static float calc_percent(unsigned long current, unsigned long total) { static void print_status(void) { - static DWORD msecs = 0; DWORD time_end; + float percent; - // TODO: use GetTickCount64 on Vista and later time_end = GetTickCount(); - /* update status every second */ - if (time_end - time_start >= msecs) { - uprintf("%6.2f%% done, %0.2f elapsed. " - "(%d/%d/%d errors)", - calc_percent((unsigned long) currently_testing, - (unsigned long) num_blocks), - (time_end - time_start)/1000.0, - num_read_errors, - num_write_errors, - num_corruption_errors); - msecs += 1000; + percent = calc_percent((unsigned long) currently_testing, + (unsigned long) num_blocks); + uprintf("%6.2f%% done, %4.0fs elapsed. " + "(%d/%d/%d errors)", + percent, + (time_end - time_start)/1000.0, + num_read_errors, + num_write_errors, + num_corruption_errors); + PostMessage(hMainDialog, UM_FORMAT_PROGRESS, (WPARAM)(DWORD)percent, (LPARAM)0); +} + +static void CALLBACK alarm_intr(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + if (!num_blocks) + return; + if (FormatStatus) { + uprintf("Interrupting at block %llu\n", + (unsigned long long) currently_testing); + cancel_ops = -1; } + print_status(); } static void pattern_fill(unsigned char *buffer, unsigned int pattern, @@ -413,10 +423,6 @@ static int do_read (HANDLE hDrive, unsigned char * buffer, int tryout, int block { long got; -#if 0 - printf("do_read: block %d, try %d\n", current_block, tryout); -#endif - if (v_flag > 1) print_status(); @@ -439,9 +445,6 @@ static int do_write(HANDLE hDrive, unsigned char * buffer, int tryout, int block { long got; -#if 0 - printf("do_write: block %lu, try %d\n", current_block, tryout); -#endif if (v_flag > 1) print_status(); @@ -483,8 +486,8 @@ static unsigned int test_ro (HANDLE hDrive, blk_t last_block, } if (!blkbuf) { - // TODO: err uprintf("could not allocate buffers\n"); + cancel_ops = -1; return 0; } if (t_flag) { @@ -505,6 +508,7 @@ static unsigned int test_ro (HANDLE hDrive, blk_t last_block, if (s_flag || v_flag) { uprintf("Too many bad blocks, aborting test\n"); } + cancel_ops = -1; break; } if (next_bad) { @@ -559,7 +563,7 @@ static unsigned int test_ro (HANDLE hDrive, blk_t last_block, static unsigned int test_rw(HANDLE hDrive, blk_t last_block, int block_size, blk_t first_block, unsigned int blocks_at_once) { - unsigned char *buffer, *read_buffer; + unsigned char *buffer = NULL, *read_buffer; const unsigned int patterns[] = {0xaa}; // {0xaa, 0x55, 0xff, 0x00}; const unsigned int *pattern; int i, tryout, got, nr_pattern, pat_idx; @@ -571,6 +575,7 @@ static unsigned int test_rw(HANDLE hDrive, blk_t last_block, int block_size, blk if (!buffer) { uprintf("Error while allocating buffers"); + cancel_ops = -1; return 0; } @@ -583,24 +588,24 @@ static unsigned int test_rw(HANDLE hDrive, blk_t last_block, int block_size, blk pattern = patterns; nr_pattern = ARRAYSIZE(patterns); } - // TODO: allow cancellation + for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) { + if (cancel_ops) goto out; pattern_fill(buffer, pattern[pat_idx], blocks_at_once * block_size); num_blocks = last_block - 1; currently_testing = first_block; -// if (s_flag && v_flag <= 1) -// alarm_intr(SIGALRM); if (s_flag | v_flag) uprintf("Writing\n"); tryout = blocks_at_once; while (currently_testing < last_block) { if (max_bb && bb_count >= max_bb) { if (s_flag || v_flag) { - // TODO: this abort blows uprintf("Too many bad blocks, aborting test\n"); } + cancel_ops = -1; break; } + if (cancel_ops) goto out; if (currently_testing + tryout > last_block) tryout = last_block - currently_testing; got = do_write(hDrive, buffer, tryout, block_size, currently_testing); @@ -623,19 +628,14 @@ static unsigned int test_rw(HANDLE hDrive, blk_t last_block, int block_size, blk } num_blocks = 0; -// alarm (0); -// if (s_flag | v_flag) -// fputs(_(done_string), stderr); if (s_flag | v_flag) - // TODO: status uprintf("Reading and comparing\n"); num_blocks = last_block; currently_testing = first_block; -// if (s_flag && v_flag <= 1) -// alarm_intr(SIGALRM); tryout = blocks_at_once; while (currently_testing < last_block) { + if (cancel_ops) goto out; if (max_bb && bb_count >= max_bb) { if (s_flag || v_flag) { uprintf("Too many bad blocks, aborting test\n"); @@ -670,10 +670,8 @@ static unsigned int test_rw(HANDLE hDrive, blk_t last_block, int block_size, blk } num_blocks = 0; -// alarm (0); -// if (s_flag | v_flag) -// fputs(_(done_string), stderr); } +out: free_buffer(buffer); return bb_count; } @@ -721,8 +719,8 @@ static unsigned int test_nd(HANDLE hDrive, blk_t last_block, test_record = malloc (blocks_at_once*sizeof(struct saved_blk_record)); if (!blkbuf || !test_record) { uprintf("Error while allocating buffers"); - // TODO - exit (1); + cancel_ops = -1; + return 0; } save_base = blkbuf; @@ -782,6 +780,7 @@ static unsigned int test_nd(HANDLE hDrive, blk_t last_block, if (s_flag || v_flag) { uprintf("Too many bad blocks, aborting test\n"); } + cancel_ops = -1; break; } tryout = granularity - buf_used; @@ -927,18 +926,20 @@ static unsigned int test_nd(HANDLE hDrive, blk_t last_block, return bb_count; } -int BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, int block_size, int test_type) +BOOL BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, int block_size, + int test_type, badblocks_report *report) { errcode_t error_code; unsigned int (*test_func)(HANDLE, blk_t, int, blk_t, unsigned int); - int num_passes = 0; - int passes_clean = 0; - blk_t bb_count = 0, first_block = 0, last_block = (blk_t)disk_size/block_size; + blk_t first_block = 0, last_block = (blk_t)disk_size/block_size; + + if (report == NULL) return FALSE; + report->bb_count = 0; error_code = ext2fs_badblocks_list_create(&bb_list, 0); if (error_code) { uprintf("Error %d while creating in-memory bad blocks list", error_code); - return -1; + return FALSE; } switch(test_type) { @@ -953,21 +954,20 @@ int BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, int block_size, int te break; } time_start = GetTickCount(); - do { - bb_count = test_func(hPhysicalDrive, last_block, block_size, first_block, EXT2_BLOCKS_AT_ONCE); - if (bb_count) - passes_clean = 0; - else - ++passes_clean; - - if (v_flag) - uprintf("Pass completed, %u bad blocks found. (%d/%d/%d errors)\n", - bb_count, num_read_errors, num_write_errors, num_corruption_errors); - - } while (passes_clean < num_passes); + cancel_ops = 0; + /* use a timer to update status every second */ + SetTimer(hMainDialog, EXT2_TIMER_ID, 1000, alarm_intr); + report->bb_count = test_func(hPhysicalDrive, last_block, block_size, first_block, EXT2_BLOCKS_AT_ONCE); + KillTimer(hMainDialog, EXT2_TIMER_ID); free(t_patts); free(bb_list->list); free(bb_list); - - return bb_count; + // TODO: report first problem block for each error + report->num_read_errors = num_read_errors; + report->num_write_errors = num_write_errors; + report->num_corruption_errors = num_corruption_errors; + + if (cancel_ops) + return FALSE; + return TRUE; } diff --git a/src/badblocks.h b/src/badblocks.h index 17ba8e3bddf..6d9ec36348d 100644 --- a/src/badblocks.h +++ b/src/badblocks.h @@ -41,6 +41,7 @@ typedef struct ext2_struct_u32_iterate *ext2_u32_iterate; #define EXT2_BAD_BLOCKS_THRESHOLD 32 #define EXT2_BLOCKS_AT_ONCE 64 #define EXT2_SYS_PAGE_SIZE 4096 +#define EXT2_TIMER_ID 0x1000 enum test_type { BADBLOCKS_RO, /* Read-only */ @@ -62,4 +63,5 @@ typedef struct { /* * Shared prototypes */ -int BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, int block_size, int test_type); +BOOL BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, int block_size, + int test_type, badblocks_report *report); diff --git a/src/format.c b/src/format.c index 84760d52986..a4c04ca3fdc 100644 --- a/src/format.c +++ b/src/format.c @@ -43,6 +43,7 @@ * Globals */ DWORD FormatStatus; +badblocks_report report; /* * FormatEx callback. Return FALSE to halt operations @@ -341,14 +342,20 @@ void __cdecl FormatThread(void* param) goto out; } - if (BadBlocks(hPhysicalDrive, SelectedDrive.DiskSize, - SelectedDrive.Geometry.BytesPerSector, BADBLOCKS_RW)) { - // TODO: report block failure number, etc + if (!BadBlocks(hPhysicalDrive, SelectedDrive.DiskSize, + SelectedDrive.Geometry.BytesPerSector, BADBLOCKS_RW, &report)) { uprintf("Bad blocks check failed.\n"); - FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_BADBLOCKS); + if (!FormatStatus) + FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)| + APPERR(ERROR_BADBLOCKS_FAILURE); + // TODO: should probably ClearMBR here as well goto out; } + uprintf("Check completed, %u bad blocks found. (%d/%d/%d errors)\n", + report.bb_count, report.num_read_errors, report.num_write_errors, report.num_corruption_errors); safe_unlockclose(hLogicalVolume); + + // TODO: check bb_count and ask user if they want to continue } // Especially after destructive badblocks test, you must zero the MBR completely @@ -382,7 +389,7 @@ void __cdecl FormatThread(void* param) if (!FormatDrive(drive_name[0])) { // Error will be set by FormatDrive() in FormatStatus - uprintf("Format error: 0x%08X\n", FormatStatus); + uprintf("Format error: %s\n", StrError(FormatStatus)); goto out; } diff --git a/src/rufus.c b/src/rufus.c index 6b6e0b3f425..40f1fc25e46 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -703,11 +703,13 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA if (MessageBoxA(hMainDialog, str, "Rufus", MB_OKCANCEL|MB_ICONWARNING) == IDOK) { // Disable all controls except cancel EnableControls(FALSE); +#if 0 // Handle marquee progress bar on quickformat SetWindowLongPtr(hProgress, GWL_STYLE, ProgressStyle | (IsChecked(IDC_QUICKFORMAT)?PBS_MARQUEE:0)); if (IsChecked(IDC_QUICKFORMAT)) { SendMessage(hProgress, PBM_SETMARQUEE, TRUE, 0); } +#endif DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex); FormatStatus = 0; format_thid = _beginthread(FormatThread, 0, (void*)(uintptr_t)DeviceNum); @@ -739,6 +741,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA format_thid = -1L; // Close the cancel MessageBox if active SendMessage(FindWindowA(MAKEINTRESOURCEA(32770), RUFUS_CANCELBOX_TITLE), WM_COMMAND, IDNO, 0); +#if 0 if (IsChecked(IDC_QUICKFORMAT)) { SendMessage(hProgress, PBM_SETMARQUEE, FALSE, 0); SetWindowLongPtr(hProgress, GWL_STYLE, ProgressStyle); @@ -747,6 +750,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA SendMessage(hProgress, PBM_SETPOS, 101, 0); SendMessage(hProgress, PBM_SETRANGE, 0, 100<<16); } +#endif SendMessage(hProgress, PBM_SETPOS, FormatStatus?0:100, 0); EnableControls(TRUE); GetUSBDevices(); diff --git a/src/rufus.h b/src/rufus.h index c1ab4f8cf24..c6fec9558f9 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -183,4 +183,4 @@ typedef struct { #define ERROR_INVALID_CLUSTER_SIZE 0x1203 #define ERROR_INVALID_VOLUME_SIZE 0x1204 #define ERROR_CANT_START_THREAD 0x1205 -#define ERROR_BADBLOCKS 0x1206 +#define ERROR_BADBLOCKS_FAILURE 0x1206 diff --git a/src/rufus.rc b/src/rufus.rc index 72f439b75a0..c1117d527fc 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -30,7 +30,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 206, 278 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_APPWINDOW -CAPTION "Rufus v1.0.2.80" +CAPTION "Rufus v1.0.2.81" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "Start",IDC_START,94,236,50,14 @@ -65,7 +65,7 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,231,175,50,14,WS_GROUP CONTROL "https://github.com/pbatard/rufus",IDC_ABOUT_RUFUS_URL, "SysLink",WS_TABSTOP,46,47,114,9 - LTEXT "Version 1.0.2 (Build 80)",IDC_STATIC,46,19,78,8 + LTEXT "Version 1.0.2 (Build 81)",IDC_STATIC,46,19,78,8 PUSHBUTTON "License...",IDC_ABOUT_LICENSE,46,175,50,14,WS_GROUP EDITTEXT IDC_ABOUT_COPYRIGHTS,46,107,235,63,ES_MULTILINE | ES_READONLY | WS_VSCROLL LTEXT "Report bugs or request enhancements at:",IDC_STATIC,46,66,187,8 @@ -164,8 +164,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,2,80 - PRODUCTVERSION 1,0,2,80 + FILEVERSION 1,0,2,81 + PRODUCTVERSION 1,0,2,81 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -182,13 +182,13 @@ BEGIN BEGIN VALUE "CompanyName", "akeo.ie" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "1.0.2.80" + VALUE "FileVersion", "1.0.2.81" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "1.0.2.80" + VALUE "ProductVersion", "1.0.2.81" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index b06b90e6661..c14c4d9a325 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -192,8 +192,8 @@ const char* StrError(DWORD error_code) return "Cancelled by user"; case ERROR_CANT_START_THREAD: return "Unable to create formatting thread"; - case ERROR_BADBLOCKS: - return "Bad blocks detected"; + case ERROR_BADBLOCKS_FAILURE: + return "Bad blocks check didn't complete"; default: uprintf("StrError: hit default - %08X\n", error_code); SetLastError(error_code);