From cbc505ee4d57373422ffa31a85c9238508d8bcec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20der=20Zee?= Date: Thu, 28 Jun 2018 13:31:48 +0200 Subject: [PATCH] add cheat mode (alt-"-") to quickly erase a flash drive by skipping blocks that are already empty (a flashdrive reads a lot faster than it writes) --- res/localization/rufus.loc | 2 + src/format.c | 81 ++++++++++++++++++++++++++++++++++++-- src/rufus.c | 10 +++++ 3 files changed, 89 insertions(+), 4 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 51212061..00fd8bdb 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -564,6 +564,7 @@ t MSG_303 "Show the log" t MSG_304 "Create a disk image of the selected device" t MSG_305 "Use this option to indicate whether you want to use this device to install Windows on another disk, " "or if you want to run Windows directly from this drive (Windows To Go)." +t MSG_306 "Erasing drive: %0.1f%% completed" ################################################################################ ############################# TRANSLATOR END COPY ############################## @@ -4550,6 +4551,7 @@ t MSG_303 "Toon het logboek" t MSG_304 "Maak een schijfkopie van het geselecteerde apparaat" t MSG_305 "Gebruik deze optie om aan te geven of u dit apparaat wilt gebruiken om Windows op een andere schijf te installeren, " "of als u Windows rechtstreeks vanaf deze schijf wilt opstarten (Windows To Go)." +t MSG_306 "Schijf wissen: %0.1f%% voltooid" ################################################################################ l "fi-FI" "Finnish (Suomi)" 0x040B diff --git a/src/format.c b/src/format.c index a4bf7522..264d2af0 100644 --- a/src/format.c +++ b/src/format.c @@ -61,7 +61,7 @@ static int task_number = 0; extern const int nb_steps[FS_MAX]; extern uint32_t dur_mins, dur_secs; static int fs_index = 0, wintogo_index = -1; -extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, enable_file_indexing, write_as_image; +extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, smart_skip, enable_file_indexing, write_as_image; uint8_t *grub2_buf = NULL; long grub2_len; static BOOL WritePBR(HANDLE hLogicalDrive); @@ -1547,11 +1547,13 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage) { BOOL s, ret = FALSE; LARGE_INTEGER li; - DWORD rSize, wSize, BufSize; + DWORD rSize, wSize, xSize, BufSize; uint64_t wb, target_size = hSourceImage?img_report.image_size:SelectedDrive.DiskSize; int64_t bled_ret; uint8_t *buffer = NULL; + uint8_t *readbuffer = NULL; int i; + int smartskip_backoff = 0; // We poked the MBR and other stuff, so we need to rewind li.QuadPart = 0; @@ -1571,7 +1573,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage) goto out; } } else { - uprintf(hSourceImage?"Writing Image...":"Zeroing drive..."); + uprintf(hSourceImage?"Writing Image...":smart_skip?"Erasing drive...":"Zeroing drive..."); // Our buffer size must be a multiple of the sector size and *ALIGNED* to the sector size BufSize = ((DD_BUFFER_SIZE + SelectedDrive.SectorSize - 1) / SelectedDrive.SectorSize) * SelectedDrive.SectorSize; buffer = (uint8_t*)_mm_malloc(BufSize, SelectedDrive.SectorSize); @@ -1586,6 +1588,21 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage) uprintf("Write buffer is not aligned"); goto out; } + // Clear buffer + memset(buffer, smart_skip?0xff:0x00, BufSize); + + readbuffer = (uint8_t*)_mm_malloc(BufSize, SelectedDrive.SectorSize); + if (readbuffer == NULL) { + FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_NOT_ENOUGH_MEMORY; + uprintf("Could not allocate disk read buffer"); + goto out; + } + // Sanity check + if ((uintptr_t)readbuffer % SelectedDrive.SectorSize != 0) { + FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_READ_FAULT; + uprintf("Read buffer is not aligned"); + goto out; + } // Don't bother trying for something clever, using double buffering overlapped and whatnot: // With Windows' default optimizations, sync read + sync write for sequential operations @@ -1595,7 +1612,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage) if (GetTickCount64() > LastRefresh + MAX_REFRESH) { LastRefresh = GetTickCount64(); format_percent = (100.0f*wb) / (1.0f*target_size); - PrintInfo(0, hSourceImage?MSG_261:MSG_286, format_percent); + PrintInfo(0, hSourceImage?MSG_261:smart_skip?MSG_306:MSG_286, format_percent); UpdateProgress(OP_FORMAT, format_percent); } @@ -1617,6 +1634,61 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage) // WriteFile fails unless the size is a multiple of sector size if (rSize % SelectedDrive.SectorSize != 0) rSize = ((rSize + SelectedDrive.SectorSize - 1) / SelectedDrive.SectorSize) * SelectedDrive.SectorSize; + + // Smart-skip: Reading a flash drive is faster than writing, so we + // can skip erasing empty blocks, or skip writing when the data is the same + // * a block is empty when all bits are either 0 (zeros) or 1 (flash block erased) + // * a back-off strategy is used to limit reading + + if (smartskip_backoff) { + smartskip_backoff--; + } else if (smart_skip && (hSourceImage == NULL)) { // currently only enabled for erase + + CHECK_FOR_USER_CANCEL; + + // Read block and compare against the block that needs to be written + s = ReadFile(hPhysicalDrive, readbuffer, rSize, &xSize, NULL); + if (!s || (xSize != rSize) ) { + uprintf("Read error: could not read data to compare - %s", WindowsErrorString()); + goto out; + } + + // erase or write + if (hSourceImage == NULL) { + // Erase, check for an empty block + int *ptr = (int*)(readbuffer); + // Get first element + int value = ptr[0]; + // Check all bits are the same + if (value!=0 && value!=-1) { + goto blocknotempty; + } + // Compare the rest of the block against the first element + for (i = 1; i < (int)(rSize/sizeof(int)); i++) { + if (ptr[i] != value) + goto blocknotempty; + } + // Block is empty, skip write + wSize = rSize; + continue; + blocknotempty: + ; + } else if (memcmp(readbuffer, buffer, rSize)==0) { + // Write, block is unchanged, skip write + wSize = rSize; + continue; + } + + // Move the file pointer position back for writing + li.QuadPart = wb; + if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN)) { + uprintf("Error: Could not reset position - %s", WindowsErrorString()); + goto out; + } + // throttle reading + smartskip_backoff = 15; + } + for (i = 1; i <= WRITE_RETRIES; i++) { CHECK_FOR_USER_CANCEL; s = WriteFile(hPhysicalDrive, buffer, rSize, &wSize, NULL); @@ -1648,6 +1720,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage) ret = TRUE; out: safe_mm_free(buffer); + safe_mm_free(readbuffer); return ret; } diff --git a/src/rufus.c b/src/rufus.c index fedab505..a040df2d 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -114,6 +114,7 @@ BOOL enable_HDDs = FALSE, force_update = FALSE, enable_ntfs_compression = FALSE, BOOL advanced_mode_device, advanced_mode_format, allow_dual_uefi_bios, detect_fakes, enable_vmdk, force_large_fat32, usb_debug; BOOL use_fake_units, preserve_timestamps = FALSE; BOOL zero_drive = FALSE, list_non_usb_removable_drives = FALSE, enable_file_indexing, large_drive = FALSE, write_as_image = FALSE; +BOOL smart_skip = FALSE; int dialog_showing = 0; uint16_t rufus_version[3], embedded_sl_version[2]; char embedded_sl_version_str[2][12] = { "?.??", "?.??" }; @@ -4290,6 +4291,15 @@ relaunch: // Alt-Z => Zero the drive if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'Z')) { zero_drive = TRUE; + smart_skip = FALSE; + // Simulate a button click for Start + PostMessage(hDlg, WM_COMMAND, (WPARAM)IDC_START, 0); + continue; + } + // Alt-"-" => Erase the drive (skips empty blocks) + if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == VK_OEM_MINUS)) { + zero_drive = TRUE; + smart_skip = TRUE; // Simulate a button click for Start PostMessage(hDlg, WM_COMMAND, (WPARAM)IDC_START, 0); continue;