From f2a539a48cdbae2c44347d5fdd10b4b6041abe3e Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 14 Jan 2016 17:43:02 +0000 Subject: [PATCH 01/91] [core] add and use WriteFileWithRetry() where possible --- src/dos.c | 12 ++++---- src/drive.c | 10 ++----- src/format.c | 2 +- src/icon.c | 31 ++++++++++----------- src/iso.c | 41 +++++++++------------------ src/rufus.c | 2 +- src/rufus.h | 4 ++- src/rufus.rc | 10 +++---- src/stdfn.c | 37 ++++++++++++++++++++++++- src/syslinux.c | 75 ++++++++++++++++++++++++-------------------------- src/vhd.c | 8 +++--- 11 files changed, 123 insertions(+), 109 deletions(-) diff --git a/src/dos.c b/src/dos.c index a08aa741..69cc467d 100644 --- a/src/dos.c +++ b/src/dos.c @@ -2,8 +2,8 @@ * Rufus: The Reliable USB Formatting Utility * DOS boot file extraction, from the FAT12 floppy image in diskcopy.dll * (MS WinME DOS) or from the embedded FreeDOS resource files - * Copyright © 2011-2015 Pete Batard - * + * Copyright © 2011-2016 Pete Batard + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -257,8 +257,8 @@ static BOOL ExtractFAT(int entry, const char* path) return FALSE; } - if ((!WriteFile(hFile, &DiskImage[filestart], (DWORD)filesize, &Size, 0)) || (filesize != Size)) { - uprintf("Couldn't write file '%s': %s.\n", filename, WindowsErrorString()); + if (!WriteFileWithRetry(hFile, &DiskImage[filestart], (DWORD)filesize, &Size, WRITE_RETRIES)) { + uprintf("Could not write file '%s': %s.\n", filename, WindowsErrorString()); safe_closehandle(hFile); return FALSE; } @@ -394,8 +394,8 @@ BOOL ExtractFreeDOS(const char* path) return FALSE; } - if ((!WriteFile(hFile, res_data, res_size, &Size, 0)) || (res_size != Size)) { - uprintf("Couldn't write file '%s': %s.\n", filename, WindowsErrorString()); + if (!WriteFileWithRetry(hFile, res_data, res_size, &Size, WRITE_RETRIES)) { + uprintf("Could not write file '%s': %s.\n", filename, WindowsErrorString()); safe_closehandle(hFile); return FALSE; } diff --git a/src/drive.c b/src/drive.c index ff464ca7..0e6c3711 100644 --- a/src/drive.c +++ b/src/drive.c @@ -1065,7 +1065,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m bufsize = 65536; // 64K should be enough for everyone buffer = calloc(bufsize, 1); if (buffer != NULL) { - if ((!WriteFile(hDrive, buffer, bufsize, &size, NULL)) || (size != bufsize)) + if (!WriteFileWithRetry(hDrive, buffer, bufsize, &size, WRITE_RETRIES)) uprintf(" Could not zero MSR: %s", WindowsErrorString()); free(buffer); } @@ -1165,12 +1165,8 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m uprintf("Could not access uefi-ntfs.img"); return FALSE; } - r = WriteFile(hDrive, buffer, bufsize, &size, NULL); - if ((!r) || (size != bufsize)) { - if (!r) - uprintf("Write error: %s", WindowsErrorString()); - else - uprintf("Write error: Wrote %d bytes, expected %d bytes\n", size, bufsize); + if(!WriteFileWithRetry(hDrive, buffer, bufsize, &size, WRITE_RETRIES)) { + uprintf("Write error: %s", WindowsErrorString()); return FALSE; } } diff --git a/src/format.c b/src/format.c index 5346c394..b70d8e9c 100644 --- a/src/format.c +++ b/src/format.c @@ -1251,7 +1251,7 @@ static BOOL SetupWinPE(char drive_letter) } } - if ((!WriteFile(handle, buf, size, &rw_size, NULL)) || (size != rw_size)) { + if (!WriteFileWithRetry(handle, buf, size, &rw_size, WRITE_RETRIES)) { uprintf("Could not write patched file: %s\n", WindowsErrorString()); goto out; } diff --git a/src/icon.c b/src/icon.c index afb3f750..ddd66eb9 100644 --- a/src/icon.c +++ b/src/icon.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Extract icon from executable and set autorun.inf - * Copyright © 2012-2013 Pete Batard + * Copyright © 2012-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -74,7 +74,7 @@ typedef struct WORD nID; // the ID } GRPICONDIRENTRY, *LPGRPICONDIRENTRY; -typedef struct +typedef struct { WORD idReserved; // Reserved (must be 0) WORD idType; // Resource type (1 for icons) @@ -103,13 +103,13 @@ static BOOL SaveIcon(const char* filename) hFile = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { - uprintf("Unable to create icon '%s': %s.\n", filename, WindowsErrorString()); + uprintf("Unable to create icon '%s': %s.", filename, WindowsErrorString()); goto out; } // Write .ico header - if ((!WriteFile(hFile, icondir, 3*sizeof(WORD), &Size, NULL)) || (Size != 3*sizeof(WORD))) { - uprintf("Couldn't write icon header: %s.\n", WindowsErrorString()); + if (!WriteFileWithRetry(hFile, icondir, 3*sizeof(WORD), &Size, WRITE_RETRIES)) { + uprintf("Could not write icon header: %s.", WindowsErrorString()); goto out; } @@ -117,15 +117,14 @@ static BOOL SaveIcon(const char* filename) offset = 3*sizeof(WORD) + icondir->idCount*sizeof(ICONDIRENTRY); for (i=0; iidCount; i++) { // Write the common part of ICONDIRENTRY - if ( (!WriteFile(hFile, &icondir->idEntries[i], sizeof(GRPICONDIRENTRY)-sizeof(WORD), &Size, NULL)) - || (Size != sizeof(GRPICONDIRENTRY)-sizeof(WORD)) ) { - uprintf("Couldn't write ICONDIRENTRY[%d]: %s.\n", i, WindowsErrorString()); + if (!WriteFileWithRetry(hFile, &icondir->idEntries[i], sizeof(GRPICONDIRENTRY)-sizeof(WORD), &Size, WRITE_RETRIES)) { + uprintf("Could not write ICONDIRENTRY[%d]: %s.", i, WindowsErrorString()); goto out; } res = FindResourceA(hMainInstance, MAKEINTRESOURCEA(icondir->idEntries[i].nID), _RT_ICON); // Write the DWORD offset - if ( (!WriteFile(hFile, &offset, sizeof(offset), &Size, NULL)) || (Size != sizeof(offset)) ) { - uprintf("Couldn't write ICONDIRENTRY[%d] offset: %s.\n", i, WindowsErrorString()); + if (!WriteFileWithRetry(hFile, &offset, sizeof(offset), &Size, WRITE_RETRIES)) { + uprintf("Could not write ICONDIRENTRY[%d] offset: %s.", i, WindowsErrorString()); goto out; } offset += SizeofResource(NULL, res); @@ -136,12 +135,12 @@ static BOOL SaveIcon(const char* filename) res_handle = LoadResource(NULL, res); res_data = (BYTE*)LockResource(res_handle); res_size = SizeofResource(NULL, res); - if ( (!WriteFile(hFile, res_data, res_size, &Size, NULL)) || (Size != res_size) ) { - uprintf("Couldn't write icon data #%d: %s.\n", i, WindowsErrorString()); + if (!WriteFileWithRetry(hFile, res_data, res_size, &Size, WRITE_RETRIES)) { + uprintf("Could not write icon data #%d: %s.", i, WindowsErrorString()); goto out; } } - uprintf("Created: %s\n", filename); + uprintf("Created: %s", filename); r = TRUE; out: @@ -163,14 +162,14 @@ BOOL SetAutorun(const char* path) safe_sprintf(filename, sizeof(filename), "%sautorun.inf", path); fd = fopen(filename, "r"); // If there's an existing autorun, don't overwrite if (fd != NULL) { - uprintf("%s already exists - keeping it\n", filename); + uprintf("%s already exists - keeping it", filename); fclose(fd); return FALSE; } // No "/autorun.inf" => create a new one in UTF-16 LE mode fd = fopen(filename, "w, ccs=UTF-16LE"); if (fd == NULL) { - uprintf("Unable to create %s\n", filename); + uprintf("Unable to create %s", filename); uprintf("NOTE: This may be caused by a poorly designed security solution. " "See http://rufus.akeo.ie/compatibility."); return FALSE; @@ -181,7 +180,7 @@ BOOL SetAutorun(const char* path) fwprintf(fd, L"; Created by %s\n; " LTEXT(RUFUS_URL) L"\n", wRufusVersion); fwprintf(fd, L"[autorun]\nicon = autorun.ico\nlabel = %s\n", wlabel); fclose(fd); - uprintf("Created: %s\n", filename); + uprintf("Created: %s", filename); // .inf -> .ico filename[strlen(filename)-1] = 'o'; diff --git a/src/iso.c b/src/iso.c index d125bdea..41769cbb 100644 --- a/src/iso.c +++ b/src/iso.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * ISO file extraction - * Copyright © 2011-2015 Pete Batard + * Copyright © 2011-2016 Pete Batard * Based on libcdio's iso & udf samples: * Copyright © 2003-2014 Rocky Bernstein * @@ -429,17 +429,11 @@ static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const cha goto out; } buf_size = (DWORD)MIN(i_file_length, i_read); - for (i=0; i= WRITE_RETRIES) goto out; i_file_length -= i_read; if (nb_blocks++ % PROGRESS_THRESHOLD == 0) UpdateProgress(OP_DOS, 100.0f*nb_blocks/total_blocks); @@ -476,7 +470,7 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) HANDLE file_handle = NULL; DWORD buf_size, wr_size, err; EXTRACT_PROPS props; - BOOL s, is_symlink, is_identical; + BOOL is_symlink, is_identical; int i_length, r = 1; char tmp[128], psz_fullpath[MAX_PATH], *psz_basename, *psz_sanpath; const char *psz_iso_name = &psz_fullpath[strlen(psz_extract_dir)]; @@ -484,7 +478,7 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) CdioListNode_t* p_entnode; iso9660_stat_t *p_statbuf; CdioList_t* p_entlist; - size_t i, j; + size_t i; lsn_t lsn; int64_t i_file_length; @@ -582,17 +576,11 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) goto out; } buf_size = (DWORD)MIN(i_file_length, ISO_BLOCKSIZE); - for (j=0; j= WRITE_RETRIES) goto out; i_file_length -= ISO_BLOCKSIZE; if (nb_blocks++ % PROGRESS_THRESHOLD == 0) UpdateProgress(OP_DOS, 100.0f*nb_blocks/total_blocks); @@ -918,7 +906,6 @@ int64_t ExtractISOFile(const char* iso, const char* iso_file, const char* dest_f int64_t file_length, r = 0; char buf[UDF_BLOCKSIZE]; DWORD buf_size, wr_size; - BOOL s; iso9660_t* p_iso = NULL; udf_t* p_udf = NULL; udf_dirent_t *p_udf_root = NULL, *p_udf_file = NULL; @@ -957,8 +944,7 @@ int64_t ExtractISOFile(const char* iso, const char* iso_file, const char* dest_f goto out; } buf_size = (DWORD)MIN(file_length, read_size); - s = WriteFile(file_handle, buf, buf_size, &wr_size, NULL); - if ((!s) || (buf_size != wr_size)) { + if (!WriteFileWithRetry(file_handle, buf, buf_size, &wr_size, WRITE_RETRIES)) { uprintf(" Error writing file %s: %s\n", dest_file, WindowsErrorString()); goto out; } @@ -989,8 +975,7 @@ try_iso: goto out; } buf_size = (DWORD)MIN(file_length, ISO_BLOCKSIZE); - s = WriteFile(file_handle, buf, buf_size, &wr_size, NULL); - if ((!s) || (buf_size != wr_size)) { + if (!WriteFileWithRetry(file_handle, buf, buf_size, &wr_size, WRITE_RETRIES)) { uprintf(" Error writing file %s: %s\n", dest_file, WindowsErrorString()); goto out; } diff --git a/src/rufus.c b/src/rufus.c index 3cd0987a..89364e91 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -2947,7 +2947,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine hFile = CreateFileU(loc_file, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if ((hFile == INVALID_HANDLE_VALUE) || (!WriteFile(hFile, loc_data, loc_size, &size, 0)) || (loc_size != size)) { + if ((hFile == INVALID_HANDLE_VALUE) || (!WriteFileWithRetry(hFile, loc_data, loc_size, &size, WRITE_RETRIES))) { uprintf("localization: unable to extract '%s': %s.\n", loc_file, WindowsErrorString()); safe_closehandle(hFile); goto out; diff --git a/src/rufus.h b/src/rufus.h index b363c27d..2e4e1ff3 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -1,6 +1,6 @@ /* * Rufus: The Reliable USB Formatting Utility - * Copyright © 2011-2015 Pete Batard + * Copyright © 2011-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -457,6 +457,8 @@ extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid extern void LostTranslatorCheck(void); extern LONG ValidateSignature(HWND hDlg, const char* path); extern BOOL IsFontAvailable(const char* font_name); +extern BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries); DWORD WINAPI FormatThread(void* param); DWORD WINAPI SaveImageThread(void* param); diff --git a/src/rufus.rc b/src/rufus.rc index 40525fd9..fec7df72 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Rufus 2.7.830" +CAPTION "Rufus 2.7.831" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -319,8 +319,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,830,0 - PRODUCTVERSION 2,7,830,0 + FILEVERSION 2,7,831,0 + PRODUCTVERSION 2,7,831,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -337,13 +337,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.830" + VALUE "FileVersion", "2.7.831" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.830" + VALUE "ProductVersion", "2.7.831" END END BLOCK "VarFileInfo" diff --git a/src/stdfn.c b/src/stdfn.c index cff6bd09..a075a438 100644 --- a/src/stdfn.c +++ b/src/stdfn.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Standard Windows function calls - * Copyright © 2013-2015 Pete Batard + * Copyright © 2013-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -810,3 +810,38 @@ BOOL SetLGP(BOOL bRestore, BOOL* bExistingKey, const char* szPath, const char* s return FALSE; return (BOOL) r; } + +BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries) +{ + DWORD nTry = 1; + BOOL readFilePointer; + LARGE_INTEGER liFilePointer, liZero = { {0,0} }; + static char* retry_msg = " - retrying..."; + + // Need to get the current file pointer in case we need to retry + readFilePointer = SetFilePointerEx(hFile, liZero, &liFilePointer, FILE_CURRENT); + if (!readFilePointer) + uprintf(" Warning - could not read file pointer: %s", WindowsErrorString()); + + do { + // Need to rewind our file position on retry + if ((nTry > 1) && (!SetFilePointerEx(hFile, liFilePointer, NULL, FILE_BEGIN))) { + uprintf(" Could not set file pointer%s", retry_msg); + goto next_try; + } + if (WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL)) { + if (nNumberOfBytesToWrite == *lpNumberOfBytesWritten) + return TRUE; + uprintf(" Wrote %d bytes but requested %d%s", *lpNumberOfBytesWritten, + nNumberOfBytesToWrite, nTry < nNumRetries ? retry_msg : ""); + SetLastError(ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INCORRECT_SIZE); + } else { + uprintf(" Write error%s", nTry < nNumRetries ? retry_msg : ""); + } +next_try: + Sleep(200); + nTry++; + } while((readFilePointer) && (nTry < nNumRetries)); + return FALSE; +} diff --git a/src/syslinux.c b/src/syslinux.c index 337ee206..2ee20bb6 100644 --- a/src/syslinux.c +++ b/src/syslinux.c @@ -2,7 +2,7 @@ * * Copyright 2003 Lars Munch Christensen - All Rights Reserved * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved - * Copyright 2012-2015 Pete Batard + * Copyright 2012-2016 Pete Batard * * Based on the Linux installer program for SYSLINUX by H. Peter Anvin * @@ -137,16 +137,16 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs_type) img_report.sl_version_ext, ldlinux, i==0?"sys":"bss"); fd = fopen(path, "rb"); if (fd == NULL) { - uprintf("Could not open %s\n", path); + uprintf("Could not open %s", path); goto out; } length = fread(syslinux_ldlinux[i], 1, (size_t)syslinux_ldlinux_len[i], fd); fclose(fd); if (length != (size_t)syslinux_ldlinux_len[i]) { - uprintf("Could not read %s\n", path); + uprintf("Could not read %s", path); goto out; } - uprintf("Using existing './%s'\n", path); + uprintf("Using existing './%s'", path); } } else { for (i=0; i<2; i++) { @@ -167,38 +167,36 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs_type) FILE_ATTRIBUTE_HIDDEN, NULL); if (f_handle == INVALID_HANDLE_VALUE) { - uprintf("Unable to create '%s'\n", &path[3]); + uprintf("Unable to create '%s'", &path[3]); goto out; } /* Write ldlinux.sys file */ - if (!WriteFile(f_handle, (const char _force *)syslinux_ldlinux[0], - syslinux_ldlinux_len[0], &bytes_written, NULL) || - bytes_written != syslinux_ldlinux_len[0]) { - uprintf("Could not write '%s'\n", &path[3]); + if (!WriteFileWithRetry(f_handle, (const char _force *)syslinux_ldlinux[0], + syslinux_ldlinux_len[0], &bytes_written, WRITE_RETRIES)) { + uprintf("Could not write '%s': %s", &path[3], WindowsErrorString()); goto out; } - if (!WriteFile(f_handle, syslinux_adv, 2 * ADV_SIZE, - &bytes_written, NULL) || - bytes_written != 2 * ADV_SIZE) { - uprintf("Could not write ADV to '%s'\n", &path[3]); + if (!WriteFileWithRetry(f_handle, syslinux_adv, 2 * ADV_SIZE, + &bytes_written, WRITE_RETRIES)) { + uprintf("Could not write ADV to '%s': %s", &path[3], WindowsErrorString()); goto out; } - uprintf("Successfully wrote '%s'\n", &path[3]); + uprintf("Successfully wrote '%s'", &path[3]); if (bt != BT_ISO) UpdateProgress(OP_DOS, -1.0f); /* Now flush the media */ if (!FlushFileBuffers(f_handle)) { - uprintf("FlushFileBuffers failed\n"); + uprintf("FlushFileBuffers failed"); goto out; } /* Reopen the volume (we already have a lock) */ d_handle = GetLogicalHandle(drive_index, TRUE, FALSE); if (d_handle == INVALID_HANDLE_VALUE) { - uprintf("Could open volume for Syslinux installation\n"); + uprintf("Could open volume for Syslinux installation"); goto out; } @@ -242,7 +240,7 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs_type) case FS_EXFAT: fs = libfat_open(libfat_readfile, (intptr_t) d_handle); if (fs == NULL) { - uprintf("Syslinux FAT access error\n"); + uprintf("Syslinux FAT access error"); goto out; } ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL); @@ -257,7 +255,7 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs_type) libfat_close(fs); break; default: - uprintf("Unsupported Syslinux filesystem\n"); + uprintf("Unsupported Syslinux filesystem"); goto out; } @@ -269,9 +267,8 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs_type) /* Rewrite the file */ if (SetFilePointer(f_handle, 0, NULL, FILE_BEGIN) != 0 || - !WriteFile(f_handle, syslinux_ldlinux[0], syslinux_ldlinux_len[0], - &bytes_written, NULL) - || bytes_written != syslinux_ldlinux_len[0]) { + !WriteFileWithRetry(f_handle, syslinux_ldlinux[0], syslinux_ldlinux_len[0], + &bytes_written, WRITE_RETRIES)) { uprintf("Could not write '%s': %s\n", &path[3], WindowsErrorString()); goto out; } @@ -282,9 +279,12 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs_type) /* Read existing FAT data into boot sector */ if (SetFilePointer(d_handle, 0, NULL, FILE_BEGIN) != 0 || !ReadFile(d_handle, sectbuf, SECTOR_SIZE, - &bytes_read, NULL) - || bytes_read != SECTOR_SIZE) { - uprintf("Could not read boot record: %s\n", WindowsErrorString()); + &bytes_read, NULL)) { + uprintf("Could not read Syslinux boot record: %s", WindowsErrorString()); + goto out; + } + if (bytes_read < SECTOR_SIZE) { + uprintf("Partial read of Syslinux boot record: read %d bytes but requested %d", bytes_read, SECTOR_SIZE); goto out; } @@ -293,14 +293,12 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs_type) /* Write boot sector back */ if (SetFilePointer(d_handle, 0, NULL, FILE_BEGIN) != 0 || - !WriteFile(d_handle, sectbuf, SECTOR_SIZE, - &bytes_written, NULL) - || bytes_written != SECTOR_SIZE) { - uprintf("Could not write Syslinux boot record: %s\n", WindowsErrorString()); + !WriteFileWithRetry(d_handle, sectbuf, SECTOR_SIZE, + &bytes_written, WRITE_RETRIES)) { + uprintf("Could not write Syslinux boot record: %s", WindowsErrorString()); goto out; } - - uprintf("Successfully wrote Syslinux boot record\n"); + uprintf("Successfully wrote Syslinux boot record"); if (bt == BT_SYSLINUX_V6) { IGNORE_RETVAL(_chdirU(app_dir)); @@ -309,17 +307,17 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs_type) static_sprintf(path, "%C:\\%s.%s", drive_letter, ldlinux, ldlinux_ext[2]); fd = fopen(&path[3], "rb"); if (fd == NULL) { - uprintf("Caution: No '%s' was provided. The target will be missing a required Syslinux file!\n", &path[3]); + uprintf("Caution: No '%s' was provided. The target will be missing a required Syslinux file!", &path[3]); } else { fclose(fd); if (CopyFileA(&path[3], path, TRUE)) { uprintf("Created '%s' (from '%s/%s-%s/%s')", path, FILES_DIR, syslinux, embedded_sl_version_str[1], &path[3]); } else { - uprintf("Failed to create '%s': %s\n", path, WindowsErrorString()); + uprintf("Failed to create '%s': %s", path, WindowsErrorString()); } } } else if (IS_REACTOS(img_report)) { - uprintf("Setting up ReactOS...\n"); + uprintf("Setting up ReactOS..."); syslinux_mboot = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_SL_MBOOT_C32), _RT_RCDATA, "mboot.c32", &syslinux_mboot_len, FALSE); if (syslinux_mboot == NULL) { @@ -334,21 +332,20 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs_type) uprintf("Unable to create '%s'\n", path); goto out; } - if (!WriteFile(f_handle, syslinux_mboot, syslinux_mboot_len, - &bytes_written, NULL) || - bytes_written != syslinux_mboot_len) { - uprintf("Could not write '%s'\n", path); + if (!WriteFileWithRetry(f_handle, syslinux_mboot, syslinux_mboot_len, + &bytes_written, WRITE_RETRIES)) { + uprintf("Could not write '%s'", path); goto out; } safe_closehandle(f_handle); static_sprintf(path, "%C:\\syslinux.cfg", drive_letter); fd = fopen(path, "w"); if (fd == NULL) { - uprintf("Could not create ReactOS 'syslinux.cfg'\n"); + uprintf("Could not create ReactOS 'syslinux.cfg'"); goto out; } /* Write the syslinux.cfg for ReactOS */ - fprintf(fd, "DEFAULT ReactOS\nLABEL ReactOS\n KERNEL %s\n APPEND %s\n", + fprintf(fd, "DEFAULT ReactOS\nLABEL ReactOS\n KERNEL %s\n APPEND %s", mboot_c32, img_report.reactos_path); fclose(fd); } diff --git a/src/vhd.c b/src/vhd.c index c3321de1..b73749a2 100644 --- a/src/vhd.c +++ b/src/vhd.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Virtual Disk Handling functions - * Copyright © 2013-2015 Pete Batard + * Copyright © 2013-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -178,7 +178,7 @@ BOOL AppendVHDFooter(const char* vhd_path) heads = 16; cylinderTimesHeads = (uint32_t)(totalSectors / sectorsPerTrack); } else { - sectorsPerTrack = 17; + sectorsPerTrack = 17; cylinderTimesHeads = (uint32_t)(totalSectors / sectorsPerTrack); heads = (cylinderTimesHeads + 1023) / 1024; @@ -207,12 +207,12 @@ BOOL AppendVHDFooter(const char* vhd_path) checksum += ((uint8_t*)footer)[i]; footer->checksum = bswap_uint32(~checksum); - if (!WriteFile(handle, footer, sizeof(vhd_footer), &size, NULL) || (size != sizeof(vhd_footer))) { + if (!WriteFileWithRetry(handle, footer, sizeof(vhd_footer), &size, WRITE_RETRIES)) { uprintf("Could not write VHD footer: %s", WindowsErrorString()); goto out; } r = TRUE; - + out: safe_free(footer); safe_closehandle(handle); From 0fe0086c8fb18017213e67f9ba52c0b3a64c567a Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 15 Jan 2016 12:26:31 +0000 Subject: [PATCH 02/91] [core] improve WriteFileWithRetry() and move it to stdio.c * Also fix uprintf() generating an error code if the log window is not instantiated yet. --- src/rufus.c | 6 +++--- src/rufus.rc | 10 +++++----- src/stdfn.c | 35 --------------------------------- src/stdio.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 57 insertions(+), 49 deletions(-) diff --git a/src/rufus.c b/src/rufus.c index 89364e91..21f3b5f2 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -2948,11 +2948,11 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine hFile = CreateFileU(loc_file, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if ((hFile == INVALID_HANDLE_VALUE) || (!WriteFileWithRetry(hFile, loc_data, loc_size, &size, WRITE_RETRIES))) { - uprintf("localization: unable to extract '%s': %s.\n", loc_file, WindowsErrorString()); + uprintf("localization: unable to extract '%s': %s", loc_file, WindowsErrorString()); safe_closehandle(hFile); goto out; } - uprintf("localization: extracted data to '%s'\n", loc_file); + uprintf("localization: extracted data to '%s'", loc_file); safe_closehandle(hFile); } else { safe_sprintf(loc_file, sizeof(loc_file), "%s\\%s", app_dir, rufus_loc); @@ -2962,7 +2962,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine if ( (!get_supported_locales(loc_file)) || ((selected_locale = ((locale_name == NULL)?get_locale_from_lcid(lcid, TRUE):get_locale_from_name(locale_name, TRUE))) == NULL) ) { - uprintf("FATAL: Could not access locale!\n"); + uprintf("FATAL: Could not access locale!"); MessageBoxU(NULL, "The locale data is missing or invalid. This application will now exit.", "Fatal error", MB_ICONSTOP|MB_SYSTEMMODAL); goto out; diff --git a/src/rufus.rc b/src/rufus.rc index fec7df72..69cd1644 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Rufus 2.7.831" +CAPTION "Rufus 2.7.832" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -319,8 +319,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,831,0 - PRODUCTVERSION 2,7,831,0 + FILEVERSION 2,7,832,0 + PRODUCTVERSION 2,7,832,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -337,13 +337,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.831" + VALUE "FileVersion", "2.7.832" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.831" + VALUE "ProductVersion", "2.7.832" END END BLOCK "VarFileInfo" diff --git a/src/stdfn.c b/src/stdfn.c index a075a438..99235128 100644 --- a/src/stdfn.c +++ b/src/stdfn.c @@ -810,38 +810,3 @@ BOOL SetLGP(BOOL bRestore, BOOL* bExistingKey, const char* szPath, const char* s return FALSE; return (BOOL) r; } - -BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, - LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries) -{ - DWORD nTry = 1; - BOOL readFilePointer; - LARGE_INTEGER liFilePointer, liZero = { {0,0} }; - static char* retry_msg = " - retrying..."; - - // Need to get the current file pointer in case we need to retry - readFilePointer = SetFilePointerEx(hFile, liZero, &liFilePointer, FILE_CURRENT); - if (!readFilePointer) - uprintf(" Warning - could not read file pointer: %s", WindowsErrorString()); - - do { - // Need to rewind our file position on retry - if ((nTry > 1) && (!SetFilePointerEx(hFile, liFilePointer, NULL, FILE_BEGIN))) { - uprintf(" Could not set file pointer%s", retry_msg); - goto next_try; - } - if (WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL)) { - if (nNumberOfBytesToWrite == *lpNumberOfBytesWritten) - return TRUE; - uprintf(" Wrote %d bytes but requested %d%s", *lpNumberOfBytesWritten, - nNumberOfBytesToWrite, nTry < nNumRetries ? retry_msg : ""); - SetLastError(ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INCORRECT_SIZE); - } else { - uprintf(" Write error%s", nTry < nNumRetries ? retry_msg : ""); - } -next_try: - Sleep(200); - nTry++; - } while((readFilePointer) && (nTry < nNumRetries)); - return FALSE; -} diff --git a/src/stdio.c b/src/stdio.c index 68db69a0..583bc2ce 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -62,12 +62,14 @@ void _uprintf(const char *format, ...) // Send output to Windows debug facility OutputDebugStringA(buf); - // Send output to our log Window - Edit_SetSel(hLog, MAX_LOG_SIZE, MAX_LOG_SIZE); - Edit_ReplaceSelU(hLog, buf); - // Make sure the message scrolls into view - // (Or see code commented in LogProc:WM_SHOWWINDOW for a less forceful scroll) - SendMessage(hLog, EM_LINESCROLL, 0, SendMessage(hLog, EM_GETLINECOUNT, 0, 0)); + if ((hLog != NULL) && (hLog != INVALID_HANDLE_VALUE)) { + // Send output to our log Window + Edit_SetSel(hLog, MAX_LOG_SIZE, MAX_LOG_SIZE); + Edit_ReplaceSelU(hLog, buf); + // Make sure the message scrolls into view + // (Or see code commented in LogProc:WM_SHOWWINDOW for a less forceful scroll) + SendMessage(hLog, EM_LINESCROLL, 0, SendMessage(hLog, EM_GETLINECOUNT, 0, 0)); + } } #endif @@ -280,3 +282,44 @@ const char* StrError(DWORD error_code, BOOL use_default_locale) toggle_default_locale(); return ret; } + + +BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries) +{ + DWORD nTry; + BOOL readFilePointer; + LARGE_INTEGER liFilePointer, liZero = { { 0,0 } }; + static char* retry_msg = " - retrying..."; + + // Need to get the current file pointer in case we need to retry + readFilePointer = SetFilePointerEx(hFile, liZero, &liFilePointer, FILE_CURRENT); + if (!readFilePointer) + uprintf(" Warning - Could not read file pointer: %s", WindowsErrorString()); + + if (nNumRetries == 0) + nNumRetries = 1; + for (nTry = 1; nTry <= nNumRetries; nTry++) { + // Need to rewind our file position on retry - if we can't even do that, just give up + if ((nTry > 1) && (!SetFilePointerEx(hFile, liFilePointer, NULL, FILE_BEGIN))) { + uprintf(" Could not set file pointer - aborting"); + break; + } + if (WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL)) { + if (nNumberOfBytesToWrite == *lpNumberOfBytesWritten) + return TRUE; + uprintf(" Wrote %d bytes but requested %d%s", *lpNumberOfBytesWritten, + nNumberOfBytesToWrite, nTry < nNumRetries ? retry_msg : ""); + } + else { + uprintf(" Write error [0x%8X]%s", GetLastError(), nTry < nNumRetries ? retry_msg : ""); + } + // If we can't reposition for the next run, just abort + if (!readFilePointer) + break; + Sleep(200); + } + if (SCODE_CODE(GetLastError()) == ERROR_SUCCESS) + SetLastError(ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT); + return FALSE; +} From b4128c5ac3ce3b93c4f3e3b4383686aef21d8b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Thanh=20T=C3=A0i?= Date: Fri, 15 Jan 2016 20:24:19 +0700 Subject: [PATCH 03/91] [loc] update Vietnamese translation to latest * Closes #675 --- res/localization/rufus.loc | 7 ++++++- src/rufus.rc | 10 +++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 0d8d8c38..fc42f9ab 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -16907,7 +16907,7 @@ t MSG_285 "Завантажений файл підписаний '%s'.\nЦе н ################################################################################ l "vi-VN" "Vietnamese (Tiếng Việt)" 0x042A -v 1.0.18 +v 1.0.19 b "en-US" # Main dialog @@ -17355,3 +17355,8 @@ t MSG_278 "Phương thức khởi động" t MSG_279 "Không có khả năng khởi động" t MSG_280 "Chọn ảnh" t MSG_281 "(Hãy chọn một ảnh)" +t MSG_282 "Khoá ổ USB đặc biệt" +t MSG_283 "Chữ ký không hợp lệ" +t MSG_284 "Tập tin thực thi đã tải xuống thiếu chữ ký số." +t MSG_285 "Tập tin thực thi đã tải xuống được ký bởi '%s'.\nĐây không phải chữ ký số chúng tôi công nhận và có thể " + "xác định là một dạng hoạt động nguy hiểm...\nBạn chắc muốn chạy tập tin này?" diff --git a/src/rufus.rc b/src/rufus.rc index 69cd1644..57a1b400 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Rufus 2.7.832" +CAPTION "Rufus 2.7.833" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -319,8 +319,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,832,0 - PRODUCTVERSION 2,7,832,0 + FILEVERSION 2,7,833,0 + PRODUCTVERSION 2,7,833,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -337,13 +337,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.832" + VALUE "FileVersion", "2.7.833" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.832" + VALUE "ProductVersion", "2.7.833" END END BLOCK "VarFileInfo" From 96f421f7d29b56df3ac606997f1b46e7f7b1a839 Mon Sep 17 00:00:00 2001 From: SeymourApps Date: Fri, 15 Jan 2016 17:20:45 +0000 Subject: [PATCH 04/91] [ui] add drag and drop support * This feature is only available for Vista or later * Closes #316 * Closes #668 --- src/rufus.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/rufus.rc | 11 ++++++----- src/stdio.c | 1 - 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/rufus.c b/src/rufus.c index 21f3b5f2..670d4614 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -72,6 +72,13 @@ #define ERROR_FILE_TOO_LARGE 223 #endif +#ifndef MSGFLT_ADD +#define MSGFLT_ADD 1 +#endif +#ifndef WM_COPYGLOBALDATA +#define WM_COPYGLOBALDATA 0x49 +#endif + struct { HIMAGELIST himl; RECT margin; @@ -2091,12 +2098,14 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA static LPITEMIDLIST pidlDesktop = NULL; static MY_SHChangeNotifyEntry NotifyEntry; DRAWITEMSTRUCT* pDI; + HDROP droppedFileInfo; POINT Point; RECT DialogRect, DesktopRect, LangToolbarRect; LONG progress_style; HDC hDC; int nDeviceIndex, fs, tt, i, nWidth, nHeight, nb_devices, selected_language, offset; char tmp[128]; + wchar_t* wbuffer = NULL; loc_cmd* lcmd = NULL; EXT_DECL(img_ext, NULL, __VA_GROUP__("*.img;*.vhd;*.gz;*.bzip2;*.xz;*.lzma;*.Z;*.zip"), __VA_GROUP__(lmprintf(MSG_095))); EXT_DECL(iso_ext, NULL, __VA_GROUP__("*.iso"), __VA_GROUP__(lmprintf(MSG_036))); @@ -2426,7 +2435,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA return (INT_PTR)TRUE; case IDC_SELECT_ISO: if (iso_provided) { - uprintf("Image provided: '%s'\n", image_path); + uprintf("\r\nImage provided: '%s'", image_path); iso_provided = FALSE; // One off thing... } else { safe_free(image_path); @@ -2613,6 +2622,25 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA break; + case WM_DROPFILES: + droppedFileInfo = (HDROP)wParam; + wbuffer = calloc(MAX_PATH, sizeof(wchar_t)); + if (wbuffer == NULL) { + uprintf("Failed to alloc buffer for drag-n-drop"); + break; + } + DragQueryFileW(droppedFileInfo, 0, wbuffer, MAX_PATH); + safe_free(image_path); + image_path = wchar_to_utf8(wbuffer); + safe_free(wbuffer); + + if (image_path != NULL) { + iso_provided = TRUE; + // Simulate ISO selection click + SendMessage(hDlg, WM_COMMAND, IDC_SELECT_ISO, 0); + } + break; + case WM_CLOSE: case WM_ENDSESSION: if (format_thid != NULL) { @@ -2782,6 +2810,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine char *tmp, *locale_name = NULL, **argv = NULL; wchar_t **wenv, **wargv; PF_TYPE_DECL(CDECL, int, __wgetmainargs, (int*, wchar_t***, wchar_t***, int, int*)); + PF_TYPE_DECL(WINAPI, BOOL, ChangeWindowMessageFilter, (UINT message, DWORD dwFlag)); HANDLE mutex = NULL, hogmutex = NULL, hFile = NULL; HWND hDlg = NULL; HDC hDC; @@ -3037,6 +3066,20 @@ relaunch: } if ((relaunch_rc.left > -65536) && (relaunch_rc.top > -65536)) SetWindowPos(hDlg, HWND_TOP, relaunch_rc.left, relaunch_rc.top, 0, 0, SWP_NOSIZE); + + // Enable drag-n-drop through the message filter (for Vista or later) + if (nWindowsVersion >= WINDOWS_VISTA) { + PF_INIT(ChangeWindowMessageFilter, user32); + if (pfChangeWindowMessageFilter != NULL) { + // NB: We use ChangeWindowMessageFilter() here because + // ChangeWindowMessageFilterEx() is not available on Vista + pfChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ADD); + pfChangeWindowMessageFilter(WM_COPYDATA, MSGFLT_ADD); + // CopyGlobalData is needed sine we are running elevated + pfChangeWindowMessageFilter(WM_COPYGLOBALDATA, MSGFLT_ADD); + } + } + ShowWindow(hDlg, SW_SHOWNORMAL); UpdateWindow(hDlg); diff --git a/src/rufus.rc b/src/rufus.rc index 57a1b400..6c6abb0f 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -32,7 +32,8 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Rufus 2.7.833" +EXSTYLE WS_EX_ACCEPTFILES +CAPTION "Rufus 2.7.834" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -319,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,833,0 - PRODUCTVERSION 2,7,833,0 + FILEVERSION 2,7,834,0 + PRODUCTVERSION 2,7,834,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -337,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.833" + VALUE "FileVersion", "2.7.834" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.833" + VALUE "ProductVersion", "2.7.834" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index 583bc2ce..eea19492 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -283,7 +283,6 @@ const char* StrError(DWORD error_code, BOOL use_default_locale) return ret; } - BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries) { From 8ca98661797e0ee8e204a5c2b22b922feee58cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kub=C3=A1nik?= Date: Fri, 15 Jan 2016 18:33:15 +0000 Subject: [PATCH 05/91] [loc] update Slovak translation to latest --- res/localization/rufus.loc | 7 ++++++- src/rufus.rc | 10 +++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index fc42f9ab..39e615e8 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -13699,7 +13699,7 @@ t MSG_286 "Anuliranje uređaja: %0.1f%% završeno" ################################################################################ l "sk-SK" "Slovak (Slovensky)" 0x041B -v 1.0.18 +v 1.0.19 b "en-US" # Main dialog @@ -14136,6 +14136,11 @@ t MSG_278 "Typ bootovania" t MSG_279 "Nie je možné bootovať" t MSG_280 "Výber obrazu" t MSG_281 "(Vyberte obraz)" +t MSG_282 "Uzamknutie USB zariadenia +t MSG_283 "Neplatný podpis +t MSG_284 "Stiahnutému inštalátoru chýba digitálny podpis." +t MSG_285 "Stiahnutý inštalátor podpísal '%s'.\nTento podpis nebol rozoznaný a môže znamenať " + "nejakú formu škodlivej aktivity...\nSte si istý, že chcete spustiť tento súbor?" ################################################################################ l "sl-SI" "Slovene (Slovenščina)" 0x0424 diff --git a/src/rufus.rc b/src/rufus.rc index 6c6abb0f..bf6a9418 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.834" +CAPTION "Rufus 2.7.835" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,834,0 - PRODUCTVERSION 2,7,834,0 + FILEVERSION 2,7,835,0 + PRODUCTVERSION 2,7,835,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.834" + VALUE "FileVersion", "2.7.835" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.834" + VALUE "ProductVersion", "2.7.835" END END BLOCK "VarFileInfo" From 35e02ae8ce23bf6519d7c2568460d2154f4a02d5 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 18 Jan 2016 12:20:49 +0000 Subject: [PATCH 06/91] [ms-sys] upgrade ms-sys to v2.5.2 --- src/ms-sys/.msvc/ms-sys.vcxproj | 2 ++ src/ms-sys/.msvc/ms-sys.vcxproj.filters | 6 +++++ src/ms-sys/br.c | 34 +++++++++++++++++-------- src/ms-sys/inc/br.h | 5 +++- src/ms-sys/inc/libintl.h | 9 +++++++ src/ms-sys/inc/nls.h | 17 +++++++++++++ src/rufus.rc | 10 ++++---- 7 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 src/ms-sys/inc/libintl.h create mode 100644 src/ms-sys/inc/nls.h diff --git a/src/ms-sys/.msvc/ms-sys.vcxproj b/src/ms-sys/.msvc/ms-sys.vcxproj index 34df5193..3f9c38b1 100644 --- a/src/ms-sys/.msvc/ms-sys.vcxproj +++ b/src/ms-sys/.msvc/ms-sys.vcxproj @@ -46,6 +46,7 @@ + @@ -59,6 +60,7 @@ + diff --git a/src/ms-sys/.msvc/ms-sys.vcxproj.filters b/src/ms-sys/.msvc/ms-sys.vcxproj.filters index 945108d4..dbc6b582 100644 --- a/src/ms-sys/.msvc/ms-sys.vcxproj.filters +++ b/src/ms-sys/.msvc/ms-sys.vcxproj.filters @@ -137,6 +137,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/src/ms-sys/br.c b/src/ms-sys/br.c index b6116faf..c6239de9 100644 --- a/src/ms-sys/br.c +++ b/src/ms-sys/br.c @@ -18,6 +18,7 @@ #include #include "file.h" +#include "nls.h" #include "br.h" unsigned long ulBytesPerSector = 512; @@ -42,6 +43,28 @@ int write_windows_disk_signature(FILE *fp, uint32_t tWDS) return write_data(fp, 0x1b8, &tWDS, 4); } /* write_windows_disk_signature */ +uint16_t read_mbr_copy_protect_bytes(FILE *fp) +{ + uint16_t tOut; + if(!read_data(fp, 0x1bc, &tOut, 2)) + return 0xffff; + return tOut; +} /* read_mbr_copy_protect_bytes */ + +const char *read_mbr_copy_protect_bytes_explained(FILE *fp) +{ + uint16_t t = read_mbr_copy_protect_bytes(fp); + switch(t) + { + case 0: + return _("not copy protected"); + case 0x5a5a: + return _("copy protected"); + default: + return _("unknown value"); + } +} /* read_mbr_copy_protect_bytes_explained */ + int is_br(FILE *fp) { /* A "file" is probably some kind of boot record if it contains the magic @@ -189,17 +212,6 @@ int is_zero_mbr(FILE *fp) /* Don't bother to check 55AA signature */ } /* is_zero_mbr */ -int is_zero_mbr_with_other_windows_disk_signature(FILE *fp) -{ - #include "mbr_zero.h" - - return - (!contains_data(fp, 0x0, mbr_zero_0x0, sizeof(mbr_zero_0x0))) && - contains_data(fp, 0x0, mbr_zero_0x0, 0x1b8); - contains_data(fp, 0x1bc, mbr_zero_0x0, 2); - /* Don't bother to check 55AA signature */ -} /* is_zero_mbr_with_other_windows_disk_signature */ - int is_zero_mbr_not_including_disk_signature_or_copy_protect(FILE *fp) { #include "mbr_zero.h" diff --git a/src/ms-sys/inc/br.h b/src/ms-sys/inc/br.h index 554b229f..16cdedb1 100644 --- a/src/ms-sys/inc/br.h +++ b/src/ms-sys/inc/br.h @@ -13,6 +13,10 @@ uint32_t read_windows_disk_signature(FILE *fp); /* Sets a new Windows Disk Signature to MBR */ int write_windows_disk_signature(FILE *fp, uint32_t tWDS); +/* Reads copy protect bytes after Windows Disk Signature from MBR */ +uint16_t read_mbr_copy_protect_bytes(FILE *fp); +const char *read_mbr_copy_protect_bytes_explained(FILE *fp); + /* returns TRUE if the file has a boot record, otherwise FALSE. The file position will change when this function is called! */ int is_br(FILE *fp); @@ -77,7 +81,6 @@ int is_syslinux_gpt_mbr(FILE *fp); /* returns TRUE if the file has a zeroed master boot record, otherwise FALSE.The file position will change when this function is called! */ int is_zero_mbr(FILE *fp); -int is_zero_mbr_with_other_windows_disk_signature(FILE *fp); int is_zero_mbr_not_including_disk_signature_or_copy_protect(FILE *fp); /* Writes a dos master boot record to a file, returns TRUE on success, otherwise diff --git a/src/ms-sys/inc/libintl.h b/src/ms-sys/inc/libintl.h new file mode 100644 index 00000000..be953585 --- /dev/null +++ b/src/ms-sys/inc/libintl.h @@ -0,0 +1,9 @@ +#ifndef LIBINTL_H +#define LIBINTL_H + +/* This file is only supposed to be used on systems which doesn't have a + builtin libintl.h and which also miss gnu gettext */ + +#define NO_LIBINTL_OR_GETTEXT + +#endif diff --git a/src/ms-sys/inc/nls.h b/src/ms-sys/inc/nls.h new file mode 100644 index 00000000..be46a2ec --- /dev/null +++ b/src/ms-sys/inc/nls.h @@ -0,0 +1,17 @@ +#ifndef NLS_H +#define NLS_H + +#include + +#ifdef NO_LIBINTL_OR_GETTEXT +#define _(String) (String) +#else +#define _(String) gettext(String) +#endif +#define gettext_noop(String) (String) +#define N_(String) gettext_noop(String) + +/* Init Native language support */ +void nls_init(void); + +#endif diff --git a/src/rufus.rc b/src/rufus.rc index bf6a9418..7b9b8f60 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.835" +CAPTION "Rufus 2.7.836" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,835,0 - PRODUCTVERSION 2,7,835,0 + FILEVERSION 2,7,836,0 + PRODUCTVERSION 2,7,836,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.835" + VALUE "FileVersion", "2.7.836" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.835" + VALUE "ProductVersion", "2.7.836" END END BLOCK "VarFileInfo" From 53cc0038d5b98f9aba41a7e01ab17b43fdf26396 Mon Sep 17 00:00:00 2001 From: Dario Komar Date: Wed, 20 Jan 2016 00:40:50 +0000 Subject: [PATCH 07/91] [loc] update Croatian translation to latest --- res/localization/rufus.loc | 7 ++++++- src/rufus.rc | 10 +++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 39e615e8..b6a090b9 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -2800,7 +2800,7 @@ t MSG_285 "下載的檔案簽章者為: '%s'.\n本軟體未使用此簽章,代 ################################################################################ l "hr-HR" "Croatian (Hrvatski)" 0x041a, 0x081a, 0x101a -v 1.0.18 +v 1.0.19 b "en-US" # Main dialog @@ -3228,6 +3228,11 @@ t MSG_278 "Boot tip" t MSG_279 "Non bootable" t MSG_280 "Odabir datoteke" t MSG_281 "(Molim odaberite datoteku)" +t MSG_282 "Ekskluzivno zaključavanje USB medija" +t MSG_283 "Nevažeći potpis" +t MSG_284 "Preuzeta aplikacija ne sadrži digitalni potpis." +t MSG_285 "Preuzeta aplikacija je potpisana od strane ‘%s’.\nOvo nije prepoznatljiv izvor " + "i može biti zlonamjeran...\nŽelite li svejedno pokrenuti program?" ################################################################################ l "cs-CZ" "Czech (Čeština)" 0x0405 diff --git a/src/rufus.rc b/src/rufus.rc index 7b9b8f60..07411b09 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.836" +CAPTION "Rufus 2.7.837" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,836,0 - PRODUCTVERSION 2,7,836,0 + FILEVERSION 2,7,837,0 + PRODUCTVERSION 2,7,837,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.836" + VALUE "FileVersion", "2.7.837" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.836" + VALUE "ProductVersion", "2.7.837" END END BLOCK "VarFileInfo" From 3b8b7fb7beb4bcfdd1f22e9872b5a9358a63522a Mon Sep 17 00:00:00 2001 From: marvelade Date: Wed, 20 Jan 2016 13:15:16 +0100 Subject: [PATCH 08/91] [loc] update Dutch translation to latest --- res/localization/rufus.loc | 8 +++++++- src/rufus.rc | 10 +++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index b6a090b9..68d8f157 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -4125,7 +4125,7 @@ t MSG_285 "Den hentede fil er signeret af '%s'.\nDet er ikke en signatur vi genk ################################################################################ l "nl-NL" "Dutch (Nederlands)" 0x0413, 0x0813 -v 1.0.18 +v 1.0.19 b "en-US" # Main dialog @@ -4575,6 +4575,12 @@ t MSG_278 "Opstart type" t MSG_279 "Niet bootable" t MSG_280 "Image selectie" t MSG_281 "(Selecteer a.u.b. een image)" +t MSG_282 "Exclusieve USB drive vergrendeling" +t MSG_283 "Ongeldige handtekening" +t MSG_284 "het gedownloade programmabestand heeft geen digitale handtekening." +t MSG_285 "Het gedownloade programmabestand is ondertekend door '%s'.\nDit is geen herkende handtekening " + "en zou dus kunnen betekenen dat iemand malware in dit bestand heeft verborgen...\nWeet u zeker dat u dit bestand wilt uitvoeren?" +t MSG_286 "Nullen schrijven : %0.1f%% voltooid" ################################################################################ l "fi-FI" "Finnish (Suomi)" 0x040B diff --git a/src/rufus.rc b/src/rufus.rc index 07411b09..ca38c320 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.837" +CAPTION "Rufus 2.7.838" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,837,0 - PRODUCTVERSION 2,7,837,0 + FILEVERSION 2,7,838,0 + PRODUCTVERSION 2,7,838,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.837" + VALUE "FileVersion", "2.7.838" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.837" + VALUE "ProductVersion", "2.7.838" END END BLOCK "VarFileInfo" From 1f2b73dfac11202d2c4c6cd14543a69096a6f7c3 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 26 Jan 2016 18:00:20 +0000 Subject: [PATCH 09/91] [vhd] fix an issue when extracting WIM with 7z * 7z has a quirk in that one MUST specify the image index when a WIM has multiple images, but the same index MUST be omitted if there is only one. * Because of this, Windows 7 Enterprise images reported a (nonfatal) extraction error when trying 7z. * Closes #680 * Also fix a typo in registry.h --- src/registry.h | 2 +- src/rufus.rc | 10 +++++----- src/stdio.c | 2 +- src/vhd.c | 54 ++++++++++++++++++++++++++++++-------------------- 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/src/registry.h b/src/registry.h index c40e60d9..24df9244 100644 --- a/src/registry.h +++ b/src/registry.h @@ -94,7 +94,7 @@ static __inline BOOL _GetRegistryKey(HKEY key_root, const char* key_name, DWORD s = RegQueryValueExA(hApp, &key_name[i], NULL, &dwType, (LPBYTE)dest, &dwSize); // No key means default value of 0 or empty string - if ((s == ERROR_FILE_NOT_FOUND) || ((s == ERROR_SUCCESS) && (dwType = reg_type) && (dwSize > 0))) { + if ((s == ERROR_FILE_NOT_FOUND) || ((s == ERROR_SUCCESS) && (dwType == reg_type) && (dwSize > 0))) { r = TRUE; } out: diff --git a/src/rufus.rc b/src/rufus.rc index ca38c320..9391c02d 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.838" +CAPTION "Rufus 2.7.839" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,838,0 - PRODUCTVERSION 2,7,838,0 + FILEVERSION 2,7,839,0 + PRODUCTVERSION 2,7,839,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.838" + VALUE "FileVersion", "2.7.839" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.838" + VALUE "ProductVersion", "2.7.839" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index eea19492..df8caf5b 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Standard User I/O Routines (logging, status, etc.) - * Copyright © 2011-2015 Pete Batard + * Copyright © 2011-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/vhd.c b/src/vhd.c index b73749a2..5a39aa49 100644 --- a/src/vhd.c +++ b/src/vhd.c @@ -439,42 +439,54 @@ out: // Extract a file from a WIM image using 7-Zip static BOOL WimExtractFile_7z(const char* image, int index, const char* src, const char* dst) { + int n; size_t i; - STARTUPINFOA si = {0}; - PROCESS_INFORMATION pi = {0}; char cmdline[MAX_PATH]; char tmpdst[MAX_PATH]; + char index_prefix[] = "#\\"; uprintf("Opening: %s:[%d] (7-Zip)", image, index); if ((image == NULL) || (src == NULL) || (dst == NULL)) return FALSE; - safe_strcpy(tmpdst, sizeof(tmpdst), dst); - for (i=strlen(tmpdst)-1; i>0; i--) { - if (tmpdst[i] == '\\') + // If you shove more than 9 images in a WIM, don't come complaining + // that this breaks! + index_prefix[0] = '0' + index; + + uprintf("Extracting: %s (From %s)", dst, src); + + // 7z has a quirk where the image index MUST be specified if a + // WIM has multiple indexes, but it MUST be removed if there is + // only one image. Because of this (and because 7z will not + // return an error code if it can't extract the file), we need + // to issue 2 passes. See github issue #680. + for (n = 0; n < 2; n++) { + safe_strcpy(tmpdst, sizeof(tmpdst), dst); + for (i = strlen(tmpdst) - 1; i > 0; i--) { + if (tmpdst[i] == '\\') + break; + } + tmpdst[i] = 0; + + safe_sprintf(cmdline, sizeof(cmdline), "\"%s\" -y e \"%s\" %s%s", sevenzip_path, + image, (n == 0) ? index_prefix : "", src); + if (RunCommand(cmdline, tmpdst, FALSE) != 0) { + uprintf(" Could not launch 7z.exe: %s", WindowsErrorString()); + return FALSE; + } + + safe_strcat(tmpdst, sizeof(tmpdst), "\\bootmgfw.efi"); + if (_access(tmpdst, 0) == 0) + // File was extracted => move on break; } - tmpdst[i] = 0; - // TODO: use RunCommand - si.cb = sizeof(si); - safe_sprintf(cmdline, sizeof(cmdline), "7z -y e \"%s\" %d\\%s", image, index, src); - uprintf("Extracting: %s (From %s)", dst, src); - if (!CreateProcessU(sevenzip_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, tmpdst, &si, &pi)) { - uprintf(" Could not launch 7z.exe: %s", WindowsErrorString()); - return FALSE; - } - WaitForSingleObject(pi.hProcess, INFINITE); - UpdateProgress(OP_FINALIZE, -1.0f); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - - safe_strcat(tmpdst, sizeof(tmpdst), "\\bootmgfw.efi"); - if (_access(tmpdst, 0) == -1) { + if (n >= 2) { uprintf(" 7z.exe did not extract %s", tmpdst); return FALSE; } + // coverity[toctou] if (rename(tmpdst, dst) != 0) { uprintf(" Could not rename %s to %s", tmpdst, dst); From 23aa48616167d09a0a8a5cd201418433ae7d4ca9 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Sun, 31 Jan 2016 20:17:08 +0000 Subject: [PATCH 10/91] [ui] adaptive height resizing of SHA-256 checksum control --- src/checksum.c | 8 +++++--- src/rufus.rc | 10 +++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/checksum.c b/src/checksum.c index 645ee4fb..7637b54b 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -4,7 +4,7 @@ * Copyright © 1998-2001 Free Software Foundation, Inc. * Copyright © 2004 g10 Code GmbH * Copyright © 2006-2012 Brad Conte - * Copyright © 2015 Pete Batard + * Copyright © 2015-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -711,7 +711,7 @@ static void md5_final(MD5_CONTEXT *ctx) */ INT_PTR CALLBACK ChecksumCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { - int i, dw; + int i, dw, dh; RECT rect; HFONT hFont; HDC hDC; @@ -737,9 +737,11 @@ INT_PTR CALLBACK ChecksumCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM GetWindowRect(GetDlgItem(hDlg, IDC_MD5), &rect); dw = rect.right - rect.left; + dh = rect.bottom - rect.top; DrawTextU(hDC, md5str, -1, &rect, DT_CALCRECT); dw = rect.right - rect.left - dw + 12; // Ideally we'd compute the field borders from the system, but hey... - ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SHA256), 0, 0, dw, 0, 1.0f); + dh = rect.bottom - rect.top - dh + 6; + ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SHA256), 0, 0, dw, dh, 1.0f); GetWindowRect(GetDlgItem(hDlg, IDC_SHA1), &rect); dw = rect.right - rect.left; diff --git a/src/rufus.rc b/src/rufus.rc index 9391c02d..aac66e26 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.839" +CAPTION "Rufus 2.7.840" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,839,0 - PRODUCTVERSION 2,7,839,0 + FILEVERSION 2,7,840,0 + PRODUCTVERSION 2,7,840,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.839" + VALUE "FileVersion", "2.7.840" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.839" + VALUE "ProductVersion", "2.7.840" END END BLOCK "VarFileInfo" From 447464286315da833adecf4982292e71baf759ab Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 2 Feb 2016 16:14:22 +0000 Subject: [PATCH 11/91] [ui] fix shutdown prevention issues * Also minor UI improvements for High DPI * Part of issue #676 --- src/rufus.c | 23 ++++++++++++++++++----- src/rufus.rc | 10 +++++----- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/rufus.c b/src/rufus.c index 670d4614..0ff2aa89 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -75,6 +75,9 @@ #ifndef MSGFLT_ADD #define MSGFLT_ADD 1 #endif +#ifndef WM_CLIENTSHUTDOWN +#define WM_CLIENTSHUTDOWN 0x3B +#endif #ifndef WM_COPYGLOBALDATA #define WM_COPYGLOBALDATA 0x49 #endif @@ -1862,9 +1865,8 @@ void InitDialog(HWND hDlg) rcSelectImage.right - rcSelectImage.left, rcBootType.bottom - rcBootType.top + 2, SWP_NOZORDER); // The things one needs to do to keep things looking good... - if (nWindowsVersion == WINDOWS_7) { - ResizeMoveCtrl(hDlg, GetDlgItem(hMainDialog, IDS_ADVANCED_OPTIONS_GRP), 0, -1, 0, 2, fScale); - ResizeMoveCtrl(hDlg, hProgress, 0, 1, 0, 0, fScale); + if (fScale > 1.4f) { + ResizeMoveCtrl(hDlg, GetDlgItem(hMainDialog, IDS_ADVANCED_OPTIONS_GRP), 0, +1, 0, 0, fScale); } // Subclass the Info box so that we can align its text vertically @@ -2641,12 +2643,23 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA } break; + // This is >>>SUPER WEIRD<<<. After a successful ISO or DD write (e.g. Arch 2016.01) + // we no longer receive WM_QUERYENDSESSION messages, only WM_ENDSESSION. + // But if we do a FreeDOS format, WM_QUERYENDSESSION is still sent to us alright. + // What the heck is going on here?!? + // Also, even as we try to work around this, WM_ENDSESSION comes too late in the game + // to prevent shutdown block. So we need to handle the _undocumented_ WM_CLIENTSHUTDOWN. case WM_CLOSE: + case WM_CLIENTSHUTDOWN: + case WM_QUERYENDSESSION: case WM_ENDSESSION: - if (format_thid != NULL) { + // TODO: Do we want to use ShutdownBlockReasonCreate() in Vista and later to stop + // forced shutdown? See https://msdn.microsoft.com/en-us/library/ms700677.aspx + if (format_op_in_progress) { + // WM_QUERYENDSESSION uses this value to prevent shutdown return (INT_PTR)TRUE; } - PostQuitMessage(0); + SendMessage(hDlg, WM_COMMAND, (WPARAM)IDCANCEL, (LPARAM)0); break; case UM_PROGRESS_INIT: diff --git a/src/rufus.rc b/src/rufus.rc index aac66e26..8b7afbc2 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.840" +CAPTION "Rufus 2.7.841" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,840,0 - PRODUCTVERSION 2,7,840,0 + FILEVERSION 2,7,841,0 + PRODUCTVERSION 2,7,841,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.840" + VALUE "FileVersion", "2.7.841" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.840" + VALUE "ProductVersion", "2.7.841" END END BLOCK "VarFileInfo" From 92cb7d68fa447cabcfb24f9d000b9a2bc543582e Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 3 Feb 2016 17:41:27 +0000 Subject: [PATCH 12/91] [misc] add support for a 'test' release channel * This gets enabled only for TEST builds * Also flesh out the sample rufus.ini --- res/rufus.ini | 23 ++++++++++++++++++++--- src/net.c | 16 +++++++++++----- src/rufus.rc | 10 +++++----- src/settings.h | 4 ++-- 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/res/rufus.ini b/res/rufus.ini index 39e621f4..69f886a3 100644 --- a/res/rufus.ini +++ b/res/rufus.ini @@ -15,9 +15,26 @@ LastUpdateCheck = 13068056756 UpdateCheckInterval = 86400 ; Whether the check for updates should also include new BETA releases CheckForBetas = 1 -; Use this to increases the log verbosity, for the update checks -VerboseUpdateCheck = 0 +; Use this to increase the log verbosity for the updates check (0-2) +; VerboseUpdateCheck = 2 ; If you are paranoid about apps writing to the registry, you can uncomment the ; following. It will disable the Local Group Policy calls that Rufus issues, to ; temporarily prevent the *annoying* notices Windows issues about new drives. -; DisableLGP = 1 \ No newline at end of file +; DisableLGP = 1 + +; Start with the 'Advanced Options' panel displayed +; AdvancedMode = 1 +; Have Rufus to preserve timestamps when copying files (Alt-T) +; PreserveTimestamps = 1 +; Disable the whole Kibi/Gibi nonsense (Alt-U) +; UseProperSizeUnits = 1 +; Display extended information duringh USB enumeration (Alt-.) +; EnableUsbDebug = 1 +; Don't perform a fake drive test during bad blocks check (Alt-B) +; DisableFakeDrivesCheck = 1 +; Allow the creation of dual UEFI+BIOS bootable drives for Windows (Alt-E) +; EnableWindowsDualUefiBiosMode = 1 +; Also use RidgeCrop's Large FAT32 format algorithm when formatting smaller drives (Alt-L) +; ForceLargeFat32Formatting = 1 +; Enable listing of VMWare's VMDK drives when used in a virtual machine (Alt-W) +; EnableVmdkDetection = 1 diff --git a/src/net.c b/src/net.c index a3d272a8..958b4210 100644 --- a/src/net.c +++ b/src/net.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Networking functionality (web file download, check for update, etc.) - * Copyright © 2012-2015 Pete Batard + * Copyright © 2012-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -80,7 +80,7 @@ static BOOL force_update_check = FALSE; /* * FormatMessage does not handle internet errors - * http://support.microsoft.com/kb/193625 + * https://msdn.microsoft.com/en-us/library/windows/desktop/aa385465.aspx */ const char* WinInetErrorString(void) { @@ -429,9 +429,9 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) BOOL releases_only, found_new_version = FALSE; int status = 0; const char* server_url = RUFUS_URL "/"; - int i, j, k, verbose = 0, verpos[4]; + int i, j, k, max_channel, verbose = 0, verpos[4]; static const char* archname[] = {"win_x86", "win_x64"}; - static const char* channel[] = {"release", "beta"}; // release channel + static const char* channel[] = {"release", "beta", "test"}; // release channel const char* accept_types[] = {"*/*\0", NULL}; DWORD dwFlags, dwSize, dwDownloaded, dwTotalSize, dwStatus; char* buf = NULL; @@ -504,7 +504,13 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) status++; // 2 releases_only = !ReadSettingBool(SETTING_INCLUDE_BETAS); - for (k=0; (k<(releases_only?1:(int)ARRAYSIZE(channel))) && (!found_new_version); k++) { + // Test releases get their own distribution channel (and also force beta checks) +#if defined(TEST) + max_channel = (int)ARRAYSIZE(channel); +#else + max_channel = releases_only ? 1 : (int)ARRAYSIZE(channel) - 1; +#endif + for (k=0; (k___.ver" diff --git a/src/rufus.rc b/src/rufus.rc index 8b7afbc2..bdcaed5c 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.841" +CAPTION "Rufus 2.7.842" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,841,0 - PRODUCTVERSION 2,7,841,0 + FILEVERSION 2,7,842,0 + PRODUCTVERSION 2,7,842,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.841" + VALUE "FileVersion", "2.7.842" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.841" + VALUE "ProductVersion", "2.7.842" END END BLOCK "VarFileInfo" diff --git a/src/settings.h b/src/settings.h index afcef81a..bb65ff1f 100644 --- a/src/settings.h +++ b/src/settings.h @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Settings access, through either registry or INI file - * Copyright 2015 Pete Batard + * Copyright 2015-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +27,7 @@ extern char* ini_file; /* * List of setting names used by this application */ -#define SETTING_VERBOSE_UPDATES "VerboseUpdateCheck" +#define SETTING_VERBOSE_UPDATES "VerboseUpdateCheck" #define SETTING_LAST_UPDATE "LastUpdateCheck" #define SETTING_UPDATE_INTERVAL "UpdateCheckInterval" #define SETTING_INCLUDE_BETAS "CheckForBetas" From 9814a638a3e4da79726344f92cf44f603119fb3e Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 3 Feb 2016 23:29:34 +0000 Subject: [PATCH 13/91] [pki] add both SHA-1 and SHA-256 digital signatures * "[Grumble] Stupid Microsoft... [Grumble] Couldn't push updated PKI algorithms to Windows platforms... [Grumble] Even if their lives depended on it..." --- _sign.cmd | 5 +++-- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/_sign.cmd b/_sign.cmd index bd53a8e4..0f50745b 100644 --- a/_sign.cmd +++ b/_sign.cmd @@ -1,6 +1,7 @@ :retry -@set /p password=Please enter PFX password: -@"C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool" sign /v /fd SHA256 /f D:\Secured\akeo\akeo.p12 /p %password% /tr http://timestamp.comodoca.com/rfc3161 /td SHA256 %1 %2 %3 %4 +@set /p password=Please enter PFX password: +@"C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool" sign /v /fd SHA1 /f D:\Secured\akeo\sha1\akeo.p12 /p %password% /tr http://timestamp.comodoca.com/rfc3161 /td SHA1 %1 %2 %3 %4 +@"C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool" sign /as /v /fd SHA256 /f D:\Secured\akeo\akeo.p12 /p %password% /tr http://timestamp.comodoca.com/rfc3161 /td SHA256 %1 %2 %3 %4 @if ERRORLEVEL 1 goto retry @set password= @exit diff --git a/src/rufus.rc b/src/rufus.rc index bdcaed5c..b75de2d9 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.842" +CAPTION "Rufus 2.7.843" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,842,0 - PRODUCTVERSION 2,7,842,0 + FILEVERSION 2,7,843,0 + PRODUCTVERSION 2,7,843,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.842" + VALUE "FileVersion", "2.7.843" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.842" + VALUE "ProductVersion", "2.7.843" END END BLOCK "VarFileInfo" From 1809ac933a660e131fb4041ffc9fe207cc528133 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 5 Feb 2016 10:29:14 +0000 Subject: [PATCH 14/91] [core] update UEFI:NTFS to latest * Also update signing script --- _sign.cmd | 14 ++++++++------ res/uefi/readme.txt | 6 +++--- res/uefi/uefi-ntfs.img | Bin 262144 -> 262144 bytes src/rufus.rc | 10 +++++----- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/_sign.cmd b/_sign.cmd index 0f50745b..6ce08968 100644 --- a/_sign.cmd +++ b/_sign.cmd @@ -1,7 +1,9 @@ +@echo off :retry -@set /p password=Please enter PFX password: -@"C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool" sign /v /fd SHA1 /f D:\Secured\akeo\sha1\akeo.p12 /p %password% /tr http://timestamp.comodoca.com/rfc3161 /td SHA1 %1 %2 %3 %4 -@"C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool" sign /as /v /fd SHA256 /f D:\Secured\akeo\akeo.p12 /p %password% /tr http://timestamp.comodoca.com/rfc3161 /td SHA256 %1 %2 %3 %4 -@if ERRORLEVEL 1 goto retry -@set password= -@exit +set /p password=Please enter PFX password: +"C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool" sign /v /fd SHA1 /f D:\Secured\akeo\sha1\akeo.p12 /p %password% /tr http://timestamp.comodoca.com/rfc3161 /td SHA1 %1 +if ERRORLEVEL 1 goto retry +"C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool" sign /as /v /fd SHA256 /f D:\Secured\akeo\akeo.p12 /p %password% /tr http://timestamp.comodoca.com/rfc3161 /td SHA256 %1 +if ERRORLEVEL 1 goto retry +set password= +exit diff --git a/res/uefi/readme.txt b/res/uefi/readme.txt index 55c85d88..5d3f40da 100644 --- a/res/uefi/readme.txt +++ b/res/uefi/readme.txt @@ -4,10 +4,10 @@ Rufus for NTFS UEFI boot support. See https://github.com/pbatard/uefi-ntfs. This image, which you can mount as FAT filesystem or open in 7-zip, contains the following data: o The NTFS UEFI drivers from efifs (https://github.com/pbatard/efifs) which were - compiled, with compression disabled, using Visual Studio 2013 Community Edition. - These are the \EFI\Rufus\ntfs_[x32|x64].efi files. + compiled, with compression disabled, using Visual Studio 2015 Community Edition. + These are the \EFI\Rufus\ntfs_[ia32|x64].efi files. o The UEFI:NTFS binaries (https://github.com/pbatard/uefi-ntfs), which were also - compiled using Visual Studio 2013 Community Edition. + compiled using Visual Studio 2015 Community Edition. These are the \EFI\Boot\boot[ia32|x64].efi files. The FAT partition was created on Debian GNU/Linux using the following commands diff --git a/res/uefi/uefi-ntfs.img b/res/uefi/uefi-ntfs.img index 150c61a3de5e7b23c5c009e5edff4c6d79babaa5..78db98c8b5e13f9587d6bb1ec79e7f020018e9d7 100644 GIT binary patch delta 68022 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 Ww(oVO1lBw-Wv{bu%HE9E%Kr_kAgy@- delta 66347 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 Date: Fri, 5 Feb 2016 14:33:41 +0200 Subject: [PATCH 15/91] [loc] update Greek localisation to latest * Closes #688 --- res/localization/rufus.loc | 8 +++++++- src/rufus.rc | 10 +++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 68d8f157..28871cec 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -5897,7 +5897,7 @@ t MSG_285 "Die heruntergeladene ausführbare Datei ist von '%s' signiert.\nDiese ################################################################################ l "el-GR" "Greek (Ελληνικά)" 0x0408 -v 1.0.18 +v 1.0.19 b "en-US" # Main dialog @@ -6369,6 +6369,12 @@ t MSG_278 "Τύπος εκκίνησης" t MSG_279 "Δεν διαθέτει δυνατότητα εκκίνησης" t MSG_280 "Επιλογή ειδώλου" t MSG_281 "(Παρακαλώ επιλέξτε κάποιο είδωλο)" +t MSG_282 "Κλείδωμα μονάδας USB" +t MSG_283 "Μη έγκυρη ψηφιακή υπογραφή" +t MSG_284 "Το εκτελέσιμο αρχείο που κατεβάσατε δεν περιλαμβάνει ψηφιακή υπογραφή." +τ MSG_285 "Το εκτελέσιμο αρχείο που κατεβάσατε έχει υπογραφτεί από τον/την '%s'.\nΑύτη η υπογραφή δεν " + "αναγνωρίζεται από το Rufus. Ενδεχομένως να υπάρχει συσχέτιση με κάποια κακόβουλη προσπάθεια...\n" + "Είστε σίγουροι ότι θέλετε να εκτελέσετε αυτό το αρχείο?" ################################################################################ l "hu-HU" "Hungarian (Magyar)" 0x040e diff --git a/src/rufus.rc b/src/rufus.rc index b1fad6b5..dd3b5cb2 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.844" +CAPTION "Rufus 2.7.845" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,844,0 - PRODUCTVERSION 2,7,844,0 + FILEVERSION 2,7,845,0 + PRODUCTVERSION 2,7,845,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.844" + VALUE "FileVersion", "2.7.845" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.844" + VALUE "ProductVersion", "2.7.845" END END BLOCK "VarFileInfo" From 65bbe984fdee3374a6522dc8cc1ccc27be1861ad Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 5 Feb 2016 13:14:22 +0000 Subject: [PATCH 16/91] [loc] remove nagging about lost translators * All things considered, this was probably more detrimental than helpful * Reverts 26af32b52221af4ceb015cd08a183fae76f950d9 --- src/net.c | 2 -- src/parser.c | 25 ++++++++----------------- src/rufus.c | 20 -------------------- src/rufus.h | 5 ----- src/rufus.rc | 10 +++++----- 5 files changed, 13 insertions(+), 49 deletions(-) diff --git a/src/net.c b/src/net.c index 958b4210..0a498d26 100644 --- a/src/net.c +++ b/src/net.c @@ -474,8 +474,6 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) vvuprintf("Local time: %" PRId64 "\n", local_time); if (local_time < reg_time + update_interval) { vuprintf("Next update check in %" PRId64 " seconds.\n", reg_time + update_interval - local_time); - // This is as good a place as any to ask for translation help - LostTranslatorCheck(); goto out; } } diff --git a/src/parser.c b/src/parser.c index 0a89a669..b59abcef 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Elementary Unicode compliant find/replace parser - * Copyright © 2012-2014 Pete Batard + * Copyright © 2012-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -239,13 +239,12 @@ BOOL get_supported_locales(const char* filename) FILE* fd = NULL; BOOL r = FALSE; char line[1024]; - char* LT[] = LOST_TRANSLATORS; //just to get the arraysize... size_t i, j, k; loc_cmd *lcmd = NULL, *last_lcmd = NULL; long end_of_block; int version_line_nr = 0; uint32_t loc_base_minor = -1, loc_base_micro = -1; - + fd = open_loc_file(filename); if (fd == NULL) goto out; @@ -346,16 +345,8 @@ BOOL get_supported_locales(const char* filename) if (lcmd->unum[2] < loc_base_micro) { luprintf("the version of this translation is older than the base one and may result in some messages not being properly translated.\n" "If you are the translator, please update your translation with the changes that intervened between v%d.%d.%d and v%d.%d.%d.\n" - "See https://github.com/pbatard/rufus/blob/master/res/localization/ChangeLog.txt", + "See https://github.com/pbatard/rufus/blob/master/res/localization/ChangeLog.txt", LOC_FRAMEWORK_VERSION, loc_base_minor, lcmd->unum[2], LOC_FRAMEWORK_VERSION, loc_base_minor, loc_base_micro); - } else if (lcmd->unum[2] >= loc_base_micro) { - // Don't bug users about a locale that may already have been upgraded - for (i=0; itxt[0], lost_translators[i]) == 0) { - uprintf("NOTE: This translation appears up to date - Removing it from LOST_TRANSLATORS"); - lost_translators[i][0] = 0; - } - } } version_line_nr = loc_line_nr; } @@ -374,7 +365,7 @@ BOOL get_supported_locales(const char* filename) } r = !list_empty(&locale_list); if (r == FALSE) - uprintf("localization: '%s' contains no valid locale sections\n", filename); + uprintf("localization: '%s' contains no valid locale sections\n", filename); out: if (fd != NULL) @@ -576,7 +567,7 @@ out: /* * Parse a line of UTF-16 text and return the data if it matches the 'token' - * The parsed line is of the form: [ ]token[ ]=[ ]["]data["][ ] and is + * The parsed line is of the form: [ ]token[ ]=[ ]["]data["][ ] and is * modified by the parser */ static wchar_t* get_token_data_line(const wchar_t* wtoken, wchar_t* wline) @@ -603,7 +594,7 @@ static wchar_t* get_token_data_line(const wchar_t* wtoken, wchar_t* wline) i += wcsspn(&wline[i], wspace); // Check for an equal sign - if (wline[i] != L'=') + if (wline[i] != L'=') return NULL; i++; @@ -1006,7 +997,7 @@ char* insert_section_data(const char* filename, const char* section, const char* break; } fseek(fd_in, 0, SEEK_SET); -// duprintf("'%s' was detected as %s\n", filename, +// duprintf("'%s' was detected as %s\n", filename, // (mode==0)?"ANSI/UTF8 (no BOM)":((mode==1)?"UTF8 (with BOM)":"UTF16 (with BOM")); wtmpname = (wchar_t*)calloc(wcslen(wfilename)+2, sizeof(wchar_t)); @@ -1145,7 +1136,7 @@ char* replace_in_token_data(const char* filename, const char* token, const char* break; } fseek(fd_in, 0, SEEK_SET); -// duprintf("'%s' was detected as %s\n", filename, +// duprintf("'%s' was detected as %s\n", filename, // (mode==0)?"ANSI/UTF8 (no BOM)":((mode==1)?"UTF8 (with BOM)":"UTF16 (with BOM")); diff --git a/src/rufus.c b/src/rufus.c index 0ff2aa89..21cd0f88 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -132,7 +132,6 @@ static HBRUSH hInfoBrush; static WNDPROC info_original_proc = NULL; char ClusterSizeLabel[MAX_CLUSTER_SIZES][64]; char msgbox[1024], msgbox_title[32], *ini_file = NULL; -char lost_translators[][6] = LOST_TRANSLATORS; /* * Globals @@ -990,25 +989,6 @@ static void CALLBACK BlockingTimer(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD } } -// Randomly nag users about translations that have been left behind -void LostTranslatorCheck(void) -{ - char *p; - char* lang = safe_strdup(selected_locale->txt[1]); - int i, r = rand() * LOST_TRANSLATOR_PROBABILITY / RAND_MAX; - for (i=0; itxt[0], lost_translators[i]) == 0) - break; - if ((r == 0) && (i != ARRAYSIZE(lost_translators)) && (lang != NULL) && ((p = strchr(lang, '(')) != NULL)) { - p[-1] = 0; - safe_sprintf(msgbox, sizeof(msgbox), "Note: The %s translation requires an update, but the original " - "translator is no longer contributing to it...\nIf you can read English and want to help complete " - "this translation, please visit: http://rufus.akeo.ie/translate.", lang); - MessageBoxU(hMainDialog, msgbox, "Translation help needed", MB_OK|MB_ICONINFORMATION); - } - safe_free(lang); -} - // Report the features of the selected ISO images static const char* YesNo(BOOL b) { return (b) ? "Yes" : "No"; diff --git a/src/rufus.h b/src/rufus.h index 2e4e1ff3..cc15adfa 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -33,10 +33,6 @@ #define RUFUS_DEBUG // print debug info to Debug facility /* Features not ready for prime time and that may *DESTROY* your data - USE AT YOUR OWN RISKS! */ // #define RUFUS_TEST -/* Languages for which translators are M.I.A. and that we could use help with */ -#define LOST_TRANSLATORS { "ms-MY" } // NB: locales MUST be <= 5 chars -/* Probability of getting the M.I.A. translator message. For more on this, see LostTranslatorCheck() */ -#define LOST_TRANSLATOR_PROBABILITY 1000 #define APPLICATION_NAME "Rufus" #define COMPANY_NAME "Akeo Consulting" @@ -454,7 +450,6 @@ extern BOOL WimApplyImage(const char* image, int index, const char* dst); extern BOOL IsBootableImage(const char* path); extern BOOL AppendVHDFooter(const char* vhd_path); extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid); -extern void LostTranslatorCheck(void); extern LONG ValidateSignature(HWND hDlg, const char* path); extern BOOL IsFontAvailable(const char* font_name); extern BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, diff --git a/src/rufus.rc b/src/rufus.rc index dd3b5cb2..839e4778 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.845" +CAPTION "Rufus 2.7.846" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,845,0 - PRODUCTVERSION 2,7,845,0 + FILEVERSION 2,7,846,0 + PRODUCTVERSION 2,7,846,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.845" + VALUE "FileVersion", "2.7.846" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.845" + VALUE "ProductVersion", "2.7.846" END END BLOCK "VarFileInfo" From 9de7d0db840c1875a32c0c1d56af4a703c8ffe2f Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 5 Feb 2016 17:18:33 +0000 Subject: [PATCH 17/91] [grub] update Grub4DOS to latest * NB: While the MBR itself didn't change, the Grub4DOS files were also updated on the server. See http://rufus.akeo.ie/files/grub4dos-0.4.5c/ and http://rufus.akeo.ie/files/grub4dos-0.4.6a/ * Closes #676 --- res/grub/readme.txt | 4 ++-- src/rufus.rc | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/res/grub/readme.txt b/res/grub/readme.txt index dafcf35a..011c461a 100644 --- a/res/grub/readme.txt +++ b/res/grub/readme.txt @@ -1,7 +1,7 @@ This directory contains the Grub4DOS boot records that are used by Rufus -* grldr.mbr was taken from the official 2015.10.21 release from - http://grub4dos.chenall.net/downloads/grub4dos-0.4.6a-2015-10-21/ +* grldr.mbr was taken from the official 2016.01.19 release from + http://grub4dos.chenall.net/downloads/grub4dos-0.4.6a-2016-01-19/ * Note that, for convenience reasons, the first 512 bytes from this grldr.mbr are *not* the ones that Rufus processes when writing the actual MBR (first 512 bytes). diff --git a/src/rufus.rc b/src/rufus.rc index 839e4778..616f0099 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.846" +CAPTION "Rufus 2.7.847" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,846,0 - PRODUCTVERSION 2,7,846,0 + FILEVERSION 2,7,847,0 + PRODUCTVERSION 2,7,847,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.846" + VALUE "FileVersion", "2.7.847" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.846" + VALUE "ProductVersion", "2.7.847" END END BLOCK "VarFileInfo" From e1499c4db0109b5b88166519b5dfeeb5e056ea65 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 5 Feb 2016 22:24:47 +0000 Subject: [PATCH 18/91] [misc] fix WDK warnings --- ChangeLog.txt | 10 ++++++++++ src/rufus.c | 4 ++-- src/rufus.rc | 10 +++++----- src/stdlg.c | 3 ++- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 1643df15..0dca37ca 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,13 @@ +o Version 2.7 (2016.02.??) + Add Thai translation, courtesy of Sippapas Wangsri + Add Drag and Drop support, courtesy of SeymourApps + Add a retry for most write operations + Update UEFI:NTFS, ms-sys and Grub4DOS to latest + Dual sign Rufus with both SHA-1 and SHA-256 + Fix 2nd line of SHA-256 being hidden on some platforms + Fix shutdown prevention issues + Additional small fixes + o Version 2.6 (2015.12.22) Add Serbian (Latin) translation, courtesy of Ivan Strugar Add a cheat mode to zero a device (Alt-Z) diff --git a/src/rufus.c b/src/rufus.c index 21cd0f88..5f7806d8 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -654,7 +654,7 @@ static void SetTargetSystem(void) static void SetProposedLabel(int ComboIndex) { - const char no_label[] = STR_NO_LABEL; + const char no_label[] = STR_NO_LABEL, empty[] = ""; int bt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType)); app_changed_label = TRUE; @@ -680,7 +680,7 @@ static void SetProposedLabel(int ComboIndex) } // Else if no existing label is available, propose one according to the size (eg: "256MB", "8GB") - if ((safe_stricmp(no_label, DriveLabel.String[ComboIndex]) == 0) || (safe_stricmp(no_label, "") == 0) + if ((safe_stricmp(no_label, DriveLabel.String[ComboIndex]) == 0) || (safe_stricmp(no_label, empty) == 0) || (safe_stricmp(lmprintf(MSG_207), DriveLabel.String[ComboIndex]) == 0)) { SetWindowTextU(hLabel, SelectedDrive.proposed_label); } else { diff --git a/src/rufus.rc b/src/rufus.rc index 616f0099..13fbcf62 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.847" +CAPTION "Rufus 2.7.848" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,847,0 - PRODUCTVERSION 2,7,847,0 + FILEVERSION 2,7,848,0 + PRODUCTVERSION 2,7,848,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.847" + VALUE "FileVersion", "2.7.848" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.847" + VALUE "ProductVersion", "2.7.848" END END BLOCK "VarFileInfo" diff --git a/src/stdlg.c b/src/stdlg.c index c9d02a85..066932db 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -1648,6 +1648,7 @@ out: LPCDLGTEMPLATE GetDialogTemplate(int Dialog_ID) { int i; + const char thai_id[] = "th-TH"; size_t len; DWORD size; DWORD* dwBuf; @@ -1672,7 +1673,7 @@ LPCDLGTEMPLATE GetDialogTemplate(int Dialog_ID) // If 'Segoe UI Symbol' is available, and we are using Thai, we're done here if (IsFontAvailable("Segoe UI Symbol") && (selected_locale != NULL) - && (safe_strcmp(selected_locale->txt[0], "th-TH") == 0)) + && (safe_strcmp(selected_locale->txt[0], thai_id) == 0)) return rcTemplate; // 'Segoe UI Symbol' cannot be used => Fall back to the best we have From f66b789071a117cb8b19f190b80dedf207ea4a54 Mon Sep 17 00:00:00 2001 From: Arif Budiman Date: Sat, 6 Feb 2016 16:17:39 +0000 Subject: [PATCH 19/91] [loc] update Indonesian translation to latest --- res/localization/rufus.loc | 10 ++++++++-- src/rufus.rc | 10 +++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 28871cec..b4ff70ee 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -6818,7 +6818,7 @@ t MSG_286 "Meghajtó kinullázása: %0.1f%% kész" ################################################################################ l "id-ID" "Indonesian (Bahasa Indonesia)" 0x0421 -v 1.0.18 +v 1.0.19 b "en-US" # Main dialog @@ -7138,7 +7138,7 @@ t MSG_158 "Ukuran minimal blok data yang akan menempati sistem berkas" t MSG_159 "Gunakan bidang ini untuk menyetel karakter Internasional yang diperbolehkan\npada label perangkat" t MSG_160 "Tombol untuk opsi lanjutan" t MSG_161 "Periksa blok buruk pada perangkat menggunakan tes pola" -t MSG_162 "Hapus centang pada kotak ini untuk \"tampilkan\" metode format" +t MSG_162 "Hapus centang kotak ini untuk menggunakan metode format \"lambat\"" t MSG_163 "Centang kotak ini untuk membuat perangkat USB bootable" t MSG_164 "Metode yang akan digunakan untuk membuat perangkat bootable" t MSG_165 "Klik untuk memilih sebuah image..." @@ -7294,6 +7294,12 @@ t MSG_278 "Tipe Boot" t MSG_279 "Non bootable" t MSG_280 "Pemilihan image" t MSG_281 "(Silakan pilih sebuah image)" +t MSG_282 "Penguncian perangkat USB khusus" +t MSG_283 "Tanda tangan digital tidak valid" +t MSG_284 "Berkas exe yang diunduh memiliki tanda tangan digital yang salah." +t MSG_285 "Berkas exe yang diunduh ditandatangani oleh '%s'.\nTanda tangan ini " + "tidak kami kenali dan bisa menjadi pertanda dari aktivitas berbahaya...\n" + "Apakah Anda yakin ingin menjalankan berkas ini?" ################################################################################ l "it-IT" "Italian (Italiano)" 0x0410, 0x0810 diff --git a/src/rufus.rc b/src/rufus.rc index 13fbcf62..96652cc5 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.848" +CAPTION "Rufus 2.7.849" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,848,0 - PRODUCTVERSION 2,7,848,0 + FILEVERSION 2,7,849,0 + PRODUCTVERSION 2,7,849,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.848" + VALUE "FileVersion", "2.7.849" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.848" + VALUE "ProductVersion", "2.7.849" END END BLOCK "VarFileInfo" From 0e91b4cf3d6efa01ed00c59018c3dffa102ea8de Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Sat, 6 Feb 2016 23:46:30 +0000 Subject: [PATCH 20/91] [iso] set ISOHybrids to DD mode if we can't support any ISO boot modes * Closes #689 --- src/rufus.c | 16 +++++++++++++--- src/rufus.rc | 10 +++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/rufus.c b/src/rufus.c index 5f7806d8..d7502392 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -1050,6 +1050,7 @@ DWORD WINAPI ISOScanThread(LPVOID param) img_report.is_iso = (BOOLEAN)ExtractISO(image_path, "", TRUE); img_report.is_bootable_img = (BOOLEAN)IsBootableImage(image_path); if (!img_report.is_iso && !img_report.is_bootable_img) { + // Failed to scan image SendMessage(hMainDialog, UM_PROGRESS_EXIT, 0, 0); PrintInfoDebug(0, MSG_203); safe_free(image_path); @@ -1065,15 +1066,24 @@ DWORD WINAPI ISOScanThread(LPVOID param) (img_report.compression_type != BLED_COMPRESSION_NONE) ? "compressed " : "", img_report.is_vhd ? "VHD" : "disk"); selection_default = BT_IMG; } + if (img_report.is_iso) { - // Will override BT_IMG above for ISOHybrid - selection_default = BT_ISO; DisplayISOProps(); + // If we have an ISOHybrid, but without an ISO method we support, disable ISO support altogether + if ((img_report.is_bootable_img) && (!img_report.has_bootmgr) && (!HAS_SYSLINUX(img_report)) && (!IS_WINPE(img_report.winpe)) + && (!IS_GRUB(img_report)) && (!img_report.has_efi) && (!IS_REACTOS(img_report)) && (!img_report.has_kolibrios)) { + uprintf("This ISOHybrid is not compatible with any of the ISO boot methods we support"); + img_report.is_iso = FALSE; + } else { + // Will override BT_IMG above for ISOHybrid + selection_default = BT_ISO; + } } // Only enable AFTER we have determined the image type EnableControls(TRUE); if ( (!img_report.has_bootmgr) && (!HAS_SYSLINUX(img_report)) && (!IS_WINPE(img_report.winpe)) && (!IS_GRUB(img_report)) - && (!img_report.has_efi) && (!IS_REACTOS(img_report) && (!img_report.has_kolibrios) && (!img_report.is_bootable_img)) ) { + && (!img_report.has_efi) && (!IS_REACTOS(img_report)) && (!img_report.has_kolibrios) && (!img_report.is_bootable_img) ) { + // No boot method that we support PrintInfo(0, MSG_081); safe_free(image_path); EnableWindow(hStatusToolbar, FALSE); diff --git a/src/rufus.rc b/src/rufus.rc index 96652cc5..1fdbb348 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.849" +CAPTION "Rufus 2.7.850" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,849,0 - PRODUCTVERSION 2,7,849,0 + FILEVERSION 2,7,850,0 + PRODUCTVERSION 2,7,850,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.849" + VALUE "FileVersion", "2.7.850" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.849" + VALUE "ProductVersion", "2.7.850" END END BLOCK "VarFileInfo" From b91dfd80488b709e4d1ca01e4b2a40a8bd0f2cac Mon Sep 17 00:00:00 2001 From: Tiryoh Date: Mon, 8 Feb 2016 00:17:47 +0000 Subject: [PATCH 21/91] [loc] update Japanese translation to latest * Closes #674 --- res/localization/rufus.loc | 203 +++++++++++++++++++------------------ src/rufus.rc | 10 +- 2 files changed, 107 insertions(+), 106 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index b4ff70ee..aee540cd 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -7775,7 +7775,7 @@ t IDS_FILESYSTEM_TXT "ファイルシステム" t IDS_CLUSTERSIZE_TXT "クラスタサイズ" t IDS_LABEL_TXT "新しいボリュームのラベル" t IDS_FORMAT_OPTIONS_GRP "フォーマット設定" -t IDC_BADBLOCKS "破損したブロックを検出する" +t IDC_BADBLOCKS "不良ブロックを検出します" t IDC_QUICKFORMAT "クイックフォーマット" t IDC_BOOT "ブートディスクを作る" t IDC_WINDOWS_INSTALL "標準のWindowsインストール" @@ -7786,7 +7786,7 @@ t IDCANCEL "閉じる" t IDC_START "スタート" t IDS_ADVANCED_OPTIONS_GRP "高度な設定" t IDC_ENABLE_FIXED_DISKS "USB接続のHDDを一覧表示する" -t IDC_EXTRA_PARTITION "古いBIOSの為に修正を追加 (拡張パーティション、並び替え、その他)" +t IDC_EXTRA_PARTITION "古いBIOSのために修正を追加 (拡張パーティション、並び替え、その他)" t IDC_RUFUS_MBR "BIOS IDでRufusのMBRを作る" # About dialog @@ -7847,13 +7847,14 @@ s IDCANCEL +10,0 m IDC_UPDATE_FREQUENCY +30,0 s IDC_UPDATE_FREQUENCY +20,0 m IDC_INCLUDE_BETAS +30,0 +s IDC_INCLUDE_BETAS +10,0 m IDS_CHECK_NOW_GRP +45,0 # Dialog that appears when a new version is available g IDD_NEW_VERSION t IDD_NEW_VERSION "アップデートの確認 - Rufus" -t IDS_NEW_VERSION_AVAIL_TXT "新しいバージョンを利用出来ます。新しいバージョンをダウンロードしてください!" -t IDC_WEBSITE "ウェブサイトへ行く為にはここをクリックしてください。" +t IDS_NEW_VERSION_AVAIL_TXT "新しいバージョンを利用できます。新しいバージョンをダウンロードしてください!" +t IDC_WEBSITE "ウェブサイトへ行くためにはここをクリックしてください。" t IDS_NEW_VERSION_NOTES_GRP "リリースノート" t IDS_NEW_VERSION_DOWNLOAD_GRP "ダウンロード" t IDC_DOWNLOAD "ダウンロード" @@ -7865,15 +7866,15 @@ t MSG_002 "Rufusはすでに実行されています。\n" "もう一度実行する前に既に起動中のRufusを閉じてください。" t MSG_003 "警告:デバイス '%s' のデータは消去されます。\n" "続けるには、OKをクリックします。取り消すには、キャンセルをクリックします。" -t MSG_004 "Rufus update policy" -t MSG_005 "Do you want to allow Rufus to check for application updates online?" +t MSG_004 "Rufusの更新ポリシー" +t MSG_005 "Rufusがオンラインで行うアプリケーションの更新確認機能を有効にしますか?" # Must be the same as IDD_DIALOG:IDCANCEL (i.e. "Close" - I know it's confusing) t MSG_006 "閉じる" t MSG_007 "キャンセル" t MSG_008 "はい" t MSG_009 "いいえ" -t MSG_010 "破損したブロックを検出しました。" -t MSG_011 "検出完了:破損したブロックの数 %d\n" +t MSG_010 "不良ブロックを検出しました。" +t MSG_011 "検出完了:不良ブロックの数 %d\n" "リードエラーの数 %d \n ライトエラーの数 %d \n 破損エラーの数 %d \n" # The following will contain the formatted message above as well as the name of the bad blocks logfile t MSG_012 "%s\n詳細なレポートはここで見ることができます:\n%s" @@ -7918,7 +7919,7 @@ t MSG_046 "%s (ディスク %d) [%s]" # Used when a drive is detected that contains more than one partition t MSG_047 "複数のパーティション" t MSG_048 "Rufus - バッファを消去中" -t MSG_049 "Rufus - 取り消し中" +t MSG_049 "Rufus - キャンセル中" # Error messages t MSG_050 "成功しました。" @@ -7928,7 +7929,7 @@ t MSG_053 "このデバイスへのアクセスは拒否されました。" t MSG_054 "メディアは書き込み禁止です。" t MSG_055 "デバイスは他のプロセスで使われています。" "デバイスにアクセスしているプロセスを停止してください。" -t MSG_056 "このデバイスはクイックフォーマットはできません。" +t MSG_056 "このデバイスはクイックフォーマットできません。" t MSG_057 "ボリュームラベルは無効です。" t MSG_058 "デバイスハンドルは無効です。" t MSG_059 "選択されたクラスタサイズはこのデバイスには無効です。" @@ -7940,49 +7941,49 @@ t MSG_064 "読み込みエラー" t MSG_065 "書き込みエラー" t MSG_066 "インストールに失敗しました。" t MSG_067 "メディアは開けませんでした。恐らく他のプログラムで使われています。" - "もう一度、接続しやり直してください。" + "もう一度接続し、やり直してください。" t MSG_068 "ドライブに、パーティションを設定している時、エラーが起きました。" -t MSG_069 "ファイルをターゲットドライブにコピー出来ませんでした。" +t MSG_069 "ファイルをターゲットドライブへコピーできませんでした。" t MSG_070 "ユーザーによるキャンセル" # See http://en.wikipedia.org/wiki/Thread_%28computing%29 t MSG_071 "作業(処理)を始められませんでした。" -t MSG_072 "破損ブロックの検出処理が完了出来ませんでした。" +t MSG_072 "不良ブロックの検出処理が完了できませんでした。" t MSG_073 "ISOイメージスキャンに失敗しました。" -t MSG_074 "ISOイメージの抽出に失敗しました。" -t MSG_075 "ボリュームを再マウント出来ません。" +t MSG_074 "ISOイメージからの抽出に失敗しました。" +t MSG_075 "ボリュームを再マウントできません。" t MSG_076 "ファイルへブート用パッチを当てられません。" -t MSG_077 "ドライブ レターを割り振れません。" -t MSG_078 "GUIDボリュームをマウント出来ません。" +t MSG_077 "ドライブレターを割り振れません。" +t MSG_078 "GUIDボリュームをマウントできません。" t MSG_079 "デバイスは準備できていません。" t MSG_080 "RufusはWindowsがUSBデバイスの内部バッファに書き込みしていること検出しました。\n\n" "特に大きなファイルの場合、USBデバイスのスピードによっては、この操作に時間がかかるかもしれません。" - "\n\nファイル破損を避ける為には、作業完了まで待つことを推奨します。" - "(しかし、一応デバイスを取り外すことは可能です)" + "\n\nファイル破損を避けるためには、作業完了まで待つことを推奨しますが、" + "デバイスを取り外すこともできます。" t MSG_081 "非対応のイメージです。" t MSG_082 "このイメージは、ブート非対応です。もしくは、Rufusでサポートされていないブート方式、圧縮方式を使用しています。" t MSG_083 "%s を交換しますか?" t MSG_084 "このISOは '%s' の古いバージョンを使うようです。\n" "ブートメニューが正しく表示できないかもしれません。\n\n" - "この問題を解決する為にRufusの新しいバージョンをダウンロード出来ます:\n" - "- インターネットに接続し、ファイルをダウンロードする為には「Yes」をクリックしてください。\n" + "この問題を解決するためにRufusの新しいバージョンをダウンロードできます:\n" + "- インターネットに接続し、ファイルをダウンロードするためには「Yes」をクリックしてください。\n" "- 既存のISOを変更しない場合は「No」をクリックしてください。\n" "どうしたらよいかわからない場合は「Yes」をクリックすることを推奨します。\n\n" - "注意: 新しいファイルは現在のディレクトリにダウンロードします。" + "注意: 新しいファイルは現在のディレクトリにダウンロードされます。" "すでに'%s'のファイルが存在している場合は自動で再利用します。" t MSG_085 "%s をダウンロード中" t MSG_086 "イメージが選択されていません。" # The content between the quotes below (\"Create a bootable disk\") should match # the beginning of the IDC_BOOT text -t MSG_087 "ブート可能なイメージを選択する為にはディスクボタンをクリックします" +t MSG_087 "ブート可能なイメージを選択するためにはディスクボタンをクリックします" "、または「ブートディスクを作る」のチェックボックスをオフにします。" t MSG_088 "イメージが大きすぎます。" -t MSG_089 "イメージは選択したターゲットには大き過ぎます。" +t MSG_089 "イメージが選択したターゲットには大き過ぎます。" t MSG_090 "非対応ISOです" -t MSG_091 "UEFIターゲットタイプを使う時、EFIでブート可能なISOだけサポートします。" +t MSG_091 "UEFIターゲットタイプを使用する場合、EFIでブート可能なISOだけをサポートします。" "EFIでブート可能なISOを選択してください、またはBIOSの設定でターゲットタイプを設定し直してください。" t MSG_092 "このファイルシステムには非対応です。" -t MSG_093 "重要:このドライブは複数のパーティションを含んでいます!! \n\n" +t MSG_093 "重要:このドライブは複数のパーティションを含んでいます!! \n\n" "Windowsが認識できないパーティションやボリューム、リスト化できないパーティションやボリュームがあるかもしれません。" "続ける場合、このパーティションのデータを失う可能性があります。" t MSG_094 "複数のパーティションを検出しました。" @@ -7995,47 +7996,47 @@ t MSG_098 "注意: 「Windows To Go」をインストールしようとしてい "Microsoftは、'REMOVABLE'属性があるドライブで動作するように設計しませんでした。" "\n\n続けて宜しいですか?\n\n" "注意:'FIXED/REMOVABLE'属性は、製造メーカーからのツール等でのみ" - "変更可能です。 しかし、その様なツールはほとんど全くと言って良い程" - "公開されていません。。。" + "変更可能ですが、そのようなツールは全くと言って良いほど" + "公開されていません..." t MSG_099 "ファイルシステム制限" t MSG_100 "ISOイメージに4GBより大きなファイルがあります。" "FAT、FAT32ファイルシステムで使用可能な最大のサイズを超えています。" t MSG_101 "不足してしまったWIMのサポートについて" -t MSG_102 "ご使用の環境ではWIMの抽出をできません。EFIでのブートを必要とする" - "Windows 7とWindows Vista用のUSBドライブを作る為に、あなたは個別にWIMの抽出が必要です。" - "7-zipの最近のバージョンでそれらが可能です。\n7-zipダウンロードページへ行きますか?" -t MSG_103 "%s? ダウンロード中" +t MSG_102 "ご使用の環境ではWIMファイルからファイルを抽出できません。" + "EFIでのブートを必要とするWindows 7とWindows Vista用のUSBドライブを作るためには、WIMファイルを展開できる必要があります。" + "7-Zipの最近のバージョンでは展開することができます。\n7-Zipのダウンロードページへ行きますか?" +t MSG_103 "ダウンロード %s?" t MSG_104 "%s 以降の物が内包されており '%s' ファイルが必要になります。\n" - "このファイルは100KBより大きいのでRufusに内蔵しません。%s にISO イメージが常時ある為です。" - "\n\nRufus で不足しているファイルをダウンロードすることが出来ます:\n" - "- インターネットに接続しファイルをダウンロードする為には、「Yes」を選択して下さい。\n" - "- 後でファイルをドライブに置いて手動でコピーする為には、「No」を選択して下さい。\n\n" - "注意:ファイルは現在のディレクトリへダウンロードします。" + "このファイルは100KBより大きいのでRufusに内蔵していません。%s にISO イメージが常時あるためです。" + "\n\nRufus で不足しているファイルをダウンロードすることができます:\n" + "- インターネットに接続し、ファイルをダウンロードするためには、「Yes」を選択してください。\n" + "- 後でファイルをドライブに置いて手動でコピーするためには、「No」を選択してください。\n\n" + "注意:ファイルは現在のディレクトリへダウンロードされます。" "'%s' が既にディレクトリにある場合、自動的に再使用します。\n" t MSG_105 "キャンセルすると、デバイスは使用に適さなくなるかもしれません。\n" - "取り消しても宜しければ、「はい」をクリックして下さい。そうではない場合、「いいえ」をクリックして下さい。" -t MSG_106 "フォルダを選択して下さい。" + "取り消しても宜しければ、「はい」をクリックしてください。そうではない場合、「いいえ」をクリックしてください。" +t MSG_106 "フォルダを選択してください。" t MSG_107 "全てのファイル" t MSG_108 "Rufusのログ" t MSG_109 "0x%02X (ディスク %d)" # "Cluster size" below should be the same as the label for IDS_CLUSTERSIZE_TXT # "kilobytes" should be the same as in MSG_027 -t MSG_110 "クラスタサイズが64KBです。MS-DOSはこの場合、ドライブからブート出来ません。\n" - "クラスタサイズを変えて下さい、またはFreeDOSを使用して下さい。" +t MSG_110 "クラスタサイズが64KBです。MS-DOSはこの場合、ドライブからブートできません。\n" + "クラスタサイズを変えてください、またはFreeDOSを使用してください。" t MSG_111 "互換性がないクラスタサイズです。" # "%d:%02d" below is a duration (mins:secs) t MSG_112 "USB2.0接続時に、大きなUDFボリュームをフォーマットすると時間がかかります。" - "フォーマットの推定完了時間は %d:%02d この間、プログレスバーはまるで進んでいないかに見えます。終了までしばらくお待ちください。" + "フォーマットの推定完了時間は %d:%02d です。この間、プログレスバーは進んでいないように見えます。終了までしばらくお待ちください。" t MSG_113 "大きなUDFボリューム" t MSG_114 "このイメージは Syslinux %s%s を使用しますが、このアプリケーションには Syslinux %s%s のインストール" "ファイルのみ内蔵しています。\n\n新しいSyslinux のバージョンは互いに互換性はありませんので、" - "Rufusはそれらを含めることは出来ません。" + "Rufusはそれらを含めることはできません。" "インターネットから二つのファイルをダウンロードしてください。('ldlinux.sys' と 'ldlinux.bss'):\n" - "- インターネットに接続しファイルをダウンロードする為には、「Yes」を選択して下さい。\n" - "- 取り消したい場合には、「No」を選択して下さい。\n\n" - "注意: ファイルは現在のディレクトリへダウンロードします。新しいファイルが既に現在のディレクトリにある場合、" + "- インターネットに接続し、ファイルをダウンロードするためには、「Yes」を選択してください。\n" + "- 取り消したい場合には、「No」を選択してください。\n\n" + "注意: ファイルは現在のディレクトリへダウンロードされます。新しいファイルが既に現在のディレクトリにある場合、" "ダウンロードせず自動的に再使用します。\n" -t MSG_115 "ダウンロード必須" +t MSG_115 "ダウンロードが必要" t MSG_116 "このイメージはGrub %s を使いますが、このアプリケーションには Grub %sのインストールファイルのみ" "内蔵しています。\n\n各々のGrubのバージョンは互いに互換性はなく、使用できません。" "しかし、Rufusはイメージと一致したバージョンのGrubインストールファイル('core.img')" @@ -8043,30 +8044,30 @@ t MSG_116 "このイメージはGrub %s を使いますが、このアプリケ "- 「Yes」を選択し、インターネットからダウンロードします\n" "- 「No」を選択し、Rufusはデフォルトのバージョンを使用します\n" "- 「Cancel」を選択し、操作を中止します\n\n" - "注意: ファイルは現在のディレクトリへダウンロードします。新しいファイルが既に現在のディレクトリにある場合、" + "注意: ファイルは現在のディレクトリへダウンロードされます。新しいファイルが既に現在のディレクトリにある場合、" "ダウンロードせず自動的に再使用します。もし、見つからなかった場合には内蔵しているバージョンの物が使用されます。\n" # Tooltips # Partition Scheme and Target Type t MSG_150 "通常では適切な選択です。しかし、UEFIコンピュータにEFIモードでOS" "をインストールする場合、他のオプションを選択する必要があります。" t MSG_151 "EFIモードでOSをインストールし、Windows XPからUSBメモリへ" - "アクセスする必要が「ある」場合、これを選択して下さい。" + "アクセスする必要が「ある」場合、これを選択してください。" t MSG_152 "EFIモードでOSをインストールし、Windows XPからUSBメモリへ" - "アクセスする必要が「ない」場合、これを選択して下さい。" + "アクセスする必要が「ない」場合、これを選択してください。" t MSG_153 "テストパターン: 0x%02X" t MSG_154 "テストパターン: 0x%02X, 0x%02X" t MSG_155 "テストパターン: 0x%02X, 0x%02X, 0x%02X" t MSG_156 "テストパターン: 0x%02X, 0x%02X, 0x%02X, 0x%02X" t MSG_157 "ターゲットのファイルシステムを設定します。" t MSG_158 "ファイルシステム内で使用するデータブロックの最小サイズです。" -t MSG_159 "ここでドライブのラベルを設定可能です、各国の文字が使用出来ます。" +t MSG_159 "ここでドライブのラベルを設定可能です、各国の文字が使用できます。" t MSG_160 "詳細設定に切り替えます" -t MSG_161 "テストパターンで破損したブロックを検出する。" -t MSG_162 "「クイック」ではないフォーマットをする為には、チェックボックスをオフにします。" -t MSG_163 "ブート可能なUSBドライブを作る為にチェックボックスをオンにします。" +t MSG_161 "テストパターンで不良ブロックを検出します。" +t MSG_162 "「クイック」ではないフォーマットをするためには、チェックボックスをオフにします。" +t MSG_163 "ブート可能なUSBドライブを作るためにはチェックボックスをオンにします。" t MSG_164 "ドライブをブート可能にします" -t MSG_165 "イメージを選択する為にクリックして下さい。" -t MSG_166 "機能拡張されたラベルを表示する為に、デバイス用アイコン(autorun.infを作成します)\n" +t MSG_165 "イメージを選択するためにクリックしてください。" +t MSG_166 "機能拡張されたラベルを表示するために、デバイス用アイコン(autorun.infを作成します)\n" "この設定を使うにはチェックボックスをオンにします。\n" "具体的な機能は以下の通りです。\n" "チェックボックスをオンにするとWindowsでRufusのアイコンが表示されます。\n" @@ -8077,7 +8078,7 @@ t MSG_168 "最優先でブート可能なUSBドライブ(通常は0x80)へ偽装 "Windows XPで複数のdiskを実装したマシンでインストールする時だけ、必要になります。" t MSG_169 "特別な隠しパーティションを作成し、各パーティションの位置合わせを行います。\n" "古いBIOS使用時にブート時の検出を改善できます。" -t MSG_170 "外付けUSB HDDのリストを有効にします。自己責任です。!!!" +t MSG_170 "外付けUSB HDDのリストを有効にします。自己責任です!!!" t MSG_171 "フォーマットを始めます。\n ターゲットのデータは全て破壊されます。" t MSG_172 "ライセンス情報とクレジット" t MSG_173 "選択するにはクリック" @@ -8085,43 +8086,43 @@ t MSG_173 "選択するにはクリック" t MSG_174 "Rufus - 信頼性の高いUSBフォーマット ユーティリティ" t MSG_175 "バージョン %d.%d (Build %d)" t MSG_176 "日本語翻訳: チャンテラ・ジャクソン \\line" - "校正、翻訳: ヨール " -t MSG_177 "バグの報告、または、お問い合わせ等はこちらから:" + "校正、翻訳: Tiryoh " +t MSG_177 "バグの報告、お問い合わせ等はこちらから:" t MSG_178 "各種著作権:" t MSG_179 "アップデートポリシー:" -t MSG_180 "このアプリケーション経由でプログラムのアップデートの確認を許可した場合、\\line" - "以下の情報をサーバーに送信すると同意します。" +t MSG_180 "このアプリケーションのアップデート確認を許可した場合、\\line" + "以下の情報をサーバーに送信することに同意します。" t MSG_181 "ご使用中のOSの種類とバージョン" t MSG_182 "ご使用中のこのアプリケーションのバージョン" t MSG_183 "IPアドレス" -t MSG_184 "私的な利用統計を作る為に、\\line" - "集めた情報は\\b最大で一年間\\b0 保管するかもしれません。 \\line" - "但し、第三者へ、その私的なデータをやすやすと開示することはありません。" +t MSG_184 "利用統計を作るために、\\line" + "集めた情報は\\b最大で一年間\\b0 保管する場合があります。 \\line" + "ただし、そのデータを安易に第三者へ開示することはありません。" t MSG_185 "アップデートの方法:" -t MSG_186 "Rufusは、インストールしていない時は勿論、バックグラウンドサービスでアップデートの処理を一切しません、手動での確認時のみです。\\line\n" - "アップデートの確認には、インターネットが必要です。" +t MSG_186 "Rufusは、本アプリケーション実行時のみアップデートの確認を行います。インストールまたはバックグラウンドサービスを実行して処理を行うことは一切ありません。\\line\n" + "また、アップデートの確認にはインターネット接続が必要です。" t MSG_187 "選択したブート設定には無効なイメージです。" -t MSG_188 "現在選択中のイメージとブート設定が違います。別のイメージを使うか、別のブート設定を使用して下さい。" +t MSG_188 "現在選択中のイメージとブート設定が違います。別のイメージを使うか、他のブート設定を使用してください。" t MSG_189 "このISOは選択中のファイルシステムと互換性がありません。" t MSG_190 "互換性のないドライブが検出されました" t MSG_191 "書き込みをパスしました" -t MSG_192 "読み出みをパスしました" +t MSG_192 "読み出しをパスしました" t MSG_193 "ダウンロード %s" -t MSG_194 "%sはダウンロード出来ませんでした" -t MSG_195 "既に組み込まれている%sファイルを使用します" -t MSG_196 "重要:このドライブは標準以外のセクタサイズを使用しています!\n\n" +t MSG_194 "%sはダウンロードできませんでした" +t MSG_195 "内蔵している %sファイルを使用します" +t MSG_196 "重要:このドライブは標準以外のセクタサイズを使用しています!\n\n" "従来のドライブは、512バイトのセクタサイズを使用しますが、このドライブは%dバイトを使用しています。" - "多くの場合、このドライブからブートできないことを意味します。\n" - "Rufusはブート可能になる様、ドライブを作成しようとします、しかし、動作する保証はありません。" + "多くの場合、このドライブからブートできません。\n" + "Rufusはブートできるように、ドライブを作成しようとします。しかし動作保証はありません。" t MSG_197 "標準以外のセクタサイズが検出されました" t MSG_198 "FIXED属性が設定されている場合に限り、GPTパーティションのドライブに「Windows To Go」を" "インストールすることができます。 現在のドライブはFIXEDとして検出されませんでした。" -t MSG_199 "インストールメディアとして選択中のデバイスを使用し、別のディスクにWindowsをインストールする場合は、選んでください。" -t MSG_200 "選択中のデバイスから直接Windowsを実行したい場合は、選んでください。" +t MSG_199 "インストールメディアとして選択中のデバイスを使用し、別のディスクにWindowsをインストールする場合は、こちらを選んでください。" +t MSG_200 "選択中のデバイスから直接Windowsを実行したい場合は、こちらを選んでください。" # Status messages - these messages will appear on the status bar -t MSG_201 "キャンセル中 - お待ちください......" -t MSG_202 "イメージをスキャン中......" +t MSG_201 "キャンセル中 - お待ちください..." +t MSG_202 "イメージをスキャン中..." t MSG_203 "イメージのスキャンに失敗しました。" # Parameter: the name of an obsolete Syslinux .c32 module. eg: "Obsolete vesamenu.c32 detected" t MSG_204 "廃止された %s を検出しました" @@ -8131,10 +8132,10 @@ t MSG_205 "%s を使用中" t MSG_206 "ファイルが見つかりません: %s" # The name proposed by Windows' Computer Management -> Disk Management when you try to format a drive # with an empty label. See http://rufus.akeo.ie/pics/default_name.png -t MSG_207 "新しいボリューム ラベル" +t MSG_207 "新しいボリュームラベル" # Same message, once for singular and plural ("1 device found", "2 devices found") -t MSG_208 "%d のデバイスを検出しました" -t MSG_209 "%d のデバイスを検出しました" +t MSG_208 "%d 個のデバイスを検出しました" +t MSG_209 "%d 個のデバイスを検出しました" t MSG_210 "準備完了" t MSG_211 "キャンセルしました" t MSG_212 "失敗しました" @@ -8152,7 +8153,7 @@ t MSG_219 "NTFS 修正中: %d%% 完了" # eg. "Formatting (UDF) - Estimated duration 3:21..." # NB: if "estimated duration" is too long, just use "estimated" or an abbreviation t MSG_220 "フォーマット中: (%s) - 残り約 %d:%02d..." -t MSG_221 "ラベル作成中(時間がかかる事があります)" +t MSG_221 "ラベル作成中(時間がかかることがあります)" # Parameter: the file system. eg. "Formatting (NTFS)..." t MSG_222 "フォーマット中: (%s)..." t MSG_223 "NTFSの修正が必要か確認中(チェックディスク)..." @@ -8164,36 +8165,36 @@ t MSG_228 "マスターブートレコードを書き込んでいます..." t MSG_229 "パーティションブートレコードを書き込んでいます..." t MSG_230 "DOSファイルをコピー中..." t MSG_231 "ISOファイルをコピー中..." -t MSG_232 "Win7 EFI ブートセットアップ中(時間がかかる事があります)" +t MSG_232 "Win7 EFI ブートセットアップ中(時間がかかることがあります)" t MSG_233 "最終処理中です。もう間もなく終わります..." # Takes a Syslinux version as parameter, eg. "Installing Syslinux v5.10..." t MSG_234 "Syslinux %s をインストール中..." # Bad blocks status. eg: "Bad Blocks: PASS 1/2 - 12.34% (0/0/1 errors)" -t MSG_235 "破損したブロック:%s %d/%d - %0.2f%% (%d/%d/%d エラー)" -t MSG_236 "破損したブロック:ランダムパターンでテスト" -t MSG_237 "破損したブロック:パターン 0x%02X でテスト" +t MSG_235 "不良ブロック:%s %d/%d - %0.2f%% (%d/%d/%d エラー)" +t MSG_236 "不良ブロック:ランダムパターンでテスト" +t MSG_237 "不良ブロック:パターン 0x%02X でテスト" t MSG_238 "パーティション分割中 (%s)..." t MSG_239 "パーティション削除中..." t MSG_240 "ダウンロード中 %s: 接続中..." t MSG_241 "ダウンロード中: %0.1f%%" t MSG_242 "ファイルのダウンロードは失敗しました。" t MSG_243 "Rufusのアップデートを探しています..." -t MSG_244 "アップデート:インターネット接続は失敗しました" -t MSG_245 "アップデート:バージョン管理データにアクセス出来ません" -t MSG_246 "Rufusの新しいバージョンを利用出来ます!" +t MSG_244 "アップデート:インターネット接続に失敗しました" +t MSG_245 "アップデート:バージョン管理データにアクセスできません" +t MSG_246 "Rufusの新しいバージョンを利用できます!" t MSG_247 "Rufusの新しいバージョンはありませんでした" t MSG_248 "アプリケーションのレジストリキーは正常に削除できました" t MSG_249 "アプリケーションのレジストリキーの削除に失敗しました" t MSG_250 "%s 有効" t MSG_251 "%s 無効" -t MSG_252 "サイズチェック" +t MSG_252 "サイズの確認" t MSG_253 "ハードディスクの検出" -t MSG_254 "強制的にラージFAT32でフォーマット" +t MSG_254 "強制的にラージFAT32でフォーマットします" t MSG_255 "NoDriveTypeAutorunは閉じる時に削除されます" -t MSG_256 "偽のドライブを検出しました" +t MSG_256 "偽装されたドライブを検出しました" t MSG_257 "Julietのサポート" t MSG_258 "Rock Ridgeのサポート" -t MSG_259 "強制アップデート" +t MSG_259 "強制的にアップデート" t MSG_260 "NTFS圧縮" t MSG_261 "イメージを書き込み中: %0.1f%% 完了" t MSG_262 "ISOのサポート" @@ -8203,17 +8204,17 @@ t MSG_265 "VMWareディスクを検出" t MSG_266 "デュアル UEFI/BIOS モード" t MSG_267 "Windowsイメージを適用中: %0.1f%% 完了" t MSG_268 "Windowsイメージを適用します..." -t MSG_269 "タイムスタンプを保持" +t MSG_269 "タイムスタンプ(ファイル日付)を保持" t MSG_270 "USBデバッグ" t MSG_271 "イメージのチェックサムを計算中 : %0.1f%% 完了" -t MSG_272 "選択したイメージのMD5、SHA1、SHA256チェックサムを計算中" +t MSG_272 "選択したイメージのMD5、SHA1、SHA256チェックサムを計算します。" t MSG_273 "アプリケーションの使用言語を変更" t MSG_274 "「ISOHybrid」イメージを検出しました" -t MSG_275 "選択されたイメージは「ISOHybrid」です。下記のいずれかで書き込むことができます: " +t MSG_275 "選択されたイメージは「ISOHybrid」です。下記のいずれかの方法で書き込むことができます: " "%s (ファイルコピー)モード又は %s (ディスクイメージ)モード。\n" - "書き込み後、ドライブへ常にフルアクセスする為に、Rufusは %s を推奨します。\n" - "ブート中エラーが発生する場合には、%s モードで、再度実行してください。\n\n" - "このイメージを書き込む為に使用するモードを選択してください:" + "書き込み後、ドライブへフルアクセスできる様、Rufusは %s を推奨します。\n" + "ブート中エラーが発生する場合には、%s モードで再度試してみてください。\n\n" + "このイメージを書き込む際に使用するモードを選択してください:" t MSG_276 "%sモードで書き込む(推奨)" t MSG_277 "%sモードで書き込む" t MSG_278 "ブートの種類" @@ -8221,11 +8222,11 @@ t MSG_279 "非ブート" t MSG_280 "イメージ選択" t MSG_281 "(イメージを選択してください)" t MSG_282 "ロックしている排他的なUSBドライブ" -t MSG_283 "無効なサイン" +t MSG_283 "無効なデジタル署名" t MSG_284 "ダウンロードした実行可能ファイルにはデジタル署名がありません。" t MSG_285 "このダウンロードした実行可能ファイルのデジタル署名は '%s' 。\nこれは私達の署名ではありません" - "悪意ある活動のいくつかの証拠を示しています...\nこのファイルを実行しても良いですか?" -t MSG_286 "0をドライブへ書き込み初期化中: %0.1f%% 完了" + "悪意のあるソフトウェアの可能性があります...\nこのファイルを実行しても良いですか?" +t MSG_286 "'0'をドライブへ書き込み初期化中: %0.1f%% 完了" ################################################################################ l "ko-KR" "Korean (한국어)" 0x0412 diff --git a/src/rufus.rc b/src/rufus.rc index 1fdbb348..efe7b7df 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.850" +CAPTION "Rufus 2.7.851" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,850,0 - PRODUCTVERSION 2,7,850,0 + FILEVERSION 2,7,851,0 + PRODUCTVERSION 2,7,851,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.850" + VALUE "FileVersion", "2.7.851" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.850" + VALUE "ProductVersion", "2.7.851" END END BLOCK "VarFileInfo" From e7f9ec6f0b6b96dfd6ac526d36df6059366bf312 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 8 Feb 2016 18:55:52 +0000 Subject: [PATCH 22/91] [net] fix OS version in user agent string --- src/net.c | 6 ++++-- src/rufus.rc | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/net.c b/src/net.c index 0a498d26..8ef0d9c3 100644 --- a/src/net.c +++ b/src/net.c @@ -300,7 +300,7 @@ DWORD DownloadFile(const char* url, const char* file, HWND hProgressDialog) uprintf("Network is unavailable: %s\n", WinInetErrorString()); goto out; } - _snprintf(agent, ARRAYSIZE(agent), APPLICATION_NAME "/%d.%d.%d (WinNT %d.%d%s)", + safe_sprintf(agent, ARRAYSIZE(agent), APPLICATION_NAME "/%d.%d.%d (Windows NT %d.%d%s)", rufus_version[0], rufus_version[1], rufus_version[2], nWindowsVersion>>4, nWindowsVersion&0x0F, is_x64()?"; WOW64":""); hSession = InternetOpenA(agent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); @@ -491,7 +491,9 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) goto out; hostname[sizeof(hostname)-1] = 0; - safe_sprintf(agent, ARRAYSIZE(agent), APPLICATION_NAME "/%d.%d.%d", rufus_version[0], rufus_version[1], rufus_version[2]); + safe_sprintf(agent, ARRAYSIZE(agent), APPLICATION_NAME "/%d.%d.%d (Windows NT %d.%d%s)", + rufus_version[0], rufus_version[1], rufus_version[2], + nWindowsVersion >> 4, nWindowsVersion & 0x0F, is_x64() ? "; WOW64" : ""); hSession = InternetOpenA(agent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (hSession == NULL) goto out; diff --git a/src/rufus.rc b/src/rufus.rc index efe7b7df..ef9b2a10 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.851" +CAPTION "Rufus 2.7.852" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,851,0 - PRODUCTVERSION 2,7,851,0 + FILEVERSION 2,7,852,0 + PRODUCTVERSION 2,7,852,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.851" + VALUE "FileVersion", "2.7.852" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.851" + VALUE "ProductVersion", "2.7.852" END END BLOCK "VarFileInfo" From 8473e9ef561295fd10dd9526010c1fd1cb1e6701 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 9 Feb 2016 12:38:09 +0000 Subject: [PATCH 23/91] [misc] disable loading of DLLs from current directory * This is done to prevent potential DLL sideloading attacks --- src/rufus.c | 3 +++ src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/rufus.c b/src/rufus.c index d7502392..2ecf99be 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -2828,6 +2828,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine {0, 0, NULL, 0} }; + // Disable loading system DLLs from the current directory (sideloading mitigation) + SetDllDirectoryA(""); + uprintf("*** " APPLICATION_NAME " init ***\n"); // Reattach the console, if we were started from commandline diff --git a/src/rufus.rc b/src/rufus.rc index ef9b2a10..1aebff79 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.852" +CAPTION "Rufus 2.7.853" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,852,0 - PRODUCTVERSION 2,7,852,0 + FILEVERSION 2,7,853,0 + PRODUCTVERSION 2,7,853,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.852" + VALUE "FileVersion", "2.7.853" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.852" + VALUE "ProductVersion", "2.7.853" END END BLOCK "VarFileInfo" From b288ec118b8d57890187225efbaeaa1def8dd18d Mon Sep 17 00:00:00 2001 From: VGPlayer Date: Sun, 14 Feb 2016 21:18:07 +0000 Subject: [PATCH 24/91] [loc] update Malay translation * Note: This translation is still missing completion for MSG_096, MSG_098, MSG_116, MSG_196, MSG_198 and MSG_199 hence v1.0.18 --- res/localization/rufus.loc | 261 ++++++++++++++++++++++--------------- src/rufus.rc | 10 +- 2 files changed, 161 insertions(+), 110 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index aee540cd..a2f3e5ba 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -9591,7 +9591,7 @@ t MSG_285 "Atsiųstą vykdomąjį failą pasirašė '%s'.\nŠio parašo mes neat ################################################################################ l "ms-MY" "Malay (Bahasa Malaysia)" 0x043e, 0x083e -v 1.0.16 +v 1.0.18 b "en-US" # Main dialog @@ -9604,7 +9604,7 @@ s IDC_FILESYSTEM +30,0 s IDC_CLUSTERSIZE +30,0 s IDC_LABEL +30,0 t IDS_DEVICE_TXT "Peranti" -t IDS_PARTITION_TYPE_TXT "Skema partition dan jenis sistem sasaran" +t IDS_PARTITION_TYPE_TXT "Skema partisyen dan jenis sistem sasaran" t IDS_FILESYSTEM_TXT "Sistem fail" t IDS_CLUSTERSIZE_TXT "Saiz gugusan" t IDS_LABEL_TXT "Label jilid baharu" @@ -9618,9 +9618,9 @@ m IDC_SELECT_ISO +30,0 s IDC_INFO +30,0 m IDC_BOOTTYPE +30,0 s IDC_BOOT +32,0 -t IDC_BOOT "Cipta disk boleh-but menggunakan" -t IDC_SET_ICON "Cipta label lanjut dan fail icon" -t IDC_ABOUT "Tentang..." +t IDC_BOOT "Cipta disk boot menggunakan" +t IDC_SET_ICON "Cipta label lanjut dan fail ikon" +t IDC_ABOUT "Mengenai..." t IDC_LOG "Log" t IDCANCEL "Tutup" m IDCANCEL +30,0 @@ -9637,7 +9637,7 @@ t IDC_RUFUS_MBR "Guna MBR Rufus dengan BIOS ID" # About dialog g IDD_ABOUTBOX -t IDD_ABOUTBOX "Tentang Rufus" +t IDD_ABOUTBOX "Mengenai Rufus" t IDC_ABOUT_LICENSE "Lesen" t IDC_ABOUT_UPDATES "Kemas kini" @@ -9648,7 +9648,7 @@ t IDCANCEL "Tutup" # Notifications. You can trigger one of these by using Alt-R and re-launching Rufus g IDD_NOTIFICATION -t IDC_MORE_INFO "Informasi lanjut" +t IDC_MORE_INFO "Maklumat lanjut" t IDYES "Ya" t IDNO "Tidak" @@ -9688,8 +9688,8 @@ t IDCANCEL "Tutup" g IDD_NEW_VERSION t IDD_NEW_VERSION "Semak untuk versi baharu - Rufus" t IDS_NEW_VERSION_AVAIL_TXT "Terdapat versi Rufus yang baharu. Sila muat turun versi yang terkini." -t IDC_WEBSITE "Klik di sini untuk ke laman web Rufus" -t IDS_NEW_VERSION_NOTES_GRP "Informasi versi terbaharu" +t IDC_WEBSITE "Klik di sini untuk ke laman sesawang Rufus" +t IDS_NEW_VERSION_NOTES_GRP "Maklumat versi terbaharu" t IDS_NEW_VERSION_DOWNLOAD_GRP "Muat turun" t IDC_DOWNLOAD "Muat turun" t IDCANCEL "Tutup" @@ -9701,24 +9701,24 @@ t MSG_002 "Terdapat aplikasi Rufus sedang berjalan.\n" t MSG_003 "AMARAN: SEMUA DATA DI DALAM PERANTI '%s' AKAN DIPADAM.\n" "Jika hendak teruskan, klik OK. Untuk berhenti, klik BATAL." t MSG_004 "Dasar kemas kini Rufus" -t MSG_005 "Adakah anda mahu membenarkan Rufus menyemak untuk versi baharu secara online?" +t MSG_005 "Adakah anda mahu membenarkan Rufus menyemak untuk versi baharu dalam talian?" # Must be the same as IDD_DIALOG:IDCANCEL (i.e. "Close" - I know it's confusing) t MSG_006 "Tutup" t MSG_007 "batal" t MSG_008 "Ya" t MSG_009 "Tidak" t MSG_010 "Blok rosak dijumpai" -t MSG_011 "Semak selsesai: %d blok rosak dijumpai\n" - " %d error membaca\n %d error menulis\n %d error korupsi\n" +t MSG_011 "Semak selesai: %d blok rosak dijumpai\n" + " %d kesilapan membaca\n %d kesilapan menulis\n %d kesilapan korupsi\n" # The following will contain the formatted message above as well as the name of the bad blocks logfile -t MSG_012 "%s\nA more detailed report can be found in:\n%s" +t MSG_012 "%s\nLaporan lebih terperinci boleh dijumpai di:\n%s" t MSG_013 "Tidak menyemak" t MSG_014 "Harian" t MSG_015 "Mingguan" t MSG_016 "Bulanan" t MSG_017 "Tetapan sendiri" -t MSG_018 "Versi anda: %d.%d (Build %d)" -t MSG_019 "Versi terkini: %d.%d (Build %d)" +t MSG_018 "Versi anda: %d.%d (Binaan %d)" +t MSG_019 "Versi terkini: %d.%d (Binaan %d)" # *Short* size names. These can be used as suffixes t MSG_020 "bait" t MSG_021 "KB" @@ -9733,9 +9733,9 @@ t MSG_028 "megabait" t MSG_029 "lalai" # The following gets appended to the file system, cluster size, etc. t MSG_030 "%s (Lalai)" -t MSG_031 "%s skema partition untuk BIOS dan %s" -t MSG_032 "%s skema partition untuk BIOS" -t MSG_033 "%s skema partition untuk UEFI" +t MSG_031 "%s skema partisyen untuk BIOS dan %s" +t MSG_032 "%s skema partisyen untuk BIOS" +t MSG_033 "%s skema partisyen untuk UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d kali lulus" @@ -9746,23 +9746,23 @@ t MSG_038 "Batal" t MSG_039 "Mula" t MSG_040 "Muat Turun" t MSG_041 "Operasi dibatalkan oleh pengguna" -t MSG_042 "Error" -t MSG_043 "Error: %s" +t MSG_042 "Kesilapan" +t MSG_043 "Kesilapan: %s" t MSG_044 "Muat turun fail" t MSG_045 "Peranti storan USB (Generik)" -t MSG_046 "%s (Disk %d) [%s]" -t MSG_047 "Beberapa Partition" -t MSG_048 "Rufus - Mengeflush buffer" +t MSG_046 "%s (Cakera %d) [%s]" +t MSG_047 "Beberapa Partisyen" +t MSG_048 "Rufus - 'Flush' penimbal" t MSG_049 "Rufus - Dibatalkan" # Error messages t MSG_050 "Berjaya." -t MSG_051 "Error yang tidak dapat ditentukan ketika berformat." +t MSG_051 "Kesilapan yang tidak dapat ditentukan ketika memformat." t MSG_052 "Tidak boleh menggunakan sistem fail yang dipilih untuk media ini." t MSG_053 "Akses kepada peranti dinafikan." t MSG_054 "Tidak boleh menulis data ke peranti (Dilindungi)" t MSG_055 "Peranti ini digunakan oleh proses lain. " - "Sila tutup mana-mana proses yang mukin menggunakan peranti ini." + "Sila tutup mana-mana proses yang mungkin menggunakan peranti ini." t MSG_056 "Format pantas tidak boleh digunakan pada peranti ini." t MSG_057 "Label jilid tidak sah." t MSG_058 "Pengendali peranti tidak sah." @@ -9770,36 +9770,35 @@ t MSG_059 "Saiz gugusan yang dipilih tidak boleh digunakan pada peranti ini." t MSG_060 "Saiz jilid tidak sah." t MSG_061 "Sila masukkan media boleh alih ke dalam pemacu." t MSG_062 "Arahan yang tidak disokong diterima." -t MSG_063 "error peruntukkan memori." -t MSG_064 "Error membaca." -t MSG_065 "Error menulis." +t MSG_063 "Kesilapan peruntukkan memori." +t MSG_064 "Kesilapan membaca." +t MSG_065 "Kesilapan menulis." t MSG_066 "Kegagalan memasang" t MSG_067 "Media tidak boleh dibuka. Ia mungkin digunakan dalam proses yang lain. " - "Tolong cabut dan masukkan semula dan cuba sekali lagi." -t MSG_068 "Masalah semasa mempartition drive." -t MSG_069 "Tidak boleh meyalin fail kepada drive." + "Sila cabut dan masukkan semula dan cuba sekali lagi." +t MSG_068 "Masalah semasa pembahagian pemacu." +t MSG_069 "Tidak boleh meyalin fail kepada pemacu." t MSG_070 "Dibatalkan oleh pengguna." # See http://en.wikipedia.org/wiki/Thread_%28computing%29 -t MSG_071 "\"Thread\" tidak boleh dimulakan'." -t MSG_072 "Penyemakan blok rosak tidak dapat dihabiskan." -t MSG_073 "Kegagalan imabasan imej ISO." +t MSG_071 "\"Bebenang\" tidak boleh dimulakan'." +t MSG_072 "Penyemakan blok rosak tidak dapat diselesaikan." +t MSG_073 "Kegagalan imbasan imej ISO." t MSG_074 "Pengekstrakan imej ISO gagal." -t MSG_075 "Tidak dapat mount semula jilid." -t MSG_076 "Tidak dapat mengepatch/menyediakan fail untuk boot." -t MSG_077 "Tidak dapat menguntukkan huruf untuk drive." -t MSG_078 "Tidak boleh mount jilid GUID." +t MSG_075 "Tidak dapat melekap semula jilid." +t MSG_076 "Tidak dapat 'patch'/menyediakan fail untuk boot." +t MSG_077 "Tidak dapat memperuntukkan huruf untuk pemacu." +t MSG_078 "Tidak boleh lekap jilid GUID." t MSG_079 "Peranti ini tidak sedia untuk digunakan" -t MSG_080 "Rufus mengesan bahawa Windows masih lagi mengeflush buffer ke dalam peranti USB.\n\n" +t MSG_080 "Rufus mengesan bahawa Windows masih lagi menarik penimbal ke dalam peranti USB.\n\n" "Bergantung kepada kelajuan peranti USB anda, operasi ini mungkin mengambil masa yang amat lama." "Terutamanya untuk fail besar .\n\nKami cadangkan anda biarkan Windows tamat dahulu untuk mengelakkan korupsi." - "Namun, jika anda kesuntukkan masa, anda boleh cabutkan peranti anda..." -t MSG_081 "ISO ini tidak disokong" -t MSG_082 "Versi Rufus ini hanya menyokong ISO boleh-but yang berdasarkan bootmgr, EFI, Grub4DOS, GRUB 2, isolinux atau WinPE.\n" - "ISO ini tidak menggunakan mana-mana antara tersebut..." + "Namun, jika anda kesuntukan masa, anda boleh cabutkan peranti anda..." +t MSG_081 "ISO tidak disokong" -> "Imej tidak disokong" +t MSG_082 -> "Imej ini sama ada tidak boleh boot, atau ia menggunakan kaedah boot atau mampatan yang tidak disokong oleh Rufus..." t MSG_083 "Gantikan %s?" -t MSG_084 "Imej ISO ini menggunakan versi '%s' yang telah usang.\n" - "Oleh sebab ini, menu but mungkin tidak dipaparkan dengan betul.\n\n" +t MSG_084 "Imej ISO ini menggunakan versi '%s' yang telah lapuk.\n" + "Oleh sebab ini, menu boot mungkin tidak dipaparkan dengan betul.\n\n" "Versi yang lebih baharu boleh dimuat turun oleh Rufus untuk memperbaiki isu ini:\n" "- Pilih 'Ya' untuk menyambung ke internet dan muat turun fail tersebut\n" "- Pilih 'Tidak' untuk tidak mengubahsuai fail ISO yang digunakan\n" @@ -9810,30 +9809,33 @@ t MSG_085 "Muat turun %s" t MSG_086 "Tiada imej yang dipilih" # The content between the quotes below (\"Create a bootable disk\") should match # the beginning of the IDC_BOOT text -t MSG_087 "Sila kilik pada butang disk untuk memilih imej yang boleh boot, " - "atau nyahtandakan kotak semak \"Cipta disk boleh boot menggunakan\"." +t MSG_087 "Sila klik pada butang cakera untuk memilih imej yang boleh boot, " + "atau nyahtandakan kotak semak \"Cipta pemacu boleh boot menggunakan\"." t MSG_088 "Imej terlalu besar" t MSG_089 "Imej ini terlalu besar untuk sasaran yang dipilih." t MSG_090 "ISO tidak disokong" -t MSG_091 "Apabila menggunakan jenis sasaran UEFI , hanya imej boleh boot jenis EFI sahaja disokong. " - "Tolong pilih ISO boleh boot jenis EFI atau tukarkan jenis sasaran kepada BIOS." +t MSG_091 "Apabila menggunakan jenis sasaran UEFI , hanya imej boot jenis EFI sahaja disokong. " + "Sila pilih ISO boot jenis EFI atau tukarkan jenis sasaran kepada BIOS." t MSG_092 "Sistem fail tidak disokong" -t MSG_093 "PENTING: PERANTI INI MEMPUNYAI BEBERAPA PARTITION!!\n\n" - "Ini mungkin termasuk partition/jilid yang tidak disenaraikan atau tidak boleh dilihat dari Windows. " - "Jika anda mahu meneruskannya, anda bertanggungjawab ke atas kehilangan data dalam partition tersebut." -t MSG_094 "Beberapa partition dikesan" +t MSG_093 "PENTING: PERANTI INI MEMPUNYAI BEBERAPA PARTISYEN!!\n\n" + "Ini mungkin termasuk partisyen/jilid yang tidak disenaraikan atau tidak boleh dilihat dari Windows. " + "Jika anda mahu meneruskannya, anda bertanggungjawab ke atas kehilangan data dalam partisyen tersebut." +t MSG_094 "Beberapa partisyen dikesan" t MSG_095 "DD Imej" +#t MSG_096 "Sistem fail yang dipilih tidak boleh digunakan dengan jenis ISO ini (...)" +t MSG_097 "'Windows To Go' hanya boleh digunakan jika sistem fail adalah NTFS." +#t MSG_098 "PENTING: Anda cuba memasang 'Windows To Go', tetapi pemacu sasaran anda tidak (...)" t MSG_099 "Had sistem fail" t MSG_100 "Imej ISO ini mengandungi fail yang lebih besar daripada 4GB " - "iaitu saiz maksima yang dibenarakan untuk sistem fail FAT/FAT32." + "iaitu saiz maksima yang dibenarkan untuk sistem fail FAT/FAT32." t MSG_101 "Tiada sokongan WIM" t MSG_102 "Platform anda tidak boleh mengekstrak fail daripada arkib WIM. Ini diperlukan " - "untuk mencipta cakera boleh boot EFI Windows 7 dan Windows Vista. Anda boleh membaikinya dengan " + "untuk mencipta cakera boot EFI Windows 7 dan Windows Vista. Anda boleh membaikinya dengan " "cara mendapatkan versi 7-Zip terbaharu.\nAdakah anda mahu ke halaman muat turun 7-zip?" t MSG_103 "Muat turun %s?" t MSG_104 "%s atau kemudian memerlukan fail '%s' di komputer anda.\n" "Oleh sebab fail tersebut lebih besar daripada 100 KB dan sentiasa ada dalam imej %s, " - "Ia tidak termasuk dalam Rufus.\n\nRufus boleh memuat turunkan fail tersebut untuk anda:\n" + "Ia tidak termasuk dalam Rufus.\n\nRufus boleh memuat turun fail tersebut untuk anda:\n" "- Pilih 'Ya' untuk muat turun fail tersebut\n" "- Pilih 'Tidak' jika anda mahu menyalin fail tersebut secara manual ke cakera ini pada masa lain\n\n" "Perhatian: Fail akan dimuat turun ke direktori bersamaan Rufus dan apabila " @@ -9843,30 +9845,31 @@ t MSG_105 "Pembatalan boleh menyebabkan peranti ini TIDAK BOLEH DIGUNAKAN SEMULA t MSG_106 "Sila pilih folder" t MSG_107 "Semua fail" t MSG_108 "Log Rufus" -t MSG_109 "0x%02X (Disk %d)" +t MSG_109 "0x%02X (Cakera %d)" # "Cluster size" below should be the same as the label for IDS_CLUSTERSIZE_TXT # "kilobytes" should be the same as in MSG_027 -t MSG_110 "MS-DOS tidak boleh-but daripada cakera yang menggunakan saiz gugusan 64 kilobait.\n" - "Tolong tukar saiz gugusan atau gunakan FreeDOS." -t MSG_111 "Incompatible Cluster size" +t MSG_110 "MS-DOS tidak boleh boot daripada cakera yang menggunakan saiz gugusan 64 kilobait.\n" + "Sila tukarkan saiz gugusan atau gunakan FreeDOS." +t MSG_111 "Saiz gugusan tidak sesuai" # "%d:%02d" below is a duration (mins:secs) -t MSG_112 "Pemformattan jilid UDF yang besar mengambil masa yang amat lama. Pada kelajuan USB 2.0 anggaran masa pemformatan " - "adalah %d:%02d, di mana bar kemajuan akan lihat seperti ia tidak bergerak. Tolong bersabar" +t MSG_112 "Pemformatan jilid UDF yang besar mengambil masa yang amat lama. Pada kelajuan USB 2.0 anggaran masa pemformatan " + "adalah %d:%02d, di mana bar kemajuan akan kelihatan seperti ia tidak bergerak. Sila tunggu" t MSG_113 "Jilid UDF besar" t MSG_114 "Imej ini menggunakan Syslinux %s%s tetapi aplikasi ini hanya mempunyai fail pemasangan untuk" "Syslinux %s%s.\n\nOleh kerana versi-versi baharu Syslinux tidak serasi dengan satu sama lain, maka tidak" - "wajarlah Rufus menyediakan semuanya, dua fail tambahan perlu dimuat turun dari" + "wajar Rufus menyediakan semuanya, dua fail tambahan perlu dimuat turun dari" "Internet ('ldlinux.sys' dan 'ldlinux.bss'):\n" "- Pilih 'Ya' untuk menyambung ke Internet dan memuat turun fail tersebut\n" "- Pilih 'Tidak' untuk membatalkan operasi\n\n" "NOTA:Fail akan dimuat turun ke dalam direktori aplikasi ini dan akan digunakan semula" "secara automatik sekiranya sedia ada.\n" t MSG_115 "Muat turun diperlukan" +#t MSG_116 "Imej ini menggunakan Grub %s tetapi penggunaan hanya termasuk fail pemasangan untuk (...)" # Tooltips # Partition Scheme and Target Type -t MSG_150 "Selalunya pilihan ini paling selamat. Namun, jika anda ada komputer UEFI dan mahu " - "install OS dalam mod EFI, anda patut pilih pilihan yang lain" +t MSG_150 "Biasanya pilihan ini paling selamat. Namun, jika anda ada komputer UEFI dan mahu " + "memasang OS dalam mod EFI, anda patut pilih pilihan yang lain" t MSG_151 "Gunakan ini jika anda mahu memasang OS dalam mod EFI, tetapi perlukan akses kepada " "kandungan USB daripada Windows XP" t MSG_152 "Pilihan yang disyorkan untuk memasang OS dalam mod EFI dan apabila " @@ -9878,100 +9881,113 @@ t MSG_156 "Uji corak: 0x%02X, 0x%02X, 0x%02X, 0x%02X" t MSG_157 "Menetapkan sistem fail sasaran" t MSG_158 "Saiz minima satu blok data akan gunakan dalam sistem fail" t MSG_159 "Gunakan ini untuk tetapkan label cakera\nHuruf antarabangsa boleh digunakan" -t MSG_160 "Togol pilihan lanjutan" +t MSG_160 "Togel pilihan lanjutan" t MSG_161 "Semak peranti untuk blok rosak menggunakan corak ujian" t MSG_162 "Jangan tanda kotak ini untuk menggunakan kaedah pemformatan \"perlahan\"" -t MSG_163 "Tanda kotak ini jika anda mahu membuat cakera USB yang boleh-but" -t MSG_164 "Kaedah yang digunakan untuk membuat cakera boleh-but" +t MSG_163 "Tanda kotak ini jika anda mahu membuat cakera USB boot" +t MSG_164 "Kaedah yang digunakan untuk membuat cakera boot" t MSG_165 "Klik untuk memilih imej..." t MSG_166 "Klik kotak ini untuk membenarkan paparan label antarabangsa " "dan menetapkan ikon cakera (akan membuat fail autorun.inf)" t MSG_167 "Memasang MBR yang membenarkan pilihan boot dan mampu menyamar ID BIOS USB" -t MSG_168 "Cuba menyamarkan cakera USB boleh-but (biasanya 0x80) sebagai disk lain.\n" - "Ini hanya diperlukan jika anda memsang Windows XP dan mempunyai lebih daripada satu cakera" -t MSG_169 "Ciptakan partition tambahan tersembunyi dan cuba melaraskan sempadan partition.\n" - "Ini boleh mempertingkatkan pengesanan but untuk BIOS lama" -t MSG_170 "Membolehkan penyenaraian pagaran cakera keras USB. GUNAKAN PADA RISIKO SENDIRI!!!" -t MSG_171 "Mulakan operasi pemformatan.\nIni akan MEMADAMKAN semua data di sasaran!" +t MSG_168 "Cuba menyamarkan cakera USB boot (biasanya 0x80) sebagai cakera lain.\n" + "Ini hanya diperlukan jika anda memasang Windows XP dan mempunyai lebih daripada satu cakera" +t MSG_169 "Ciptakan partisyen tambahan tersembunyi dan cuba melaraskan sempadan partisyen.\n" + "Ini boleh mempertingkatkan pengesanan boot untuk BIOS lama" +t MSG_170 "Membolehkan penyenaraian pagaran cakera keras USB. GUNAKAN ATAS RISIKO SENDIRI!!!" +t MSG_171 "Mulakan operasi pemformatan.\nIni akan MEMADAMKAN semua data pada sasaran!" t MSG_172 "Maklumat pelesenan dan penghargaan" t MSG_173 "Klik untuk memilih..." # The following will appear in the about dialog t MSG_174 "Rufus - Utiliti pemformatan USB yang dipercayai" t MSG_175 "Versi %d.%d (Build %d)" -t MSG_176 "Terjemahan Bahasa Malaysia: Muhammad Aman " +t MSG_176 "Terjemahan Bahasa Malaysia:\\line\n" + "Muhammad Aman \\line\n" + "VGPlayer " t MSG_177 "Laporkan masalah atau cadangan penambahbaikan di:" t MSG_178 "Hak cipta tambahan:" -t MSG_179 "Polisi mengemaskini:" -t MSG_180 "jika anda pilih untuk membenarakan program ini menyemak untuk versi baru, " - "anda bersetuju untuk membenarkan server kami mengumpulkan maklumat berikut:" -t MSG_181 "Versi dan arkitekture sistem operasi" +t MSG_179 "Polisi kemaskini:" +t MSG_180 "jika anda pilih untuk membenarkan aturcara ini menyemak untuk versi baru, " + "anda bersetuju untuk membenarkan pelayan kami mengumpulkan maklumat berikut:" +t MSG_181 "Versi dan kerangka sistem operasi" t MSG_182 "Versi aplikasi yang anda gunakan" -t MSG_183 "IP address anda" -t MSG_184 "Untuk tujuan menjana statistik penggunaan peribadi , kami mungkin menyimpan informasi yang dikumpulkan, " - "\\b untuk sekurang-paling setahun\\b0 . Namun, kami tidak rela untuk mendedahkan informasi ini kepada mana-mana pihak ketiga." +t MSG_183 "Alamat IP anda" +t MSG_184 "Untuk tujuan menjana statistik penggunaan peribadi , kami mungkin menyimpan maklumat yang dikumpulkan, " + "\\b untuk sekurang-kurangnya setahun\\b0 . Namun, kami tidak rela untuk mendedahkan maklumat ini kepada mana-mana pihak ketiga." t MSG_185 "Proses mengemas kini:" t MSG_186 "Rufus tidak memasang atau menjalankan servis di latar belakang. Oleh itu, semakan kemas kini hanya dijalankan apabila aplikasi utama berjalan.\\line\n" - "Akses internet diperlukan untuk menymeak untuk versi baru." + "Akses internet diperlukan untuk menyemak untuk versi baru." t MSG_187 "Imej tidak sah untuk pilihan boot yang dipilih" -t MSG_188 "Imej tidak serasi dengan pilihan boot yang dipilih. Tolong gunakan imej lain atau pilih pilihan boot lain." +t MSG_188 "Imej tidak serasi dengan pilihan boot yang dipilih. Sila gunakan imej lain atau pilih pilihan boot lain." t MSG_189 "Imej ISO ini tidak serasi dengan sistem fail yang dipilih" +t MSG_190 "Pemacu tidak serasi dikesan" +t MSG_191 "Melepasi tulisan" +t MSG_192 "Melepasi bacaan" +t MSG_193 "Muat turun %s" +t MSG_194 "Tidak boleh muat turun %s" +t MSG_195 "Menggunakan %s fail versi dibenam" +#t MSG_196 "PENTING: PEMACU INI MENGGUNAKAN SAIZ SEKTOR BUKAN STANDARD!! (...)" +t MSG_197 "Saiz sektor bukan standard dikesan" +#t MSG_198 "'Windows To Go' hanya boleh dipasang di pemacu dibahagi GPT jika ia ada (...)" +#t MSG_199 "Pilih ini jika anda merancang untuk memasang Windows, ke cakera lain, menggunakan (...)" +t MSG_200 "Pilih ini jika anda mahu untuk menjalankan Windows secara langsung dari peranti dipilih." # Status messages - these messages will appear on the status bar t MSG_201 "Sedang membatalkan - Sila tunggu..." t MSG_202 "Mengimbas imej..." t MSG_203 "Imbasan imej gagal" # Parameter: the name of an obsolete Syslinux .c32 module. eg: "Obsolete vesamenu.c32 detected" -t MSG_204 "%s usang dikesan" +t MSG_204 "%s lapuk dikesan" # Display the name of the ISO selected. eg: "Using ISO: en_win7_x64_sp1.iso" -t MSG_205 "Menggunakan ISO: %s" +t MSG_205 "Menggunakan ISO: %s" -> "Menggunakan imej: %s" # Typically "Missing ldlinux.c32 file" -t MSG_206 "Tidak jumpa fail %s" +t MSG_206 "Tidak menjumpai fail %s" # The name proposed by Windows' Computer Management -> Disk Management when you try to format a drive # with an empty label. See http://rufus.akeo.ie/pics/default_name.png t MSG_207 "Jilid baharu" # Same message, once for singular and plural ("1 device found", "2 devices found") -t MSG_208 "%d peranti dijumpa" -t MSG_209 "%d peranti dijumpa" -t MSG_210 "SELESAI" +t MSG_208 "%d peranti dijumpai" +t MSG_209 "%d peranti dijumpai" +t MSG_210 "SELESAI" -> "SEDIA". t MSG_211 "DIBATALKAN" t MSG_212 "GAGAL" # Used when a new update has been downloaded and launched t MSG_213 "Melancarkan aplikasi baru..." -t MSG_214 "Gagal untuk melancakan aplikasi baru" +t MSG_214 "Gagal untuk melancarkan aplikasi baru" # Open/Save file t MSG_215 "%s dibuka" t MSG_216 "%s disimpan" # Formatting status (make sure you use a double % to print the percent sign) t MSG_217 "Pemformatan: %0.1f%% selesai" t MSG_218 "Mencipta sistem fail: Tugas %d/%d selesai" -t MSG_219 "NTFS Fixup: %d%% selesai" +t MSG_219 "Pembaikian NTFS: %d%% selesai" # Parameter: the file system and an estimated duration in mins and secs. # eg. "Formatting (UDF) - Jangka masa anggaran 3:21..." # NB: if "estimated duration" is too long, just use "estimated" or an abbreviation -t MSG_220 "Pemformattan (%s) - Jangka masa anggaran %d:%02d..." +t MSG_220 "Pemformatan (%s) - Jangka masa anggaran %d:%02d..." t MSG_221 "Menetapkan label (Ini mungkin mengambil sedikit masa)..." # Parameter: the file system. eg. "Formatting (NTFS)..." -t MSG_222 "Pemformattan (%s)..." -t MSG_223 "NTFS Fixup (Checkdisk)..." +t MSG_222 "Pemformatan (%s)..." +t MSG_223 "Pembaikian NTFS (Periksa cakera)..." t MSG_224 "Memadam struktur MBR/PBR/GPT..." t MSG_225 "Meminta akses cakera..." -t MSG_226 "Menganalisis rekod but sedia ada..." +t MSG_226 "Menganalisis rekod boot sedia ada..." t MSG_227 "Menutup jilid sedia ada..." -t MSG_228 "Menulis \"Master boot record\"..." -t MSG_229 "Menulis rekod but partition..." +t MSG_228 "Menulis \"Rekod master boot\"..." +t MSG_229 "Menulis rekod boot partisyen..." t MSG_230 "Menyalin fail DOS..." t MSG_231 "Menyalin fail ISO..." t MSG_232 "Persediaan boot EFI Win7 (ini mungkin mengambil sedikit masa)..." -t MSG_233 "Memuktamadkan, sila tunggu..." +t MSG_233 "Menyiapkan, sila tunggu..." # Takes the Syslinux version as parameter, eg. "Installing Syslinux v5..." t MSG_234 "Memasang Syslinux %s..." # Bad blocks status. eg: "Bad Blocks: PASS 1/2 - 12.34% (0/0/1 errors)" -t MSG_235 "Blok rosak: %s %d/%d - %0.2f%% (%d/%d/%d errors)" +t MSG_235 "Blok rosak: MELEPASI %d/%d - %0.2f%% (%d/%d/%d kesilapan)" -> "Blok rosak: %s %d/%d - %0.2f%% (%d/%d/%d kesilapan)" t MSG_236 "Blok rosak: menguji dengan corak rawak" t MSG_237 "Blok rosak: Menguji dengan corak 0x%02X" # eg. "Partitioning (MBR)..." -t MSG_238 "Mempartition (%s)..." -t MSG_239 "Memadam partition..." +t MSG_238 "Mempartisyenkan (%s)..." +t MSG_239 "Memadam partisyen..." t MSG_240 "Memuat turun %s: menyambung ke internet..." t MSG_241 "memuat turun: %0.1f%%" t MSG_242 "Gagal memuat turun fail." @@ -9980,13 +9996,13 @@ t MSG_244 "Kemas kini: Tidak dapat menyambung ke internet" t MSG_245 "Kemsa kini: Tidak dapat mengakses data versi" t MSG_246 "Versi baru Rufus boleh didapati!" t MSG_247 "Tiada versi baru Rufus didapati" -t MSG_248 "Kekunci registry aplikasi berjaya dipadam" -t MSG_249 "Gagal memadam kekunci registry aplikasi" +t MSG_248 "Kekunci daftar aplikasi berjaya dipadam" +t MSG_249 "Gagal memadam kekunci daftar aplikasi" # eg. "Fixed disk detection enabled" "ISO size check disabled" t MSG_250 "%s dibolehkan" t MSG_251 "%s tidak dibolehkan" t MSG_252 "Menyemak saiz" -t MSG_253 "Pengesanan cakera tetap" +t MSG_253 "Pengesanan cakera tetap" -> "Pengesanan cakera keras" t MSG_254 "Memaksa pemformatan FAT32 besar" t MSG_255 "NoDriveTypeAutorun akan dipadam apabila keluar" t MSG_256 "Pengesanan cakera palsu" @@ -9997,6 +10013,41 @@ t MSG_260 "Mampatan NTFS" t MSG_261 "Menulis imej: %0.1f%% selesai" t MSG_262 "Sokongan ISO" t MSG_263 "Guna saiz seunit yang BETUL" +t MSG_264 "Memadam direktori '%s'" +t MSG_265 "Pengesanan cakera VMWare" +t MSG_266 "Mod dwi UEFI/BIOS" +t MSG_267 "Menggunakan imej Windows: %0.1f%% selesai" +t MSG_268 "Menggunakan imej Windows..." +t MSG_269 "Mengekalkan cap masa" +t MSG_270 "Nyahpijat USB" +t MSG_271 "Mengira semak tambah imej: %0.1f%% selesai" +t MSG_272 "Mengira semak tambah MD5, SHA1 dan SHA256 imej dipilih" +t MSG_273 "Menukar bahasa aplikasi" +t MSG_274 "Imej ISOHybrid dikesan" +# '%s' below will be replaced with your translations for MSG_036 ("ISO Image") and MSG_095 ("DD Image") +t MSG_275 "Imej yang anda telah pilih adalah imej 'ISOHybrid'. Ini bermaksud ia boleh ditulis sama ada dalam " + "%s mod (salinan fail) atau %s mod (imej cakera).\n" + "Rufus galakkan menggunakan mod %s, jadi anda selalu mempunyai akses penuh ke pemacu selepas menulisnya.\n" + "Bagaimanapun, jika anda menghadapi isu-isu semasa boot, anda boleh cuba menulis imej ini lagi dalam mod %s.\n\n" + "Sila pilih mod yang anda mahu guna untuk menulis imej ini:" +# '%s' below will be replaced with your translation for MSG_036 ("ISO Image") +t MSG_276 "Menulis dalam mod %s (Digalakkan)" +# '%s' below will be replaced with your translation for MSG_095 ("DD Image") +t MSG_277 "Menulis dalam mod %s" +# The following will be used for new controls of the Rufus 3.0 interface +# They are added as messages, so that I will have them available when needed. +# 278 & 280 will be dropdown titles, similar to how IDS_DEVICE_TXT or IDS_PARTITION_TYPE_TXT are used +# 279 & 281 will be items that can appear in the dropdowns +t MSG_278 "Jenis boot" +t MSG_279 "Tidak boleh boot" +t MSG_280 "Pilihan imej" +t MSG_281 "(Sila pilih satu imej)" +t MSG_282 "Penguncian pemacu USB eksklusif" +t MSG_283 "tandatangan tidak sah" +t MSG_284 "'Executable' yang dimuat turun kehilangan tandatangan digital." +t MSG_285 "'Executable' yang dimuat turun ditandatangani oleh '%s'.\nIni bukannya tandatangan yang kami kenal dan boleh " + "menunjukkan beberapa bentuk aktiviti berniat jahat...\nAdakah anda pasti anda mahu menjalankan fail ini?" +t MSG_286 "Mensifarkan pemacu: %0.1f%% selesai" ################################################################################ l "nb-NO" "Norwegian (Norsk)" 0x0414 diff --git a/src/rufus.rc b/src/rufus.rc index 1aebff79..60bb0f01 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.853" +CAPTION "Rufus 2.7.854" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,853,0 - PRODUCTVERSION 2,7,853,0 + FILEVERSION 2,7,854,0 + PRODUCTVERSION 2,7,854,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.853" + VALUE "FileVersion", "2.7.854" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.853" + VALUE "ProductVersion", "2.7.854" END END BLOCK "VarFileInfo" From 5e8a4598288e38559227d31c2dc1f4f7cee66203 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Sun, 14 Feb 2016 21:20:47 +0000 Subject: [PATCH 25/91] v2.7 (build 855) --- ChangeLog.txt | 4 ++-- src/rufus.rc | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 0dca37ca..445d6868 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,4 +1,4 @@ -o Version 2.7 (2016.02.??) +o Version 2.7 (2016.02.14) Add Thai translation, courtesy of Sippapas Wangsri Add Drag and Drop support, courtesy of SeymourApps Add a retry for most write operations @@ -6,7 +6,7 @@ o Version 2.7 (2016.02.??) Dual sign Rufus with both SHA-1 and SHA-256 Fix 2nd line of SHA-256 being hidden on some platforms Fix shutdown prevention issues - Additional small fixes + Additional fixes & translation updates o Version 2.6 (2015.12.22) Add Serbian (Latin) translation, courtesy of Ivan Strugar diff --git a/src/rufus.rc b/src/rufus.rc index 60bb0f01..10d062f8 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.854" +CAPTION "Rufus 2.7.855" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,854,0 - PRODUCTVERSION 2,7,854,0 + FILEVERSION 2,7,855,0 + PRODUCTVERSION 2,7,855,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.854" + VALUE "FileVersion", "2.7.855" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.854" + VALUE "ProductVersion", "2.7.855" END END BLOCK "VarFileInfo" From 140236acd6f2bfc316a535761f9d5b1735ba5505 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 15 Feb 2016 12:50:06 +0000 Subject: [PATCH 26/91] [loc] display a note in the log when a translation is behind * Also make sure the messages regarding language pack availability are visible to the users in the log * Also fix a typo in the Malay translation --- res/localization/rufus.loc | 2 +- src/localization.c | 9 ++++++--- src/localization.h | 3 +-- src/parser.c | 3 +-- src/rufus.c | 8 +++++++- src/rufus.h | 4 ++++ src/rufus.rc | 10 +++++----- src/stdio.c | 1 + 8 files changed, 26 insertions(+), 14 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index a2f3e5ba..6033b66b 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -9795,7 +9795,7 @@ t MSG_080 "Rufus mengesan bahawa Windows masih lagi menarik penimbal ke dalam pe "Terutamanya untuk fail besar .\n\nKami cadangkan anda biarkan Windows tamat dahulu untuk mengelakkan korupsi." "Namun, jika anda kesuntukan masa, anda boleh cabutkan peranti anda..." t MSG_081 "ISO tidak disokong" -> "Imej tidak disokong" -t MSG_082 -> "Imej ini sama ada tidak boleh boot, atau ia menggunakan kaedah boot atau mampatan yang tidak disokong oleh Rufus..." +t MSG_082 "Imej ini sama ada tidak boleh boot, atau ia menggunakan kaedah boot atau mampatan yang tidak disokong oleh Rufus..." t MSG_083 "Gantikan %s?" t MSG_084 "Imej ISO ini menggunakan versi '%s' yang telah lapuk.\n" "Oleh sebab ini, menu boot mungkin tidak dipaparkan dengan betul.\n\n" diff --git a/src/localization.c b/src/localization.c index 923e0cab..a3eaad3b 100644 --- a/src/localization.c +++ b/src/localization.c @@ -602,13 +602,15 @@ WORD get_language_id(loc_cmd* lcmd) wchar_t wlang[5]; LANGID lang_id = GetUserDefaultUILanguage(); + // Log will be reset, so we need to use the buffered uprintf() to get our messages to the user + ubclear(); if (lcmd == NULL) return MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); // Find if the selected language is the user default for (i = 0; iunum_size; i++) { if (lcmd->unum[i] == lang_id) { - uprintf("localization: will use default UI language 0x%04X", lang_id); + ubpushf("Will use default UI locale 0x%04X", lang_id); return MAKELANGID(lang_id, SUBLANG_DEFAULT); } } @@ -622,11 +624,12 @@ WORD get_language_id(loc_cmd* lcmd) // boolean to tell us that we found what we were after. EnumUILanguages(EnumUILanguagesProc, 0x4, (LONG_PTR)wlang); // 0x04 = MUI_LANGUAGE_ID if (found_lang) { - uprintf("localization: detected installed language pack for 0x%04X", lcmd->unum[i]); + ubpushf("Detected installed Windows Language Pack for 0x%04X (%s)", lcmd->unum[i], lcmd->txt[1]); return MAKELANGID(lcmd->unum[i], SUBLANG_DEFAULT); } } - uprintf("localization: no matching language pack - some messages will be displayed using default locale"); + ubpushf("NOTE: No Windows Language Pack is installed for %s on this system.\r\n" + "This means that some controls will still be displayed using the system locale.", lcmd->txt[1]); return MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); } diff --git a/src/localization.h b/src/localization.h index c4b1ab9e..1fa9e3c8 100644 --- a/src/localization.h +++ b/src/localization.h @@ -30,8 +30,7 @@ // Attributes that can be set by a translation #define LOC_RIGHT_TO_LEFT 0x00000001 -#define LOC_ARABIC_NUMERALS 0x00000002 -#define LOC_JAPANESE_NUMERALS 0x00000004 +#define LOC_NEEDS_UPDATE 0x00000002 // The [v]ersion major from a translation must match this number or // the translation will be ignored diff --git a/src/parser.c b/src/parser.c index b59abcef..6568102e 100644 --- a/src/parser.c +++ b/src/parser.c @@ -41,8 +41,6 @@ static const char* conversion_error = "Could not convert '%s' to UTF-16"; const struct {char c; int flag;} attr_parse[] = { { 'r', LOC_RIGHT_TO_LEFT }, - { 'a', LOC_ARABIC_NUMERALS }, // NOT IMPLEMENTED - { 'j', LOC_JAPANESE_NUMERALS }, // NOT IMPLEMENTED }; /* @@ -343,6 +341,7 @@ BOOL get_supported_locales(const char* filename) LOC_FRAMEWORK_VERSION, loc_base_minor); } else { if (lcmd->unum[2] < loc_base_micro) { + last_lcmd->ctrl_id |= LOC_NEEDS_UPDATE; luprintf("the version of this translation is older than the base one and may result in some messages not being properly translated.\n" "If you are the translator, please update your translation with the changes that intervened between v%d.%d.%d and v%d.%d.%d.\n" "See https://github.com/pbatard/rufus/blob/master/res/localization/ChangeLog.txt", diff --git a/src/rufus.c b/src/rufus.c index 2ecf99be..6d7da1b6 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -1744,7 +1744,13 @@ void InitDialog(HWND hDlg) uprintf("Syslinux versions: %s%s, %s%s", embedded_sl_version_str[0], embedded_sl_version_ext[0], embedded_sl_version_str[1], embedded_sl_version_ext[1]); uprintf("Grub versions: %s, %s", GRUB4DOS_VERSION, GRUB2_PACKAGE_VERSION); - uprintf("Locale ID: 0x%04X", GetUserDefaultUILanguage()); + uprintf("System locale ID: 0x%04X", GetUserDefaultUILanguage()); + ubpop(); + if (selected_locale->ctrl_id & LOC_NEEDS_UPDATE) { + uprintf("NOTE: The %s translation requires an update, but the current translator hasn't submitted " + "one. Because of this, some messages will only be displayed in English.", selected_locale->txt[1]); + uprintf("If you think you can help update this translation, please e-mail ."); + } SetClusterSizeLabels(); diff --git a/src/rufus.h b/src/rufus.h index cc15adfa..4f174b8f 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -113,6 +113,9 @@ #ifdef RUFUS_DEBUG extern void _uprintf(const char *format, ...); #define uprintf(...) _uprintf(__VA_ARGS__) +#define ubclear() do { ubuffer[0] = 0; } while (0); +#define ubpushf(...) static_sprintf(ubuffer, __VA_ARGS__) +#define ubpop() uprintf("%s", ubuffer) #define vuprintf(...) if (verbose) _uprintf(__VA_ARGS__) #define vvuprintf(...) if (verbose > 1) _uprintf(__VA_ARGS__) #define suprintf(...) if (!bSilent) _uprintf(__VA_ARGS__) @@ -375,6 +378,7 @@ extern int64_t iso_blocking_status; extern uint16_t rufus_version[3], embedded_sl_version[2]; extern int nWindowsVersion; extern char WindowsVersionStr[128]; +extern char ubuffer[256]; extern char embedded_sl_version_str[2][12]; extern RUFUS_UPDATE update; extern int dialog_showing; diff --git a/src/rufus.rc b/src/rufus.rc index 10d062f8..4dcc3756 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.855" +CAPTION "Rufus 2.7.856" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,855,0 - PRODUCTVERSION 2,7,855,0 + FILEVERSION 2,7,856,0 + PRODUCTVERSION 2,7,856,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.855" + VALUE "FileVersion", "2.7.856" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.855" + VALUE "ProductVersion", "2.7.856" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index df8caf5b..af0f9e41 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -38,6 +38,7 @@ * Globals */ HWND hStatus; +char ubuffer[256]; // Buffer for ubpushf() messages we don't log right away #ifdef RUFUS_DEBUG void _uprintf(const char *format, ...) From 58755c1bc4632114f1c30df06b53151da202c8e4 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 15 Feb 2016 23:02:02 +0000 Subject: [PATCH 27/91] [loc] ensure that the log content is displayed LTR * Part of #694 * This avoids weird interpretation of content from Windows' RTL logic * Also fix a WDK compilation error --- src/localization.c | 4 ++-- src/localization.h | 2 +- src/rufus.c | 17 ++++++++++++++++- src/rufus.rc | 10 +++++----- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/localization.c b/src/localization.c index a3eaad3b..e713999f 100644 --- a/src/localization.c +++ b/src/localization.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Localization functions, a.k.a. "Everybody is doing it wrong but me!" - * Copyright © 2013-2015 Pete Batard + * Copyright © 2013-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -630,6 +630,6 @@ WORD get_language_id(loc_cmd* lcmd) } ubpushf("NOTE: No Windows Language Pack is installed for %s on this system.\r\n" - "This means that some controls will still be displayed using the system locale.", lcmd->txt[1]); + "This means that some controls may still be displayed using the system locale.", lcmd->txt[1]); return MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); } diff --git a/src/localization.h b/src/localization.h index 1fa9e3c8..ddb0f01d 100644 --- a/src/localization.h +++ b/src/localization.h @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Localization functions, a.k.a. "Everybody is doing it wrong but me!" - * Copyright © 2013-2014 Pete Batard + * Copyright © 2013-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/rufus.c b/src/rufus.c index 6d7da1b6..28811b82 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -888,7 +888,7 @@ BOOL CALLBACK LogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; HFONT hf; - long lfHeight; + long lfHeight, style; DWORD log_size; char *log_buffer = NULL, *filepath; EXT_DECL(log_ext, "rufus.log", __VA_GROUP__("*.log"), __VA_GROUP__("Rufus log")); @@ -896,6 +896,7 @@ BOOL CALLBACK LogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) case WM_INITDIALOG: apply_localization(IDD_LOG, hDlg); hLog = GetDlgItem(hDlg, IDC_LOG_EDIT); + // Increase the size of our log textbox to MAX_LOG_SIZE (unsigned word) PostMessage(hLog, EM_LIMITTEXT, MAX_LOG_SIZE , 0); // Set the font to Unicode so that we can display anything @@ -908,6 +909,18 @@ BOOL CALLBACK LogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) SendDlgItemMessageA(hDlg, IDC_LOG_EDIT, WM_SETFONT, (WPARAM)hf, TRUE); // Set 'Close Log' as the selected button SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDCANCEL), TRUE); + + // Suppress any inherited RTL flags from our edit control's style. Otherwise + // the displayed text becomes a mess due to Windows trying to interpret + // dots, parenthesis, columns and so on in an RTL context... + // We also take this opportunity to fix the scroll bar and text alignment. + style = GetWindowLong(hLog, GWL_EXSTYLE); + style &= ~(WS_EX_RTLREADING | WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR); + SetWindowLong(hLog, GWL_EXSTYLE, style); + style = GetWindowLong(hLog, GWL_STYLE); + style &= ~(ES_RIGHT); + SetWindowLong(hLog, GWL_STYLE, style); + break; case WM_COMMAND: switch (LOWORD(wParam)) { @@ -2835,7 +2848,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine }; // Disable loading system DLLs from the current directory (sideloading mitigation) +#ifndef DDKBUILD // WDK doesn't know about that one SetDllDirectoryA(""); +#endif uprintf("*** " APPLICATION_NAME " init ***\n"); diff --git a/src/rufus.rc b/src/rufus.rc index 4dcc3756..58e94ab3 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.856" +CAPTION "Rufus 2.7.857" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,856,0 - PRODUCTVERSION 2,7,856,0 + FILEVERSION 2,7,857,0 + PRODUCTVERSION 2,7,857,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.856" + VALUE "FileVersion", "2.7.857" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.856" + VALUE "ProductVersion", "2.7.857" END END BLOCK "VarFileInfo" From f88faf1a4f74dca1c88e2324acb041b094b0f999 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 16 Feb 2016 17:47:07 +0000 Subject: [PATCH 28/91] [usb] enable listing of non USB card readers * Also fix the VID:PID population of USB card readers * Also improve enumeration debugging * Also add an unofficial cheat mode to list non USB *REMOVABLE* drives * Closes #693 --- src/drive.c | 8 +- src/format.c | 2 +- src/rufus.c | 25 ++++- src/rufus.rc | 10 +- src/usb.c | 284 ++++++++++++++++++++++++++++++++++++--------------- src/usb.h | 19 ++-- 6 files changed, 248 insertions(+), 100 deletions(-) diff --git a/src/drive.c b/src/drive.c index 0e6c3711..65980555 100644 --- a/src/drive.c +++ b/src/drive.c @@ -395,10 +395,10 @@ static BOOL _GetDriveLettersAndType(DWORD DriveIndex, char* drive_letters, UINT* 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. */ + // 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#issuecomment-3785956 _drive_type = GetDriveTypeA(drive); if ((_drive_type != DRIVE_REMOVABLE) && (_drive_type != DRIVE_FIXED)) diff --git a/src/format.c b/src/format.c index b70d8e9c..0c2c8487 100644 --- a/src/format.c +++ b/src/format.c @@ -1883,7 +1883,7 @@ DWORD WINAPI FormatThread(void* param) } else if (tt == TT_UEFI) { // For once, no need to do anything - just check our sanity if ( (bt != BT_ISO) || (!img_report.has_efi) || (fs > FS_NTFS) ) { - uprintf("Spock gone crazy error!\n"); + uprintf("Spock gone crazy error in %s:%d", __FILE__, __LINE__); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INSTALL_FAILURE; goto out; } diff --git a/src/rufus.c b/src/rufus.c index 28811b82..377449e9 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -152,7 +152,7 @@ BOOL use_own_c32[NB_OLD_C32] = {FALSE, FALSE}, mbr_selected_by_user = FALSE, tog BOOL iso_op_in_progress = FALSE, format_op_in_progress = FALSE, right_to_left_mode = FALSE; BOOL enable_HDDs = FALSE, force_update = FALSE, enable_ntfs_compression = FALSE, no_confirmation_on_cancel = FALSE, lock_drive = TRUE; BOOL advanced_mode, allow_dual_uefi_bios, detect_fakes, enable_vmdk, force_large_fat32, usb_debug, use_fake_units, preserve_timestamps; -BOOL zero_drive = FALSE; +BOOL zero_drive = FALSE, list_non_usb_removable_drives = FALSE; int dialog_showing = 0, lang_button_id = 0; uint16_t rufus_version[3], embedded_sl_version[2]; char embedded_sl_version_str[2][12] = { "?.??", "?.??" }; @@ -1762,7 +1762,7 @@ void InitDialog(HWND hDlg) if (selected_locale->ctrl_id & LOC_NEEDS_UPDATE) { uprintf("NOTE: The %s translation requires an update, but the current translator hasn't submitted " "one. Because of this, some messages will only be displayed in English.", selected_locale->txt[1]); - uprintf("If you think you can help update this translation, please e-mail ."); + uprintf("If you think you can help update this translation, please e-mail the author of this application"); } SetClusterSizeLabels(); @@ -2826,6 +2826,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine int wait_for_mutex = 0; FILE* fd; BOOL attached_console = FALSE, external_loc_file = FALSE, lgp_set = FALSE, automount, disable_hogger = FALSE; + BOOL previous_enable_HDDs = FALSE; BYTE *loc_data; DWORD loc_size, size; char tmp_path[MAX_PATH] = "", loc_file[MAX_PATH] = "", ini_path[MAX_PATH], ini_flags[] = "rb"; @@ -3278,6 +3279,26 @@ relaunch: PostMessage(hDlg, WM_COMMAND, (WPARAM)IDC_START, 0); } + // Hazardous cheat modes require Ctrl + Alt + // Ctrl-Alt-F => List non USB removable drives such as eSATA, etc - CAUTION!!! + if ((msg.message == WM_KEYDOWN) && (msg.wParam == 'F') && + (GetKeyState(VK_CONTROL) & 0x8000) && (GetKeyState(VK_MENU) & 0x8000)) { + list_non_usb_removable_drives = !list_non_usb_removable_drives; + if (list_non_usb_removable_drives) { + previous_enable_HDDs = enable_HDDs; + enable_HDDs = TRUE; + } else { + enable_HDDs = previous_enable_HDDs; + } + CheckDlgButton(hMainDialog, IDC_ENABLE_FIXED_DISKS, enable_HDDs ? BST_CHECKED : BST_UNCHECKED); + PrintStatus2000("Listing of non-USB removable drives", list_non_usb_removable_drives); + uprintf("NOTE: Listing of non-USB removable drives has been %s.", (list_non_usb_removable_drives)?"enabled (CAUTION!)":"disabled"); + if (list_non_usb_removable_drives) + uprintf("By using this unofficial cheat mode you forfeit ANY RIGHT to complain if you lose valuable data!"); + GetUSBDevices(0); + continue; + } + // Let the system handle dialog messages (e.g. those from the tab key) if (!IsDialogMessage(hDlg, &msg) && !IsDialogMessage(hLogDlg, &msg)) { TranslateMessage(&msg); diff --git a/src/rufus.rc b/src/rufus.rc index 58e94ab3..4e650db2 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.857" +CAPTION "Rufus 2.7.858" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,857,0 - PRODUCTVERSION 2,7,857,0 + FILEVERSION 2,7,858,0 + PRODUCTVERSION 2,7,858,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.857" + VALUE "FileVersion", "2.7.858" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.857" + VALUE "ProductVersion", "2.7.858" END END BLOCK "VarFileInfo" diff --git a/src/usb.c b/src/usb.c index 8954d23b..acf0246c 100644 --- a/src/usb.c +++ b/src/usb.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * USB device listing - * Copyright 2014 Pete Batard + * Copyright 2014-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,7 +41,7 @@ #include "usb.h" extern StrArray DriveID, DriveLabel; -extern BOOL enable_HDDs, use_fake_units, enable_vmdk, usb_debug; +extern BOOL enable_HDDs, use_fake_units, enable_vmdk, usb_debug, list_non_usb_removable_drives; /* * Get the VID, PID and current device speed @@ -133,6 +133,17 @@ static __inline BOOL IsVHD(const char* buffer) return FALSE; } +static __inline BOOL IsRemovable(const char* buffer) +{ + switch (*((DWORD*)buffer)) { + case CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL: + case CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL: + return TRUE; + default: + return FALSE; + } +} + /* For debugging user reports of HDDs vs UFDs */ //#define FORCED_DEVICE #ifdef FORCED_DEVICE @@ -146,29 +157,50 @@ static __inline BOOL IsVHD(const char* buffer) */ BOOL GetUSBDevices(DWORD devnum) { - // The first two are standard Microsoft drivers (including the Windows 8 UASP one). - // The rest are the vendor UASP drivers I know of so far - list may be incomplete! - const char* storage_name[] = { "USBSTOR", "UASPSTOR", "VUSBSTOR", "ETRONSTOR", "ASUSSTPT" }; - const char* scsi_name = "SCSI"; + // List of USB storage drivers we know - list may be incomplete! + const char* usbstor_name[] = { + // Standard MS USB storage driver + "USBSTOR", + // USB card readers, with proprietary drivers (Realtek,etc...) + // Mostly "guessed" from http://www.carrona.org/dvrref.php + "RTSUER", "CMIUCR", "EUCR", + // UASP Drivers *MUST* be listed after this, starting with "UASPSTOR" + // (which is Microsoft's native UASP driver for Windows 8 and later) + // as we use "UASPSTOR" as a delimiter + "UASPSTOR", "VUSBSTOR", "ETRONSTOR", "ASUSSTPT" + }; + // These are the generic (non USB) storage enumerators we also test + const char* genstor_name[] = { + // Generic storage drivers (Careful now!) + "SCSI", // "STORAGE", // "STORAGE" is used by 'Storage Spaces" and stuff => DANGEROUS! + // Non-USB card reader drivers - *MUST* start with "SD" (delimiter) + // See http://itdoc.hitachi.co.jp/manuals/3021/30213B5200e/DMDS0094.HTM + // Also http://www.carrona.org/dvrref.php. NB: These should be reported + // as enumerators by Rufus when Enum Debug is enabled + "SD", "PCISTOR", "RTSOR", "JMCR", "JMCF", "RIMMPTSK", "RIMSPTSK", "RIXDPTSK", + "TI21SONY", "ESD7SK", "ESM7SK", "O2MD", "O2SD", "VIACR" + }; const char* usb_speed_name[USB_SPEED_MAX] = { "USB", "USB 1.0", "USB 1.1", "USB 2.0", "USB 3.0" }; // Hash table and String Array used to match a Device ID with the parent hub's Device Interface Path htab_table htab_devid = HTAB_EMPTY; StrArray dev_if_path; char letter_name[] = " (?:)"; + char drive_name[] = "?:\\"; char uefi_togo_check[] = "?:\\EFI\\Rufus\\ntfs_x64.efi"; - BOOL r = FALSE, found = FALSE, is_SCSI, post_backslash; + BOOL r = FALSE, found = FALSE, post_backslash; HDEVINFO dev_info = NULL; SP_DEVINFO_DATA dev_info_data; SP_DEVICE_INTERFACE_DATA devint_data; PSP_DEVICE_INTERFACE_DETAIL_DATA_A devint_detail_data; - DEVINST parent_inst, grandparent_inst, device_inst; + DEVINST parent_inst, grandparent_inst, sibling_inst, device_inst; DWORD size, i, j, k, l, datatype, drive_index; - ULONG list_size[ARRAYSIZE(storage_name)] = { 0 }, list_start[ARRAYSIZE(storage_name)] = { 0 }, full_list_size, ulFlags; + DWORD uasp_start = ARRAYSIZE(usbstor_name), card_start = ARRAYSIZE(genstor_name); + ULONG list_size[ARRAYSIZE(usbstor_name)] = { 0 }, list_start[ARRAYSIZE(usbstor_name)] = { 0 }, full_list_size, ulFlags; HANDLE hDrive; LONG maxwidth = 0; int s, score, drive_number, remove_drive; char drive_letters[27], *device_id, *devid_list = NULL, entry_msg[128]; - char *label, *entry, buffer[MAX_PATH], str[MAX_PATH], *method_str; + char *p, *label, *entry, buffer[MAX_PATH], str[MAX_PATH], *method_str; usb_device_props props; IGNORE_RETVAL(ComboBox_ResetContent(hDeviceList)); @@ -235,29 +267,47 @@ BOOL GetUSBDevices(DWORD devnum) ulFlags = CM_GETIDLIST_FILTER_SERVICE; if (nWindowsVersion >= WINDOWS_7) ulFlags |= CM_GETIDLIST_FILTER_PRESENT; - for (s=0; s= ARRAYSIZE(usbstor_name))) { + uprintf("Spock gone crazy error in %s:%d", __FILE__, __LINE__); + goto out; + } + if ((card_start <= 0) || (card_start >= ARRAYSIZE(genstor_name))) { + uprintf("Spock gone crazy error in %s:%d", __FILE__, __LINE__); + goto out; + } devid_list = NULL; if (full_list_size != 0) { full_list_size += 1; // add extra NUL terminator devid_list = (char*)malloc(full_list_size); if (devid_list == NULL) { uprintf("Could not allocate Device ID list\n"); - return FALSE; + goto out; } - for (s=0, i=0; s 1) { - if (CM_Get_Device_ID_ListA(storage_name[s], &devid_list[i], list_size[s], ulFlags) != CR_SUCCESS) + if (CM_Get_Device_ID_ListA(usbstor_name[s], &devid_list[i], list_size[s], ulFlags) != CR_SUCCESS) continue; if (usb_debug) { - uprintf("Processing IDs belonging to %s:", storage_name[s]); + uprintf("Processing IDs belonging to '%s':", usbstor_name[s]); for (device_id = &devid_list[i]; *device_id != 0; device_id += strlen(device_id) + 1) uprintf(" %s", device_id); } @@ -270,7 +320,7 @@ BOOL GetUSBDevices(DWORD devnum) } } - // Now use SetupDi to enumerate all our storage devices + // Now use SetupDi to enumerate all our disk storage devices dev_info = SetupDiGetClassDevsA(&_GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); if (dev_info == INVALID_HANDLE_VALUE) { uprintf("SetupDiGetClassDevs (Interface) failed: %s\n", WindowsErrorString()); @@ -279,24 +329,49 @@ BOOL GetUSBDevices(DWORD devnum) dev_info_data.cbSize = sizeof(dev_info_data); for (i=0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) { memset(buffer, 0, sizeof(buffer)); + memset(&props, 0, sizeof(props)); method_str = ""; if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME, &datatype, (LPBYTE)buffer, sizeof(buffer), &size)) { uprintf("SetupDiGetDeviceRegistryProperty (Enumerator Name) failed: %s\n", WindowsErrorString()); continue; } - // UASP drives are listed under SCSI (along with regular SYSTEM drives => "DANGER, WILL ROBINSON!!!") - is_SCSI = (safe_stricmp(buffer, scsi_name) == 0); - if ((safe_stricmp(buffer, storage_name[0]) != 0) && (!is_SCSI)) + + for (j = 0; j < ARRAYSIZE(usbstor_name); j++) { + if (safe_stricmp(buffer, usbstor_name[0]) == 0) { + props.is_USB = TRUE; + if ((j != 0) && (j < uasp_start)) + props.is_CARD = TRUE; + break; + } + } + + // UASP drives are listed under SCSI, and we also have non USB card readers to populate + for (j = 0; j < ARRAYSIZE(genstor_name); j++) { + if (safe_stricmp(buffer, genstor_name[j]) == 0) { + props.is_SCSI = TRUE; + if (j >= card_start) + props.is_CARD = TRUE; + break; + } + } + + uuprintf("Processing '%s' device:", buffer); + if ((!props.is_USB) && (!props.is_SCSI)) { + uuprintf(" Disabled by policy"); continue; + } // We can't use the friendly name to find if a drive is a VHD, as friendly name string gets translated // according to your locale, so we poke the Hardware ID - memset(&props, 0, sizeof(props)); memset(buffer, 0, sizeof(buffer)); props.is_VHD = SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_HARDWAREID, &datatype, (LPBYTE)buffer, sizeof(buffer), &size) && IsVHD(buffer); - uuprintf("Processing Device: '%s'", buffer); + uuprintf(" Hardware ID: '%s'", buffer); + + memset(buffer, 0, sizeof(buffer)); + props.is_Removable = SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_REMOVAL_POLICY, + &datatype, (LPBYTE)buffer, sizeof(buffer), &size) && IsRemovable(buffer); memset(buffer, 0, sizeof(buffer)); if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_FRIENDLYNAME, @@ -307,72 +382,92 @@ BOOL GetUSBDevices(DWORD devnum) } else if ((!props.is_VHD) && (devid_list != NULL)) { // Get the properties of the device. We could avoid doing this lookup every time by keeping // a lookup table, but there shouldn't be that many USB storage devices connected... - // NB: Each of these Device IDs have an _only_ child, from which we get the Device Instance match. + // NB: Each of these Device IDs should have a child, from which we get the Device Instance match. for (device_id = devid_list; *device_id != 0; device_id += strlen(device_id) + 1) { - if ( (CM_Locate_DevNodeA(&parent_inst, device_id, 0) == CR_SUCCESS) - && (CM_Get_Child(&device_inst, parent_inst, 0) == CR_SUCCESS) - && (device_inst == dev_info_data.DevInst) ) { - post_backslash = FALSE; - method_str = ""; - - // If we're not dealing with the USBSTOR part of our list, then this is an UASP device - props.is_UASP = ((((uintptr_t)device_id)+2) >= ((uintptr_t)devid_list)+list_start[1]); - // Now get the properties of the device, and its Device ID, which we need to populate the properties - j = htab_hash(device_id, &htab_devid); - uuprintf(" Matched with ID[%03d]: %s", j, device_id); - - // Try to parse the current device_id string for VID:PID - // We'll use that if we can't get anything better - for (k = 0, l = 0; (k 0), - // we might have an extra vendor driver in between (e.g. "ASUS USB 3.0 Boost Storage Driver" - // for UASP devices in ASUS "Turbo Mode" or "Apple Mobile Device USB Driver" for iPods) - // so try to see if we can match the grandparent. - if ( ((uintptr_t)htab_devid.table[j].data == 0) - && (CM_Get_Parent(&grandparent_inst, parent_inst, 0) == CR_SUCCESS) - && (CM_Get_Device_IDA(grandparent_inst, str, MAX_PATH, 0) == CR_SUCCESS) ) { - device_id = str; - method_str = "[GP]"; - j = htab_hash(device_id, &htab_devid); - uuprintf(" Matched with (GP) ID[%03d]: %s", j, device_id); - } - if ((uintptr_t)htab_devid.table[j].data > 0) { - uuprintf(" Matched with Hub[%d]: '%s'", (uintptr_t)htab_devid.table[j].data, - dev_if_path.String[(uintptr_t)htab_devid.table[j].data]); - if (GetUSBProperties(dev_if_path.String[(uintptr_t)htab_devid.table[j].data], device_id, &props)) - method_str = ""; -#ifdef FORCED_DEVICE - props.vid = FORCED_VID; - props.pid = FORCED_PID; - safe_strcpy(buffer, sizeof(buffer), FORCED_NAME); -#endif - } - break; + if (device_inst != dev_info_data.DevInst) + continue; } + post_backslash = FALSE; + method_str = ""; + + // If we're not dealing with the USBSTOR part of our list, then this is an UASP device + props.is_UASP = ((((uintptr_t)device_id)+2) >= ((uintptr_t)devid_list)+list_start[uasp_start]); + // Now get the properties of the device, and its Device ID, which we need to populate the properties + j = htab_hash(device_id, &htab_devid); + uuprintf(" Matched with ID[%03d]: %s", j, device_id); + + // Try to parse the current device_id string for VID:PID + // We'll use that if we can't get anything better + for (k = 0, l = 0; (k 0), + // we might have an extra vendor driver in between (e.g. "ASUS USB 3.0 Boost Storage Driver" + // for UASP devices in ASUS "Turbo Mode" or "Apple Mobile Device USB Driver" for iPods) + // so try to see if we can match the grandparent. + if ( ((uintptr_t)htab_devid.table[j].data == 0) + && (CM_Get_Parent(&grandparent_inst, parent_inst, 0) == CR_SUCCESS) + && (CM_Get_Device_IDA(grandparent_inst, str, MAX_PATH, 0) == CR_SUCCESS) ) { + device_id = str; + method_str = "[GP]"; + j = htab_hash(device_id, &htab_devid); + uuprintf(" Matched with (GP) ID[%03d]: %s", j, device_id); + } + if ((uintptr_t)htab_devid.table[j].data > 0) { + uuprintf(" Matched with Hub[%d]: '%s'", (uintptr_t)htab_devid.table[j].data, + dev_if_path.String[(uintptr_t)htab_devid.table[j].data]); + if (GetUSBProperties(dev_if_path.String[(uintptr_t)htab_devid.table[j].data], device_id, &props)) + method_str = ""; +#ifdef FORCED_DEVICE + props.vid = FORCED_VID; + props.pid = FORCED_PID; + safe_strcpy(buffer, sizeof(buffer), FORCED_NAME); +#endif + } + break; } } if (props.is_VHD) { uprintf("Found VHD device '%s'", buffer); + } else if ((props.is_CARD) && ((!props.is_USB) || ((props.vid == 0) && (props.pid == 0)))) { + uprintf("Found card reader device '%s'", buffer); + } else if ((!props.is_USB) && (props.is_Removable) && (!props.is_UASP)) { + uprintf("Found non-USB removable device '%s'", buffer); } else { if ((props.vid == 0) && (props.pid == 0)) { - if (is_SCSI) { - // If we have an SCSI drive and couldn't get a VID:PID, we are most likely - // dealing with a system drive => eliminate it! - uuprintf(" Non USB => Eliminated"); + if (!props.is_USB) { + // If we have a non removable SCSI drive and couldn't get a VID:PID, + // we are most likely dealing with a system drive => eliminate it! + uuprintf(" Non-USB or non-removable => Eliminated"); continue; } safe_strcpy(str, sizeof(str), "????:????"); // Couldn't figure VID:PID @@ -444,11 +539,36 @@ BOOL GetUSBDevices(DWORD devnum) } if (GetDriveLabel(drive_index, drive_letters, &label)) { - if ((!enable_HDDs) && (!props.is_VHD) && + if ((props.is_SCSI) && (!props.is_UASP) && (!props.is_VHD)) { + if (!props.is_Removable) { + // Non removables should have been eliminated above, but since we + // are potentially dealing with system drives, better safe than sorry + safe_closehandle(hDrive); + safe_free(devint_detail_data); + break; + } + if (!list_non_usb_removable_drives) { + // Go over the mounted partitions and find if GetDriveType() says they are + // removable. If they are not removable, don't allow the drive to be listed + for (p = drive_letters; *p; p++) { + drive_name[0] = *p; + if (GetDriveTypeA(drive_name) != DRIVE_REMOVABLE) + break; + } + if (*p) { + uprintf("Device eliminated because it contains a mounted partition that is set as non-removable"); + safe_closehandle(hDrive); + safe_free(devint_detail_data); + break; + } + } + } + if ((!enable_HDDs) && (!props.is_VHD) && (!props.is_CARD) && ((score = IsHDD(drive_index, (uint16_t)props.vid, (uint16_t)props.pid, buffer)) > 0)) { - uprintf("Device eliminated because it was detected as an USB Hard Drive (score %d > 0)\n", score); - uprintf("If this device is not an USB Hard Drive, please e-mail the author of this application\n"); - uprintf("NOTE: You can enable the listing of USB Hard Drives in 'Advanced Options' (after clicking the white triangle)"); + uprintf("Device eliminated because it was detected as a Hard Drive (score %d > 0)", score); + if (!list_non_usb_removable_drives) + uprintf("If this device is not a Hard Drive, please e-mail the author of this application"); + uprintf("NOTE: You can enable the listing of Hard Drives in 'Advanced Options' (after clicking the white triangle)"); safe_closehandle(hDrive); safe_free(devint_detail_data); break; diff --git a/src/usb.h b/src/usb.h index ece838b7..d67e018c 100644 --- a/src/usb.h +++ b/src/usb.h @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * USB device listing - * Copyright 2014 Pete Batard + * Copyright 2014-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,8 +32,12 @@ typedef struct usb_device_props { uint32_t pid; uint32_t speed; uint32_t port; + BOOLEAN is_USB; + BOOLEAN is_SCSI; + BOOLEAN is_CARD; BOOLEAN is_UASP; BOOLEAN is_VHD; + BOOLEAN is_Removable; BOOLEAN is_LowerSpeed; } usb_device_props; @@ -46,12 +50,15 @@ typedef DWORD RETURN_TYPE; typedef RETURN_TYPE CONFIGRET; typedef CHAR *DEVINSTID_A; -#define CR_SUCCESS 0x00000000 -#define CR_NO_SUCH_DEVNODE 0x0000000D -#define CM_GETIDLIST_FILTER_SERVICE 0x00000002 +#define CR_SUCCESS 0x00000000 +#define CR_NO_SUCH_DEVNODE 0x0000000D +#define CM_GETIDLIST_FILTER_SERVICE 0x00000002 +#define CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL 0x00000001 +#define CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL 0x00000002 +#define CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL 0x00000003 // /!\ The following flag is only available on Windows 7 or later! -#define CM_GETIDLIST_FILTER_PRESENT 0x00000100 -#define CM_DRP_ADDRESS 0x0000001D +#define CM_GETIDLIST_FILTER_PRESENT 0x00000100 +#define CM_DRP_ADDRESS 0x0000001D #ifndef METHOD_BUFFERED #define METHOD_BUFFERED 0 From 9ebdecc124a7b7f028b6c7ce22dcb69b781f52b5 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 17 Feb 2016 11:38:12 +0000 Subject: [PATCH 29/91] [ui] fix label not being blanked on device removal * Part of #694 * Also set rufus-next to 2.8 --- configure | 20 ++++++++++---------- configure.ac | 2 +- src/rufus.c | 8 +++++--- src/rufus.rc | 10 +++++----- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/configure b/configure index db419884..8812587f 100644 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for rufus 2.7. +# Generated by GNU Autoconf 2.69 for rufus 2.8. # # Report bugs to . # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='rufus' PACKAGE_TARNAME='rufus' -PACKAGE_VERSION='2.7' -PACKAGE_STRING='rufus 2.7' +PACKAGE_VERSION='2.8' +PACKAGE_STRING='rufus 2.8' PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues' PACKAGE_URL='http://rufus.akeo.ie' @@ -1228,7 +1228,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures rufus 2.7 to adapt to many kinds of systems. +\`configure' configures rufus 2.8 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1294,7 +1294,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of rufus 2.7:";; + short | recursive ) echo "Configuration of rufus 2.8:";; esac cat <<\_ACEOF @@ -1385,7 +1385,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -rufus configure 2.7 +rufus configure 2.8 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1440,7 +1440,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by rufus $as_me 2.7, which was +It was created by rufus $as_me 2.8, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2303,7 +2303,7 @@ fi # Define the identity of the package. PACKAGE='rufus' - VERSION='2.7' + VERSION='2.8' cat >>confdefs.h <<_ACEOF @@ -4480,7 +4480,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by rufus $as_me 2.7, which was +This file was extended by rufus $as_me 2.8, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4534,7 +4534,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -rufus config.status 2.7 +rufus config.status 2.8 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 32ecdfc5..b40bed1f 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([rufus], [2.7], [https://github.com/pbatard/rufus/issues], [rufus], [http://rufus.akeo.ie]) +AC_INIT([rufus], [2.8], [https://github.com/pbatard/rufus/issues], [rufus], [http://rufus.akeo.ie]) AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies]) AC_CONFIG_SRCDIR([src/rufus.c]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/src/rufus.c b/src/rufus.c index 377449e9..8c42f241 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -702,10 +702,12 @@ static BOOL PopulateProperties(int ComboIndex) memset(&SelectedDrive, 0, sizeof(SelectedDrive)); if (ComboIndex < 0) - return TRUE; + goto out; - if (!SetDriveInfo(ComboIndex)) // This also populates FS + if (!SetDriveInfo(ComboIndex)) { // This also populates FS + SetProposedLabel(-1); return FALSE; + } SetTargetSystem(); SetFSFromISO(); EnableBootOptions(TRUE, TRUE); @@ -723,8 +725,8 @@ static BOOL PopulateProperties(int ComboIndex) free(device_tooltip); } +out: SetProposedLabel(ComboIndex); - return TRUE; } diff --git a/src/rufus.rc b/src/rufus.rc index 4e650db2..9b43696e 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.7.858" +CAPTION "Rufus 2.8.859" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,7,858,0 - PRODUCTVERSION 2,7,858,0 + FILEVERSION 2,8,859,0 + PRODUCTVERSION 2,8,859,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.7.858" + VALUE "FileVersion", "2.8.859" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.7.858" + VALUE "ProductVersion", "2.8.859" END END BLOCK "VarFileInfo" From d3c9afa2fd525b5ab6eba71aedfda33e88c608aa Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 19 Feb 2016 12:10:17 +0000 Subject: [PATCH 30/91] [ui] improve removal of <8MB devices * Closes #692 --- src/rufus.c | 5 ----- src/rufus.h | 1 + src/rufus.rc | 10 +++++----- src/usb.c | 6 ++++++ 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/rufus.c b/src/rufus.c index 8c42f241..b58cab78 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -227,10 +227,6 @@ static BOOL DefineClusterSizes(void) default_fs = FS_UNKNOWN; memset(&SelectedDrive.ClusterSize, 0, sizeof(SelectedDrive.ClusterSize)); - if (SelectedDrive.DiskSize < 8*MB) { - uprintf("Device was eliminated because it is smaller than 8 MB\n"); - goto out; - } /* * The following are MS's allowed cluster sizes for FAT16 and FAT32: @@ -343,7 +339,6 @@ static BOOL DefineClusterSizes(void) } } -out: // Only add the filesystems we can service for (fs=0; fs Date: Sat, 20 Feb 2016 22:52:32 +0000 Subject: [PATCH 31/91] [misc] add missing.h header * Also clean up code --- src/.msvc/rufus.vcxproj | 1 + src/.msvc/rufus.vcxproj.filters | 3 + src/badblocks.c | 11 +- src/checksum.c | 3 +- src/dos.c | 3 +- src/drive.c | 18 +-- src/format.c | 8 +- src/icon.c | 2 +- src/iso.c | 87 +------------ src/missing.h | 214 ++++++++++++++++++++++++++++++++ src/net.c | 34 +---- src/parser.c | 1 + src/pki.c | 4 +- src/rufus.c | 68 ++-------- src/rufus.h | 30 ----- src/rufus.rc | 10 +- src/smart.c | 13 +- src/stdfn.c | 5 +- src/stdio.c | 2 +- src/stdlg.c | 5 +- src/syslinux.c | 5 +- src/usb.c | 8 +- src/vhd.c | 12 +- 23 files changed, 289 insertions(+), 258 deletions(-) create mode 100644 src/missing.h diff --git a/src/.msvc/rufus.vcxproj b/src/.msvc/rufus.vcxproj index 5992d19d..be5ef45f 100644 --- a/src/.msvc/rufus.vcxproj +++ b/src/.msvc/rufus.vcxproj @@ -209,6 +209,7 @@ + diff --git a/src/.msvc/rufus.vcxproj.filters b/src/.msvc/rufus.vcxproj.filters index bd16ab97..41f2ae8a 100644 --- a/src/.msvc/rufus.vcxproj.filters +++ b/src/.msvc/rufus.vcxproj.filters @@ -137,6 +137,9 @@ Header Files + + Header Files + diff --git a/src/badblocks.c b/src/badblocks.c index c5ac77f3..571625d9 100644 --- a/src/badblocks.c +++ b/src/badblocks.c @@ -7,7 +7,7 @@ * * Copyright 1995, 1996, 1997, 1998, 1999 by Theodore Ts'o * Copyright 1999 by David Beattie - * Copyright 2011-2015 by Pete Batard + * Copyright 2011-2016 by Pete Batard * * This file is based on the minix file system programs fsck and mkfs * written and copyrighted by Linus Torvalds @@ -42,11 +42,12 @@ #include #include "rufus.h" +#include "resource.h" +#include "msapi_utf8.h" +#include "localization.h" + #include "badblocks.h" #include "file.h" -#include "msapi_utf8.h" -#include "resource.h" -#include "localization.h" FILE* log_fd = NULL; static const char* abort_msg = "Too many bad blocks, aborting test\n"; @@ -257,7 +258,7 @@ static bb_badblocks_iterate bb_iter = NULL; static __inline void *allocate_buffer(size_t size) { #ifdef __MINGW32__ return __mingw_aligned_malloc(size, BB_SYS_PAGE_SIZE); -#else +#else return _aligned_malloc(size, BB_SYS_PAGE_SIZE); #endif } diff --git a/src/checksum.c b/src/checksum.c index 7637b54b..4e429d2f 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -51,9 +51,10 @@ #include #include #include -#include "msapi_utf8.h" + #include "rufus.h" #include "resource.h" +#include "msapi_utf8.h" #include "localization.h" #undef BIG_ENDIAN_HOST diff --git a/src/dos.c b/src/dos.c index 69cc467d..0f506dc9 100644 --- a/src/dos.c +++ b/src/dos.c @@ -31,9 +31,10 @@ #include #include "rufus.h" -#include "dos.h" #include "resource.h" +#include "dos.h" + static BYTE* DiskImage = NULL; static DWORD DiskImageSize; diff --git a/src/drive.c b/src/drive.c index 65980555..894b2873 100644 --- a/src/drive.c +++ b/src/drive.c @@ -26,17 +26,19 @@ #include #include -#include "msapi_utf8.h" #include "rufus.h" +#include "missing.h" +#include "resource.h" +#include "msapi_utf8.h" +#include "localization.h" + #include "file.h" #include "drive.h" -#include "resource.h" #include "sys_types.h" #include "br.h" #include "fat16.h" #include "fat32.h" #include "ntfs.h" -#include "localization.h" #if !defined(PARTITION_BASIC_DATA_GUID) const GUID PARTITION_BASIC_DATA_GUID = @@ -1045,7 +1047,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m // Compute the start offset of our first partition if ((partition_style == PARTITION_STYLE_GPT) || (!IsChecked(IDC_EXTRA_PARTITION))) { // Go with the MS 1 MB wastage at the beginning... - DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = 1024*1024; + DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = MB; } else { // Align on Cylinder DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = bytes_per_track; @@ -1054,7 +1056,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m // If required, set the MSR partition (GPT only - must be created before the data part) if ((partition_style == PARTITION_STYLE_GPT) && (extra_partitions & XP_MSR)) { uprintf("Adding MSR partition"); - DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = 128*1024*1024; + DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = 128*MB; DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_MSFT_RESERVED_GUID; IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId)); // coverity[strcpy_overrun] @@ -1090,11 +1092,11 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m // The size of the EFI partition depends on the minimum size we're able to format in FAT32, // which in turn depends on the cluster size used, which in turn depends on the disk sector size. if (SelectedDrive.Geometry.BytesPerSector <= 1024) - ms_efi_size = 100*1024*1024; + ms_efi_size = 100*MB; else if (SelectedDrive.Geometry.BytesPerSector <= 4096) - ms_efi_size = 300*1024*1024; + ms_efi_size = 300*MB; else - ms_efi_size = 1200*1024*1024; // That'll teach you to have a nonstandard disk! + ms_efi_size = 1200*MB; // That'll teach you to have a nonstandard disk! extra_part_size_in_tracks = (ms_efi_size + bytes_per_track - 1) / bytes_per_track; } else if (extra_partitions & XP_UEFI_NTFS) extra_part_size_in_tracks = (MIN_EXTRA_PART_SIZE + bytes_per_track - 1) / bytes_per_track; diff --git a/src/format.c b/src/format.c index 0c2c8487..5a488544 100644 --- a/src/format.c +++ b/src/format.c @@ -32,9 +32,12 @@ #include #include -#include "msapi_utf8.h" #include "rufus.h" +#include "missing.h" #include "resource.h" +#include "msapi_utf8.h" +#include "localization.h" + #include "br.h" #include "fat16.h" #include "fat32.h" @@ -44,7 +47,6 @@ #include "drive.h" #include "format.h" #include "badblocks.h" -#include "localization.h" #include "bled/bled.h" #include "../res/grub/grub_version.h" @@ -999,7 +1001,7 @@ static BOOL WriteSBR(HANDLE hPhysicalDrive) set_bytes_per_sector(SelectedDrive.Geometry.BytesPerSector); // Ensure that we have sufficient space for the SBR max_size = IsChecked(IDC_EXTRA_PARTITION) ? - (DWORD)(SelectedDrive.Geometry.BytesPerSector * SelectedDrive.Geometry.SectorsPerTrack) : 1024 * 1024; + (DWORD)(SelectedDrive.Geometry.BytesPerSector * SelectedDrive.Geometry.SectorsPerTrack) : 1*MB; max_size -= mbr_size; // Syslinux has precedence over Grub if ((bt == BT_ISO) && (!HAS_SYSLINUX(img_report))) { diff --git a/src/icon.c b/src/icon.c index ddd66eb9..5e1985b3 100644 --- a/src/icon.c +++ b/src/icon.c @@ -27,9 +27,9 @@ #include #include -#include "msapi_utf8.h" #include "rufus.h" #include "resource.h" +#include "msapi_utf8.h" #pragma pack(push) #pragma pack(2) diff --git a/src/iso.c b/src/iso.c index 41769cbb..c7e0177e 100644 --- a/src/iso.c +++ b/src/iso.c @@ -39,8 +39,9 @@ #include #include "rufus.h" -#include "msapi_utf8.h" +#include "missing.h" #include "resource.h" +#include "msapi_utf8.h" #include "localization.h" // How often should we update the progress bar (in 2K blocks) as updating @@ -1068,91 +1069,9 @@ out: if (p_udf != NULL) udf_close(p_udf); safe_free(wim_path); - return bswap_32(r); + return bswap_uint32(r); } -/* - * The following is used for native ISO mounting in Windows 8 or later - */ -#define VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT \ - { 0xEC984AECL, 0xA0F9, 0x47e9, { 0x90, 0x1F, 0x71, 0x41, 0x5A, 0x66, 0x34, 0x5B } } - -typedef enum _VIRTUAL_DISK_ACCESS_MASK { - VIRTUAL_DISK_ACCESS_NONE = 0x00000000, - VIRTUAL_DISK_ACCESS_ATTACH_RO = 0x00010000, - VIRTUAL_DISK_ACCESS_ATTACH_RW = 0x00020000, - VIRTUAL_DISK_ACCESS_DETACH = 0x00040000, - VIRTUAL_DISK_ACCESS_GET_INFO = 0x00080000, - VIRTUAL_DISK_ACCESS_CREATE = 0x00100000, - VIRTUAL_DISK_ACCESS_METAOPS = 0x00200000, - VIRTUAL_DISK_ACCESS_READ = 0x000d0000, - VIRTUAL_DISK_ACCESS_ALL = 0x003f0000, - VIRTUAL_DISK_ACCESS_WRITABLE = 0x00320000 -} VIRTUAL_DISK_ACCESS_MASK; - -typedef enum _OPEN_VIRTUAL_DISK_FLAG { - OPEN_VIRTUAL_DISK_FLAG_NONE = 0x00000000, - OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS = 0x00000001, - OPEN_VIRTUAL_DISK_FLAG_BLANK_FILE = 0x00000002, - OPEN_VIRTUAL_DISK_FLAG_BOOT_DRIVE = 0x00000004, - OPEN_VIRTUAL_DISK_FLAG_CACHED_IO = 0x00000008, - OPEN_VIRTUAL_DISK_FLAG_CUSTOM_DIFF_CHAIN = 0x00000010 -} OPEN_VIRTUAL_DISK_FLAG; - -typedef enum _OPEN_VIRTUAL_DISK_VERSION { - OPEN_VIRTUAL_DISK_VERSION_UNSPECIFIED = 0, - OPEN_VIRTUAL_DISK_VERSION_1 = 1, - OPEN_VIRTUAL_DISK_VERSION_2 = 2 -} OPEN_VIRTUAL_DISK_VERSION; - -typedef enum _ATTACH_VIRTUAL_DISK_FLAG { - ATTACH_VIRTUAL_DISK_FLAG_NONE = 0x00000000, - ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY = 0x00000001, - ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER = 0x00000002, - ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME = 0x00000004, - ATTACH_VIRTUAL_DISK_FLAG_NO_LOCAL_HOST = 0x00000008 -} ATTACH_VIRTUAL_DISK_FLAG; - -typedef enum _ATTACH_VIRTUAL_DISK_VERSION { - ATTACH_VIRTUAL_DISK_VERSION_UNSPECIFIED = 0, - ATTACH_VIRTUAL_DISK_VERSION_1 = 1 -} ATTACH_VIRTUAL_DISK_VERSION; - -typedef enum _DETACH_VIRTUAL_DISK_FLAG { - DETACH_VIRTUAL_DISK_FLAG_NONE = 0x00000000 -} DETACH_VIRTUAL_DISK_FLAG; - -#ifndef _VIRTUAL_STORAGE_TYPE_DEFINED -#define _VIRTUAL_STORAGE_TYPE_DEFINED -typedef struct _VIRTUAL_STORAGE_TYPE { - ULONG DeviceId; - GUID VendorId; -} VIRTUAL_STORAGE_TYPE, *PVIRTUAL_STORAGE_TYPE; -#endif - -typedef struct _OPEN_VIRTUAL_DISK_PARAMETERS { - OPEN_VIRTUAL_DISK_VERSION Version; - union { - struct { - ULONG RWDepth; - } Version1; - struct { - BOOL GetInfoOnly; - BOOL ReadOnly; - GUID ResiliencyGuid; - } Version2; - }; -} OPEN_VIRTUAL_DISK_PARAMETERS, *POPEN_VIRTUAL_DISK_PARAMETERS; - -typedef struct _ATTACH_VIRTUAL_DISK_PARAMETERS { - ATTACH_VIRTUAL_DISK_VERSION Version; - union { - struct { - ULONG Reserved; - } Version1; - }; -} ATTACH_VIRTUAL_DISK_PARAMETERS, *PATTACH_VIRTUAL_DISK_PARAMETERS; - // VirtDisk API Prototypes - Only available for Windows 8 or later PF_TYPE_DECL(WINAPI, DWORD, OpenVirtualDisk, (PVIRTUAL_STORAGE_TYPE, PCWSTR, VIRTUAL_DISK_ACCESS_MASK, OPEN_VIRTUAL_DISK_FLAG, POPEN_VIRTUAL_DISK_PARAMETERS, PHANDLE)); diff --git a/src/missing.h b/src/missing.h new file mode 100644 index 00000000..2ecacd06 --- /dev/null +++ b/src/missing.h @@ -0,0 +1,214 @@ +/* +* Rufus: The Reliable USB Formatting Utility +* Constants and defines missing from various toolchains +* Copyright © 2016 Pete Batard +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include +#include +#include +#include + +#pragma once + +/* Convenient to have around */ +#define KB 1024LL +#define MB 1048576LL +#define GB 1073741824LL +#define TB 1099511627776LL + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#if defined(_MSC_VER) +#define bswap_uint64 _byteswap_uint64 +#define bswap_uint32 _byteswap_ulong +#define bswap_uint16 _byteswap_ushort +#else +#define bswap_uint64 __builtin_bswap64 +#define bswap_uint32 __builtin_bswap32 +#define bswap_uint16 __builtin_bswap16 +#endif + +static __inline void *_reallocf(void *ptr, size_t size) { + void *ret = realloc(ptr, size); + if (!ret) + free(ptr); + return ret; +} + +/* UI redefinitions for WDK and MinGW */ +#ifndef PBM_SETSTATE +#define PBM_SETSTATE (WM_USER+16) +#endif +#ifndef PBST_NORMAL +#define PBST_NORMAL 1 +#endif +#ifndef PBST_ERROR +#define PBST_ERROR 2 +#endif +#ifndef PBST_PAUSED +#define PBST_PAUSED 3 +#endif +#ifndef BUTTON_IMAGELIST_ALIGN_CENTER +#define BUTTON_IMAGELIST_ALIGN_CENTER 4 +#endif +#ifndef BCM_SETIMAGELIST +#define BCM_SETIMAGELIST 0x1602 +#endif +#ifndef DBT_CUSTOMEVENT +#define DBT_CUSTOMEVENT 0x8006 +#endif +#ifndef ERROR_FILE_TOO_LARGE +#define ERROR_FILE_TOO_LARGE 223 +#endif +#ifndef MSGFLT_ADD +#define MSGFLT_ADD 1 +#endif +#ifndef WM_CLIENTSHUTDOWN +#define WM_CLIENTSHUTDOWN 0x3B +#endif +#ifndef WM_COPYGLOBALDATA +#define WM_COPYGLOBALDATA 0x49 +#endif +#ifndef PBS_MARQUEE +#define PBS_MARQUEE 0x08 +#endif +#ifndef PBM_SETMARQUEE +#define PBM_SETMARQUEE (WM_USER+10) +#endif + +typedef struct { + HIMAGELIST himl; + RECT margin; + UINT uAlign; +} MY_BUTTON_IMAGELIST; + +typedef struct +{ + LPCITEMIDLIST pidl; + BOOL fRecursive; +} MY_SHChangeNotifyEntry; + +/* The following is used for native ISO mounting in Windows 8 or later */ +#define VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT \ + { 0xEC984AECL, 0xA0F9, 0x47e9, { 0x90, 0x1F, 0x71, 0x41, 0x5A, 0x66, 0x34, 0x5B } } + +typedef enum _VIRTUAL_DISK_ACCESS_MASK { + VIRTUAL_DISK_ACCESS_NONE = 0x00000000, + VIRTUAL_DISK_ACCESS_ATTACH_RO = 0x00010000, + VIRTUAL_DISK_ACCESS_ATTACH_RW = 0x00020000, + VIRTUAL_DISK_ACCESS_DETACH = 0x00040000, + VIRTUAL_DISK_ACCESS_GET_INFO = 0x00080000, + VIRTUAL_DISK_ACCESS_CREATE = 0x00100000, + VIRTUAL_DISK_ACCESS_METAOPS = 0x00200000, + VIRTUAL_DISK_ACCESS_READ = 0x000d0000, + VIRTUAL_DISK_ACCESS_ALL = 0x003f0000, + VIRTUAL_DISK_ACCESS_WRITABLE = 0x00320000 +} VIRTUAL_DISK_ACCESS_MASK; + +typedef enum _OPEN_VIRTUAL_DISK_FLAG { + OPEN_VIRTUAL_DISK_FLAG_NONE = 0x00000000, + OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS = 0x00000001, + OPEN_VIRTUAL_DISK_FLAG_BLANK_FILE = 0x00000002, + OPEN_VIRTUAL_DISK_FLAG_BOOT_DRIVE = 0x00000004, + OPEN_VIRTUAL_DISK_FLAG_CACHED_IO = 0x00000008, + OPEN_VIRTUAL_DISK_FLAG_CUSTOM_DIFF_CHAIN = 0x00000010 +} OPEN_VIRTUAL_DISK_FLAG; + +typedef enum _OPEN_VIRTUAL_DISK_VERSION { + OPEN_VIRTUAL_DISK_VERSION_UNSPECIFIED = 0, + OPEN_VIRTUAL_DISK_VERSION_1 = 1, + OPEN_VIRTUAL_DISK_VERSION_2 = 2 +} OPEN_VIRTUAL_DISK_VERSION; + +typedef enum _ATTACH_VIRTUAL_DISK_FLAG { + ATTACH_VIRTUAL_DISK_FLAG_NONE = 0x00000000, + ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY = 0x00000001, + ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER = 0x00000002, + ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME = 0x00000004, + ATTACH_VIRTUAL_DISK_FLAG_NO_LOCAL_HOST = 0x00000008 +} ATTACH_VIRTUAL_DISK_FLAG; + +typedef enum _ATTACH_VIRTUAL_DISK_VERSION { + ATTACH_VIRTUAL_DISK_VERSION_UNSPECIFIED = 0, + ATTACH_VIRTUAL_DISK_VERSION_1 = 1 +} ATTACH_VIRTUAL_DISK_VERSION; + +typedef enum _DETACH_VIRTUAL_DISK_FLAG { + DETACH_VIRTUAL_DISK_FLAG_NONE = 0x00000000 +} DETACH_VIRTUAL_DISK_FLAG; + +#ifndef _VIRTUAL_STORAGE_TYPE_DEFINED +#define _VIRTUAL_STORAGE_TYPE_DEFINED +typedef struct _VIRTUAL_STORAGE_TYPE { + ULONG DeviceId; + GUID VendorId; +} VIRTUAL_STORAGE_TYPE, *PVIRTUAL_STORAGE_TYPE; +#endif + +typedef struct _OPEN_VIRTUAL_DISK_PARAMETERS { + OPEN_VIRTUAL_DISK_VERSION Version; + union { + struct { + ULONG RWDepth; + } Version1; + struct { + BOOL GetInfoOnly; + BOOL ReadOnly; + GUID ResiliencyGuid; + } Version2; + }; +} OPEN_VIRTUAL_DISK_PARAMETERS, *POPEN_VIRTUAL_DISK_PARAMETERS; + +typedef struct _ATTACH_VIRTUAL_DISK_PARAMETERS { + ATTACH_VIRTUAL_DISK_VERSION Version; + union { + struct { + ULONG Reserved; + } Version1; + }; +} ATTACH_VIRTUAL_DISK_PARAMETERS, *PATTACH_VIRTUAL_DISK_PARAMETERS; + +/* Networking constants missing from MinGW */ +#if !defined(ERROR_INTERNET_DISCONNECTED) +#define ERROR_INTERNET_DISCONNECTED (INTERNET_ERROR_BASE + 163) +#endif +#if !defined(ERROR_INTERNET_SERVER_UNREACHABLE) +#define ERROR_INTERNET_SERVER_UNREACHABLE (INTERNET_ERROR_BASE + 164) +#endif +#if !defined(ERROR_INTERNET_PROXY_SERVER_UNREACHABLE) +#define ERROR_INTERNET_PROXY_SERVER_UNREACHABLE (INTERNET_ERROR_BASE + 165) +#endif +#if !defined(ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT) +#define ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT (INTERNET_ERROR_BASE + 166) +#endif +#if !defined(ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT) +#define ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT (INTERNET_ERROR_BASE + 167) +#endif +#if !defined(ERROR_INTERNET_FAILED_DUETOSECURITYCHECK) +#define ERROR_INTERNET_FAILED_DUETOSECURITYCHECK (INTERNET_ERROR_BASE + 171) +#endif +#if !defined(ERROR_INTERNET_NOT_INITIALIZED) +#define ERROR_INTERNET_NOT_INITIALIZED (INTERNET_ERROR_BASE + 172) +#endif +#if !defined(ERROR_INTERNET_NEED_MSN_SSPI_PKG) +#define ERROR_INTERNET_NEED_MSN_SSPI_PKG (INTERNET_ERROR_BASE + 173) +#endif +#if !defined(ERROR_INTERNET_LOGIN_FAILURE_DISPLAY_ENTITY_BODY) +#define ERROR_INTERNET_LOGIN_FAILURE_DISPLAY_ENTITY_BODY (INTERNET_ERROR_BASE + 174) +#endif diff --git a/src/net.c b/src/net.c index 8ef0d9c3..f6af0e61 100644 --- a/src/net.c +++ b/src/net.c @@ -30,12 +30,13 @@ #include #include -#include "msapi_utf8.h" #include "rufus.h" -#include "settings.h" #include "resource.h" +#include "msapi_utf8.h" #include "localization.h" +#include "settings.h" + /* Maximum download chunk size, in bytes */ #define DOWNLOAD_BUFFER_SIZE 10240 /* Default delay between update checks (1 day) */ @@ -49,35 +50,6 @@ static DWORD error_code; static BOOL update_check_in_progress = FALSE; static BOOL force_update_check = FALSE; -/* MinGW is missing some of those */ -#if !defined(ERROR_INTERNET_DISCONNECTED) -#define ERROR_INTERNET_DISCONNECTED (INTERNET_ERROR_BASE + 163) -#endif -#if !defined(ERROR_INTERNET_SERVER_UNREACHABLE) -#define ERROR_INTERNET_SERVER_UNREACHABLE (INTERNET_ERROR_BASE + 164) -#endif -#if !defined(ERROR_INTERNET_PROXY_SERVER_UNREACHABLE) -#define ERROR_INTERNET_PROXY_SERVER_UNREACHABLE (INTERNET_ERROR_BASE + 165) -#endif -#if !defined(ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT) -#define ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT (INTERNET_ERROR_BASE + 166) -#endif -#if !defined(ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT) -#define ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT (INTERNET_ERROR_BASE + 167) -#endif -#if !defined(ERROR_INTERNET_FAILED_DUETOSECURITYCHECK) -#define ERROR_INTERNET_FAILED_DUETOSECURITYCHECK (INTERNET_ERROR_BASE + 171) -#endif -#if !defined(ERROR_INTERNET_NOT_INITIALIZED) -#define ERROR_INTERNET_NOT_INITIALIZED (INTERNET_ERROR_BASE + 172) -#endif -#if !defined(ERROR_INTERNET_NEED_MSN_SSPI_PKG) -#define ERROR_INTERNET_NEED_MSN_SSPI_PKG (INTERNET_ERROR_BASE + 173) -#endif -#if !defined(ERROR_INTERNET_LOGIN_FAILURE_DISPLAY_ENTITY_BODY) -#define ERROR_INTERNET_LOGIN_FAILURE_DISPLAY_ENTITY_BODY (INTERNET_ERROR_BASE + 174) -#endif - /* * FormatMessage does not handle internet errors * https://msdn.microsoft.com/en-us/library/windows/desktop/aa385465.aspx diff --git a/src/parser.c b/src/parser.c index 6568102e..8c94dc6b 100644 --- a/src/parser.c +++ b/src/parser.c @@ -32,6 +32,7 @@ #include #include "rufus.h" +#include "missing.h" #include "msapi_utf8.h" #include "localization.h" diff --git a/src/pki.c b/src/pki.c index 76e4d9dd..13ee38f7 100644 --- a/src/pki.c +++ b/src/pki.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * PKI functions (code signing, etc.) - * Copyright © 2015 Pete Batard + * Copyright © 2015-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,8 +29,8 @@ #include #include "rufus.h" -#include "msapi_utf8.h" #include "resource.h" +#include "msapi_utf8.h" #include "localization.h" #define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING) diff --git a/src/rufus.c b/src/rufus.c index b58cab78..87fba22d 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -35,69 +35,23 @@ #include #include -#include "msapi_utf8.h" -#include "resource.h" #include "rufus.h" +#include "missing.h" +#include "resource.h" +#include "msapi_utf8.h" +#include "localization.h" + #include "drive.h" #include "settings.h" -#include "localization.h" #include "bled/bled.h" #include "../res/grub/grub_version.h" #include "../res/grub2/grub2_version.h" -/* Redefinitions for WDK and MinGW */ -// TODO: these would be better in a 'missing.h' file -#ifndef PBM_SETSTATE -#define PBM_SETSTATE (WM_USER+16) -#endif -#ifndef PBST_NORMAL -#define PBST_NORMAL 1 -#endif -#ifndef PBST_ERROR -#define PBST_ERROR 2 -#endif -#ifndef PBST_PAUSED -#define PBST_PAUSED 3 -#endif -#ifndef BUTTON_IMAGELIST_ALIGN_CENTER -#define BUTTON_IMAGELIST_ALIGN_CENTER 4 -#endif -#ifndef BCM_SETIMAGELIST -#define BCM_SETIMAGELIST 0x1602 -#endif -#ifndef DBT_CUSTOMEVENT -#define DBT_CUSTOMEVENT 0x8006 -#endif -#ifndef ERROR_FILE_TOO_LARGE -#define ERROR_FILE_TOO_LARGE 223 -#endif - -#ifndef MSGFLT_ADD -#define MSGFLT_ADD 1 -#endif -#ifndef WM_CLIENTSHUTDOWN -#define WM_CLIENTSHUTDOWN 0x3B -#endif -#ifndef WM_COPYGLOBALDATA -#define WM_COPYGLOBALDATA 0x49 -#endif - -struct { - HIMAGELIST himl; - RECT margin; - UINT uAlign; -} bi_iso = {0}, bi_up = {0}, bi_down = {0}; // BUTTON_IMAGELIST - -typedef struct -{ - LPCITEMIDLIST pidl; - BOOL fRecursive; -} MY_SHChangeNotifyEntry; - // MinGW doesn't know these PF_TYPE(WINAPI, HIMAGELIST, ImageList_Create, (int, int, UINT, int, int)); PF_TYPE(WINAPI, int, ImageList_AddIcon, (HIMAGELIST, HICON)); PF_TYPE(WINAPI, int, ImageList_ReplaceIcon, (HIMAGELIST, int, HICON)); + // WDK blows up when trying to using PF_TYPE_DECL() for the ImageList calls... so we don't. PF_DECL(ImageList_Create); PF_DECL(ImageList_AddIcon); @@ -139,6 +93,7 @@ char msgbox[1024], msgbox_title[32], *ini_file = NULL; OPENED_LIBRARIES_VARS; HINSTANCE hMainInstance; HWND hMainDialog, hLangToolbar = NULL, hUpdatesDlg = NULL; +MY_BUTTON_IMAGELIST bi_iso = { 0 }, bi_up = { 0 }, bi_down = { 0 }; char szFolderPath[MAX_PATH], app_dir[MAX_PATH], system_dir[MAX_PATH], sysnative_dir[MAX_PATH]; char* image_path = NULL; float fScale = 1.0f; @@ -193,11 +148,6 @@ static __inline void SetComboEntry(HWND hDlg, int data) { } } -#define KB 1024LL -#define MB 1048576LL -#define GB 1073741824LL -#define TB 1099511627776LL - /* * Fill in the cluster size names */ @@ -370,10 +320,6 @@ static BOOL DefineClusterSizes(void) return r; } -#undef KB -#undef MB -#undef GB -#undef TB /* * Populate the Allocation unit size field diff --git a/src/rufus.h b/src/rufus.h index 6348423e..c42fbf64 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -469,25 +469,6 @@ static __inline BOOL UnlockDrive(HANDLE hDrive) { return DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &size, NULL); } -static __inline void *_reallocf(void *ptr, size_t size) { - void *ret = realloc(ptr, size); - if (!ret) - free(ptr); - return ret; -} - -static __inline uint16_t bswap_16(uint16_t x) { - return (x >> 8) | (x << 8); -} - -static __inline uint32_t bswap_32(uint32_t x) { - return (bswap_16(x & 0xffff) << 16) | (bswap_16(x >> 16)); -} - -static __inline uint64_t bswap_64(uint64_t x) { - return (((uint64_t) bswap_32(x & 0xffffffffull)) << 32) | (bswap_32(x >> 32)); -} - /* Hash tables */ typedef struct htab_entry { uint32_t used; @@ -580,17 +561,6 @@ static __inline HMODULE GetLibraryHandle(char* szLibraryName) { #define ERROR_CANT_ASSIGN_LETTER 0x120B #define ERROR_CANT_MOUNT_VOLUME 0x120C -/* More niceties */ -#ifndef MIN -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef PBS_MARQUEE -#define PBS_MARQUEE 0x08 -#endif -#ifndef PBM_SETMARQUEE -#define PBM_SETMARQUEE (WM_USER+10) -#endif - /* Why oh why does Microsoft have to make everybody suffer with their braindead use of Unicode? */ #define _RT_ICON MAKEINTRESOURCEA(3) #define _RT_DIALOG MAKEINTRESOURCEA(5) diff --git a/src/rufus.rc b/src/rufus.rc index 72471d9f..8530a789 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.860" +CAPTION "Rufus 2.8.861" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,860,0 - PRODUCTVERSION 2,8,860,0 + FILEVERSION 2,8,861,0 + PRODUCTVERSION 2,8,861,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.860" + VALUE "FileVersion", "2.8.861" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.860" + VALUE "ProductVersion", "2.8.861" END END BLOCK "VarFileInfo" diff --git a/src/smart.c b/src/smart.c index a6526893..a07de632 100644 --- a/src/smart.c +++ b/src/smart.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * SMART HDD vs Flash detection (using ATA over USB, S.M.A.R.T., etc.) - * Copyright © 2013-2014 Pete Batard + * Copyright © 2013-2016 Pete Batard * * Based in part on scsiata.cpp from Smartmontools: http://smartmontools.sourceforge.net * Copyright © 2006-12 Douglas Gilbert @@ -31,8 +31,10 @@ #include #include -#include "msapi_utf8.h" #include "rufus.h" +#include "missing.h" +#include "msapi_utf8.h" + #include "drive.h" #include "smart.h" #include "hdd_vs_ufd.h" @@ -43,7 +45,7 @@ static uint8_t GetAtaDirection(uint8_t AtaCmd, uint8_t Features) { // Far from complete -- only the commands we *may* use. // Most SMART commands require DATA_IN but there are a couple exceptions - BOOL smart_out = (AtaCmd == ATA_SMART_CMD) && + BOOL smart_out = (AtaCmd == ATA_SMART_CMD) && ((Features == ATA_SMART_STATUS) || (Features == ATA_SMART_WRITE_LOG_SECTOR)); switch (AtaCmd) { @@ -413,7 +415,7 @@ BOOL SmartGetVersion(HANDLE hdevice) * THUS, IF DATA LOSS IS INCURRED DUE TO THIS, OR ANY OTHER PART OF THIS APPLICATION, * NOT BEHAVING IN THE MANNER YOU EXPECTED, THE RESPONSIBILITY IS ENTIRELY ON YOU! * - * What you have below, then, is our *current best guess* at differentiating UFDs + * What you have below, then, is our *current best guess* at differentiating UFDs * from HDDs. But short of a crystal ball, this remains just a guess, which may be * way off mark. Still, you are also reminded that Rufus does produce PROMINENT * warnings before you format a drive, and also provides extensive info about the @@ -426,7 +428,7 @@ BOOL SmartGetVersion(HANDLE hdevice) * - some UFDs (SanDisk Extreme) have added S.M.A.R.T. support, which also used to be * reserved for HDDs => can't use that either * - even if S.M.A.R.T. was enough, not all USB->IDE or USB->SATA bridges support ATA - * passthrough, which is required S.M.A.R.T. data, and each manufacturer of an + * passthrough, which is required S.M.A.R.T. data, and each manufacturer of an * USB<->(S)ATA bridge seem to have their own method of implementing passthrough. * - SSDs have also changed the deal completely, as you can get something that looks * like Flash but that is really an HDD. @@ -436,7 +438,6 @@ BOOL SmartGetVersion(HANDLE hdevice) * from the above) => there is no magic API we can query that will tell us what we're * really looking at. */ -#define GB 1073741824LL int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid) { int score = 0; diff --git a/src/stdfn.c b/src/stdfn.c index 99235128..b5391751 100644 --- a/src/stdfn.c +++ b/src/stdfn.c @@ -24,12 +24,13 @@ #include #include -#include "msapi_utf8.h" #include "rufus.h" #include "resource.h" -#include "settings.h" +#include "msapi_utf8.h" #include "localization.h" +#include "settings.h" + int nWindowsVersion = WINDOWS_UNDEFINED; char WindowsVersionStr[128] = "Windows "; diff --git a/src/stdio.c b/src/stdio.c index af0f9e41..581861fd 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -29,9 +29,9 @@ #include #include -#include "msapi_utf8.h" #include "rufus.h" #include "resource.h" +#include "msapi_utf8.h" #include "localization.h" /* diff --git a/src/stdlg.c b/src/stdlg.c index 066932db..bf606ae7 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -35,12 +35,13 @@ #include #include "rufus.h" +#include "resource.h" #include "msapi_utf8.h" +#include "localization.h" + #include "registry.h" #include "settings.h" -#include "resource.h" #include "license.h" -#include "localization.h" #if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) PF_TYPE_DECL(WINAPI, HRESULT, SHCreateItemFromParsingName, (PCWSTR, IBindCtx*, REFIID, void **)); diff --git a/src/syslinux.c b/src/syslinux.c index 2ee20bb6..ed979c38 100644 --- a/src/syslinux.c +++ b/src/syslinux.c @@ -27,10 +27,11 @@ #include #include "rufus.h" -#include "drive.h" #include "resource.h" -#include "localization.h" #include "msapi_utf8.h" +#include "localization.h" + +#include "drive.h" #include "syslinux.h" #include "syslxfs.h" diff --git a/src/usb.c b/src/usb.c index 762429d3..8abff8b3 100644 --- a/src/usb.c +++ b/src/usb.c @@ -33,11 +33,13 @@ #include #include -#include "msapi_utf8.h" #include "rufus.h" -#include "drive.h" +#include "missing.h" #include "resource.h" +#include "msapi_utf8.h" #include "localization.h" + +#include "drive.h" #include "usb.h" extern StrArray DriveID, DriveLabel; @@ -537,7 +539,7 @@ BOOL GetUSBDevices(DWORD devnum) safe_free(devint_detail_data); break; } - if (GetDriveSize(drive_index) < (MIN_DRIVE_SIZE*1024*1024)) { + if (GetDriveSize(drive_index) < (MIN_DRIVE_SIZE*MB)) { uprintf("Device eliminated because it is smaller than %d MB\n", MIN_DRIVE_SIZE); safe_closehandle(hDrive); safe_free(devint_detail_data); diff --git a/src/vhd.c b/src/vhd.c index 5a39aa49..ddc361c6 100644 --- a/src/vhd.c +++ b/src/vhd.c @@ -24,22 +24,14 @@ #include #include "rufus.h" +#include "missing.h" #include "resource.h" #include "msapi_utf8.h" + #include "drive.h" #include "registry.h" #include "bled/bled.h" -#if defined(_MSC_VER) -#define bswap_uint64 _byteswap_uint64 -#define bswap_uint32 _byteswap_ulong -#define bswap_uint16 _byteswap_ushort -#else -#define bswap_uint64 __builtin_bswap64 -#define bswap_uint32 __builtin_bswap32 -#define bswap_uint16 __builtin_bswap16 -#endif - #define VHD_FOOTER_COOKIE { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x' } #define VHD_FOOTER_FEATURES_NONE 0x00000000 From 64828934e064b3c42592f08bae7b3569d0280917 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Sun, 21 Feb 2016 19:58:48 +0000 Subject: [PATCH 32/91] [usb] fix processing of sibling device instances * Issue introduced in f88faf1a4f74dca1c88e2324acb041b094b0f999 * Closes #696 --- src/rufus.rc | 10 +++++----- src/usb.c | 7 +++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/rufus.rc b/src/rufus.rc index 8530a789..fcbc1936 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.861" +CAPTION "Rufus 2.8.862" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,861,0 - PRODUCTVERSION 2,8,861,0 + FILEVERSION 2,8,862,0 + PRODUCTVERSION 2,8,862,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.861" + VALUE "FileVersion", "2.8.862" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.861" + VALUE "ProductVersion", "2.8.862" END END BLOCK "VarFileInfo" diff --git a/src/usb.c b/src/usb.c index 8abff8b3..05fa769a 100644 --- a/src/usb.c +++ b/src/usb.c @@ -194,7 +194,7 @@ BOOL GetUSBDevices(DWORD devnum) SP_DEVINFO_DATA dev_info_data; SP_DEVICE_INTERFACE_DATA devint_data; PSP_DEVICE_INTERFACE_DETAIL_DATA_A devint_detail_data; - DEVINST parent_inst, grandparent_inst, sibling_inst, device_inst; + DEVINST parent_inst, grandparent_inst, device_inst; DWORD size, i, j, k, l, datatype, drive_index; DWORD uasp_start = ARRAYSIZE(usbstor_name), card_start = ARRAYSIZE(genstor_name); ULONG list_size[ARRAYSIZE(usbstor_name)] = { 0 }, list_start[ARRAYSIZE(usbstor_name)] = { 0 }, full_list_size, ulFlags; @@ -396,10 +396,9 @@ BOOL GetUSBDevices(DWORD devnum) } if (device_inst != dev_info_data.DevInst) { // Try the siblings - while (CM_Get_Sibling(&sibling_inst, device_inst, 0) == CR_SUCCESS) { - if (sibling_inst == dev_info_data.DevInst) { + while (CM_Get_Sibling(&device_inst, device_inst, 0) == CR_SUCCESS) { + if (device_inst == dev_info_data.DevInst) { uuprintf("NOTE: Matched instance from sibling for '%s'", device_id); - device_inst = sibling_inst; break; } } From 3a266d92a781036687b1cdb05c1491fdfb36fe91 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 22 Feb 2016 12:51:27 +0000 Subject: [PATCH 33/91] [misc] improve the reporting of ISO props --- src/rufus.c | 40 ++++++++++++++++------------------------ src/rufus.rc | 10 +++++----- 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/rufus.c b/src/rufus.c index 87fba22d..276a724d 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -946,48 +946,40 @@ static void CALLBACK BlockingTimer(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD } // Report the features of the selected ISO images -static const char* YesNo(BOOL b) { - return (b) ? "Yes" : "No"; -} +#define PRINT_ISO_PROP(b, ...) do {if (b) uprintf(__VA_ARGS__);} while(0) static void DisplayISOProps(void) { int i; - char isolinux_str[16] = "No"; - if (HAS_SYSLINUX(img_report)) { - safe_sprintf(isolinux_str, sizeof(isolinux_str), "Yes (%s)", img_report.sl_version_str); - } - - // TODO: Only report features that are present uprintf("ISO label: '%s'", img_report.label); uprintf(" Size: %" PRIu64 " bytes", img_report.projected_size); - uprintf(" Has a >64 chars filename: %s", YesNo(img_report.has_long_filename)); - uprintf(" Has Symlinks: %s", YesNo(img_report.has_symlinks)); - uprintf(" Has a >4GB file: %s", YesNo(img_report.has_4GB_file)); - uprintf(" Uses Bootmgr: %s", YesNo(img_report.has_bootmgr)); - uprintf(" Uses EFI: %s%s", YesNo(img_report.has_efi), IS_WIN7_EFI(img_report) ? " (win7_x64)" : ""); - uprintf(" Uses Grub 2: %s", YesNo(img_report.has_grub2)); - uprintf(" Uses Grub4DOS: %s", YesNo(img_report.has_grub4dos)); - uprintf(" Uses isolinux: %s", isolinux_str); + PRINT_ISO_PROP(img_report.has_4GB_file, " Has a >4GB file"); + PRINT_ISO_PROP(img_report.has_long_filename, " Has a >64 chars filename"); + PRINT_ISO_PROP(HAS_SYSLINUX(img_report), " Uses: Syslinux/Isolinux v%s", img_report.sl_version_str); if (HAS_SYSLINUX(img_report) && (SL_MAJOR(img_report.sl_version) < 5)) { for (i = 0; i> 24) & 0xff, + uprintf(" Uses: Install.wim (version %d.%d.%d)", (img_report.install_wim_version >> 24) & 0xff, (img_report.install_wim_version >> 16) & 0xff, (img_report.install_wim_version >> 8) & 0xff); // Microsoft somehow managed to make their ESD WIMs incompatible with their own APIs // (yes, EVEN the Windows 10 APIs), so we must filter them out... if (img_report.install_wim_version >= MAX_WIM_VERSION) uprintf(" Note: This WIM version is NOT compatible with Windows To Go"); } + PRINT_ISO_PROP(img_report.has_symlinks, " Note: This ISO uses symbolic links, which will not be replicated due to file system limitations."); + PRINT_ISO_PROP(img_report.has_symlinks, " Because of this, some features from this image may not work..."); - // We don't support ToGo on Windows 7 or earlier, for lack of ISO mount capabilities - // TODO: add install.wim extraction workaround for Windows 7 + // We don't support ToGo on Windows 7 or earlier, for lack of native ISO mounting capabilities if (nWindowsVersion >= WINDOWS_8) if ( ((!togo_mode) && (HAS_TOGO(img_report))) || ((togo_mode) && (!HAS_TOGO(img_report))) ) ToggleToGo(); diff --git a/src/rufus.rc b/src/rufus.rc index fcbc1936..b98ef8da 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.862" +CAPTION "Rufus 2.8.863" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,862,0 - PRODUCTVERSION 2,8,862,0 + FILEVERSION 2,8,863,0 + PRODUCTVERSION 2,8,863,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.862" + VALUE "FileVersion", "2.8.863" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.862" + VALUE "ProductVersion", "2.8.863" END END BLOCK "VarFileInfo" From 0e65b1c920bafa043cd332ac68e26c4c717f725b Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 23 Feb 2016 11:21:36 +0000 Subject: [PATCH 34/91] [ui] fix flickering of Status and Info fields * Closes #634 --- src/checksum.c | 2 +- src/iso.c | 2 -- src/localization.c | 54 ++++++++++++++++++++++++++++++++++++++++------ src/rufus.h | 2 ++ src/rufus.rc | 10 ++++----- 5 files changed, 56 insertions(+), 14 deletions(-) diff --git a/src/checksum.c b/src/checksum.c index 4e429d2f..a5240d6c 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -1,6 +1,6 @@ /* * Rufus: The Reliable USB Formatting Utility - * Message-Digest algorithms (sha1sum, md5sum) + * Message-Digest algorithms (md5sum, sha1sum, sha256sum) * Copyright © 1998-2001 Free Software Foundation, Inc. * Copyright © 2004 g10 Code GmbH * Copyright © 2006-2012 Brad Conte diff --git a/src/iso.c b/src/iso.c index c7e0177e..838f6e6d 100644 --- a/src/iso.c +++ b/src/iso.c @@ -307,8 +307,6 @@ static void print_extracted_file(char* psz_fullpath, int64_t i_file_length) safe_sprintf(&psz_fullpath[nul_pos], 24, " (%s)", SizeToHumanReadable(i_file_length, TRUE, FALSE)); uprintf("Extracting: %s\n", psz_fullpath); safe_sprintf(&psz_fullpath[nul_pos], 24, " (%s)", SizeToHumanReadable(i_file_length, FALSE, FALSE)); - // TODO: I don't think we need both of these... - SendMessageLU(hStatus, SB_SETTEXTW, SBT_OWNERDRAW | SB_SECTION_LEFT, psz_fullpath); PrintStatus(0, MSG_000, psz_fullpath); // MSG_000 is "%s" // ISO9660 cannot handle backslashes for (i=0; i arm a timer + output_msg[i] = msg; + SetTimer(hMainDialog, TID_OUTPUT_INFO + i, (UINT)(MSG_DELAY - delta), OutputMessageTimeout); + bOutputTimerArmed[i] = TRUE; + } else { + PrintMessage[i](msg); + last_msg_time[i] = GetTickCount64(); + } + } } static void CALLBACK PrintMessageTimeout(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) diff --git a/src/rufus.h b/src/rufus.h index c42fbf64..b0683da6 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -168,6 +168,8 @@ typedef struct { enum timer_type { TID_MESSAGE_INFO = 0x1000, TID_MESSAGE_STATUS, + TID_OUTPUT_INFO, + TID_OUTPUT_STATUS, TID_BADBLOCKS_UPDATE, TID_APP_TIMER, TID_BLOCKING_TIMER, diff --git a/src/rufus.rc b/src/rufus.rc index b98ef8da..bd4bf82f 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.863" +CAPTION "Rufus 2.8.864" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,863,0 - PRODUCTVERSION 2,8,863,0 + FILEVERSION 2,8,864,0 + PRODUCTVERSION 2,8,864,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.863" + VALUE "FileVersion", "2.8.864" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.863" + VALUE "ProductVersion", "2.8.864" END END BLOCK "VarFileInfo" From db0880e534e4e9504e8c283256fbfbd0683abded Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 23 Feb 2016 20:52:06 +0000 Subject: [PATCH 35/91] [syslinux] update Syslinux to better align with its official source * This means disabling some warnings and removing explicit casts, but so be it... * Also fix the minfatsize check for Large FAT32 --- configure | 3 + configure.ac | 1 + rufus.sln | 13 +- src/.msvc/rufus.vcxproj | 11 +- src/.msvc/rufus_sources | 3 +- src/Makefile.am | 6 +- src/Makefile.in | 10 +- src/rufus.h | 2 +- src/rufus.rc | 10 +- src/syslinux.c | 4 +- src/syslinux/libfat/.msvc/libfat.vcxproj | 4 + src/syslinux/libfat/.msvc/libfat_sources | 2 +- src/syslinux/libfat/fatchain.c | 2 +- src/syslinux/libfat/open.c | 9 +- src/syslinux/libfat/searchdir.c | 2 +- .../libinstaller/.msvc/libinstaller.vcxproj | 6 +- .../.msvc/libinstaller.vcxproj.filters | 6 - .../libinstaller/.msvc/libinstaller_sources | 3 +- src/syslinux/libinstaller/Makefile.am | 2 +- src/syslinux/libinstaller/Makefile.in | 9 +- src/syslinux/libinstaller/setadv.c | 5 +- src/syslinux/libinstaller/syslinux.h | 8 +- src/syslinux/libinstaller/syslxint.h | 4 +- src/syslinux/libinstaller/syslxmod.c | 12 +- src/syslinux/win/.msvc/win.vcxproj | 174 ++++++++++++++++++ src/syslinux/win/.msvc/win.vcxproj.filters | 23 +++ src/syslinux/win/.msvc/win_sources | 15 ++ src/syslinux/{libinstaller => win}/ntfssect.c | 63 ++++++- src/syslinux/{libinstaller => win}/ntfssect.h | 0 wdk_build.cmd | 15 ++ 30 files changed, 352 insertions(+), 75 deletions(-) create mode 100644 src/syslinux/win/.msvc/win.vcxproj create mode 100644 src/syslinux/win/.msvc/win.vcxproj.filters create mode 100644 src/syslinux/win/.msvc/win_sources rename src/syslinux/{libinstaller => win}/ntfssect.c (83%) rename src/syslinux/{libinstaller => win}/ntfssect.h (100%) diff --git a/configure b/configure index 8812587f..62ee0102 100644 --- a/configure +++ b/configure @@ -3922,6 +3922,8 @@ ac_config_files="$ac_config_files src/syslinux/libfat/Makefile" ac_config_files="$ac_config_files src/syslinux/libinstaller/Makefile" +ac_config_files="$ac_config_files src/syslinux/win/Makefile" + cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure @@ -4657,6 +4659,7 @@ do "src/ms-sys/Makefile") CONFIG_FILES="$CONFIG_FILES src/ms-sys/Makefile" ;; "src/syslinux/libfat/Makefile") CONFIG_FILES="$CONFIG_FILES src/syslinux/libfat/Makefile" ;; "src/syslinux/libinstaller/Makefile") CONFIG_FILES="$CONFIG_FILES src/syslinux/libinstaller/Makefile" ;; + "src/syslinux/win/Makefile") CONFIG_FILES="$CONFIG_FILES src/syslinux/win/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff --git a/configure.ac b/configure.ac index b40bed1f..f80c281b 100644 --- a/configure.ac +++ b/configure.ac @@ -80,4 +80,5 @@ AC_CONFIG_FILES([res/localization/Makefile]) AC_CONFIG_FILES([src/ms-sys/Makefile]) AC_CONFIG_FILES([src/syslinux/libfat/Makefile]) AC_CONFIG_FILES([src/syslinux/libinstaller/Makefile]) +AC_CONFIG_FILES([src/syslinux/win/Makefile]) AC_OUTPUT diff --git a/rufus.sln b/rufus.sln index 0e7aa061..945ad47d 100644 --- a/rufus.sln +++ b/rufus.sln @@ -1,7 +1,6 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rufus", "src\.msvc\rufus.vcxproj", "{731858A7-0303-4988-877B-9C0DD6471864}" EndProject @@ -11,6 +10,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "syslinux-libfat", "src\sysl EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "syslinux-libinstaller", "src\syslinux\libinstaller\.msvc\libinstaller.vcxproj", "{266502AC-CD74-4581-B707-938A7D05AD7A}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "syslinux-win", "src\syslinux\win\.msvc\win.vcxproj", "{7D2E9784-DDF7-4988-A887-CF099BC3B340}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcdio-iso9660", "src\libcdio\iso9660\.msvc\iso9660.vcxproj", "{D4E80F35-2604-40AC-B436-97B052ECB572}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcdio-udf", "src\libcdio\udf\.msvc\udf.vcxproj", "{0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}" @@ -61,6 +62,14 @@ Global {266502AC-CD74-4581-B707-938A7D05AD7A}.Release|x86_32.Build.0 = Release|Win32 {266502AC-CD74-4581-B707-938A7D05AD7A}.Release|x86_64.ActiveCfg = Release|x64 {266502AC-CD74-4581-B707-938A7D05AD7A}.Release|x86_64.Build.0 = Release|x64 + {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|x86_32.ActiveCfg = Debug|Win32 + {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|x86_32.Build.0 = Debug|Win32 + {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|x86_64.ActiveCfg = Debug|x64 + {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|x86_64.Build.0 = Debug|x64 + {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|x86_32.ActiveCfg = Release|Win32 + {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|x86_32.Build.0 = Release|Win32 + {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|x86_64.ActiveCfg = Release|x64 + {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|x86_64.Build.0 = Release|x64 {D4E80F35-2604-40AC-B436-97B052ECB572}.Debug|x86_32.ActiveCfg = Debug|Win32 {D4E80F35-2604-40AC-B436-97B052ECB572}.Debug|x86_32.Build.0 = Debug|Win32 {D4E80F35-2604-40AC-B436-97B052ECB572}.Debug|x86_64.ActiveCfg = Debug|x64 diff --git a/src/.msvc/rufus.vcxproj b/src/.msvc/rufus.vcxproj index be5ef45f..82fc4a9c 100644 --- a/src/.msvc/rufus.vcxproj +++ b/src/.msvc/rufus.vcxproj @@ -84,7 +84,7 @@ _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) MultiThreadedDebug Level3 - ..\msvc-missing;..\ms-sys\inc;..\syslinux\libinstaller;..\syslinux\libfat;..\libcdio;..\getopt;%(AdditionalIncludeDirectories) + ..\msvc-missing;..\ms-sys\inc;..\syslinux\libinstaller;..\syslinux\libfat;..\syslinux\win;..\libcdio;..\getopt;%(AdditionalIncludeDirectories) CompileAsC true false @@ -108,7 +108,7 @@ X64 - ..\msvc-missing;..\ms-sys\inc;..\syslinux\libinstaller;..\syslinux\libfat;..\libcdio;..\getopt;%(AdditionalIncludeDirectories) + ..\msvc-missing;..\ms-sys\inc;..\syslinux\libinstaller;..\syslinux\libfat;..\syslinux\win;..\libcdio;..\getopt;%(AdditionalIncludeDirectories) _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) MultiThreadedDebug Level3 @@ -136,7 +136,7 @@ _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;%(PreprocessorDefinitions) MultiThreaded Level3 - ..\msvc-missing;..\ms-sys\inc;..\syslinux\libinstaller;..\syslinux\libfat;..\libcdio;..\getopt;%(AdditionalIncludeDirectories) + ..\msvc-missing;..\ms-sys\inc;..\syslinux\libinstaller;..\syslinux\libfat;..\syslinux\win;..\libcdio;..\getopt;%(AdditionalIncludeDirectories) CompileAsC true false @@ -163,7 +163,7 @@ _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;%(PreprocessorDefinitions) MultiThreaded Level3 - ..\msvc-missing;..\ms-sys\inc;..\syslinux\libinstaller;..\syslinux\libfat;..\libcdio;..\getopt;%(AdditionalIncludeDirectories) + ..\msvc-missing;..\ms-sys\inc;..\syslinux\libinstaller;..\syslinux\libfat;..\syslinux\win;..\libcdio;..\getopt;%(AdditionalIncludeDirectories) CompileAsC true false @@ -262,6 +262,9 @@ {266502ac-cd74-4581-b707-938a7d05ad7a} + + {7d2e9784-ddf7-4988-a887-cf099bc3b340} + diff --git a/src/.msvc/rufus_sources b/src/.msvc/rufus_sources index f14f1178..46ab8b7f 100644 --- a/src/.msvc/rufus_sources +++ b/src/.msvc/rufus_sources @@ -3,7 +3,7 @@ TARGETTYPE=PROGRAM UMTYPE=windows UMENTRY=winmain -INCLUDES=$(DDK_INC_PATH);.\ms-sys\inc;.\syslinux\libfat;.\syslinux\libinstaller;.\msvc-missing;.\libcdio;.\getopt;.\bled +INCLUDES=$(DDK_INC_PATH);.\ms-sys\inc;.\syslinux\libfat;.\syslinux\libinstaller;.\syslinux\win;.\msvc-missing;.\libcdio;.\getopt;.\bled C_DEFINES = $(C_DEFINES) /DDDKBUILD /DUNICODE /D_UNICODE /DRUFUS_LOC /DISOLATION_AWARE_ENABLED !IFNDEF MSC_WARNING_LEVEL @@ -25,6 +25,7 @@ TARGETLIBS=$(SDK_LIB_PATH)\kernel32.lib \ .\ms-sys\ms-sys.lib \ .\syslinux\libfat\libfat.lib \ .\syslinux\libinstaller\libinstaller.lib \ + .\syslinux\win\win.lib \ .\libcdio\iso9660\iso9660.lib \ .\libcdio\udf\udf.lib \ .\libcdio\driver\driver.lib \ diff --git a/src/Makefile.am b/src/Makefile.am index 0833d07e..d2fe6359 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = bled ms-sys syslinux/libfat syslinux/libinstaller libcdio/iso9660 libcdio/udf libcdio/driver ../res/localization +SUBDIRS = bled ms-sys syslinux/libfat syslinux/libinstaller syslinux/win libcdio/iso9660 libcdio/udf libcdio/driver ../res/localization noinst_PROGRAMS = rufus @@ -12,7 +12,7 @@ AM_V_WINDRES = $(AM_V_WINDRES_$(V)) rufus_SOURCES = badblocks.c checksum.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c net.c parser.c \ pki.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c usb.c vhd.c -rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./libcdio $(AM_CFLAGS) +rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS) rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows -rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \ +rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \ libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust diff --git a/src/Makefile.in b/src/Makefile.in index dd429125..137a8a86 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -100,8 +100,8 @@ am_rufus_OBJECTS = rufus-badblocks.$(OBJEXT) rufus-checksum.$(OBJEXT) \ rufus_OBJECTS = $(am_rufus_OBJECTS) rufus_DEPENDENCIES = rufus_rc.o bled/libbled.a ms-sys/libmssys.a \ syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \ - libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a \ - libcdio/driver/libdriver.a + syslinux/win/libwin.a libcdio/iso9660/libiso9660.a \ + libcdio/udf/libudf.a libcdio/driver/libdriver.a rufus_LINK = $(CCLD) $(rufus_CFLAGS) $(CFLAGS) $(rufus_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) @@ -265,7 +265,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -SUBDIRS = bled ms-sys syslinux/libfat syslinux/libinstaller libcdio/iso9660 libcdio/udf libcdio/driver ../res/localization +SUBDIRS = bled ms-sys syslinux/libfat syslinux/libinstaller syslinux/win libcdio/iso9660 libcdio/udf libcdio/driver ../res/localization AM_V_WINDRES_0 = @echo " RC $@";$(WINDRES) AM_V_WINDRES_1 = $(WINDRES) AM_V_WINDRES_ = $(AM_V_WINDRES_$(AM_DEFAULT_VERBOSITY)) @@ -273,9 +273,9 @@ AM_V_WINDRES = $(AM_V_WINDRES_$(V)) rufus_SOURCES = badblocks.c checksum.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c net.c parser.c \ pki.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c usb.c vhd.c -rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./libcdio $(AM_CFLAGS) +rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS) rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows -rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \ +rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \ libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust all: all-recursive diff --git a/src/rufus.h b/src/rufus.h index b0683da6..5adcf912 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -371,7 +371,7 @@ extern char szFolderPath[MAX_PATH], app_dir[MAX_PATH], system_dir[MAX_PATH], sys extern char* image_path; extern DWORD FormatStatus, DownloadStatus; extern BOOL PromptOnError; -extern DWORD syslinux_ldlinux_len[2]; +extern unsigned long syslinux_ldlinux_len[2]; extern RUFUS_DRIVE_INFO SelectedDrive; extern const int nb_steps[FS_MAX]; extern BOOL use_own_c32[NB_OLD_C32], detect_fakes, iso_op_in_progress, format_op_in_progress, right_to_left_mode; diff --git a/src/rufus.rc b/src/rufus.rc index bd4bf82f..5c11a943 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.864" +CAPTION "Rufus 2.8.865" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,864,0 - PRODUCTVERSION 2,8,864,0 + FILEVERSION 2,8,865,0 + PRODUCTVERSION 2,8,865,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.864" + VALUE "FileVersion", "2.8.865" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.864" + VALUE "ProductVersion", "2.8.865" END END BLOCK "VarFileInfo" diff --git a/src/syslinux.c b/src/syslinux.c index ed979c38..d18ff0c6 100644 --- a/src/syslinux.c +++ b/src/syslinux.c @@ -40,9 +40,9 @@ #include "ntfssect.h" unsigned char* syslinux_ldlinux[2] = { NULL, NULL }; -DWORD syslinux_ldlinux_len[2]; +unsigned long syslinux_ldlinux_len[2]; unsigned char* syslinux_mboot = NULL; -DWORD syslinux_mboot_len; +unsigned long syslinux_mboot_len; // Workaround for 4K support uint32_t SECTOR_SHIFT = 9; diff --git a/src/syslinux/libfat/.msvc/libfat.vcxproj b/src/syslinux/libfat/.msvc/libfat.vcxproj index 64241db6..5c31a205 100644 --- a/src/syslinux/libfat/.msvc/libfat.vcxproj +++ b/src/syslinux/libfat/.msvc/libfat.vcxproj @@ -104,6 +104,7 @@ ..;..\..\..\msvc-missing;%(AdditionalIncludeDirectories) MultiThreadedDebug ProgramDatabase + 4018;4244 Windows @@ -124,6 +125,7 @@ ..;..\..\..\msvc-missing;%(AdditionalIncludeDirectories) MultiThreaded ProgramDatabase + 4018;4244 MachineX86 @@ -139,6 +141,7 @@ ..;..\..\..\msvc-missing;%(AdditionalIncludeDirectories) MultiThreadedDebug ProgramDatabase + 4018;4244 Windows @@ -159,6 +162,7 @@ ..;..\..\..\msvc-missing;%(AdditionalIncludeDirectories) MultiThreaded ProgramDatabase + 4018;4244 Windows diff --git a/src/syslinux/libfat/.msvc/libfat_sources b/src/syslinux/libfat/.msvc/libfat_sources index 49e50780..9059eb50 100644 --- a/src/syslinux/libfat/.msvc/libfat_sources +++ b/src/syslinux/libfat/.msvc/libfat_sources @@ -5,7 +5,7 @@ INCLUDES=$(DDK_INC_PATH);..\..\msvc-missing C_DEFINES=$(C_DEFINES) /Dinline=__inline /DDDKBUILD /DUNICODE /D_UNICODE /DISOLATION_AWARE_ENABLED !IFNDEF MSC_WARNING_LEVEL -MSC_WARNING_LEVEL=/W3 +MSC_WARNING_LEVEL=/W2 !ENDIF USE_MSVCRT=1 diff --git a/src/syslinux/libfat/fatchain.c b/src/syslinux/libfat/fatchain.c index 16d2111a..9853a726 100644 --- a/src/syslinux/libfat/fatchain.c +++ b/src/syslinux/libfat/fatchain.c @@ -66,7 +66,7 @@ libfat_sector_t libfat_nextsector(struct libfat_filesystem * fs, if (~rs & clustmask) return s + 1; /* Next sector in cluster */ - cluster = (int32_t) (2 + (rs >> fs->clustshift)); + cluster = 2 + (rs >> fs->clustshift); if (cluster >= fs->endcluster) return -1; diff --git a/src/syslinux/libfat/open.c b/src/syslinux/libfat/open.c index c3520ddc..dad372b3 100644 --- a/src/syslinux/libfat/open.c +++ b/src/syslinux/libfat/open.c @@ -77,7 +77,7 @@ libfat_open(int (*readfunc) (intptr_t, void *, size_t, libfat_sector_t), goto barf; /* Figure out how many clusters */ - nclusters = (uint32_t) ((fs->end - fs->data) >> fs->clustshift); + nclusters = (fs->end - fs->data) >> fs->clustshift; fs->endcluster = nclusters + 2; if (nclusters <= 0xff4) { @@ -92,15 +92,10 @@ libfat_open(int (*readfunc) (intptr_t, void *, size_t, libfat_sector_t), } else goto barf; /* Impossibly many clusters */ - /* This check doesn't hold for Large FAT32 => remove it */ -#if 0 - minfatsize = (minfatsize + LIBFAT_SECTOR_SIZE - 1) >> LIBFAT_SECTOR_SHIFT; + minfatsize >>= LIBFAT_SECTOR_SHIFT; if (minfatsize > fatsize) goto barf; /* The FATs don't fit */ -#else - (void)(minfatsize); /* silence an unused warning in MinGW */ -#endif if (fs->fat_type == FAT28) fs->rootcluster = read32(&bs->u.fat32.bpb_rootclus); diff --git a/src/syslinux/libfat/searchdir.c b/src/syslinux/libfat/searchdir.c index 7e47fe58..4964120b 100644 --- a/src/syslinux/libfat/searchdir.c +++ b/src/syslinux/libfat/searchdir.c @@ -25,7 +25,7 @@ int32_t libfat_searchdir(struct libfat_filesystem *fs, int32_t dirclust, const void *name, struct libfat_direntry *direntry) { struct fat_dirent *dep; - unsigned int nent; + int nent; libfat_sector_t s = libfat_clustertosector(fs, dirclust); while (1) { diff --git a/src/syslinux/libinstaller/.msvc/libinstaller.vcxproj b/src/syslinux/libinstaller/.msvc/libinstaller.vcxproj index e0ac17b6..d266224a 100644 --- a/src/syslinux/libinstaller/.msvc/libinstaller.vcxproj +++ b/src/syslinux/libinstaller/.msvc/libinstaller.vcxproj @@ -20,7 +20,6 @@ - @@ -28,7 +27,6 @@ - @@ -106,6 +104,7 @@ ..;..\..\..\msvc-missing;%(AdditionalIncludeDirectories) MultiThreadedDebug ProgramDatabase + 4244;4267 Windows @@ -126,6 +125,7 @@ ..;..\..\..\msvc-missing;%(AdditionalIncludeDirectories) MultiThreaded ProgramDatabase + 4244;4267 MachineX86 @@ -141,6 +141,7 @@ ..;..\..\..\msvc-missing;%(AdditionalIncludeDirectories) MultiThreadedDebug ProgramDatabase + 4244;4267 Windows @@ -161,6 +162,7 @@ ..;..\..\..\msvc-missing;%(AdditionalIncludeDirectories) MultiThreaded ProgramDatabase + 4244;4267 Windows diff --git a/src/syslinux/libinstaller/.msvc/libinstaller.vcxproj.filters b/src/syslinux/libinstaller/.msvc/libinstaller.vcxproj.filters index 29591d44..5cc1daa8 100644 --- a/src/syslinux/libinstaller/.msvc/libinstaller.vcxproj.filters +++ b/src/syslinux/libinstaller/.msvc/libinstaller.vcxproj.filters @@ -26,9 +26,6 @@ Header Files - - Header Files - @@ -40,8 +37,5 @@ Source Files - - Source Files - \ No newline at end of file diff --git a/src/syslinux/libinstaller/.msvc/libinstaller_sources b/src/syslinux/libinstaller/.msvc/libinstaller_sources index 57d6b7ae..80d1d686 100644 --- a/src/syslinux/libinstaller/.msvc/libinstaller_sources +++ b/src/syslinux/libinstaller/.msvc/libinstaller_sources @@ -5,7 +5,7 @@ INCLUDES=$(DDK_INC_PATH);..\..\msvc-missing C_DEFINES=$(C_DEFINES) /Dinline=__inline /DDDKBUILD /DUNICODE /D_UNICODE /DISOLATION_AWARE_ENABLED !IFNDEF MSC_WARNING_LEVEL -MSC_WARNING_LEVEL=/W3 +MSC_WARNING_LEVEL=/W2 !ENDIF USE_MSVCRT=1 @@ -13,6 +13,5 @@ TARGETLIBS=$(SDK_LIB_PATH)\kernel32.lib \ $(SDK_LIB_PATH)\user32.lib SOURCES=fs.c \ - ntfssect.c \ setadv.c \ syslxmod.c \ No newline at end of file diff --git a/src/syslinux/libinstaller/Makefile.am b/src/syslinux/libinstaller/Makefile.am index 71948b40..21249cde 100644 --- a/src/syslinux/libinstaller/Makefile.am +++ b/src/syslinux/libinstaller/Makefile.am @@ -1,4 +1,4 @@ noinst_LIBRARIES = libinstaller.a -libinstaller_a_SOURCES = fs.c ntfssect.c setadv.c syslxmod.c +libinstaller_a_SOURCES = fs.c setadv.c syslxmod.c libinstaller_a_CFLAGS = $(AM_CFLAGS) \ No newline at end of file diff --git a/src/syslinux/libinstaller/Makefile.in b/src/syslinux/libinstaller/Makefile.in index 47f34cc3..18f5e725 100644 --- a/src/syslinux/libinstaller/Makefile.in +++ b/src/syslinux/libinstaller/Makefile.in @@ -94,7 +94,6 @@ am__v_AR_1 = libinstaller_a_AR = $(AR) $(ARFLAGS) libinstaller_a_LIBADD = am_libinstaller_a_OBJECTS = libinstaller_a-fs.$(OBJEXT) \ - libinstaller_a-ntfssect.$(OBJEXT) \ libinstaller_a-setadv.$(OBJEXT) \ libinstaller_a-syslxmod.$(OBJEXT) libinstaller_a_OBJECTS = $(am_libinstaller_a_OBJECTS) @@ -244,7 +243,7 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ noinst_LIBRARIES = libinstaller.a -libinstaller_a_SOURCES = fs.c ntfssect.c setadv.c syslxmod.c +libinstaller_a_SOURCES = fs.c setadv.c syslxmod.c libinstaller_a_CFLAGS = $(AM_CFLAGS) all: all-am @@ -307,12 +306,6 @@ libinstaller_a-fs.o: fs.c libinstaller_a-fs.obj: fs.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libinstaller_a_CFLAGS) $(CFLAGS) -c -o libinstaller_a-fs.obj `if test -f 'fs.c'; then $(CYGPATH_W) 'fs.c'; else $(CYGPATH_W) '$(srcdir)/fs.c'; fi` -libinstaller_a-ntfssect.o: ntfssect.c - $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libinstaller_a_CFLAGS) $(CFLAGS) -c -o libinstaller_a-ntfssect.o `test -f 'ntfssect.c' || echo '$(srcdir)/'`ntfssect.c - -libinstaller_a-ntfssect.obj: ntfssect.c - $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libinstaller_a_CFLAGS) $(CFLAGS) -c -o libinstaller_a-ntfssect.obj `if test -f 'ntfssect.c'; then $(CYGPATH_W) 'ntfssect.c'; else $(CYGPATH_W) '$(srcdir)/ntfssect.c'; fi` - libinstaller_a-setadv.o: setadv.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libinstaller_a_CFLAGS) $(CFLAGS) -c -o libinstaller_a-setadv.o `test -f 'setadv.c' || echo '$(srcdir)/'`setadv.c diff --git a/src/syslinux/libinstaller/setadv.c b/src/syslinux/libinstaller/setadv.c index 66601f7c..437583e9 100644 --- a/src/syslinux/libinstaller/setadv.c +++ b/src/syslinux/libinstaller/setadv.c @@ -20,7 +20,6 @@ * Return 0 on success, -1 on error, and set errno. * */ -//#define _GNU_SOURCE #include #include @@ -110,8 +109,8 @@ int syslinux_setadv(int tag, size_t size, const void *data) return -1; } - *p++ = (uint8_t) tag; - *p++ = (uint8_t) size; + *p++ = tag; + *p++ = size; memcpy(p, data, size); p += size; left -= size + 2; diff --git a/src/syslinux/libinstaller/syslinux.h b/src/syslinux/libinstaller/syslinux.h index 1f6fe278..6e1d864d 100644 --- a/src/syslinux/libinstaller/syslinux.h +++ b/src/syslinux/libinstaller/syslinux.h @@ -13,7 +13,6 @@ #ifndef SYSLINUX_H #define SYSLINUX_H -#include #include #include "advconst.h" #include "setadv.h" @@ -28,7 +27,7 @@ /* The standard boot sector and ldlinux image */ extern unsigned char* syslinux_ldlinux[2]; -extern DWORD syslinux_ldlinux_len[2]; +extern unsigned long syslinux_ldlinux_len[2]; extern const int syslinux_ldlinux_mtime[2]; #define boot_sector syslinux_ldlinux[1] @@ -40,12 +39,9 @@ extern unsigned char syslinux_mbr[]; extern const unsigned int syslinux_mbr_len; extern const int syslinux_mbr_mtime; -/* Sector size assumptions... */ -// Workaround for 4K support +/* Sector size variables are defined externally for 4K support */ extern uint32_t SECTOR_SHIFT; extern uint32_t SECTOR_SIZE; -//#define SECTOR_SHIFT 9 -//#define SECTOR_SIZE (1 << SECTOR_SHIFT) /* This takes a boot sector and merges in the syslinux fields */ void syslinux_make_bootsect(void *bs, int fs_type); diff --git a/src/syslinux/libinstaller/syslxint.h b/src/syslinux/libinstaller/syslxint.h index 95eef2bc..9ff63f2e 100644 --- a/src/syslinux/libinstaller/syslxint.h +++ b/src/syslinux/libinstaller/syslxint.h @@ -92,8 +92,8 @@ static inline void set_16(uint16_t *p, uint16_t v) *p = v; #else uint8_t *pp = (uint8_t *) p; - pp[0] = (v & 0xff); - pp[1] = ((v >> 8) & 0xff); + pp[0] = v; + pp[1] = v >> 8; #endif } diff --git a/src/syslinux/libinstaller/syslxmod.c b/src/syslinux/libinstaller/syslxmod.c index 88dd490c..581f9fce 100644 --- a/src/syslinux/libinstaller/syslxmod.c +++ b/src/syslinux/libinstaller/syslxmod.c @@ -60,7 +60,7 @@ static void generate_extents(struct syslinux_extent _slimg *ex, int nptrs, } set_64_sl(&ex->lba, lba); - set_16_sl(&ex->len, (uint16_t) len); + set_16_sl(&ex->len, len); ex++; } @@ -75,7 +75,7 @@ static void generate_extents(struct syslinux_extent _slimg *ex, int nptrs, if (len) { set_64_sl(&ex->lba, lba); - set_16_sl(&ex->len, (uint16_t) len); + set_16_sl(&ex->len, len); ex++; } } @@ -132,8 +132,8 @@ int syslinux_patch(const sector_t *sectp, int nsectors, epa = slptr(boot_image, &patcharea->epaoffset); /* First sector need pointer in boot sector */ - set_32(ptr(sbs, &epa->sect1ptr0), (uint32_t) sectp[0]); - set_32(ptr(sbs, &epa->sect1ptr1), (uint32_t) (sectp[0] >> 32)); + set_32(ptr(sbs, &epa->sect1ptr0), sectp[0]); + set_32(ptr(sbs, &epa->sect1ptr1), sectp[0] >> 32); sectp++; /* Handle RAID mode */ @@ -176,7 +176,7 @@ int syslinux_patch(const sector_t *sectp, int nsectors, /* Poke in the base directory path */ if (subdir) { - int sublen = (int) (strlen(subdir) + 1); + int sublen = strlen(subdir) + 1; if (get_16_sl(&epa->dirlen) < sublen) { fprintf(stderr, "Subdirectory path too long... aborting install!\n"); exit(1); @@ -186,7 +186,7 @@ int syslinux_patch(const sector_t *sectp, int nsectors, /* Poke in the subvolume information */ if (subvol) { - int sublen = (int) (strlen(subvol) + 1); + int sublen = strlen(subvol) + 1; if (get_16_sl(&epa->subvollen) < sublen) { fprintf(stderr, "Subvol name too long... aborting install!\n"); exit(1); diff --git a/src/syslinux/win/.msvc/win.vcxproj b/src/syslinux/win/.msvc/win.vcxproj new file mode 100644 index 00000000..bd35ad48 --- /dev/null +++ b/src/syslinux/win/.msvc/win.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + {7D2E9784-DDF7-4988-A887-CF099BC3B340} + Win32Proj + win + syslinux-win + + + + StaticLibrary + true + Unicode + v140 + + + StaticLibrary + false + true + Unicode + v140 + + + StaticLibrary + true + Unicode + v140 + + + StaticLibrary + false + true + Unicode + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)x86_32\$(Configuration)\ + $(SolutionDir)x86_32\$(Configuration)\$(ProjectName)\ + $(SolutionDir)x86_32\$(Configuration)\ + $(SolutionDir)x86_32\$(Configuration)\$(ProjectName)\ + $(SolutionDir)x86_64\$(Configuration)\ + $(SolutionDir)x86_64\$(Configuration)\$(ProjectName)\ + $(SolutionDir)x86_64\$(Configuration)\ + $(SolutionDir)x86_64\$(Configuration)\$(ProjectName)\ + false + false + false + false + + + + + + Level3 + Disabled + inline=__inline;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) + ..;..\..\..\msvc-missing;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + 4244;4267;4996 + + + Windows + true + + + MachineX86 + + + + + Level3 + + + MaxSpeed + true + inline=__inline;%(PreprocessorDefinitions) + ..;..\..\..\msvc-missing;%(AdditionalIncludeDirectories) + MultiThreaded + ProgramDatabase + 4244;4267;4996 + + + MachineX86 + + + + + + + Level3 + Disabled + inline=__inline;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) + ..;..\..\..\msvc-missing;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + 4244;4267;4996 + + + Windows + true + + + MachineX64 + + + + + Level3 + + + MaxSpeed + true + inline=__inline;%(PreprocessorDefinitions) + ..;..\..\..\msvc-missing;%(AdditionalIncludeDirectories) + MultiThreaded + ProgramDatabase + 4244;4267;4996 + + + Windows + true + true + true + + + MachineX64 + + + + + + \ No newline at end of file diff --git a/src/syslinux/win/.msvc/win.vcxproj.filters b/src/syslinux/win/.msvc/win.vcxproj.filters new file mode 100644 index 00000000..ce6dd6c7 --- /dev/null +++ b/src/syslinux/win/.msvc/win.vcxproj.filters @@ -0,0 +1,23 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/src/syslinux/win/.msvc/win_sources b/src/syslinux/win/.msvc/win_sources new file mode 100644 index 00000000..6cc0bb71 --- /dev/null +++ b/src/syslinux/win/.msvc/win_sources @@ -0,0 +1,15 @@ +TARGETNAME=win +TARGETTYPE=LIBRARY + +INCLUDES=$(DDK_INC_PATH);..\..\msvc-missing +C_DEFINES=$(C_DEFINES) /Dinline=__inline /DDDKBUILD /DUNICODE /D_UNICODE /DISOLATION_AWARE_ENABLED + +!IFNDEF MSC_WARNING_LEVEL +MSC_WARNING_LEVEL=/W2 +!ENDIF +USE_MSVCRT=1 + +TARGETLIBS=$(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\user32.lib + +SOURCES=ntfssect.c diff --git a/src/syslinux/libinstaller/ntfssect.c b/src/syslinux/win/ntfssect.c similarity index 83% rename from src/syslinux/libinstaller/ntfssect.c rename to src/syslinux/win/ntfssect.c index 414e7d49..3dd6d7f0 100644 --- a/src/syslinux/libinstaller/ntfssect.c +++ b/src/syslinux/win/ntfssect.c @@ -18,9 +18,6 @@ * With special thanks to Mark Roddy for his article: * http://www.wd-3.com/archive/luserland.htm */ -#if defined(_MSC_VER) -#pragma warning(disable:4996) -#endif #include #include @@ -33,6 +30,10 @@ #define M_ERR(msg) (NtfsSectLastErrorMessage = (msg)) /*** Function declarations */ +static DWORD NtfsSectGetVolumeHandle( + CHAR * VolumeName, + S_NTFSSECT_VOLINFO * VolumeInfo + ); static DWORD NtfsSectGetVolumePartitionLba(S_NTFSSECT_VOLINFO * VolumeInfo); /*** Objects */ @@ -44,7 +45,7 @@ DWORD M_NTFSSECT_API NtfsSectGetFileVcnExtent( LARGE_INTEGER * Vcn, S_NTFSSECT_EXTENT * Extent ) { - BOOL bad, ok; + BOOL bad; DWORD output_size, rc; STARTING_VCN_INPUT_BUFFER input; RETRIEVAL_POINTERS_BUFFER output; @@ -59,7 +60,7 @@ DWORD M_NTFSSECT_API NtfsSectGetFileVcnExtent( return ERROR_INVALID_PARAMETER; input.StartingVcn = *Vcn; - ok = DeviceIoControl( + DeviceIoControl( File, FSCTL_GET_RETRIEVAL_POINTERS, &input, @@ -69,7 +70,6 @@ DWORD M_NTFSSECT_API NtfsSectGetFileVcnExtent( &output_size, NULL ); - ok = ok; rc = GetLastError(); switch (rc) { case NO_ERROR: @@ -89,6 +89,52 @@ DWORD M_NTFSSECT_API NtfsSectGetFileVcnExtent( return rc; } +/* Internal use only */ +static DWORD NtfsSectGetVolumeHandle( + CHAR * VolumeName, + S_NTFSSECT_VOLINFO * VolumeInfo + ) { + #define M_VOL_PREFIX "\\\\.\\" + CHAR volname[sizeof M_VOL_PREFIX - 1 + MAX_PATH + 1] = M_VOL_PREFIX; + CHAR * const volname_short = volname + sizeof M_VOL_PREFIX - 1; + CHAR * c; + DWORD rc; + + /* Prefix "\\.\" onto the passed volume name */ + strcpy(volname + sizeof M_VOL_PREFIX - 1, VolumeName); + + /* Find the last non-null character */ + for (c = volname_short; *c; ++c) + ; + + /* Remove trailing back-slash */ + if (c[-1] == '\\') + c[-1] = 0; + + /* Open the volume */ + VolumeInfo->Handle = CreateFileA( + volname, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + rc = GetLastError(); + if (VolumeInfo->Handle == INVALID_HANDLE_VALUE) { + M_ERR("Unable to open volume handle!"); + goto err_handle; + } + + return ERROR_SUCCESS; + + CloseHandle(VolumeInfo->Handle); + err_handle: + + return rc; + } + DWORD M_NTFSSECT_API NtfsSectGetVolumeInfo( CHAR * VolumeName, S_NTFSSECT_VOLINFO * VolumeInfo @@ -100,6 +146,10 @@ DWORD M_NTFSSECT_API NtfsSectGetVolumeInfo( if (!VolumeName || !VolumeInfo) return ERROR_INVALID_PARAMETER; + rc = NtfsSectGetVolumeHandle(VolumeName, VolumeInfo); + if (rc != ERROR_SUCCESS) + goto err_handle; + rc = NtfsSectLoadXpFuncs(&xp_funcs); if (rc != ERROR_SUCCESS) goto err_xp_funcs; @@ -135,6 +185,7 @@ DWORD M_NTFSSECT_API NtfsSectGetVolumeInfo( CloseHandle(VolumeInfo->Handle); VolumeInfo->Handle = INVALID_HANDLE_VALUE; } + err_handle: return rc; } diff --git a/src/syslinux/libinstaller/ntfssect.h b/src/syslinux/win/ntfssect.h similarity index 100% rename from src/syslinux/libinstaller/ntfssect.h rename to src/syslinux/win/ntfssect.h diff --git a/wdk_build.cmd b/wdk_build.cmd index c51fe49f..e8118fd6 100644 --- a/wdk_build.cmd +++ b/wdk_build.cmd @@ -70,6 +70,21 @@ copy obj%BUILD_ALT_DIR%\%ARCH_DIR%\libinstaller.lib . >NUL 2>&1 if EXIST Makefile.hide ren Makefile.hide Makefile if EXIST sources del sources >NUL 2>&1 +::# SysLinux win Library +cd ..\win +if EXIST Makefile ren Makefile Makefile.hide + +copy .msvc\win_sources sources >NUL 2>&1 + +@echo on +%BUILD_CMD% +@echo off +if errorlevel 1 goto builderror +copy obj%BUILD_ALT_DIR%\%ARCH_DIR%\win.lib . >NUL 2>&1 + +if EXIST Makefile.hide ren Makefile.hide Makefile +if EXIST sources del sources >NUL 2>&1 + ::# libcdio iso9660 Library cd ..\..\libcdio\iso9660 if EXIST Makefile ren Makefile Makefile.hide From d20eb9262ba95f59e3d0ed563512c502b2daa8d8 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 24 Feb 2016 14:35:51 +0000 Subject: [PATCH 36/91] [misc] fix MinGW compilation * Makefile was missing from previous patch --- src/rufus.rc | 10 +- src/syslinux/win/Makefile.am | 4 + src/syslinux/win/Makefile.in | 477 +++++++++++++++++++++++++++++++++++ 3 files changed, 486 insertions(+), 5 deletions(-) create mode 100644 src/syslinux/win/Makefile.am create mode 100644 src/syslinux/win/Makefile.in diff --git a/src/rufus.rc b/src/rufus.rc index 5c11a943..82d21f91 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.865" +CAPTION "Rufus 2.8.866" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,865,0 - PRODUCTVERSION 2,8,865,0 + FILEVERSION 2,8,866,0 + PRODUCTVERSION 2,8,866,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.865" + VALUE "FileVersion", "2.8.866" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.865" + VALUE "ProductVersion", "2.8.866" END END BLOCK "VarFileInfo" diff --git a/src/syslinux/win/Makefile.am b/src/syslinux/win/Makefile.am new file mode 100644 index 00000000..56be0a73 --- /dev/null +++ b/src/syslinux/win/Makefile.am @@ -0,0 +1,4 @@ +noinst_LIBRARIES = libwin.a + +libwin_a_SOURCES = ntfssect.c +libwin_a_CFLAGS = $(AM_CFLAGS) diff --git a/src/syslinux/win/Makefile.in b/src/syslinux/win/Makefile.in new file mode 100644 index 00000000..fabb80fe --- /dev/null +++ b/src/syslinux/win/Makefile.in @@ -0,0 +1,477 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = src/syslinux/win +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libwin_a_AR = $(AR) $(ARFLAGS) +libwin_a_LIBADD = +am_libwin_a_OBJECTS = libwin_a-ntfssect.$(OBJEXT) +libwin_a_OBJECTS = $(am_libwin_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = +am__depfiles_maybe = +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libwin_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EXEEXT = @EXEEXT@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SUFFIX = @SUFFIX@ +VERSION = @VERSION@ +VISIBILITY_CFLAGS = @VISIBILITY_CFLAGS@ +WINDRES = @WINDRES@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +am__leading_dot = @am__leading_dot@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LIBRARIES = libwin.a +libwin_a_SOURCES = ntfssect.c +libwin_a_CFLAGS = $(AM_CFLAGS) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps src/syslinux/win/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps src/syslinux/win/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libwin.a: $(libwin_a_OBJECTS) $(libwin_a_DEPENDENCIES) $(EXTRA_libwin_a_DEPENDENCIES) + $(AM_V_at)-rm -f libwin.a + $(AM_V_AR)$(libwin_a_AR) libwin.a $(libwin_a_OBJECTS) $(libwin_a_LIBADD) + $(AM_V_at)$(RANLIB) libwin.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(AM_V_CC)$(COMPILE) -c -o $@ $< + +.c.obj: + $(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +libwin_a-ntfssect.o: ntfssect.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwin_a_CFLAGS) $(CFLAGS) -c -o libwin_a-ntfssect.o `test -f 'ntfssect.c' || echo '$(srcdir)/'`ntfssect.c + +libwin_a-ntfssect.obj: ntfssect.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwin_a_CFLAGS) $(CFLAGS) -c -o libwin_a-ntfssect.obj `if test -f 'ntfssect.c'; then $(CYGPATH_W) 'ntfssect.c'; else $(CYGPATH_W) '$(srcdir)/ntfssect.c'; fi` + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-tags dvi dvi-am \ + html html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: From 250d46e4019151d14ced0cd2e8360c13da19cfe4 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 24 Feb 2016 16:10:54 +0000 Subject: [PATCH 37/91] [core] use GetTickCount64() always where possible * Damn you XP!!! * Also some more code cleanup --- src/checksum.c | 8 ++++---- src/dos.c | 3 ++- src/drive.c | 2 +- src/format.c | 22 +++++++++++----------- src/icon.c | 1 + src/localization.c | 6 +++--- src/missing.h | 16 ++++++++++++++++ src/net.c | 3 ++- src/rufus.c | 13 ++++++++----- src/rufus.h | 21 +++++---------------- src/rufus.rc | 10 +++++----- src/settings.h | 2 +- src/stdlg.c | 7 ++++--- src/syslinux.c | 1 + src/vhd.c | 6 +++--- 15 files changed, 67 insertions(+), 54 deletions(-) diff --git a/src/checksum.c b/src/checksum.c index a5240d6c..5631c33d 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -778,8 +778,8 @@ INT_PTR CALLBACK ChecksumCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM DWORD WINAPI SumThread(void* param) { HANDLE h = INVALID_HANDLE_VALUE; - DWORD rSize = 0, LastRefresh = 0; - uint64_t rb; + DWORD rSize = 0; + uint64_t rb, LastRefresh = 0; char buffer[4096]; SHA1_CONTEXT sha1_ctx; SHA256_CONTEXT sha256_ctx; @@ -804,8 +804,8 @@ DWORD WINAPI SumThread(void* param) md5_init(&md5_ctx); for (rb = 0; ; rb += rSize) { - if (GetTickCount() > LastRefresh + 25) { - LastRefresh = GetTickCount(); + if (_GetTickCount64() > LastRefresh + 25) { + LastRefresh = _GetTickCount64(); format_percent = (100.0f*rb) / (1.0f*img_report.projected_size); PrintInfo(0, MSG_271, format_percent); SendMessage(hProgress, PBM_SETPOS, (WPARAM)((format_percent/100.0f)*MAX_PROGRESS), 0); diff --git a/src/dos.c b/src/dos.c index 0f506dc9..db57ee01 100644 --- a/src/dos.c +++ b/src/dos.c @@ -31,6 +31,7 @@ #include #include "rufus.h" +#include "missing.h" #include "resource.h" #include "dos.h" @@ -325,7 +326,7 @@ static BOOL ExtractMSDOS(const char* path) goto out; // Sanity check - if (DiskImageSize < 700*1024) { + if (DiskImageSize < 700*KB) { uprintf("MS-DOS disk image is too small (%d bytes)\n", dllname, DiskImageSize); goto out; } diff --git a/src/drive.c b/src/drive.c index 894b2873..95ce1b49 100644 --- a/src/drive.c +++ b/src/drive.c @@ -1189,7 +1189,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m // This helps us reselect the partition scheme option that was used when creating the // drive in Rufus. As far as I can tell, Windows doesn't care much if this signature // isn't unique for USB drives. - CreateDisk.Mbr.Signature = mbr_uefi_marker?MBR_UEFI_MARKER:GetTickCount(); + CreateDisk.Mbr.Signature = mbr_uefi_marker?MBR_UEFI_MARKER:(DWORD)_GetTickCount64(); DriveLayoutEx.PartitionStyle = PARTITION_STYLE_MBR; DriveLayoutEx.PartitionCount = 4; // Must be multiple of 4 for MBR diff --git a/src/format.c b/src/format.c index 5a488544..4adbce86 100644 --- a/src/format.c +++ b/src/format.c @@ -55,7 +55,7 @@ */ DWORD FormatStatus; badblocks_report report; -static DWORD LastRefresh; +static uint64_t LastRefresh; static float format_percent = 0.0f; static int task_number = 0; extern const int nb_steps[FS_MAX]; @@ -623,8 +623,8 @@ static BOOL FormatFAT32(DWORD DriveIndex) format_percent = 0.0f; for (i=0; i<(SystemAreaSize+BurstSize-1); i+=BurstSize) { - if (GetTickCount() > LastRefresh + 25) { - LastRefresh = GetTickCount(); + if (_GetTickCount64() > LastRefresh + 25) { + LastRefresh = _GetTickCount64(); format_percent = (100.0f*i)/(1.0f*(SystemAreaSize+BurstSize)); PrintInfo(0, MSG_217, format_percent); UpdateProgress(OP_FORMAT, format_percent); @@ -1460,8 +1460,8 @@ DWORD WINAPI CloseFormatPromptThread(LPVOID param) { void update_progress(const uint64_t processed_bytes) { - if (GetTickCount() > LastRefresh + 25) { - LastRefresh = GetTickCount(); + if (_GetTickCount64() > LastRefresh + 25) { + LastRefresh = _GetTickCount64(); format_percent = (100.0f*processed_bytes)/(1.0f*img_report.projected_size); PrintInfo(0, MSG_261, format_percent); UpdateProgress(OP_FORMAT, format_percent); @@ -1613,8 +1613,8 @@ DWORD WINAPI FormatThread(void* param) // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747.aspx does buffer sector alignment aligned_buffer = ((void *)((((uintptr_t)(buffer)) + (SectorSize)-1) & (~(((uintptr_t)(SectorSize)) - 1)))); for (wb = 0, wSize = 0; wb < (uint64_t)SelectedDrive.DiskSize; wb += wSize) { - if (GetTickCount() > LastRefresh + 25) { - LastRefresh = GetTickCount(); + if (_GetTickCount64() > LastRefresh + 25) { + LastRefresh = _GetTickCount64(); format_percent = (100.0f*wb) / (1.0f*SelectedDrive.DiskSize); PrintInfo(0, MSG_286, format_percent); UpdateProgress(OP_FORMAT, format_percent); @@ -1762,8 +1762,8 @@ DWORD WINAPI FormatThread(void* param) } if (rSize == 0) break; - if (GetTickCount() > LastRefresh + 25) { - LastRefresh = GetTickCount(); + if (_GetTickCount64() > LastRefresh + 25) { + LastRefresh = _GetTickCount64(); format_percent = (100.0f*wb)/(1.0f*img_report.projected_size); PrintInfo(0, MSG_261, format_percent); UpdateProgress(OP_FORMAT, format_percent); @@ -2084,8 +2084,8 @@ DWORD WINAPI SaveImageThread(void* param) } if (rSize == 0) break; - if (GetTickCount() > LastRefresh + 25) { - LastRefresh = GetTickCount(); + if (_GetTickCount64() > LastRefresh + 25) { + LastRefresh = _GetTickCount64(); format_percent = (100.0f*wb)/(1.0f*SelectedDrive.DiskSize); PrintInfo(0, MSG_261, format_percent); UpdateProgress(OP_FORMAT, format_percent); diff --git a/src/icon.c b/src/icon.c index 5e1985b3..45fd2d2f 100644 --- a/src/icon.c +++ b/src/icon.c @@ -28,6 +28,7 @@ #include #include "rufus.h" +#include "missing.h" #include "resource.h" #include "msapi_utf8.h" diff --git a/src/localization.c b/src/localization.c index d39f8eff..6e14957f 100644 --- a/src/localization.c +++ b/src/localization.c @@ -446,7 +446,7 @@ static void CALLBACK OutputMessageTimeout(HWND hWnd, UINT uMsg, UINT_PTR idEvent KillTimer(hMainDialog, idEvent); bOutputTimerArmed[i] = FALSE; PrintMessage[i](output_msg[i]); - last_msg_time[i] = GetTickCount64(); + last_msg_time[i] = _GetTickCount64(); } static void OutputMessage(BOOL info, char* msg) @@ -459,7 +459,7 @@ static void OutputMessage(BOOL info, char* msg) output_msg[i] = msg; } else { // Find if we need to arm a timer - delta = GetTickCount64() - last_msg_time[i]; + delta = _GetTickCount64() - last_msg_time[i]; if (delta < MSG_DELAY) { // Not enough time has elapsed since our last output => arm a timer output_msg[i] = msg; @@ -467,7 +467,7 @@ static void OutputMessage(BOOL info, char* msg) bOutputTimerArmed[i] = TRUE; } else { PrintMessage[i](msg); - last_msg_time[i] = GetTickCount64(); + last_msg_time[i] = _GetTickCount64(); } } } diff --git a/src/missing.h b/src/missing.h index 2ecacd06..0ad3d5e2 100644 --- a/src/missing.h +++ b/src/missing.h @@ -51,6 +51,12 @@ static __inline void *_reallocf(void *ptr, size_t size) { return ret; } +/* Why oh why does Microsoft have to make everybody suffer with their braindead use of Unicode? */ +#define _RT_ICON MAKEINTRESOURCEA(3) +#define _RT_DIALOG MAKEINTRESOURCEA(5) +#define _RT_RCDATA MAKEINTRESOURCEA(10) +#define _RT_GROUP_ICON MAKEINTRESOURCEA((ULONG_PTR)(MAKEINTRESOURCEA(3) + 11)) + /* UI redefinitions for WDK and MinGW */ #ifndef PBM_SETSTATE #define PBM_SETSTATE (WM_USER+16) @@ -212,3 +218,13 @@ typedef struct _ATTACH_VIRTUAL_DISK_PARAMETERS { #if !defined(ERROR_INTERNET_LOGIN_FAILURE_DISPLAY_ENTITY_BODY) #define ERROR_INTERNET_LOGIN_FAILURE_DISPLAY_ENTITY_BODY (INTERNET_ERROR_BASE + 174) #endif + +/* Clang/MinGW32 has an issue with intptr_t */ +#ifndef _UINTPTR_T_DEFINED +#define _UINTPTR_T_DEFINED +#ifdef _WIN64 +typedef unsigned __int64 uintptr_t; +#else +typedef unsigned int uintptr_t; +#endif +#endif diff --git a/src/net.c b/src/net.c index f6af0e61..d47ce7a3 100644 --- a/src/net.c +++ b/src/net.c @@ -31,6 +31,7 @@ #include #include "rufus.h" +#include "missing.h" #include "resource.h" #include "msapi_utf8.h" #include "localization.h" @@ -38,7 +39,7 @@ #include "settings.h" /* Maximum download chunk size, in bytes */ -#define DOWNLOAD_BUFFER_SIZE 10240 +#define DOWNLOAD_BUFFER_SIZE 10*KB /* Default delay between update checks (1 day) */ #define DEFAULT_UPDATE_INTERVAL (24*3600) diff --git a/src/rufus.c b/src/rufus.c index 276a724d..45d8eb59 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -94,6 +94,7 @@ OPENED_LIBRARIES_VARS; HINSTANCE hMainInstance; HWND hMainDialog, hLangToolbar = NULL, hUpdatesDlg = NULL; MY_BUTTON_IMAGELIST bi_iso = { 0 }, bi_up = { 0 }, bi_down = { 0 }; +GetTickCount64_t pfGetTickCount64 = NULL; char szFolderPath[MAX_PATH], app_dir[MAX_PATH], system_dir[MAX_PATH], sysnative_dir[MAX_PATH]; char* image_path = NULL; float fScale = 1.0f; @@ -2038,7 +2039,8 @@ void SaveVHD(void) */ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { - static DWORD DeviceNum = 0, LastRefresh = 0; + static DWORD DeviceNum = 0; + static uint64_t LastRefresh = 0; static BOOL first_log_display = TRUE, isMarquee = FALSE; static ULONG ulRegister = 0; static LPITEMIDLIST pidlDesktop = NULL; @@ -2078,15 +2080,15 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA case DBT_DEVICEARRIVAL: case DBT_DEVICEREMOVECOMPLETE: case DBT_CUSTOMEVENT: // Sent by our timer refresh function or for card reader media change - LastRefresh = GetTickCount(); // Don't care about 49.7 days rollback of GetTickCount() + LastRefresh = _GetTickCount64(); KillTimer(hMainDialog, TID_REFRESH_TIMER); GetUSBDevices((DWORD)ComboBox_GetItemData(hDeviceList, ComboBox_GetCurSel(hDeviceList))); user_changed_label = FALSE; return (INT_PTR)TRUE; case DBT_DEVNODES_CHANGED: // If it's been more than a second since last device refresh, arm a refresh timer - if (GetTickCount() > LastRefresh + 1000) { - LastRefresh = GetTickCount(); + if (_GetTickCount64() > LastRefresh + 1000) { + LastRefresh = _GetTickCount64(); SetTimer(hMainDialog, TID_REFRESH_TIMER, 1000, RefreshTimer); } break; @@ -2789,6 +2791,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine #endif uprintf("*** " APPLICATION_NAME " init ***\n"); + PF_INIT(GetTickCount64, kernel32); // Reattach the console, if we were started from commandline if (AttachConsole(ATTACH_PARENT_PROCESS) != 0) { @@ -3009,7 +3012,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine uprintf("Failed to enable AutoMount"); } } - srand((unsigned int)GetTickCount()); + srand((unsigned int)_GetTickCount64()); relaunch: uprintf("localization: using locale '%s'\n", selected_locale->txt[0]); diff --git a/src/rufus.h b/src/rufus.h index 5adcf912..61b9b2dc 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -23,7 +23,7 @@ #if defined(_MSC_VER) // Disable some VS2012 Code Analysis warnings #pragma warning(disable: 4996) // Ignore deprecated (eg. GetVersionEx()), as we have to contend with XP -#pragma warning(disable: 28159) // VS2012 wants us to use GetTickCount64(), but it's not available on XP +#pragma warning(disable: 28159) // We use GetTickCount64() where possible, but it's not available on XP #pragma warning(disable: 6258) // I know what I'm using TerminateThread for #endif @@ -537,16 +537,6 @@ static __inline HMODULE GetLibraryHandle(char* szLibraryName) { if (pf##proc == NULL) {uprintf("Unable to locate %s() in %s.dll: %s\n", \ #proc, #name, WindowsErrorString()); goto out;} } while(0) -/* Clang/MinGW32 has an issue with intptr_t */ -#ifndef _UINTPTR_T_DEFINED -#define _UINTPTR_T_DEFINED -#ifdef _WIN64 - typedef unsigned __int64 uintptr_t; -#else - typedef unsigned int uintptr_t; -#endif -#endif - /* Custom application errors */ #define FAC(f) (f<<16) #define APPERR(err) (APPLICATION_ERROR_MASK|err) @@ -563,8 +553,7 @@ static __inline HMODULE GetLibraryHandle(char* szLibraryName) { #define ERROR_CANT_ASSIGN_LETTER 0x120B #define ERROR_CANT_MOUNT_VOLUME 0x120C -/* Why oh why does Microsoft have to make everybody suffer with their braindead use of Unicode? */ -#define _RT_ICON MAKEINTRESOURCEA(3) -#define _RT_DIALOG MAKEINTRESOURCEA(5) -#define _RT_RCDATA MAKEINTRESOURCEA(10) -#define _RT_GROUP_ICON MAKEINTRESOURCEA((ULONG_PTR)(MAKEINTRESOURCEA(3) + 11)) +/* GetTickCount64 not being available on XP is a massive bother */ +PF_TYPE(WINAPI, ULONGLONG, GetTickCount64, (void)); +extern GetTickCount64_t pfGetTickCount64; +#define _GetTickCount64() ((pfGetTickCount64 != NULL)?(uint64_t)pfGetTickCount64():(uint64_t)GetTickCount()) diff --git a/src/rufus.rc b/src/rufus.rc index 82d21f91..1262516a 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.866" +CAPTION "Rufus 2.8.867" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,866,0 - PRODUCTVERSION 2,8,866,0 + FILEVERSION 2,8,867,0 + PRODUCTVERSION 2,8,867,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.866" + VALUE "FileVersion", "2.8.867" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.866" + VALUE "ProductVersion", "2.8.867" END END BLOCK "VarFileInfo" diff --git a/src/settings.h b/src/settings.h index bb65ff1f..c65682f5 100644 --- a/src/settings.h +++ b/src/settings.h @@ -31,7 +31,7 @@ extern char* ini_file; #define SETTING_LAST_UPDATE "LastUpdateCheck" #define SETTING_UPDATE_INTERVAL "UpdateCheckInterval" #define SETTING_INCLUDE_BETAS "CheckForBetas" -#define SETTING_COMM_CHECK "CommCheck" +#define SETTING_COMM_CHECK "CommCheck64" #define SETTING_LOCALE "Locale" #define SETTING_DISABLE_LGP "DisableLGP" diff --git a/src/stdlg.c b/src/stdlg.c index bf606ae7..e530c7dc 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -35,6 +35,7 @@ #include #include "rufus.h" +#include "missing.h" #include "resource.h" #include "msapi_utf8.h" #include "localization.h" @@ -1358,14 +1359,14 @@ INT_PTR CALLBACK UpdateCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM l BOOL SetUpdateCheck(void) { BOOL enable_updates; - DWORD commcheck = GetTickCount(); + uint64_t commcheck = _GetTickCount64(); notification_info more_info = { IDD_UPDATE_POLICY, UpdateCallback }; char filename[MAX_PATH] = "", exename[] = APPLICATION_NAME ".exe"; size_t fn_len, exe_len; // Test if we can read and write settings. If not, forget it. - WriteSetting32(SETTING_COMM_CHECK, commcheck); - if (ReadSetting32(SETTING_COMM_CHECK) != commcheck) + WriteSetting64(SETTING_COMM_CHECK, commcheck); + if (ReadSetting64(SETTING_COMM_CHECK) != commcheck) return FALSE; settings_commcheck = TRUE; diff --git a/src/syslinux.c b/src/syslinux.c index d18ff0c6..f29f2706 100644 --- a/src/syslinux.c +++ b/src/syslinux.c @@ -27,6 +27,7 @@ #include #include "rufus.h" +#include "missing.h" #include "resource.h" #include "msapi_utf8.h" #include "localization.h" diff --git a/src/vhd.c b/src/vhd.c index ddc361c6..d10a8c2f 100644 --- a/src/vhd.c +++ b/src/vhd.c @@ -103,7 +103,7 @@ static char sevenzip_path[MAX_PATH]; static const char conectix_str[] = VHD_FOOTER_COOKIE; static uint32_t wim_nb_files, wim_proc_files; static BOOL count_files; -static DWORD LastRefresh; +static uint64_t LastRefresh; static BOOL Get7ZipPath(void) { @@ -573,12 +573,12 @@ DWORD WINAPI WimProgressCallback(DWORD dwMsgId, WPARAM wParam, LPARAM lParam, PV wim_nb_files++; } else { wim_proc_files++; - if (GetTickCount() > LastRefresh + 100) { + if (_GetTickCount64() > LastRefresh + 100) { // At the end of an actual apply, the WIM API re-lists a bunch of directories it // already processed, so we end up with more entries than counted - ignore those. if (wim_proc_files > wim_nb_files) wim_proc_files = wim_nb_files; - LastRefresh = GetTickCount(); + LastRefresh = _GetTickCount64(); // x^3 progress, so as not to give a better idea right from the onset // as to the dismal speed with which the WIM API can actually apply files... apply_percent = 4.636942595f * ((float)wim_proc_files) / ((float)wim_nb_files); From ade5639c0047ee813f71a8bfef8b1cc7be551009 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 25 Feb 2016 18:21:31 +0000 Subject: [PATCH 38/91] [misc] more headers cleanup --- src/drive.h | 30 ++++++++++++++++++++++++++++-- src/rufus.h | 26 -------------------------- src/rufus.rc | 10 +++++----- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/drive.h b/src/drive.h index 584977ec..dd6de5e9 100644 --- a/src/drive.h +++ b/src/drive.h @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Drive access function calls - * Copyright © 2011-2014 Pete Batard + * Copyright © 2011-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include #include +#include // for DISK_GEOMETRY #pragma once @@ -26,7 +27,7 @@ #define MOUNTMGRCONTROLTYPE ((ULONG)'m') #define MOUNTMGR_DOS_DEVICE_NAME "\\\\.\\MountPointManager" #define IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT \ - CTL_CODE(MOUNTMGRCONTROLTYPE, 15, METHOD_BUFFERED, FILE_ANY_ACCESS) + CTL_CODE(MOUNTMGRCONTROLTYPE, 15, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_MOUNTMGR_SET_AUTO_MOUNT \ CTL_CODE(MOUNTMGRCONTROLTYPE, 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) @@ -48,6 +49,31 @@ typedef struct { DISK_EXTENT Extents[8]; } VOLUME_DISK_EXTENTS_REDEF; +static __inline BOOL UnlockDrive(HANDLE hDrive) { + DWORD size; + return DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &size, NULL); +} +#define safe_unlockclose(h) do {if ((h != INVALID_HANDLE_VALUE) && (h != NULL)) {UnlockDrive(h); CloseHandle(h); h = INVALID_HANDLE_VALUE;}} while(0) + +/* Current drive info */ +typedef struct { + DWORD DeviceNumber; + LONGLONG DiskSize; + DISK_GEOMETRY Geometry; + DWORD FirstSector; + char proposed_label[16]; + int PartitionType; + int nPartitions; // number of partitions we actually care about + int FSType; + BOOL has_protective_mbr; + BOOL has_mbr_uefi_marker; + struct { + ULONG Allowed; + ULONG Default; + } ClusterSize[FS_MAX]; +} RUFUS_DRIVE_INFO; +extern RUFUS_DRIVE_INFO SelectedDrive; + BOOL SetAutoMount(BOOL enable); BOOL GetAutoMount(BOOL* enabled); char* GetPhysicalName(DWORD DriveIndex); diff --git a/src/rufus.h b/src/rufus.h index 61b9b2dc..2a1c2bfd 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -16,7 +16,6 @@ * along with this program. If not, see . */ #include -#include // for DISK_GEOMETRY #include #include @@ -99,7 +98,6 @@ #define safe_strncmp(str1, str2, count) strncmp(((str1==NULL)?"":str1), ((str2==NULL)?"":str2), count) #define safe_strnicmp(str1, str2, count) _strnicmp(((str1==NULL)?"":str1), ((str2==NULL)?"":str2), count) #define safe_closehandle(h) do {if ((h != INVALID_HANDLE_VALUE) && (h != NULL)) {CloseHandle(h); h = INVALID_HANDLE_VALUE;}} while(0) -#define safe_unlockclose(h) do {if ((h != INVALID_HANDLE_VALUE) && (h != NULL)) {UnlockDrive(h); CloseHandle(h); h = INVALID_HANDLE_VALUE;}} while(0) #define safe_release_dc(hDlg, hDC) do {if ((hDC != INVALID_HANDLE_VALUE) && (hDC != NULL)) {ReleaseDC(hDlg, hDC); hDC = NULL;}} while(0) #define safe_sprintf(dst, count, ...) do {_snprintf(dst, count, __VA_ARGS__); (dst)[(count)-1] = 0; } while(0) #define static_sprintf(dst, ...) safe_sprintf(dst, sizeof(dst), __VA_ARGS__) @@ -225,24 +223,6 @@ enum target_type { #define GETTARGETTYPE(x) (((x)>0)?(((x) >> 16) & 0xFFFF):0) #define GETPARTTYPE(x) (((x)>0)?((x) & 0xFFFF):0); -/* Current drive info */ -typedef struct { - DWORD DeviceNumber; - LONGLONG DiskSize; - DISK_GEOMETRY Geometry; - DWORD FirstSector; - char proposed_label[16]; - int PartitionType; - int nPartitions; // number of partitions we actually care about - int FSType; - BOOL has_protective_mbr; - BOOL has_mbr_uefi_marker; - struct { - ULONG Allowed; - ULONG Default; - } ClusterSize[FS_MAX]; -} RUFUS_DRIVE_INFO; - /* Special handling for old .c32 files we need to replace */ #define NB_OLD_C32 2 #define OLD_C32_NAMES { "menu.c32", "vesamenu.c32" } @@ -372,7 +352,6 @@ extern char* image_path; extern DWORD FormatStatus, DownloadStatus; extern BOOL PromptOnError; extern unsigned long syslinux_ldlinux_len[2]; -extern RUFUS_DRIVE_INFO SelectedDrive; extern const int nb_steps[FS_MAX]; extern BOOL use_own_c32[NB_OLD_C32], detect_fakes, iso_op_in_progress, format_op_in_progress, right_to_left_mode; extern BOOL allow_dual_uefi_bios, togo_mode; @@ -466,11 +445,6 @@ DWORD WINAPI FormatThread(void* param); DWORD WINAPI SaveImageThread(void* param); DWORD WINAPI SumThread(void* param); -static __inline BOOL UnlockDrive(HANDLE hDrive) { - DWORD size; - return DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &size, NULL); -} - /* Hash tables */ typedef struct htab_entry { uint32_t used; diff --git a/src/rufus.rc b/src/rufus.rc index 1262516a..34895c52 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.867" +CAPTION "Rufus 2.8.868" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,867,0 - PRODUCTVERSION 2,8,867,0 + FILEVERSION 2,8,868,0 + PRODUCTVERSION 2,8,868,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.867" + VALUE "FileVersion", "2.8.868" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.867" + VALUE "ProductVersion", "2.8.868" END END BLOCK "VarFileInfo" From b9caf8b6058de12bf028f907471561a6aa50f7e9 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 26 Feb 2016 13:26:34 +0000 Subject: [PATCH 39/91] [core] fix computation of FAT size for Large FAT32 * Ridgecropt's GetFATSizeSectors() computation was incorrect and resulted in data sectors being "wasted" (unaddressable) * See: http://www.syslinux.org/archives/2016-February/024850.html * Also revert the minfatsize check of Syslinux, since it no longer fails. --- src/format.c | 25 +++++++------------------ src/rufus.rc | 10 +++++----- src/syslinux/libfat/open.c | 2 +- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/format.c b/src/format.c index 4adbce86..56c4d9d4 100644 --- a/src/format.c +++ b/src/format.c @@ -347,31 +347,20 @@ static DWORD GetVolumeID(void) } /* - * This is the Microsoft calculation from FATGEN - * - * DWORD RootDirSectors = 0; - * DWORD TmpVal1, TmpVal2, FATSz; - * - * TmpVal1 = DskSize - (ReservedSecCnt + RootDirSectors); - * TmpVal2 = (256 * SecPerClus) + NumFATs; - * TmpVal2 = TmpVal2 / 2; - * FATSz = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2; - * - * return( FatSz ); + * Proper computation of FAT size + * See: http://www.syslinux.org/archives/2016-February/024850.html + * and subsequent replies. */ static DWORD GetFATSizeSectors(DWORD DskSize, DWORD ReservedSecCnt, DWORD SecPerClus, DWORD NumFATs, DWORD BytesPerSect) { ULONGLONG Numerator, Denominator; ULONGLONG FatElementSize = 4; + ULONGLONG ReservedClusCnt = 2; ULONGLONG FatSz; - // This is based on - // http://hjem.get2net.dk/rune_moeller_barnkob/filesystems/fat.html - Numerator = FatElementSize * (DskSize - ReservedSecCnt); - Denominator = (SecPerClus * BytesPerSect) + (FatElementSize * NumFATs); - FatSz = Numerator / Denominator; - // round up - FatSz += 1; + Numerator = DskSize - ReservedSecCnt + ReservedClusCnt * SecPerClus; + Denominator = SecPerClus * BytesPerSect / FatElementSize + NumFATs; + FatSz = Numerator / Denominator + 1; // +1 to ensure we are rounded up return (DWORD)FatSz; } diff --git a/src/rufus.rc b/src/rufus.rc index 34895c52..8921c761 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.868" +CAPTION "Rufus 2.8.869" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,868,0 - PRODUCTVERSION 2,8,868,0 + FILEVERSION 2,8,869,0 + PRODUCTVERSION 2,8,869,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.868" + VALUE "FileVersion", "2.8.869" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.868" + VALUE "ProductVersion", "2.8.869" END END BLOCK "VarFileInfo" diff --git a/src/syslinux/libfat/open.c b/src/syslinux/libfat/open.c index dad372b3..4f0334d7 100644 --- a/src/syslinux/libfat/open.c +++ b/src/syslinux/libfat/open.c @@ -92,7 +92,7 @@ libfat_open(int (*readfunc) (intptr_t, void *, size_t, libfat_sector_t), } else goto barf; /* Impossibly many clusters */ - minfatsize >>= LIBFAT_SECTOR_SHIFT; + minfatsize = (minfatsize + LIBFAT_SECTOR_SIZE - 1) >> LIBFAT_SECTOR_SHIFT; if (minfatsize > fatsize) goto barf; /* The FATs don't fit */ From bab3453f4d8318d8acd924231d0e839bf5a41418 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Sat, 27 Feb 2016 22:51:43 +0000 Subject: [PATCH 40/91] [checksum] factorize common algorithm elements --- src/checksum.c | 201 +++++++++++++++++++++++-------------------------- src/rufus.rc | 10 +-- 2 files changed, 100 insertions(+), 111 deletions(-) diff --git a/src/checksum.c b/src/checksum.c index 5631c33d..d36b1763 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -60,7 +60,7 @@ #undef BIG_ENDIAN_HOST /* Globals */ -char sha1str[41], sha256str[65], md5str[33]; +char sum_str[3][65]; #if defined(__GNUC__) #define ALIGNED(m) __attribute__ ((__aligned__(m))) @@ -103,27 +103,27 @@ static const uint32_t k[64] = { 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 }; -typedef struct ALIGNED(8) { - unsigned char buf[64]; - uint32_t state[5]; - uint32_t count; - uint64_t nblocks; -} SHA1_CONTEXT; - +/* + * For convenience, we use a common context for all the checksums algorithms, + * which means some elements may be unused... + */ typedef struct ALIGNED(8) { unsigned char buf[64]; uint32_t state[8]; - uint32_t datalen; - uint64_t bitlen; -} SHA256_CONTEXT; - -typedef struct ALIGNED(8) { - unsigned char buf[64]; - uint32_t state[4]; uint64_t bitcount; -} MD5_CONTEXT; + uint32_t bytecount; +} SUM_CONTEXT; -static void sha1_init(SHA1_CONTEXT *ctx) +static void md5_init(SUM_CONTEXT *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xefcdab89; + ctx->state[2] = 0x98badcfe; + ctx->state[3] = 0x10325476; +} + +static void sha1_init(SUM_CONTEXT *ctx) { memset(ctx, 0, sizeof(*ctx)); ctx->state[0] = 0x67452301; @@ -133,7 +133,7 @@ static void sha1_init(SHA1_CONTEXT *ctx) ctx->state[4] = 0xc3d2e1f0; } -static void sha256_init(SHA256_CONTEXT *ctx) +static void sha256_init(SUM_CONTEXT *ctx) { memset(ctx, 0, sizeof(*ctx)); ctx->state[0] = 0x6a09e667; @@ -146,17 +146,9 @@ static void sha256_init(SHA256_CONTEXT *ctx) ctx->state[7] = 0x5be0cd19; } -static void md5_init(MD5_CONTEXT *ctx) -{ - memset(ctx, 0, sizeof(*ctx)); - ctx->state[0] = 0x67452301; - ctx->state[1] = 0xefcdab89; - ctx->state[2] = 0x98badcfe; - ctx->state[3] = 0x10325476; -} /* Transform the message X which consists of 16 32-bit-words (SHA-1) */ -static void sha1_transform(SHA1_CONTEXT *ctx, const unsigned char *data) +static void sha1_transform(SUM_CONTEXT *ctx, const unsigned char *data) { uint32_t a, b, c, d, e, tm; uint32_t x[16]; @@ -290,7 +282,7 @@ static void sha1_transform(SHA1_CONTEXT *ctx, const unsigned char *data) ctx->state[4] += e; } -static void sha256_transform(SHA256_CONTEXT *ctx, const unsigned char *data) +static void sha256_transform(SUM_CONTEXT *ctx, const unsigned char *data) { uint32_t a, b, c, d, e, f, g, h, i, t1, t2, m[64]; @@ -355,7 +347,7 @@ static void sha256_transform(SHA256_CONTEXT *ctx, const unsigned char *data) } /* Transform the message X which consists of 16 32-bit-words (MD5) */ -static void md5_transform(MD5_CONTEXT *ctx, const unsigned char *data) +static void md5_transform(SUM_CONTEXT *ctx, const unsigned char *data) { uint32_t a, b, c, d; uint32_t x[16]; @@ -469,18 +461,18 @@ static void md5_transform(MD5_CONTEXT *ctx, const unsigned char *data) } /* Update the message digest with the contents of the buffer (SHA-1) */ -static void sha1_write(SHA1_CONTEXT *ctx, const unsigned char *buf, size_t len) +static void sha1_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) { - if (ctx->count == 64) { /* flush the buffer */ + if (ctx->bytecount == 64) { /* flush the buffer */ sha1_transform(ctx, ctx->buf); - ctx->count = 0; - ctx->nblocks++; + ctx->bytecount = 0; + ctx->bitcount += 64 * 8; } if (!buf) return; - if (ctx->count) { - for (; len && ctx->count < 64; len--) - ctx->buf[ctx->count++] = *buf++; + if (ctx->bytecount) { + for (; len && ctx->bytecount < 64; len--) + ctx->buf[ctx->bytecount++] = *buf++; sha1_write(ctx, NULL, 0); if (!len) return; @@ -488,32 +480,32 @@ static void sha1_write(SHA1_CONTEXT *ctx, const unsigned char *buf, size_t len) while (len >= 64) { sha1_transform(ctx, buf); - ctx->count = 0; - ctx->nblocks++; + ctx->bytecount = 0; + ctx->bitcount += 64 * 8; len -= 64; buf += 64; } - for (; len && ctx->count < 64; len--) - ctx->buf[ctx->count++] = *buf++; + for (; len && ctx->bytecount < 64; len--) + ctx->buf[ctx->bytecount++] = *buf++; } -static void sha256_write(SHA256_CONTEXT *ctx, const unsigned char *buf, size_t len) +static void sha256_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) { uint32_t i; for (i = 0; i < len; ++i) { - ctx->buf[ctx->datalen] = buf[i]; - ctx->datalen++; - if (ctx->datalen == 64) { + ctx->buf[ctx->bytecount] = buf[i]; + ctx->bytecount++; + if (ctx->bytecount == 64) { sha256_transform(ctx, ctx->buf); - ctx->bitlen += 512; - ctx->datalen = 0; + ctx->bitcount += 64 * 8; + ctx->bytecount = 0; } } } /* Update the message digest with the contents of the buffer (MD5) */ -static void md5_write(MD5_CONTEXT *ctx, const unsigned char *buf, size_t len) +static void md5_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) { uint32_t t; @@ -550,36 +542,33 @@ static void md5_write(MD5_CONTEXT *ctx, const unsigned char *buf, size_t len) } /* The routine final terminates the computation and returns the digest (SHA-1) */ -static void sha1_final(SHA1_CONTEXT *ctx) +static void sha1_final(SUM_CONTEXT *ctx) { - uint64_t bitcount; unsigned char *p; sha1_write(ctx, NULL, 0); /* flush */; - bitcount = ctx->nblocks * 64 * 8; - - if (ctx->count < 56) { /* enough room */ - ctx->buf[ctx->count++] = 0x80; /* pad */ - while (ctx->count < 56) - ctx->buf[ctx->count++] = 0; /* pad */ + if (ctx->bytecount < 56) { /* enough room */ + ctx->buf[ctx->bytecount++] = 0x80; /* pad */ + while (ctx->bytecount < 56) + ctx->buf[ctx->bytecount++] = 0; /* pad */ } else { /* need one extra block */ - ctx->buf[ctx->count++] = 0x80; /* pad character */ - while (ctx->count < 64) - ctx->buf[ctx->count++] = 0; + ctx->buf[ctx->bytecount++] = 0x80; /* pad character */ + while (ctx->bytecount < 64) + ctx->buf[ctx->bytecount++] = 0; sha1_write(ctx, NULL, 0); /* flush */; memset(ctx->buf, 0, 56); /* fill next block with zeroes */ } /* append the 64 bit count (big-endian) */ - ctx->buf[56] = (unsigned char) (bitcount >> 56); - ctx->buf[57] = (unsigned char) (bitcount >> 48); - ctx->buf[58] = (unsigned char) (bitcount >> 40); - ctx->buf[59] = (unsigned char) (bitcount >> 32); - ctx->buf[60] = (unsigned char) (bitcount >> 24); - ctx->buf[61] = (unsigned char) (bitcount >> 16); - ctx->buf[62] = (unsigned char) (bitcount >> 8); - ctx->buf[63] = (unsigned char) bitcount; + ctx->buf[56] = (unsigned char) (ctx->bitcount >> 56); + ctx->buf[57] = (unsigned char) (ctx->bitcount >> 48); + ctx->buf[58] = (unsigned char) (ctx->bitcount >> 40); + ctx->buf[59] = (unsigned char) (ctx->bitcount >> 32); + ctx->buf[60] = (unsigned char) (ctx->bitcount >> 24); + ctx->buf[61] = (unsigned char) (ctx->bitcount >> 16); + ctx->buf[62] = (unsigned char) (ctx->bitcount >> 8); + ctx->buf[63] = (unsigned char) ctx->bitcount; sha1_transform(ctx, ctx->buf); @@ -598,15 +587,15 @@ static void sha1_final(SHA1_CONTEXT *ctx) #undef X } -static void sha256_final(SHA256_CONTEXT *ctx) +static void sha256_final(SUM_CONTEXT *ctx) { uint32_t i; unsigned char *p; - i = ctx->datalen; + i = ctx->bytecount; // Pad whatever data is left in the buffer. - if (ctx->datalen < 56) { + if (ctx->bytecount < 56) { ctx->buf[i++] = 0x80; while (i < 56) ctx->buf[i++] = 0x00; @@ -620,15 +609,15 @@ static void sha256_final(SHA256_CONTEXT *ctx) } // Append to the padding the total message's length in bits and transform. - ctx->bitlen += ctx->datalen * 8; - ctx->buf[63] = (unsigned char) (ctx->bitlen); - ctx->buf[62] = (unsigned char) (ctx->bitlen >> 8); - ctx->buf[61] = (unsigned char) (ctx->bitlen >> 16); - ctx->buf[60] = (unsigned char) (ctx->bitlen >> 24); - ctx->buf[59] = (unsigned char) (ctx->bitlen >> 32); - ctx->buf[58] = (unsigned char) (ctx->bitlen >> 40); - ctx->buf[57] = (unsigned char) (ctx->bitlen >> 48); - ctx->buf[56] = (unsigned char) (ctx->bitlen >> 56); + ctx->bitcount += ctx->bytecount * 8; + ctx->buf[63] = (unsigned char) (ctx->bitcount); + ctx->buf[62] = (unsigned char) (ctx->bitcount >> 8); + ctx->buf[61] = (unsigned char) (ctx->bitcount >> 16); + ctx->buf[60] = (unsigned char) (ctx->bitcount >> 24); + ctx->buf[59] = (unsigned char) (ctx->bitcount >> 32); + ctx->buf[58] = (unsigned char) (ctx->bitcount >> 40); + ctx->buf[57] = (unsigned char) (ctx->bitcount >> 48); + ctx->buf[56] = (unsigned char) (ctx->bitcount >> 56); sha256_transform(ctx, ctx->buf); @@ -651,7 +640,7 @@ static void sha256_final(SHA256_CONTEXT *ctx) } /* The routine final terminates the computation and returns the digest (MD5) */ -static void md5_final(MD5_CONTEXT *ctx) +static void md5_final(SUM_CONTEXT *ctx) { uint32_t count; unsigned char *p; @@ -728,9 +717,9 @@ INT_PTR CALLBACK ChecksumCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM SendDlgItemMessageA(hDlg, IDC_MD5, WM_SETFONT, (WPARAM)hFont, TRUE); SendDlgItemMessageA(hDlg, IDC_SHA1, WM_SETFONT, (WPARAM)hFont, TRUE); SendDlgItemMessageA(hDlg, IDC_SHA256, WM_SETFONT, (WPARAM)hFont, TRUE); - SetWindowTextA(GetDlgItem(hDlg, IDC_MD5), md5str); - SetWindowTextA(GetDlgItem(hDlg, IDC_SHA1), sha1str); - SetWindowTextA(GetDlgItem(hDlg, IDC_SHA256), sha256str); + SetWindowTextA(GetDlgItem(hDlg, IDC_MD5), sum_str[0]); + SetWindowTextA(GetDlgItem(hDlg, IDC_SHA1), sum_str[1]); + SetWindowTextA(GetDlgItem(hDlg, IDC_SHA256), sum_str[2]); // Move/Resize the controls as needed to fit our text hDC = GetDC(GetDlgItem(hDlg, IDC_MD5)); @@ -739,14 +728,14 @@ INT_PTR CALLBACK ChecksumCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM GetWindowRect(GetDlgItem(hDlg, IDC_MD5), &rect); dw = rect.right - rect.left; dh = rect.bottom - rect.top; - DrawTextU(hDC, md5str, -1, &rect, DT_CALCRECT); + DrawTextU(hDC, sum_str[0], -1, &rect, DT_CALCRECT); dw = rect.right - rect.left - dw + 12; // Ideally we'd compute the field borders from the system, but hey... dh = rect.bottom - rect.top - dh + 6; ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SHA256), 0, 0, dw, dh, 1.0f); GetWindowRect(GetDlgItem(hDlg, IDC_SHA1), &rect); dw = rect.right - rect.left; - DrawTextU(hDC, sha1str, -1, &rect, DT_CALCRECT); + DrawTextU(hDC, sum_str[1], -1, &rect, DT_CALCRECT); dw = rect.right - rect.left - dw + 12; ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_MD5), 0, 0, dw, 0, 1.0f); ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SHA1), 0, 0, dw, 0, 1.0f); @@ -774,6 +763,13 @@ INT_PTR CALLBACK ChecksumCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM return (INT_PTR)FALSE; } +typedef void sum_init_t(SUM_CONTEXT *ctx); +typedef void sum_write_t(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len); +typedef void sum_final_t(SUM_CONTEXT *ctx); +sum_init_t *sum_init[3] = { md5_init, sha1_init , sha256_init }; +sum_write_t *sum_write[3] = { md5_write, sha1_write , sha256_write }; +sum_final_t *sum_final[3] = { md5_final, sha1_final , sha256_final }; +int sum_count[3] = { 16, 20, 32 }; DWORD WINAPI SumThread(void* param) { @@ -781,10 +777,8 @@ DWORD WINAPI SumThread(void* param) DWORD rSize = 0; uint64_t rb, LastRefresh = 0; char buffer[4096]; - SHA1_CONTEXT sha1_ctx; - SHA256_CONTEXT sha256_ctx; - MD5_CONTEXT md5_ctx; - int i, r = -1; + SUM_CONTEXT sum_ctx[3]; + int i, j, r = -1; float format_percent = 0.0f; if (image_path == NULL) @@ -799,9 +793,8 @@ DWORD WINAPI SumThread(void* param) goto out; } - sha1_init(&sha1_ctx); - sha256_init(&sha256_ctx); - md5_init(&md5_ctx); + for (i = 0; i < ARRAYSIZE(sum_init); i++) + sum_init[i](&sum_ctx[i]); for (rb = 0; ; rb += rSize) { if (_GetTickCount64() > LastRefresh + 25) { @@ -819,24 +812,20 @@ DWORD WINAPI SumThread(void* param) } if (rSize == 0) break; - sha1_write(&sha1_ctx, buffer, (size_t)rSize); - sha256_write(&sha256_ctx, buffer, (size_t)rSize); - md5_write(&md5_ctx, buffer, (size_t)rSize); + for (i = 0; i < ARRAYSIZE(sum_init); i++) + sum_write[i](&sum_ctx[i], buffer, (size_t)rSize); } - sha1_final(&sha1_ctx); - sha256_final(&sha256_ctx); - md5_final(&md5_ctx); + for (i = 0; i < ARRAYSIZE(sum_init); i++) { + memset(&sum_str[i], 0, ARRAYSIZE(sum_str[i])); + sum_final[i](&sum_ctx[i]); + for (j = 0; j < sum_count[i]; j++) + safe_sprintf(&sum_str[i][2 * j], ARRAYSIZE(sum_str[i]) - 2 * j, "%02x", sum_ctx[i].buf[j]); + } + uprintf(" MD5:\t %s", sum_str[0]); + uprintf(" SHA1:\t %s", sum_str[1]); + uprintf(" SHA256: %s", sum_str[2]); - for (i = 0; i < 16; i++) - safe_sprintf(&md5str[2*i], sizeof(md5str) - 2*i, "%02x", md5_ctx.buf[i]); - uprintf(" MD5:\t %s", md5str); - for (i = 0; i < 20; i++) - safe_sprintf(&sha1str[2*i], sizeof(sha1str) - 2*i, "%02x", sha1_ctx.buf[i]); - uprintf(" SHA1:\t %s", sha1str); - for (i = 0; i < 32; i++) - safe_sprintf(&sha256str[2*i], sizeof(sha256str) - 2*i, "%02x", sha256_ctx.buf[i]); - uprintf(" SHA256: %s", sha256str); r = 0; out: diff --git a/src/rufus.rc b/src/rufus.rc index 8921c761..9346cd46 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.869" +CAPTION "Rufus 2.8.870" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,869,0 - PRODUCTVERSION 2,8,869,0 + FILEVERSION 2,8,870,0 + PRODUCTVERSION 2,8,870,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.869" + VALUE "FileVersion", "2.8.870" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.869" + VALUE "ProductVersion", "2.8.870" END END BLOCK "VarFileInfo" From e6d3653cac3e455f409a9443f664843ffe675566 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 29 Feb 2016 21:36:28 +0000 Subject: [PATCH 41/91] [checksum] use multiple threads and double buffering * Can reduce the duration of checksum computations by about 1/3rd, if you have quad core CPU or better. --- src/checksum.c | 181 +++++++++++++++++++++++++++++++++++++++++-------- src/missing.h | 16 +++++ src/rufus.c | 4 +- src/rufus.h | 7 ++ src/rufus.rc | 10 +-- 5 files changed, 185 insertions(+), 33 deletions(-) diff --git a/src/checksum.c b/src/checksum.c index d36b1763..f5f43476 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -53,14 +53,22 @@ #include #include "rufus.h" +#include "missing.h" #include "resource.h" #include "msapi_utf8.h" #include "localization.h" #undef BIG_ENDIAN_HOST +#define BUFFER_SIZE 4096 +#define WAIT_TIME 5000 + /* Globals */ -char sum_str[3][65]; +char sum_str[NUM_CHECKSUMS][65]; +int bufnum, sum_count[NUM_CHECKSUMS] = { 16, 20, 32 }; +HANDLE data_ready[NUM_CHECKSUMS], thread_ready[NUM_CHECKSUMS]; +DWORD rSize[2]; +char buffer[2][BUFFER_SIZE]; #if defined(__GNUC__) #define ALIGNED(m) __attribute__ ((__aligned__(m))) @@ -766,25 +774,116 @@ INT_PTR CALLBACK ChecksumCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM typedef void sum_init_t(SUM_CONTEXT *ctx); typedef void sum_write_t(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len); typedef void sum_final_t(SUM_CONTEXT *ctx); -sum_init_t *sum_init[3] = { md5_init, sha1_init , sha256_init }; -sum_write_t *sum_write[3] = { md5_write, sha1_write , sha256_write }; -sum_final_t *sum_final[3] = { md5_final, sha1_final , sha256_final }; -int sum_count[3] = { 16, 20, 32 }; +sum_init_t *sum_init[NUM_CHECKSUMS] = { md5_init, sha1_init , sha256_init }; +sum_write_t *sum_write[NUM_CHECKSUMS] = { md5_write, sha1_write , sha256_write }; +sum_final_t *sum_final[NUM_CHECKSUMS] = { md5_final, sha1_final , sha256_final }; + +/* + * We want the maximum speed we can get out of the checksum computation, + * so, if we have a multiprocessor/multithreaded machine, we'll assign of + * each of the individual checksum threads to a specific virtual core, and + * assign the read thread to one of the remainder virtual cores. + * To do just that, we need the following function call. + * Oh, and BOY is this thing sensitive to whether the first sum affinity + * is on an even or odd virtual core! + */ +BOOL SetChecksumAffinity(CHECKSUM_AFFINITY* checksum_affinity) +{ + int i, pc; + DWORD_PTR affinity, dummy; + + memset(checksum_affinity, 0, sizeof(CHECKSUM_AFFINITY)); + if (!GetProcessAffinityMask(GetCurrentProcess(), &affinity, &dummy)) + return FALSE; + + // If we don't have enough virtual cores to evenly spread our load forget it + pc = popcnt64(affinity); + if (pc < NUM_CHECKSUMS + 1) + return FALSE; + + // We'll use the NUM_CHECKSUMS least significant set bits in our mask for + // the individual checksum threads, and the remainder for the read thread. + // From an empirical perspective, this looks like the best "one-size-fits-all" + // to spread the load. + checksum_affinity->read_thread = affinity; + for (i = 0; i < NUM_CHECKSUMS; i++) { + checksum_affinity->sum_thread[i] = affinity & (-1LL * affinity); + affinity ^= checksum_affinity->sum_thread[i]; + checksum_affinity->read_thread ^= checksum_affinity->sum_thread[i]; + } + return TRUE; +} + +// Individual thread that computes one of MD5, SHA1 or SHA256 in parallel +DWORD WINAPI IndividualSumThread(void* param) +{ + SUM_CONTEXT sum_ctx; + int i = (int)(uintptr_t)param, j; + + sum_init[i](&sum_ctx); + // Signal that we're ready to service requests + if (!SetEvent(thread_ready[i])) + goto error; + + // Wait for requests + while (1) { + if (WaitForSingleObject(data_ready[i], WAIT_TIME) != WAIT_OBJECT_0) { + uprintf("Failed to wait for event for checksum thread #%d: %s", i, WindowsErrorString()); + return 1; + } + if (rSize[bufnum] != 0) { + sum_write[i](&sum_ctx, buffer[bufnum], (size_t)rSize[bufnum]); + if (!SetEvent(thread_ready[i])) + goto error; + } else { + sum_final[i](&sum_ctx); + memset(&sum_str[i], 0, ARRAYSIZE(sum_str[i])); + for (j = 0; j < sum_count[i]; j++) + safe_sprintf(&sum_str[i][2 * j], ARRAYSIZE(sum_str[i]) - 2 * j, "%02x", sum_ctx.buf[j]); + return 0; + } + } +error: + uprintf("Failed to set event for checksum thread #%d: %s", i, WindowsErrorString()); + return 1; +} DWORD WINAPI SumThread(void* param) { + CHECKSUM_AFFINITY* checksum_affinity = (CHECKSUM_AFFINITY*)param; + HANDLE sum_thread[NUM_CHECKSUMS] = { NULL, NULL, NULL }; HANDLE h = INVALID_HANDLE_VALUE; - DWORD rSize = 0; uint64_t rb, LastRefresh = 0; - char buffer[4096]; - SUM_CONTEXT sum_ctx[3]; - int i, j, r = -1; + int i, _bufnum, r = -1; float format_percent = 0.0f; - if (image_path == NULL) + if ((image_path == NULL) || (checksum_affinity == NULL)) goto out; uprintf("\r\nComputing checksum for '%s'...", image_path); + + if (checksum_affinity->read_thread != 0) + SetThreadAffinityMask(GetCurrentThread(), checksum_affinity->read_thread); + + for (i = 0; i < NUM_CHECKSUMS; i++) { + // NB: Can't use a single manual-reset event for data_ready as we + // wouldn't be able to ensure the event is reset before the threa + // gets into its next wait loop + data_ready[i] = CreateEvent(NULL, FALSE, FALSE, NULL); + thread_ready[i] = CreateEvent(NULL, FALSE, FALSE, NULL); + if ((data_ready == NULL) || (thread_ready[i] == NULL)) { + uprintf("Unable to create checksum thread event: %s", WindowsErrorString()); + goto out; + } + sum_thread[i] = CreateThread(NULL, 0, IndividualSumThread, (LPVOID)(uintptr_t)i, 0, NULL); + if (sum_thread[i] == NULL) { + uprintf("Unable to start checksum thread #%d", i); + goto out; + } + if (checksum_affinity->sum_thread[i] != 0) + SetThreadAffinityMask(sum_thread[i], checksum_affinity->sum_thread[i]); + } + h = CreateFileU(image_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (h == INVALID_HANDLE_VALUE) { @@ -793,42 +892,70 @@ DWORD WINAPI SumThread(void* param) goto out; } - for (i = 0; i < ARRAYSIZE(sum_init); i++) - sum_init[i](&sum_ctx[i]); - - for (rb = 0; ; rb += rSize) { + bufnum = 0; + _bufnum = 0; + rSize[0] = 1; // Don't trigger the first loop break + for (rb = 0; ;rb += rSize[_bufnum]) { + // Update the progress and check for cancel if (_GetTickCount64() > LastRefresh + 25) { LastRefresh = _GetTickCount64(); format_percent = (100.0f*rb) / (1.0f*img_report.projected_size); PrintInfo(0, MSG_271, format_percent); - SendMessage(hProgress, PBM_SETPOS, (WPARAM)((format_percent/100.0f)*MAX_PROGRESS), 0); + SendMessage(hProgress, PBM_SETPOS, (WPARAM)((format_percent / 100.0f)*MAX_PROGRESS), 0); SetTaskbarProgressValue(rb, img_report.projected_size); } CHECK_FOR_USER_CANCEL; - if (!ReadFile(h, buffer, sizeof(buffer), &rSize, NULL)) { + + // Signal the threads that we have data to process + if (rb != 0) { + bufnum = _bufnum; + // Toggle the read buffer + _bufnum = (bufnum + 1) % 2; + // Signal the waiting threads + for (i = 0; i < NUM_CHECKSUMS; i++) { + if (!SetEvent(data_ready[i])) { + uprintf("Could not signal checksum thread %d: %s", i, WindowsErrorString()); + goto out; + } + } + } + + // Break the loop when data has been exhausted + if (rSize[bufnum] == 0) + break; + + // Read data (double buffered) + if (!ReadFile(h, buffer[_bufnum], BUFFER_SIZE, &rSize[_bufnum], NULL)) { FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_READ_FAULT; - uprintf(" Read error: %s", WindowsErrorString()); + uprintf("Read error: %s", WindowsErrorString()); + goto out; + } + + // Wait for the thread to signal they are ready to process data + if (WaitForMultipleObjects(NUM_CHECKSUMS, thread_ready, TRUE, WAIT_TIME) != WAIT_OBJECT_0) { + uprintf("Checksum threads failed to signal: %s", WindowsErrorString()); goto out; } - if (rSize == 0) - break; - for (i = 0; i < ARRAYSIZE(sum_init); i++) - sum_write[i](&sum_ctx[i], buffer, (size_t)rSize); } - for (i = 0; i < ARRAYSIZE(sum_init); i++) { - memset(&sum_str[i], 0, ARRAYSIZE(sum_str[i])); - sum_final[i](&sum_ctx[i]); - for (j = 0; j < sum_count[i]; j++) - safe_sprintf(&sum_str[i][2 * j], ARRAYSIZE(sum_str[i]) - 2 * j, "%02x", sum_ctx[i].buf[j]); + // Our last event with rSize=0 signaled the threads to exit - wait for that to happen + if (WaitForMultipleObjects(NUM_CHECKSUMS, sum_thread, TRUE, WAIT_TIME) != WAIT_OBJECT_0) { + uprintf("Checksum threads did not finalize: %s", WindowsErrorString()); + goto out; } + uprintf(" MD5:\t %s", sum_str[0]); uprintf(" SHA1:\t %s", sum_str[1]); uprintf(" SHA256: %s", sum_str[2]); - r = 0; out: + for (i = 0; i < NUM_CHECKSUMS; i++) { + if (sum_thread[i] != NULL) + TerminateThread(sum_thread[i], 1); + CloseHandle(data_ready[i]); + CloseHandle(thread_ready[i]); + } safe_closehandle(h); PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0); if (r == 0) diff --git a/src/missing.h b/src/missing.h index 0ad3d5e2..a97b8485 100644 --- a/src/missing.h +++ b/src/missing.h @@ -21,6 +21,7 @@ #include #include #include +#include #pragma once @@ -44,6 +45,21 @@ #define bswap_uint16 __builtin_bswap16 #endif +/* + * Nibbled from https://github.com/hanji/popcnt/blob/master/populationcount.cpp + * Since MSVC x86_32 does not have intrinsic popcount64 and I don't have all day + */ +static inline int popcnt64(register uint64_t u) +{ + u = (u & 0x5555555555555555) + ((u >> 1) & 0x5555555555555555); + u = (u & 0x3333333333333333) + ((u >> 2) & 0x3333333333333333); + u = (u & 0x0f0f0f0f0f0f0f0f) + ((u >> 4) & 0x0f0f0f0f0f0f0f0f); + u = (u & 0x00ff00ff00ff00ff) + ((u >> 8) & 0x00ff00ff00ff00ff); + u = (u & 0x0000ffff0000ffff) + ((u >> 16) & 0x0000ffff0000ffff); + u = (u & 0x00000000ffffffff) + ((u >> 32) & 0x00000000ffffffff); + return (int)u; +} + static __inline void *_reallocf(void *ptr, size_t size) { void *ret = realloc(ptr, size); if (!ret) diff --git a/src/rufus.c b/src/rufus.c index 45d8eb59..1ff78b68 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -2045,6 +2045,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA static ULONG ulRegister = 0; static LPITEMIDLIST pidlDesktop = NULL; static MY_SHChangeNotifyEntry NotifyEntry; + static CHECKSUM_AFFINITY checksum_affinity; DRAWITEMSTRUCT* pDI; HDROP droppedFileInfo; POINT Point; @@ -2529,7 +2530,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA // Disable all controls except cancel EnableControls(FALSE); InitProgress(FALSE); - format_thid = CreateThread(NULL, 0, SumThread, NULL, 0, NULL); + SetChecksumAffinity(&checksum_affinity); + format_thid = CreateThread(NULL, 0, SumThread, (LPVOID)&checksum_affinity, 0, NULL); if (format_thid != NULL) { PrintInfo(0, -1); timer = 0; diff --git a/src/rufus.h b/src/rufus.h index 2a1c2bfd..cd2ba385 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -60,6 +60,7 @@ #define MAX_SECTORS_TO_CLEAR 128 // nb sectors to zap when clearing the MBR/GPT (must be >34) #define MBR_UEFI_MARKER 0x49464555 // 'U', 'E', 'F', 'I', as a 32 bit little endian longword #define WRITE_RETRIES 3 +#define NUM_CHECKSUMS 3 // Number of checksum algorithms we support (MD5, SHA1, SHA256) #define FS_DEFAULT FS_FAT32 #define SINGLE_CLUSTERSIZE_DEFAULT 0x00000100 #define BADBLOCK_PATTERNS {0xaa, 0x55, 0xff, 0x00} @@ -290,6 +291,11 @@ typedef struct { char* path; } VHD_SAVE; +typedef struct { + DWORD_PTR read_thread; + DWORD_PTR sum_thread[NUM_CHECKSUMS]; +} CHECKSUM_AFFINITY; + /* * Structure and macros used for the extensions specification of FileDialog() * You can use: @@ -440,6 +446,7 @@ extern LONG ValidateSignature(HWND hDlg, const char* path); extern BOOL IsFontAvailable(const char* font_name); extern BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries); +extern BOOL SetChecksumAffinity(CHECKSUM_AFFINITY* checksum_affinity); DWORD WINAPI FormatThread(void* param); DWORD WINAPI SaveImageThread(void* param); diff --git a/src/rufus.rc b/src/rufus.rc index 9346cd46..5bec592b 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.870" +CAPTION "Rufus 2.8.871" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,870,0 - PRODUCTVERSION 2,8,870,0 + FILEVERSION 2,8,871,0 + PRODUCTVERSION 2,8,871,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.870" + VALUE "FileVersion", "2.8.871" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.870" + VALUE "ProductVersion", "2.8.871" END END BLOCK "VarFileInfo" From e1c7c9670b2e43afd99067f2c01f9c55374f7082 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 1 Mar 2016 17:13:37 +0000 Subject: [PATCH 42/91] [checksum] more load balancing optimizations * SetChecksumAffinity() now spreads the affinity evenly between cores * Also increase the read buffer size to help with performance * At this stage, the only limiting factor regarding performance seems to be the speed of the SHA-256 algorithm... --- src/checksum.c | 69 +++++++++++++++++++++++++++----------------------- src/rufus.c | 6 ++--- src/rufus.h | 10 +++----- src/rufus.rc | 10 ++++---- src/stdio.c | 28 ++++++++++++++++++++ 5 files changed, 77 insertions(+), 46 deletions(-) diff --git a/src/checksum.c b/src/checksum.c index f5f43476..5e6694aa 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -60,7 +60,7 @@ #undef BIG_ENDIAN_HOST -#define BUFFER_SIZE 4096 +#define BUFFER_SIZE (64*KB) #define WAIT_TIME 5000 /* Globals */ @@ -704,6 +704,13 @@ static void md5_final(SUM_CONTEXT *ctx) #undef X } +typedef void sum_init_t(SUM_CONTEXT *ctx); +typedef void sum_write_t(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len); +typedef void sum_final_t(SUM_CONTEXT *ctx); +sum_init_t *sum_init[NUM_CHECKSUMS] = { md5_init, sha1_init , sha256_init }; +sum_write_t *sum_write[NUM_CHECKSUMS] = { md5_write, sha1_write , sha256_write }; +sum_final_t *sum_final[NUM_CHECKSUMS] = { md5_final, sha1_final , sha256_final }; + /* * Checksum dialog callback */ @@ -771,53 +778,47 @@ INT_PTR CALLBACK ChecksumCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM return (INT_PTR)FALSE; } -typedef void sum_init_t(SUM_CONTEXT *ctx); -typedef void sum_write_t(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len); -typedef void sum_final_t(SUM_CONTEXT *ctx); -sum_init_t *sum_init[NUM_CHECKSUMS] = { md5_init, sha1_init , sha256_init }; -sum_write_t *sum_write[NUM_CHECKSUMS] = { md5_write, sha1_write , sha256_write }; -sum_final_t *sum_final[NUM_CHECKSUMS] = { md5_final, sha1_final , sha256_final }; - /* * We want the maximum speed we can get out of the checksum computation, - * so, if we have a multiprocessor/multithreaded machine, we'll assign of - * each of the individual checksum threads to a specific virtual core, and - * assign the read thread to one of the remainder virtual cores. + * so, if we have a multiprocessor/multithreaded machine, we try to assign + * each of the individual checksum threads to a different core. * To do just that, we need the following function call. - * Oh, and BOY is this thing sensitive to whether the first sum affinity - * is on an even or odd virtual core! */ -BOOL SetChecksumAffinity(CHECKSUM_AFFINITY* checksum_affinity) +extern BOOL usb_debug; // For uuprintf +BOOL SetChecksumAffinity(DWORD_PTR* thread_affinity) { - int i, pc; + int i, j, pc; DWORD_PTR affinity, dummy; - memset(checksum_affinity, 0, sizeof(CHECKSUM_AFFINITY)); + memset(thread_affinity, 0, 4 * sizeof(DWORD_PTR)); if (!GetProcessAffinityMask(GetCurrentProcess(), &affinity, &dummy)) return FALSE; + uuprintf("\r\nChecksum affinities:"); + uuprintf("global:\t%s", printbitslz(affinity)); // If we don't have enough virtual cores to evenly spread our load forget it pc = popcnt64(affinity); if (pc < NUM_CHECKSUMS + 1) return FALSE; - // We'll use the NUM_CHECKSUMS least significant set bits in our mask for - // the individual checksum threads, and the remainder for the read thread. - // From an empirical perspective, this looks like the best "one-size-fits-all" - // to spread the load. - checksum_affinity->read_thread = affinity; + // Spread the affinity as evenly as we can + thread_affinity[NUM_CHECKSUMS] = affinity; for (i = 0; i < NUM_CHECKSUMS; i++) { - checksum_affinity->sum_thread[i] = affinity & (-1LL * affinity); - affinity ^= checksum_affinity->sum_thread[i]; - checksum_affinity->read_thread ^= checksum_affinity->sum_thread[i]; + for (j = 0; j < pc / (NUM_CHECKSUMS + 1); j++) { + thread_affinity[i] |= affinity & (-1LL * affinity); + affinity ^= affinity & (-1LL * affinity); + } + uuprintf("sum%d:\t%s", i, printbitslz(thread_affinity[i])); + thread_affinity[NUM_CHECKSUMS] ^= thread_affinity[i]; } + uuprintf("sum%d:\t%s", i, printbitslz(thread_affinity[i])); return TRUE; } // Individual thread that computes one of MD5, SHA1 or SHA256 in parallel DWORD WINAPI IndividualSumThread(void* param) { - SUM_CONTEXT sum_ctx; + SUM_CONTEXT sum_ctx = { 0 }; // There's a memset in sum_init, but static analyzers still bug us int i = (int)(uintptr_t)param, j; sum_init[i](&sum_ctx); @@ -850,24 +851,28 @@ error: DWORD WINAPI SumThread(void* param) { - CHECKSUM_AFFINITY* checksum_affinity = (CHECKSUM_AFFINITY*)param; + DWORD_PTR* thread_affinity = (DWORD_PTR*)param; HANDLE sum_thread[NUM_CHECKSUMS] = { NULL, NULL, NULL }; HANDLE h = INVALID_HANDLE_VALUE; uint64_t rb, LastRefresh = 0; int i, _bufnum, r = -1; float format_percent = 0.0f; - if ((image_path == NULL) || (checksum_affinity == NULL)) + if ((image_path == NULL) || (thread_affinity == NULL)) goto out; uprintf("\r\nComputing checksum for '%s'...", image_path); - if (checksum_affinity->read_thread != 0) - SetThreadAffinityMask(GetCurrentThread(), checksum_affinity->read_thread); + if (thread_affinity[0] != 0) + // Use the first affinity mask, as our read thread is the least + // CPU intensive (mostly waits on disk I/O or on the other threads) + // whereas the OS is likely to requisition the first Core, which + // is usually in this first mask, for other tasks. + SetThreadAffinityMask(GetCurrentThread(), thread_affinity[0]); for (i = 0; i < NUM_CHECKSUMS; i++) { // NB: Can't use a single manual-reset event for data_ready as we - // wouldn't be able to ensure the event is reset before the threa + // wouldn't be able to ensure the event is reset before the thread // gets into its next wait loop data_ready[i] = CreateEvent(NULL, FALSE, FALSE, NULL); thread_ready[i] = CreateEvent(NULL, FALSE, FALSE, NULL); @@ -880,8 +885,8 @@ DWORD WINAPI SumThread(void* param) uprintf("Unable to start checksum thread #%d", i); goto out; } - if (checksum_affinity->sum_thread[i] != 0) - SetThreadAffinityMask(sum_thread[i], checksum_affinity->sum_thread[i]); + if (thread_affinity[i+1] != 0) + SetThreadAffinityMask(sum_thread[i], thread_affinity[i+1]); } h = CreateFileU(image_path, GENERIC_READ, FILE_SHARE_READ, NULL, diff --git a/src/rufus.c b/src/rufus.c index 1ff78b68..56b47f45 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -2045,7 +2045,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA static ULONG ulRegister = 0; static LPITEMIDLIST pidlDesktop = NULL; static MY_SHChangeNotifyEntry NotifyEntry; - static CHECKSUM_AFFINITY checksum_affinity; + static DWORD_PTR sumthread_affinity[4]; DRAWITEMSTRUCT* pDI; HDROP droppedFileInfo; POINT Point; @@ -2530,8 +2530,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA // Disable all controls except cancel EnableControls(FALSE); InitProgress(FALSE); - SetChecksumAffinity(&checksum_affinity); - format_thid = CreateThread(NULL, 0, SumThread, (LPVOID)&checksum_affinity, 0, NULL); + SetChecksumAffinity(sumthread_affinity); + format_thid = CreateThread(NULL, 0, SumThread, (LPVOID)sumthread_affinity, 0, NULL); if (format_thid != NULL) { PrintInfo(0, -1); timer = 0; diff --git a/src/rufus.h b/src/rufus.h index cd2ba385..06b68ce8 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -291,11 +291,6 @@ typedef struct { char* path; } VHD_SAVE; -typedef struct { - DWORD_PTR read_thread; - DWORD_PTR sum_thread[NUM_CHECKSUMS]; -} CHECKSUM_AFFINITY; - /* * Structure and macros used for the extensions specification of FileDialog() * You can use: @@ -446,7 +441,10 @@ extern LONG ValidateSignature(HWND hDlg, const char* path); extern BOOL IsFontAvailable(const char* font_name); extern BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries); -extern BOOL SetChecksumAffinity(CHECKSUM_AFFINITY* checksum_affinity); +extern BOOL SetChecksumAffinity(DWORD_PTR* thread_affinity); +#define printbits(x) _printbits(sizeof(x), &x, 0) +#define printbitslz(x) _printbits(sizeof(x), &x, 1) +extern char* _printbits(size_t const size, void const * const ptr, int leading_zeroes); DWORD WINAPI FormatThread(void* param); DWORD WINAPI SaveImageThread(void* param); diff --git a/src/rufus.rc b/src/rufus.rc index 5bec592b..524352fa 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.871" +CAPTION "Rufus 2.8.872" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,871,0 - PRODUCTVERSION 2,8,871,0 + FILEVERSION 2,8,872,0 + PRODUCTVERSION 2,8,872,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.871" + VALUE "FileVersion", "2.8.872" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.871" + VALUE "ProductVersion", "2.8.872" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index 581861fd..d1f68759 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -74,6 +74,34 @@ void _uprintf(const char *format, ...) } #endif +// Prints a bitstring of a number of any size, with or without leading zeroes. +// See also the printbits() and printbitslz() helper macros in rufus.h +char *_printbits(size_t const size, void const * const ptr, int leading_zeroes) +{ + // sizeof(uintmax_t) so that we have enough space to store whatever is thrown at us + static char str[sizeof(uintmax_t) * 8 + 3]; + size_t i; + uint8_t* b = (uint8_t*)ptr; + uintmax_t mask, lzmask = 0, val = 0; + + // Little endian, the SCOURGE of any rational computing + for (i = 0; i < size; i++) + val |= ((uintmax_t)b[i]) << (8 * i); + + str[0] = '0'; + str[1] = 'b'; + if (leading_zeroes) + lzmask = 1ULL << (size * 8 - 1); + for (i = 2, mask = 1ULL << (sizeof(uintmax_t) * 8 - 1); mask != 0; mask >>= 1) { + if ((i > 2) || (lzmask & mask)) + str[i++] = (val & mask) ? '1' : '0'; + else if (val & mask) + str[i++] = '1'; + } + str[i] = '\0'; + return str; +} + void DumpBufferHex(void *buf, size_t size) { unsigned char* buffer = (unsigned char*)buf; From b89beceedf40d5e20c6c04877c85c20d134e27ed Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 2 Mar 2016 11:00:27 +0000 Subject: [PATCH 43/91] [grub] update GRUB to 2.02~beta3 --- res/grub2/core.img | Bin 31724 -> 31568 bytes res/grub2/grub2_version.h | 2 +- res/grub2/readme.txt | 4 ++-- src/rufus.rc | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/res/grub2/core.img b/res/grub2/core.img index 63098ba6c928d99d7e99eca912c549a97dd6e9b6..f1c8e47fd3e949f63ebb24625b9fa6d90e18a611 100644 GIT binary patch delta 30019 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%0D`PnqWeWpK(5>p%n|r#e_t*Ck=I&| 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 SK!gj(M5c#ldeyE@_j*L3TPNfI delta 30173 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 diff --git a/res/grub2/grub2_version.h b/res/grub2/grub2_version.h index 7b069ed0..c8a28420 100644 --- a/res/grub2/grub2_version.h +++ b/res/grub2/grub2_version.h @@ -2,4 +2,4 @@ * This file contains the version string of the GRUB 2.x binary embedded in Rufus. * Should be the same as GRUB's PACKAGE_VERSION in config.h. */ -#define GRUB2_PACKAGE_VERSION "2.02~beta2" +#define GRUB2_PACKAGE_VERSION "2.02~beta3" diff --git a/res/grub2/readme.txt b/res/grub2/readme.txt index 7fc23199..9358dca9 100644 --- a/res/grub2/readme.txt +++ b/res/grub2/readme.txt @@ -1,7 +1,7 @@ This directory contains the Grub 2.0 boot records that are used by Rufus -* boot.img and core.img were compiled from git://git.savannah.gnu.org/grub.git, - commit 72ec399ad8d6348b6c74ea63d80c79784c8b84ae, on a Debian 7.7.0 x64 system. +* boot.img and core.img were compiled from + http://alpha.gnu.org/gnu/grub/grub-2.02~beta3.tar.xz, on a Debian 8.3 x64 system. This was done following the guide from: http://pete.akeo.ie/2014/05/compiling-and-installing-grub2-for.html. diff --git a/src/rufus.rc b/src/rufus.rc index 524352fa..1339802f 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.872" +CAPTION "Rufus 2.8.873" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,872,0 - PRODUCTVERSION 2,8,872,0 + FILEVERSION 2,8,873,0 + PRODUCTVERSION 2,8,873,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.872" + VALUE "FileVersion", "2.8.873" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.872" + VALUE "ProductVersion", "2.8.873" END END BLOCK "VarFileInfo" From 07114edc6f9faaa26364e6b6db1686856be16951 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 2 Mar 2016 13:40:37 +0000 Subject: [PATCH 44/91] [checksum] more cleanup and optimization * Why... can't I stop... trying to optimize... this thing?!? --- src/checksum.c | 63 ++++++++++++++++++-------------------------------- src/missing.h | 17 ++++++++++++++ src/rufus.rc | 10 ++++---- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/checksum.c b/src/checksum.c index 5e6694aa..ac0b8f28 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -68,36 +68,15 @@ char sum_str[NUM_CHECKSUMS][65]; int bufnum, sum_count[NUM_CHECKSUMS] = { 16, 20, 32 }; HANDLE data_ready[NUM_CHECKSUMS], thread_ready[NUM_CHECKSUMS]; DWORD rSize[2]; -char buffer[2][BUFFER_SIZE]; +char ALIGNED(64) buffer[2][BUFFER_SIZE]; -#if defined(__GNUC__) -#define ALIGNED(m) __attribute__ ((__aligned__(m))) -#elif defined(_MSC_VER) -#define ALIGNED(m) __declspec(align(m)) -#endif - -/* Rotate a 32 bit integer by n bytes */ -#if defined(__GNUC__) && defined(__i386__) -static inline uint32_t rol(uint32_t x, int n) -{ - __asm__("roll %%cl,%0" - :"=r" (x) - :"0" (x),"c" (n)); - return x; -} -#elif defined(_MSC_VER) && (_M_IX86 >= 300) -static __inline uint32_t rol(uint32_t x, int n) -{ - __asm { - mov eax, x - mov ecx, n - rol eax, cl - } - /* returns with result in EAX */ -} -#else -#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) -#endif +/* + * Rotate 32 bit integers by n bytes. + * Don't bother trying to hand-optimize those, as the + * compiler usually does a pretty good job at that. + */ +#define ROL(a,b) (((a) << (b)) | ((a) >> (32-(b)))) +#define ROR(a,b) (((a) >> (b)) | ((a) << (32-(b)))) // For SHA-256 static const uint32_t k[64] = { @@ -154,7 +133,6 @@ static void sha256_init(SUM_CONTEXT *ctx) ctx->state[7] = 0x5be0cd19; } - /* Transform the message X which consists of 16 32-bit-words (SHA-1) */ static void sha1_transform(SUM_CONTEXT *ctx, const unsigned char *data) { @@ -192,10 +170,10 @@ static void sha1_transform(SUM_CONTEXT *ctx, const unsigned char *data) #define F3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) #define F4(x,y,z) ( x ^ y ^ z ) -#define M(i) ( tm = x[i&0x0f] ^ x[(i-14)&0x0f] ^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f], (x[i&0x0f] = rol(tm,1)) ) +#define M(i) ( tm = x[i&0x0f] ^ x[(i-14)&0x0f] ^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f], (x[i&0x0f] = ROL(tm,1)) ) -#define SHA1STEP(a,b,c,d,e,f,k,m) do { e += rol(a, 5) + f(b, c, d) + k + m; \ - b = rol(b, 30); } while(0) +#define SHA1STEP(a,b,c,d,e,f,k,m) do { e += ROL(a, 5) + f(b, c, d) + k + m; \ + b = ROL(b, 30); } while(0) SHA1STEP(a, b, c, d, e, F1, K1, x[0]); SHA1STEP(e, a, b, c, d, F1, K1, x[1]); SHA1STEP(d, e, a, b, c, F1, K1, x[2]); @@ -303,15 +281,12 @@ static void sha256_transform(SUM_CONTEXT *ctx, const unsigned char *data) g = ctx->state[6]; h = ctx->state[7]; -#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) -#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) - #define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) -#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) -#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) -#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) -#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) +#define EP0(x) (ROR(x,2) ^ ROR(x,13) ^ ROR(x,22)) +#define EP1(x) (ROR(x,6) ^ ROR(x,11) ^ ROR(x,25)) +#define SIG0(x) (ROR(x,7) ^ ROR(x,18) ^ ((x) >> 3)) +#define SIG1(x) (ROR(x,17) ^ ROR(x,19) ^ ((x) >> 10)) #ifdef BIG_ENDIAN_HOST @@ -487,6 +462,7 @@ static void sha1_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) } while (len >= 64) { + PREFETCH64(&buf[64]); sha1_transform(ctx, buf); ctx->bytecount = 0; ctx->bitcount += 64 * 8; @@ -505,6 +481,7 @@ static void sha256_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) ctx->buf[ctx->bytecount] = buf[i]; ctx->bytecount++; if (ctx->bytecount == 64) { + PREFETCH64(&buf[i + 64]); sha256_transform(ctx, ctx->buf); ctx->bitcount += 64 * 8; ctx->bytecount = 0; @@ -539,6 +516,7 @@ static void md5_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) /* Process data in 64-byte chunks */ while (len >= 64) { + PREFETCH64(&buf[64]); memcpy(ctx->buf, buf, 64); md5_transform(ctx, ctx->buf); buf += 64; @@ -704,6 +682,11 @@ static void md5_final(SUM_CONTEXT *ctx) #undef X } +// These 'null' calls are useful for testing load balancing and individual algorithm speed +static void null_init(SUM_CONTEXT *ctx) { memset(ctx, 0, sizeof(*ctx)); } +static void null_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) { } +static void null_final(SUM_CONTEXT *ctx) { } + typedef void sum_init_t(SUM_CONTEXT *ctx); typedef void sum_write_t(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len); typedef void sum_final_t(SUM_CONTEXT *ctx); diff --git a/src/missing.h b/src/missing.h index a97b8485..7c5f6333 100644 --- a/src/missing.h +++ b/src/missing.h @@ -35,6 +35,23 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif +#if defined(__GNUC__) +#define ALIGNED(m) __attribute__ ((__aligned__(m))) +#elif defined(_MSC_VER) +#define ALIGNED(m) __declspec(align(m)) +#endif + +/* + * Prefetch 64 bytes at address m, for read-only operation + * We account for these built-in calls doing nothing if the + * line has already been fetched, or if the address is invalid. + */ +#if defined(__GNUC__) +#define PREFETCH64(m) do { __builtin_prefetch(m, 0, 0); __builtin_prefetch(m+32, 0, 0); } while(0) +#elif defined(_MSC_VER) +#define PREFETCH64(m) do { _m_prefetch(m); _m_prefetch(m+32); } while(0) +#endif + #if defined(_MSC_VER) #define bswap_uint64 _byteswap_uint64 #define bswap_uint32 _byteswap_ulong diff --git a/src/rufus.rc b/src/rufus.rc index 1339802f..d22250ff 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.873" +CAPTION "Rufus 2.8.874" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,873,0 - PRODUCTVERSION 2,8,873,0 + FILEVERSION 2,8,874,0 + PRODUCTVERSION 2,8,874,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.873" + VALUE "FileVersion", "2.8.874" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.873" + VALUE "ProductVersion", "2.8.874" END END BLOCK "VarFileInfo" From 00ffbae61f9e4e96f5aece3192def1c27bd77d66 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 2 Mar 2016 18:51:43 +0000 Subject: [PATCH 45/91] [checksum] switch to 7-zip's SHA-256 algorithm * That's more like it! When compiled in 64-bit we get about the same speed as 7-zip (slower when 32-bit, but shhh, or people will ask for a 64-bit version of Rufus...) * Looks like what was holding us back was the sha256_write() from Brad Conte's * Also fix WDK compilation and harmonize the BE->LE conversions --- src/checksum.c | 155 +++++++++++++++++++++++++++---------------------- src/license.h | 5 +- src/missing.h | 14 ++++- src/rufus.rc | 10 ++-- 4 files changed, 106 insertions(+), 78 deletions(-) diff --git a/src/checksum.c b/src/checksum.c index ac0b8f28..3aa51aa4 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -3,7 +3,7 @@ * Message-Digest algorithms (md5sum, sha1sum, sha256sum) * Copyright © 1998-2001 Free Software Foundation, Inc. * Copyright © 2004 g10 Code GmbH - * Copyright © 2006-2012 Brad Conte + * Copyright © 2002-2015 Wei Dai & Igor Pavlov * Copyright © 2015-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify @@ -23,8 +23,7 @@ /* * SHA-1 code taken from GnuPG, as per copyrights above. * - * SHA-256 code modified from crypto-algorithms by Brad Conte: - * https://github.com/B-Con/crypto-algorithms - Public Domain + * SHA-256 taken from 7-zip's Sha256.c, itself based on Crypto++ - Public Domain * * MD5 code from various public domain sources sharing the following * copyright declaration: @@ -79,7 +78,7 @@ char ALIGNED(64) buffer[2][BUFFER_SIZE]; #define ROR(a,b) (((a) >> (b)) | ((a) << (32-(b)))) // For SHA-256 -static const uint32_t k[64] = { +static const uint32_t K[64] = { 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, @@ -97,8 +96,8 @@ static const uint32_t k[64] = { typedef struct ALIGNED(8) { unsigned char buf[64]; uint32_t state[8]; + uint64_t bytecount; uint64_t bitcount; - uint32_t bytecount; } SUM_CONTEXT; static void md5_init(SUM_CONTEXT *ctx) @@ -150,13 +149,13 @@ static void sha1_transform(SUM_CONTEXT *ctx, const unsigned char *data) memcpy(x, data, sizeof(x)); #else { - int i; - unsigned char *p2; - for (i = 0, p2 = (unsigned char*)x; i < 16; i++, p2 += 4) { - p2[3] = *data++; - p2[2] = *data++; - p2[1] = *data++; - p2[0] = *data++; + unsigned k; + for (k = 0; k < 16; k += 4) { + const unsigned char *p2 = data + k * 4; + x[k] = get_be32(p2); + x[k + 1] = get_be32(p2 + 4); + x[k + 2] = get_be32(p2 + 8); + x[k + 3] = get_be32(p2 + 12); } } #endif @@ -270,7 +269,7 @@ static void sha1_transform(SUM_CONTEXT *ctx, const unsigned char *data) static void sha256_transform(SUM_CONTEXT *ctx, const unsigned char *data) { - uint32_t a, b, c, d, e, f, g, h, i, t1, t2, m[64]; + uint32_t a, b, c, d, e, f, g, h, j, x[16]; a = ctx->state[0]; b = ctx->state[1]; @@ -281,44 +280,53 @@ static void sha256_transform(SUM_CONTEXT *ctx, const unsigned char *data) g = ctx->state[6]; h = ctx->state[7]; -#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) -#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define CH(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define MAJ(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) #define EP0(x) (ROR(x,2) ^ ROR(x,13) ^ ROR(x,22)) #define EP1(x) (ROR(x,6) ^ ROR(x,11) ^ ROR(x,25)) #define SIG0(x) (ROR(x,7) ^ ROR(x,18) ^ ((x) >> 3)) #define SIG1(x) (ROR(x,17) ^ ROR(x,19) ^ ((x) >> 10)) - +#define BLK0(i) (x[i]) +#define BLK2(i) (x[i] += SIG1(x[((i)-2)&15]) + x[((i)-7)&15] + SIG0(x[((i)-15)&15])) +#define R(a,b,c,d,e,f,g,h, i) \ + h += EP1(e) + CH(e,f,g) + K[(i)+(j)] + (j ? BLK2(i) : BLK0(i)); \ + d += h; \ + h += EP0(a) + MAJ(a, b, c) +#define RX_8(i) \ + R(a,b,c,d,e,f,g,h, i); \ + R(h,a,b,c,d,e,f,g, i+1); \ + R(g,h,a,b,c,d,e,f, i+2); \ + R(f,g,h,a,b,c,d,e, i+3); \ + R(e,f,g,h,a,b,c,d, i+4); \ + R(d,e,f,g,h,a,b,c, i+5); \ + R(c,d,e,f,g,h,a,b, i+6); \ + R(b,c,d,e,f,g,h,a, i+7) #ifdef BIG_ENDIAN_HOST - memcpy(m, data, sizeof(m)); + memcpy(x, data, sizeof(x)); #else { - unsigned char *p2; - for (i = 0, p2 = (unsigned char*)m; i < 16; i++, p2 += 4) { - p2[3] = *data++; - p2[2] = *data++; - p2[1] = *data++; - p2[0] = *data++; + unsigned k; + for (k = 0; k < 16; k += 4) { + const unsigned char *p2 = data + k * 4; + x[k] = get_be32(p2); + x[k + 1] = get_be32(p2 + 4); + x[k + 2] = get_be32(p2 + 8); + x[k + 3] = get_be32(p2 + 12); } } #endif - for (i = 16; i < 64; ++i) - m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; - - for (i = 0; i < 64; ++i) { - t1 = h + EP1(e) + CH(e, f, g) + k[i] + m[i]; - t2 = EP0(a) + MAJ(a, b, c); - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; + for (j = 0; j < 64; j += 16) { + RX_8(0); + RX_8(8); } +#undef EP0 +#undef EP1 +#undef SIG0 +#undef SIG1 + ctx->state[0] += a; ctx->state[1] += b; ctx->state[2] += c; @@ -344,13 +352,13 @@ static void md5_transform(SUM_CONTEXT *ctx, const unsigned char *data) memcpy(x, data, sizeof(x)); #else { - int i; - unsigned char *p; - for (i = 0, p = (unsigned char*)x; i < 16; i++, p += 4) { - p[3] = *data++; - p[2] = *data++; - p[1] = *data++; - p[0] = *data++; + unsigned k; + for (k = 0; k < 16; k += 4) { + const unsigned char *p2 = data + k * 4; + x[k] = get_be32(p2); + x[k + 1] = get_be32(p2 + 4); + x[k + 2] = get_be32(p2 + 8); + x[k + 3] = get_be32(p2 + 12); } } #endif @@ -475,18 +483,32 @@ static void sha1_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) static void sha256_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) { - uint32_t i; + uint64_t pos = ctx->bytecount & 0x3F; + uint64_t num; - for (i = 0; i < len; ++i) { - ctx->buf[ctx->bytecount] = buf[i]; - ctx->bytecount++; - if (ctx->bytecount == 64) { - PREFETCH64(&buf[i + 64]); - sha256_transform(ctx, ctx->buf); - ctx->bitcount += 64 * 8; - ctx->bytecount = 0; - } + ctx->bytecount += len; + + num = 64 - pos; + if (num > len) { + memcpy(ctx->buf + pos, buf, len); + return; } + len -= num; + memcpy(ctx->buf + pos, buf, num); + buf += num; + + for (;;) { + PREFETCH64(buf + 64); + sha256_transform(ctx, ctx->buf); + if (len < 64) + break; + len -= 64; + memcpy(ctx->buf, buf, 64); + buf += 64; + } + + if (len != 0) + memcpy(ctx->buf, buf, len); } /* Update the message digest with the contents of the buffer (MD5) */ @@ -575,27 +597,21 @@ static void sha1_final(SUM_CONTEXT *ctx) static void sha256_final(SUM_CONTEXT *ctx) { - uint32_t i; + uint64_t pos = ctx->bytecount & 0x3F; unsigned char *p; - i = ctx->bytecount; + ctx->buf[pos++] = 0x80; // Pad whatever data is left in the buffer. - if (ctx->bytecount < 56) { - ctx->buf[i++] = 0x80; - while (i < 56) - ctx->buf[i++] = 0x00; - } - else { - ctx->buf[i++] = 0x80; - while (i < 64) - ctx->buf[i++] = 0x00; - sha256_transform(ctx, ctx->buf); - memset(ctx->buf, 0, 56); + while (pos != (64 - 8)) { + pos &= 0x3F; + if (pos == 0) + sha256_transform(ctx, ctx->buf); + ctx->buf[pos++] = 0; } // Append to the padding the total message's length in bits and transform. - ctx->bitcount += ctx->bytecount * 8; + ctx->bitcount = ctx->bytecount << 3; ctx->buf[63] = (unsigned char) (ctx->bitcount); ctx->buf[62] = (unsigned char) (ctx->bitcount >> 8); ctx->buf[61] = (unsigned char) (ctx->bitcount >> 16); @@ -682,10 +698,13 @@ static void md5_final(SUM_CONTEXT *ctx) #undef X } +//#define NULL_TEST +#ifdef NULL_TEST // These 'null' calls are useful for testing load balancing and individual algorithm speed static void null_init(SUM_CONTEXT *ctx) { memset(ctx, 0, sizeof(*ctx)); } static void null_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) { } static void null_final(SUM_CONTEXT *ctx) { } +#endif typedef void sum_init_t(SUM_CONTEXT *ctx); typedef void sum_write_t(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len); diff --git a/src/license.h b/src/license.h index 9b3d2225..0fdc08d3 100644 --- a/src/license.h +++ b/src/license.h @@ -108,8 +108,9 @@ const char* additional_copyrights = "https://www.gnupg.org\\line\n" "GNU General Public License (GPL) v3 or later\\line\n" "\\line\n" -"SHA-256 checksum from Brad Conte's crypto-algorithms:\\line\n" -"https://github.com/B-Con/crypto-algorithms\\line\n" +"SHA-256 checksum from 7-zip by Igor Pavlov and Crypto++ by Wei Dai:\\line\n" +"http://7-zip.org\\line\n" +"https://github.com/weidai11/cryptopp/\\line\n" "Public Domain\\line\n" "\\line\n" "About and License dialogs inspired by WinSCP by Martin Prikryl\\line\n" diff --git a/src/missing.h b/src/missing.h index 7c5f6333..17cedfc7 100644 --- a/src/missing.h +++ b/src/missing.h @@ -52,21 +52,29 @@ #define PREFETCH64(m) do { _m_prefetch(m); _m_prefetch(m+32); } while(0) #endif -#if defined(_MSC_VER) +#if defined (_MSC_VER) && (_MSC_VER >= 1300) +#include +#pragma intrinsic(_byteswap_ushort) +#pragma intrinsic(_byteswap_ulong) +#pragma intrinsic(_byteswap_uint64) #define bswap_uint64 _byteswap_uint64 #define bswap_uint32 _byteswap_ulong #define bswap_uint16 _byteswap_ushort -#else +#define get_be32(p) bswap_uint32(*(const uint32_t *)(const uint8_t *)(p)) +#define get_be64(p) bswap_uint64(*(const uint64_t *)(const uint8_t *)(p)) +#elif defined (__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))) #define bswap_uint64 __builtin_bswap64 #define bswap_uint32 __builtin_bswap32 #define bswap_uint16 __builtin_bswap16 +#define get_be32(p) bswap_uint32(*(const uint32_t *)(const uint8_t *)(p)) +#define get_be64(p) bswap_uint64(*(const uint32_t *)(const uint8_t *)(p)) #endif /* * Nibbled from https://github.com/hanji/popcnt/blob/master/populationcount.cpp * Since MSVC x86_32 does not have intrinsic popcount64 and I don't have all day */ -static inline int popcnt64(register uint64_t u) +static __inline int popcnt64(register uint64_t u) { u = (u & 0x5555555555555555) + ((u >> 1) & 0x5555555555555555); u = (u & 0x3333333333333333) + ((u >> 2) & 0x3333333333333333); diff --git a/src/rufus.rc b/src/rufus.rc index d22250ff..c3734aef 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.874" +CAPTION "Rufus 2.8.875" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,874,0 - PRODUCTVERSION 2,8,874,0 + FILEVERSION 2,8,875,0 + PRODUCTVERSION 2,8,875,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.874" + VALUE "FileVersion", "2.8.875" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.874" + VALUE "ProductVersion", "2.8.875" END END BLOCK "VarFileInfo" From 0313e5ca54625a5aafa1df856d0dace010d480a8 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 3 Mar 2016 14:58:49 +0000 Subject: [PATCH 46/91] [checksum] additional cleanup --- src/checksum.c | 98 +++++++++++++++++++++++++------------------------- src/missing.h | 11 +++--- src/rufus.rc | 10 +++--- 3 files changed, 60 insertions(+), 59 deletions(-) diff --git a/src/checksum.c b/src/checksum.c index 3aa51aa4..c26aa4c6 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -64,9 +64,9 @@ /* Globals */ char sum_str[NUM_CHECKSUMS][65]; -int bufnum, sum_count[NUM_CHECKSUMS] = { 16, 20, 32 }; +uint32_t bufnum, sum_count[NUM_CHECKSUMS] = { 16, 20, 32 }; HANDLE data_ready[NUM_CHECKSUMS], thread_ready[NUM_CHECKSUMS]; -DWORD rSize[2]; +DWORD read_size[2]; char ALIGNED(64) buffer[2][BUFFER_SIZE]; /* @@ -77,7 +77,7 @@ char ALIGNED(64) buffer[2][BUFFER_SIZE]; #define ROL(a,b) (((a) << (b)) | ((a) >> (32-(b)))) #define ROR(a,b) (((a) >> (b)) | ((a) << (32-(b)))) -// For SHA-256 +/* SHA-256 constants */ static const uint32_t K[64] = { 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, @@ -135,8 +135,7 @@ static void sha256_init(SUM_CONTEXT *ctx) /* Transform the message X which consists of 16 32-bit-words (SHA-1) */ static void sha1_transform(SUM_CONTEXT *ctx, const unsigned char *data) { - uint32_t a, b, c, d, e, tm; - uint32_t x[16]; + uint32_t a, b, c, d, e, tm, x[16]; /* get values from the chaining vars */ a = ctx->state[0]; @@ -152,10 +151,10 @@ static void sha1_transform(SUM_CONTEXT *ctx, const unsigned char *data) unsigned k; for (k = 0; k < 16; k += 4) { const unsigned char *p2 = data + k * 4; - x[k] = get_be32(p2); - x[k + 1] = get_be32(p2 + 4); - x[k + 2] = get_be32(p2 + 8); - x[k + 3] = get_be32(p2 + 12); + x[k] = read_swap32(p2); + x[k + 1] = read_swap32(p2 + 4); + x[k + 2] = read_swap32(p2 + 8); + x[k + 3] = read_swap32(p2 + 12); } } #endif @@ -267,6 +266,7 @@ static void sha1_transform(SUM_CONTEXT *ctx, const unsigned char *data) ctx->state[4] += e; } +/* Transform the message X which consists of 16 32-bit-words (SHA-256) */ static void sha256_transform(SUM_CONTEXT *ctx, const unsigned char *data) { uint32_t a, b, c, d, e, f, g, h, j, x[16]; @@ -309,10 +309,10 @@ static void sha256_transform(SUM_CONTEXT *ctx, const unsigned char *data) unsigned k; for (k = 0; k < 16; k += 4) { const unsigned char *p2 = data + k * 4; - x[k] = get_be32(p2); - x[k + 1] = get_be32(p2 + 4); - x[k + 2] = get_be32(p2 + 8); - x[k + 3] = get_be32(p2 + 12); + x[k] = read_swap32(p2); + x[k + 1] = read_swap32(p2 + 4); + x[k + 2] = read_swap32(p2 + 8); + x[k + 3] = read_swap32(p2 + 12); } } #endif @@ -340,27 +340,26 @@ static void sha256_transform(SUM_CONTEXT *ctx, const unsigned char *data) /* Transform the message X which consists of 16 32-bit-words (MD5) */ static void md5_transform(SUM_CONTEXT *ctx, const unsigned char *data) { - uint32_t a, b, c, d; - uint32_t x[16]; + uint32_t a, b, c, d, x[16]; a = ctx->state[0]; b = ctx->state[1]; c = ctx->state[2]; d = ctx->state[3]; -#ifndef BIG_ENDIAN_HOST - memcpy(x, data, sizeof(x)); -#else +#ifdef BIG_ENDIAN_HOST { unsigned k; for (k = 0; k < 16; k += 4) { const unsigned char *p2 = data + k * 4; - x[k] = get_be32(p2); - x[k + 1] = get_be32(p2 + 4); - x[k + 2] = get_be32(p2 + 8); - x[k + 3] = get_be32(p2 + 12); + x[k] = read_swap32(p2); + x[k + 1] = read_swap32(p2 + 4); + x[k + 2] = read_swap32(p2 + 8); + x[k + 3] = read_swap32(p2 + 12); } } +#else + memcpy(x, data, sizeof(x)); #endif #define F1(x, y, z) (z ^ (x & (y ^ z))) @@ -470,7 +469,7 @@ static void sha1_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) } while (len >= 64) { - PREFETCH64(&buf[64]); + PREFETCH64(buf + 64); sha1_transform(ctx, buf); ctx->bytecount = 0; ctx->bitcount += 64 * 8; @@ -481,10 +480,10 @@ static void sha1_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) ctx->buf[ctx->bytecount++] = *buf++; } +/* Update the message digest with the contents of the buffer (SHA-256) */ static void sha256_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) { - uint64_t pos = ctx->bytecount & 0x3F; - uint64_t num; + size_t num, pos = ctx->bytecount & 0x3F; ctx->bytecount += len; @@ -514,7 +513,7 @@ static void sha256_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) /* Update the message digest with the contents of the buffer (MD5) */ static void md5_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) { - uint32_t t; + size_t t; /* Update bitcount */ ctx->bitcount += (len << 3); @@ -538,7 +537,7 @@ static void md5_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) /* Process data in 64-byte chunks */ while (len >= 64) { - PREFETCH64(&buf[64]); + PREFETCH64(buf + 64); memcpy(ctx->buf, buf, 64); md5_transform(ctx, ctx->buf); buf += 64; @@ -549,7 +548,7 @@ static void md5_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) memcpy(ctx->buf, buf, len); } -/* The routine final terminates the computation and returns the digest (SHA-1) */ +/* Finalize the computation and write the digest in ctx->state[] (SHA-1) */ static void sha1_final(SUM_CONTEXT *ctx) { unsigned char *p; @@ -583,9 +582,8 @@ static void sha1_final(SUM_CONTEXT *ctx) p = ctx->buf; #ifdef BIG_ENDIAN_HOST #define X(a) do { *(uint32_t*)p = ctx->state[a]; p += 4; } while(0) -#else /* little endian */ -#define X(a) do { *p++ = (unsigned char) (ctx->state[a] >> 24); *p++ = (unsigned char) (ctx->state[a] >> 16); \ - *p++ = (unsigned char) (ctx->state[a] >> 8); *p++ = (unsigned char) ctx->state[a]; } while(0) +#else +#define X(a) do { write_swap32(p, ctx->state[a]); p += 4; } while(0); #endif X(0); X(1); @@ -595,14 +593,15 @@ static void sha1_final(SUM_CONTEXT *ctx) #undef X } +/* Finalize the computation and write the digest in ctx->state[] (SHA-256) */ static void sha256_final(SUM_CONTEXT *ctx) { - uint64_t pos = ctx->bytecount & 0x3F; + size_t pos = ctx->bytecount & 0x3F; unsigned char *p; ctx->buf[pos++] = 0x80; - // Pad whatever data is left in the buffer. + /* Pad whatever data is left in the buffer */ while (pos != (64 - 8)) { pos &= 0x3F; if (pos == 0) @@ -610,7 +609,7 @@ static void sha256_final(SUM_CONTEXT *ctx) ctx->buf[pos++] = 0; } - // Append to the padding the total message's length in bits and transform. + /* Append to the padding the total message's length in bits and transform */ ctx->bitcount = ctx->bytecount << 3; ctx->buf[63] = (unsigned char) (ctx->bitcount); ctx->buf[62] = (unsigned char) (ctx->bitcount >> 8); @@ -626,9 +625,8 @@ static void sha256_final(SUM_CONTEXT *ctx) p = ctx->buf; #ifdef BIG_ENDIAN_HOST #define X(a) do { *(uint32_t*)p = ctx->state[a]; p += 4; } while(0) -#else /* little endian */ -#define X(a) do { *p++ = (unsigned char) (ctx->state[a] >> 24); *p++ = (unsigned char) (ctx->state[a] >> 16); \ - *p++ = (unsigned char) (ctx->state[a] >> 8); *p++ = (unsigned char) ctx->state[a]; } while(0) +#else +#define X(a) do { write_swap32(p, ctx->state[a]); p += 4; } while(0); #endif X(0); X(1); @@ -641,10 +639,10 @@ static void sha256_final(SUM_CONTEXT *ctx) #undef X } -/* The routine final terminates the computation and returns the digest (MD5) */ +/* Finalize the computation and write the digest in ctx->state[] (MD5) */ static void md5_final(SUM_CONTEXT *ctx) { - uint32_t count; + size_t count; unsigned char *p; /* Compute number of bytes mod 64 */ @@ -686,9 +684,8 @@ static void md5_final(SUM_CONTEXT *ctx) p = ctx->buf; #ifdef BIG_ENDIAN_HOST -#define X(a) do { *p++ = (unsigned char) (ctx->state[a] >> 24); *p++ = (unsigned char) (ctx->state[a] >> 16); \ - *p++ = (unsigned char) (ctx->state[a] >> 8); *p++ = (unsigned char) ctx->state[a]; } while(0) -#else /* little endian */ +#define X(a) do { write_swap32(p, ctx->state[a]); p += 4; } while(0); +#else #define X(a) do { *(uint32_t*)p = ctx->state[a]; p += 4; } while(0) #endif X(0); @@ -698,6 +695,7 @@ static void md5_final(SUM_CONTEXT *ctx) #undef X } + //#define NULL_TEST #ifdef NULL_TEST // These 'null' calls are useful for testing load balancing and individual algorithm speed @@ -821,7 +819,7 @@ BOOL SetChecksumAffinity(DWORD_PTR* thread_affinity) DWORD WINAPI IndividualSumThread(void* param) { SUM_CONTEXT sum_ctx = { 0 }; // There's a memset in sum_init, but static analyzers still bug us - int i = (int)(uintptr_t)param, j; + uint32_t i = (uint32_t)(uintptr_t)param, j; sum_init[i](&sum_ctx); // Signal that we're ready to service requests @@ -834,8 +832,8 @@ DWORD WINAPI IndividualSumThread(void* param) uprintf("Failed to wait for event for checksum thread #%d: %s", i, WindowsErrorString()); return 1; } - if (rSize[bufnum] != 0) { - sum_write[i](&sum_ctx, buffer[bufnum], (size_t)rSize[bufnum]); + if (read_size[bufnum] != 0) { + sum_write[i](&sum_ctx, buffer[bufnum], (size_t)read_size[bufnum]); if (!SetEvent(thread_ready[i])) goto error; } else { @@ -901,8 +899,8 @@ DWORD WINAPI SumThread(void* param) bufnum = 0; _bufnum = 0; - rSize[0] = 1; // Don't trigger the first loop break - for (rb = 0; ;rb += rSize[_bufnum]) { + read_size[0] = 1; // Don't trigger the first loop break + for (rb = 0; ;rb += read_size[_bufnum]) { // Update the progress and check for cancel if (_GetTickCount64() > LastRefresh + 25) { LastRefresh = _GetTickCount64(); @@ -928,11 +926,11 @@ DWORD WINAPI SumThread(void* param) } // Break the loop when data has been exhausted - if (rSize[bufnum] == 0) + if (read_size[bufnum] == 0) break; // Read data (double buffered) - if (!ReadFile(h, buffer[_bufnum], BUFFER_SIZE, &rSize[_bufnum], NULL)) { + if (!ReadFile(h, buffer[_bufnum], BUFFER_SIZE, &read_size[_bufnum], NULL)) { FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_READ_FAULT; uprintf("Read error: %s", WindowsErrorString()); goto out; @@ -945,7 +943,7 @@ DWORD WINAPI SumThread(void* param) } } - // Our last event with rSize=0 signaled the threads to exit - wait for that to happen + // Our last event with read_size=0 signaled the threads to exit - wait for that to happen if (WaitForMultipleObjects(NUM_CHECKSUMS, sum_thread, TRUE, WAIT_TIME) != WAIT_OBJECT_0) { uprintf("Checksum threads did not finalize: %s", WindowsErrorString()); goto out; diff --git a/src/missing.h b/src/missing.h index 17cedfc7..62a96ab8 100644 --- a/src/missing.h +++ b/src/missing.h @@ -52,6 +52,7 @@ #define PREFETCH64(m) do { _m_prefetch(m); _m_prefetch(m+32); } while(0) #endif +/* Read/write with endianness swap */ #if defined (_MSC_VER) && (_MSC_VER >= 1300) #include #pragma intrinsic(_byteswap_ushort) @@ -60,15 +61,17 @@ #define bswap_uint64 _byteswap_uint64 #define bswap_uint32 _byteswap_ulong #define bswap_uint16 _byteswap_ushort -#define get_be32(p) bswap_uint32(*(const uint32_t *)(const uint8_t *)(p)) -#define get_be64(p) bswap_uint64(*(const uint64_t *)(const uint8_t *)(p)) #elif defined (__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))) #define bswap_uint64 __builtin_bswap64 #define bswap_uint32 __builtin_bswap32 #define bswap_uint16 __builtin_bswap16 -#define get_be32(p) bswap_uint32(*(const uint32_t *)(const uint8_t *)(p)) -#define get_be64(p) bswap_uint64(*(const uint32_t *)(const uint8_t *)(p)) #endif +#define read_swap16(p) bswap_uint16(*(const uint16_t*)(const uint8_t*)(p)) +#define read_swap32(p) bswap_uint32(*(const uint32_t*)(const uint8_t*)(p)) +#define read_swap64(p) bswap_uint64(*(const uint64_t*)(const uint8_t*)(p)) +#define write_swap16(p,v) (*(uint16_t*)(void*)(p)) = bswap_uint16(v) +#define write_swap32(p,v) (*(uint32_t*)(void*)(p)) = bswap_uint32(v) +#define write_swap64(p,v) (*(uint32_t*)(void*)(p)) = bswap_uint64(v) /* * Nibbled from https://github.com/hanji/popcnt/blob/master/populationcount.cpp diff --git a/src/rufus.rc b/src/rufus.rc index c3734aef..00e7d8cf 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.875" +CAPTION "Rufus 2.8.876" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,875,0 - PRODUCTVERSION 2,8,875,0 + FILEVERSION 2,8,876,0 + PRODUCTVERSION 2,8,876,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.875" + VALUE "FileVersion", "2.8.876" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.875" + VALUE "ProductVersion", "2.8.876" END END BLOCK "VarFileInfo" From d385a097c04a33794a023484fbd0e8bbf4df9a96 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 3 Mar 2016 17:24:54 +0000 Subject: [PATCH 47/91] [misc] make the affinity setup fn more generic and move it to stdfn * Also align checksum context to 64 bytes (cache line) --- src/checksum.c | 39 +-------------------------------------- src/rufus.c | 6 +++--- src/rufus.h | 2 +- src/rufus.rc | 10 +++++----- src/stdfn.c | 36 ++++++++++++++++++++++++++++++++++++ 5 files changed, 46 insertions(+), 47 deletions(-) diff --git a/src/checksum.c b/src/checksum.c index c26aa4c6..c3037061 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -93,7 +93,7 @@ static const uint32_t K[64] = { * For convenience, we use a common context for all the checksums algorithms, * which means some elements may be unused... */ -typedef struct ALIGNED(8) { +typedef struct ALIGNED(64) { unsigned char buf[64]; uint32_t state[8]; uint64_t bytecount; @@ -778,43 +778,6 @@ INT_PTR CALLBACK ChecksumCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM return (INT_PTR)FALSE; } -/* - * We want the maximum speed we can get out of the checksum computation, - * so, if we have a multiprocessor/multithreaded machine, we try to assign - * each of the individual checksum threads to a different core. - * To do just that, we need the following function call. - */ -extern BOOL usb_debug; // For uuprintf -BOOL SetChecksumAffinity(DWORD_PTR* thread_affinity) -{ - int i, j, pc; - DWORD_PTR affinity, dummy; - - memset(thread_affinity, 0, 4 * sizeof(DWORD_PTR)); - if (!GetProcessAffinityMask(GetCurrentProcess(), &affinity, &dummy)) - return FALSE; - uuprintf("\r\nChecksum affinities:"); - uuprintf("global:\t%s", printbitslz(affinity)); - - // If we don't have enough virtual cores to evenly spread our load forget it - pc = popcnt64(affinity); - if (pc < NUM_CHECKSUMS + 1) - return FALSE; - - // Spread the affinity as evenly as we can - thread_affinity[NUM_CHECKSUMS] = affinity; - for (i = 0; i < NUM_CHECKSUMS; i++) { - for (j = 0; j < pc / (NUM_CHECKSUMS + 1); j++) { - thread_affinity[i] |= affinity & (-1LL * affinity); - affinity ^= affinity & (-1LL * affinity); - } - uuprintf("sum%d:\t%s", i, printbitslz(thread_affinity[i])); - thread_affinity[NUM_CHECKSUMS] ^= thread_affinity[i]; - } - uuprintf("sum%d:\t%s", i, printbitslz(thread_affinity[i])); - return TRUE; -} - // Individual thread that computes one of MD5, SHA1 or SHA256 in parallel DWORD WINAPI IndividualSumThread(void* param) { diff --git a/src/rufus.c b/src/rufus.c index 56b47f45..ef5c507f 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -2045,7 +2045,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA static ULONG ulRegister = 0; static LPITEMIDLIST pidlDesktop = NULL; static MY_SHChangeNotifyEntry NotifyEntry; - static DWORD_PTR sumthread_affinity[4]; + static DWORD_PTR thread_affinity[4]; DRAWITEMSTRUCT* pDI; HDROP droppedFileInfo; POINT Point; @@ -2530,8 +2530,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA // Disable all controls except cancel EnableControls(FALSE); InitProgress(FALSE); - SetChecksumAffinity(sumthread_affinity); - format_thid = CreateThread(NULL, 0, SumThread, (LPVOID)sumthread_affinity, 0, NULL); + SetThreadAffinity(thread_affinity, NUM_CHECKSUMS + 1); + format_thid = CreateThread(NULL, 0, SumThread, (LPVOID)thread_affinity, 0, NULL); if (format_thid != NULL) { PrintInfo(0, -1); timer = 0; diff --git a/src/rufus.h b/src/rufus.h index 06b68ce8..3979eaf1 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -441,7 +441,7 @@ extern LONG ValidateSignature(HWND hDlg, const char* path); extern BOOL IsFontAvailable(const char* font_name); extern BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries); -extern BOOL SetChecksumAffinity(DWORD_PTR* thread_affinity); +extern BOOL SetThreadAffinity(DWORD_PTR* thread_affinity, size_t num_threads); #define printbits(x) _printbits(sizeof(x), &x, 0) #define printbitslz(x) _printbits(sizeof(x), &x, 1) extern char* _printbits(size_t const size, void const * const ptr, int leading_zeroes); diff --git a/src/rufus.rc b/src/rufus.rc index 00e7d8cf..8038065a 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.876" +CAPTION "Rufus 2.8.877" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,876,0 - PRODUCTVERSION 2,8,876,0 + FILEVERSION 2,8,877,0 + PRODUCTVERSION 2,8,877,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.876" + VALUE "FileVersion", "2.8.877" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.876" + VALUE "ProductVersion", "2.8.877" END END BLOCK "VarFileInfo" diff --git a/src/stdfn.c b/src/stdfn.c index b5391751..afa21717 100644 --- a/src/stdfn.c +++ b/src/stdfn.c @@ -25,12 +25,14 @@ #include #include "rufus.h" +#include "missing.h" #include "resource.h" #include "msapi_utf8.h" #include "localization.h" #include "settings.h" +extern BOOL usb_debug; // For uuprintf int nWindowsVersion = WINDOWS_UNDEFINED; char WindowsVersionStr[128] = "Windows "; @@ -811,3 +813,37 @@ BOOL SetLGP(BOOL bRestore, BOOL* bExistingKey, const char* szPath, const char* s return FALSE; return (BOOL) r; } + +/* + * This call tries to evenly balance the affinities for an array of + * num_threads, according to the number of cores at our disposal... + */ +BOOL SetThreadAffinity(DWORD_PTR* thread_affinity, size_t num_threads) +{ + int i, j, pc; + DWORD_PTR affinity, dummy; + + memset(thread_affinity, 0, num_threads * sizeof(DWORD_PTR)); + if (!GetProcessAffinityMask(GetCurrentProcess(), &affinity, &dummy)) + return FALSE; + uuprintf("\r\nThread affinities:"); + uuprintf(" avail:\t%s", printbitslz(affinity)); + + // If we don't have enough virtual cores to evenly spread our load forget it + pc = popcnt64(affinity); + if (pc < num_threads) + return FALSE; + + // Spread the affinity as evenly as we can + thread_affinity[num_threads - 1] = affinity; + for (i = 0; i < num_threads - 1; i++) { + for (j = 0; j < pc / num_threads; j++) { + thread_affinity[i] |= affinity & (-1LL * affinity); + affinity ^= affinity & (-1LL * affinity); + } + uuprintf(" thr_%d:\t%s", i, printbitslz(thread_affinity[i])); + thread_affinity[num_threads - 1] ^= thread_affinity[i]; + } + uuprintf(" thr_%d:\t%s", i, printbitslz(thread_affinity[i])); + return TRUE; +} From 71520baf31de4c30a295b5df8ae1a132cc8dab98 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 4 Mar 2016 16:34:50 +0000 Subject: [PATCH 48/91] [core] factorize the img/zero disk writing code * Also fix a WDK warning --- src/format.c | 234 ++++++++++++++++++++++----------------------------- src/rufus.rc | 10 +-- src/stdfn.c | 3 +- 3 files changed, 109 insertions(+), 138 deletions(-) diff --git a/src/format.c b/src/format.c index 56c4d9d4..45421753 100644 --- a/src/format.c +++ b/src/format.c @@ -1264,7 +1264,7 @@ out: // incompatibilities from one version of Windows to the next. // Maybe when we use wimlib we'll review this, but for now just turn it off. //#define SET_INTERNAL_DRIVES_OFFLINE -BOOL SetupWinToGo(const char* drive_name, BOOL use_ms_efi) +static BOOL SetupWinToGo(const char* drive_name, BOOL use_ms_efi) { #ifdef SET_INTERNAL_DRIVES_OFFLINE static char san_policy_path[] = "?:\\san_policy.xml"; @@ -1432,7 +1432,7 @@ static BOOL CALLBACK FormatPromptCallback(HWND hWnd, LPARAM lParam) * disk in drive X: before you can use it'. You will also get that popup if you start a * bad blocks check and cancel it before it completes. We have to close that popup manually. */ -DWORD WINAPI CloseFormatPromptThread(LPVOID param) { +static DWORD WINAPI CloseFormatPromptThread(LPVOID param) { HWND hFormatPrompt; while(format_op_in_progress) { @@ -1447,7 +1447,7 @@ DWORD WINAPI CloseFormatPromptThread(LPVOID param) { ExitThread(0); } -void update_progress(const uint64_t processed_bytes) +static void update_progress(const uint64_t processed_bytes) { if (_GetTickCount64() > LastRefresh + 25) { LastRefresh = _GetTickCount64(); @@ -1457,6 +1457,99 @@ void update_progress(const uint64_t processed_bytes) } } +/* Write an image file or zero a drive */ +static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage) +{ + const DWORD SectorSize = SelectedDrive.Geometry.BytesPerSector; + BOOL s, ret = FALSE; + LARGE_INTEGER li; + DWORD rSize, wSize, BufSize; + uint64_t wb, target_size = hSourceImage?img_report.projected_size:SelectedDrive.DiskSize; + uint8_t *buffer = NULL, *aligned_buffer; + int i; + + // We poked the MBR and other stuff, so we need to rewind + li.QuadPart = 0; + if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN)) + uprintf("Warning: Unable to rewind image position - wrong data might be copied!"); + LastRefresh = 0; + + if (img_report.compression_type != BLED_COMPRESSION_NONE) { + uprintf("Writing Compressed Image..."); + bled_init(_uprintf, update_progress, &FormatStatus); + bled_uncompress_with_handles(hSourceImage, hPhysicalDrive, img_report.compression_type); + bled_exit(); + } else { + uprintf(hSourceImage?"Writing Image...":"Zeroing drive..."); + // Our buffer size must be a multiple of the sector size + BufSize = ((DD_BUFFER_SIZE + SectorSize - 1) / SectorSize) * SectorSize; + buffer = (uint8_t*)calloc(BufSize + SectorSize, 1); // +1 sector for align + if (buffer == NULL) { + FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_NOT_ENOUGH_MEMORY; + uprintf("could not allocate disk write buffer"); + goto out; + } + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747.aspx does buffer sector alignment + aligned_buffer = ((void *)((((uintptr_t)(buffer)) + (SectorSize)-1) & (~(((uintptr_t)(SectorSize)) - 1)))); + + // Don't bother trying for something clever, using double buffering overlapped and whatnot: + // With Windows' default optimizations, sync read + sync write for sequential operations + // will be as fast, if not faster, than whatever async scheme you can come up with. + rSize = BufSize; + for (wb = 0, wSize = 0; wb < (uint64_t)SelectedDrive.DiskSize; wb += wSize) { + if (_GetTickCount64() > LastRefresh + 25) { + LastRefresh = _GetTickCount64(); + format_percent = (100.0f*wb) / (1.0f*target_size); + PrintInfo(0, hSourceImage?MSG_261:MSG_286, format_percent); + UpdateProgress(OP_FORMAT, format_percent); + } + + if (hSourceImage != NULL) { + s = ReadFile(hSourceImage, aligned_buffer, BufSize, &rSize, NULL); + if (!s) { + FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_READ_FAULT; + uprintf("read error: %s", WindowsErrorString()); + goto out; + } + if (rSize == 0) + break; + } + // Don't overflow our projected size (mostly for VHDs) + if (wb + rSize > target_size) { + rSize = (DWORD)(target_size - wb); + } + + // WriteFile fails unless the size is a multiple of sector size + if (rSize % SectorSize != 0) + rSize = ((rSize + SectorSize - 1) / SectorSize) * SectorSize; + for (i = 0; i < WRITE_RETRIES; i++) { + CHECK_FOR_USER_CANCEL; + s = WriteFile(hPhysicalDrive, aligned_buffer, rSize, &wSize, NULL); + if ((s) && (wSize == rSize)) + break; + if (s) + uprintf("write error: Wrote %d bytes, expected %d bytes\n", wSize, rSize); + else + uprintf("write error: %s", WindowsErrorString()); + if (i < WRITE_RETRIES - 1) { + li.QuadPart = wb; + SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN); + uprintf(" RETRYING...\n"); + } else { + FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_WRITE_FAULT; + goto out; + } + } + if (i >= WRITE_RETRIES) goto out; + } + } + RefreshDriveLayout(hPhysicalDrive); + ret = TRUE; +out: + safe_free(buffer); + return ret; +} + /* * Standalone thread for the formatting operation * According to http://msdn.microsoft.com/en-us/library/windows/desktop/aa364562.aspx @@ -1471,20 +1564,18 @@ void update_progress(const uint64_t processed_bytes) DWORD WINAPI FormatThread(void* param) { int i, r, pt, tt, fs, bt; - BOOL s, ret, use_large_fat32, windows_to_go; + BOOL ret, use_large_fat32, windows_to_go; const DWORD SectorSize = SelectedDrive.Geometry.BytesPerSector; - DWORD rSize, wSize, BufSize, DriveIndex = (DWORD)(uintptr_t)param; + DWORD DriveIndex = (DWORD)(uintptr_t)param; HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE; HANDLE hLogicalVolume = INVALID_HANDLE_VALUE; HANDLE hSourceImage = INVALID_HANDLE_VALUE; SYSTEMTIME lt; FILE* log_fd; - LARGE_INTEGER li; - uint64_t wb; - uint8_t *buffer = NULL, *aligned_buffer, extra_partitions = 0; + uint8_t *buffer = NULL, extra_partitions = 0; char *bb_msg, *guid_volume = NULL; char drive_name[] = "?:\\"; - char drive_letters[27]; + char drive_letters[27], fs_type[32]; char logfile[MAX_PATH], *userdir; char efi_dst[] = "?:\\efi\\boot\\bootx64.efi"; char kolibri_dst[] = "?:\\MTLD_F32"; @@ -1586,57 +1677,8 @@ DWORD WINAPI FormatThread(void* param) } CreateThread(NULL, 0, CloseFormatPromptThread, NULL, 0, NULL); - // TODO: factorize this with DD write? if (zero_drive) { - li.QuadPart = 0; - SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN); - uprintf("Zeroing drive..."); - // Our buffer size must be a multiple of the sector size - BufSize = ((DD_BUFFER_SIZE + SectorSize - 1) / SectorSize) * SectorSize; - buffer = (uint8_t*)calloc(BufSize + SectorSize, 1); // +1 sector for align - if (buffer == NULL) { - FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_NOT_ENOUGH_MEMORY; - uprintf("could not allocate zeroing buffer"); - goto out; - } - // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747.aspx does buffer sector alignment - aligned_buffer = ((void *)((((uintptr_t)(buffer)) + (SectorSize)-1) & (~(((uintptr_t)(SectorSize)) - 1)))); - for (wb = 0, wSize = 0; wb < (uint64_t)SelectedDrive.DiskSize; wb += wSize) { - if (_GetTickCount64() > LastRefresh + 25) { - LastRefresh = _GetTickCount64(); - format_percent = (100.0f*wb) / (1.0f*SelectedDrive.DiskSize); - PrintInfo(0, MSG_286, format_percent); - UpdateProgress(OP_FORMAT, format_percent); - } - // Don't overflow our projected size - if (wb + BufSize > (uint64_t)SelectedDrive.DiskSize) { - BufSize = (DWORD)(SelectedDrive.DiskSize - wb); - } - // WriteFile fails unless the size is a multiple of sector size - if (BufSize % SectorSize != 0) - BufSize = ((BufSize + SectorSize - 1) / SectorSize) * SectorSize; - for (i = 0; i < WRITE_RETRIES; i++) { - CHECK_FOR_USER_CANCEL; - s = WriteFile(hPhysicalDrive, aligned_buffer, BufSize, &wSize, NULL); - if ((s) && (wSize == BufSize)) - break; - if (s) - uprintf("write error: Wrote %d bytes, expected %d bytes\n", wSize, BufSize); - else - uprintf("write error: %s", WindowsErrorString()); - if (i < WRITE_RETRIES - 1) { - li.QuadPart = wb; - SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN); - uprintf(" RETRYING...\n"); - } - else { - FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_WRITE_FAULT; - goto out; - } - } - if (i >= WRITE_RETRIES) goto out; - } - RefreshDriveLayout(hPhysicalDrive); + WriteDrive(hPhysicalDrive, NULL); goto out; } @@ -1707,11 +1749,6 @@ DWORD WINAPI FormatThread(void* param) // Write an image file if (IsChecked(IDC_BOOT) && (bt == BT_IMG)) { - char fs_type[32]; - // We poked the MBR and other stuff, so we need to rewind - li.QuadPart = 0; - if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN)) - uprintf("Warning: Unable to rewind image position - wrong data might be copied!"); hSourceImage = CreateFileU(image_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hSourceImage == INVALID_HANDLE_VALUE) { @@ -1719,75 +1756,10 @@ DWORD WINAPI FormatThread(void* param) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; goto out; } - LastRefresh = 0; - if (img_report.compression_type != BLED_COMPRESSION_NONE) { - uprintf("Writing Compressed Image..."); - bled_init(_uprintf, update_progress, &FormatStatus); - bled_uncompress_with_handles(hSourceImage, hPhysicalDrive, img_report.compression_type); - bled_exit(); - } else { - uprintf("Writing Image..."); - // Our buffer size must be a multiple of the sector size - BufSize = ((DD_BUFFER_SIZE + SectorSize - 1) / SectorSize) * SectorSize; - buffer = (uint8_t*)malloc(BufSize + SectorSize); // +1 sector for align - if (buffer == NULL) { - FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_ENOUGH_MEMORY; - uprintf("could not allocate DD buffer"); - goto out; - } - // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747.aspx does buffer sector alignment - aligned_buffer = ((void *) ((((uintptr_t)(buffer)) + (SectorSize) - 1) & (~(((uintptr_t)(SectorSize)) - 1)))); - - // Don't bother trying for something clever, using double buffering overlapped and whatnot: - // With Windows' default optimizations, sync read + sync write for sequential operations - // will be as fast, if not faster, than whatever async scheme you can come up with. - for (wb = 0, wSize = 0; ; wb += wSize) { - s = ReadFile(hSourceImage, aligned_buffer, BufSize, &rSize, NULL); - if (!s) { - FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_READ_FAULT; - uprintf("read error: %s", WindowsErrorString()); - goto out; - } - if (rSize == 0) - break; - if (_GetTickCount64() > LastRefresh + 25) { - LastRefresh = _GetTickCount64(); - format_percent = (100.0f*wb)/(1.0f*img_report.projected_size); - PrintInfo(0, MSG_261, format_percent); - UpdateProgress(OP_FORMAT, format_percent); - } - // Don't overflow our projected size (mostly for VHDs) - if (wb + rSize > img_report.projected_size) { - rSize = (DWORD)(img_report.projected_size - wb); - } - // WriteFile fails unless the size is a multiple of sector size - if (rSize % SectorSize != 0) - rSize = ((rSize + SectorSize -1) / SectorSize) * SectorSize; - for (i=0; i < WRITE_RETRIES; i++) { - CHECK_FOR_USER_CANCEL; - s = WriteFile(hPhysicalDrive, aligned_buffer, rSize, &wSize, NULL); - if ((s) && (wSize == rSize)) - break; - if (s) - uprintf("write error: Wrote %d bytes, expected %d bytes\n", wSize, rSize); - else - uprintf("write error: %s", WindowsErrorString()); - if (i < WRITE_RETRIES-1) { - li.QuadPart = wb; - SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN); - uprintf(" RETRYING...\n"); - } else { - FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; - goto out; - } - } - if (i >= WRITE_RETRIES) goto out; - } - } + WriteDrive(hPhysicalDrive, hSourceImage); // If the image contains a partition we might be able to access, try to re-mount it - RefreshDriveLayout(hPhysicalDrive); safe_unlockclose(hPhysicalDrive); safe_unlockclose(hLogicalVolume); Sleep(200); @@ -1797,8 +1769,6 @@ DWORD WINAPI FormatThread(void* param) if ((guid_volume != NULL) && (MountVolume(drive_name, guid_volume))) uprintf("Remounted %s on %s\n", guid_volume, drive_name); } - - uprintf("Done"); goto out; } diff --git a/src/rufus.rc b/src/rufus.rc index 8038065a..4a48866c 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.877" +CAPTION "Rufus 2.8.878" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,877,0 - PRODUCTVERSION 2,8,877,0 + FILEVERSION 2,8,878,0 + PRODUCTVERSION 2,8,878,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.877" + VALUE "FileVersion", "2.8.878" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.877" + VALUE "ProductVersion", "2.8.878" END END BLOCK "VarFileInfo" diff --git a/src/stdfn.c b/src/stdfn.c index afa21717..a8989bf3 100644 --- a/src/stdfn.c +++ b/src/stdfn.c @@ -820,7 +820,8 @@ BOOL SetLGP(BOOL bRestore, BOOL* bExistingKey, const char* szPath, const char* s */ BOOL SetThreadAffinity(DWORD_PTR* thread_affinity, size_t num_threads) { - int i, j, pc; + + size_t i, j, pc; DWORD_PTR affinity, dummy; memset(thread_affinity, 0, num_threads * sizeof(DWORD_PTR)); From 5afffd101866f1dfbf4727b14fc47f2379918bf7 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Sat, 5 Mar 2016 21:20:09 +0000 Subject: [PATCH 49/91] [checksum] additional cleanup and optimization * Use the commonly used function names for SHA-256 (Sigma, etc.) * Use the same xxx_write for all, and avoid unwarranted memcpy * Remove the bitcount * Use nested ROR() speedup --- src/checksum.c | 202 +++++++++++++++++++++++++------------------------ src/rufus.rc | 10 +-- src/stdfn.c | 1 - 3 files changed, 110 insertions(+), 103 deletions(-) diff --git a/src/checksum.c b/src/checksum.c index c3037061..ab896d29 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -97,7 +97,6 @@ typedef struct ALIGNED(64) { unsigned char buf[64]; uint32_t state[8]; uint64_t bytecount; - uint64_t bitcount; } SUM_CONTEXT; static void md5_init(SUM_CONTEXT *ctx) @@ -267,7 +266,7 @@ static void sha1_transform(SUM_CONTEXT *ctx, const unsigned char *data) } /* Transform the message X which consists of 16 32-bit-words (SHA-256) */ -static void sha256_transform(SUM_CONTEXT *ctx, const unsigned char *data) +static __inline void sha256_transform(SUM_CONTEXT *ctx, const unsigned char *data) { uint32_t a, b, c, d, e, f, g, h, j, x[16]; @@ -282,16 +281,17 @@ static void sha256_transform(SUM_CONTEXT *ctx, const unsigned char *data) #define CH(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) #define MAJ(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) -#define EP0(x) (ROR(x,2) ^ ROR(x,13) ^ ROR(x,22)) -#define EP1(x) (ROR(x,6) ^ ROR(x,11) ^ ROR(x,25)) -#define SIG0(x) (ROR(x,7) ^ ROR(x,18) ^ ((x) >> 3)) -#define SIG1(x) (ROR(x,17) ^ ROR(x,19) ^ ((x) >> 10)) +// Nesting the ROR allows for single register compiler optimizations +#define S0(x) (ROR(ROR(ROR(x,9)^(x),11)^(x),2)) +#define S1(x) (ROR(ROR(ROR(x,14)^(x),5)^(x),6)) +#define s0(x) (ROR(ROR(x,11)^(x),7)^((x)>>3)) +#define s1(x) (ROR(ROR(x,2)^(x),17)^((x)>>10)) #define BLK0(i) (x[i]) -#define BLK2(i) (x[i] += SIG1(x[((i)-2)&15]) + x[((i)-7)&15] + SIG0(x[((i)-15)&15])) -#define R(a,b,c,d,e,f,g,h, i) \ - h += EP1(e) + CH(e,f,g) + K[(i)+(j)] + (j ? BLK2(i) : BLK0(i)); \ +#define BLK2(i) (x[i] += s1(x[((i)-2)&15]) + x[((i)-7)&15] + s0(x[((i)-15)&15])) +#define R(a,b,c,d,e,f,g,h,i) \ + h += S1(e) + CH(e,f,g) + K[(i)+(j)] + (j ? BLK2(i) : BLK0(i)); \ d += h; \ - h += EP0(a) + MAJ(a, b, c) + h += S0(a) + MAJ(a, b, c) #define RX_8(i) \ R(a,b,c,d,e,f,g,h, i); \ R(h,a,b,c,d,e,f,g, i+1); \ @@ -322,10 +322,10 @@ static void sha256_transform(SUM_CONTEXT *ctx, const unsigned char *data) RX_8(8); } -#undef EP0 -#undef EP1 -#undef SIG0 -#undef SIG1 +#undef S0 +#undef S1 +#undef s0 +#undef s1 ctx->state[0] += a; ctx->state[1] += b; @@ -453,61 +453,75 @@ static void md5_transform(SUM_CONTEXT *ctx, const unsigned char *data) /* Update the message digest with the contents of the buffer (SHA-1) */ static void sha1_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) { - if (ctx->bytecount == 64) { /* flush the buffer */ - sha1_transform(ctx, ctx->buf); - ctx->bytecount = 0; - ctx->bitcount += 64 * 8; - } - if (!buf) - return; - if (ctx->bytecount) { - for (; len && ctx->bytecount < 64; len--) - ctx->buf[ctx->bytecount++] = *buf++; - sha1_write(ctx, NULL, 0); - if (!len) + size_t t; + + /* Update bytecount */ + ctx->bytecount += len; + + t = ctx->bytecount & 0x3f; + + /* Handle any leading odd-sized chunks */ + if (t) { + unsigned char *p = ctx->buf + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); return; + } + memcpy(p, buf, t); + sha1_transform(ctx, ctx->buf); + buf += t; + len -= t; } + /* Process data in 64-byte chunks */ while (len >= 64) { PREFETCH64(buf + 64); sha1_transform(ctx, buf); - ctx->bytecount = 0; - ctx->bitcount += 64 * 8; - len -= 64; buf += 64; + len -= 64; } - for (; len && ctx->bytecount < 64; len--) - ctx->buf[ctx->bytecount++] = *buf++; + + /* Handle any remaining bytes of data. */ + memcpy(ctx->buf, buf, len); } /* Update the message digest with the contents of the buffer (SHA-256) */ static void sha256_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) { - size_t num, pos = ctx->bytecount & 0x3F; + size_t t; + /* Update bytecount */ ctx->bytecount += len; - num = 64 - pos; - if (num > len) { - memcpy(ctx->buf + pos, buf, len); - return; - } - len -= num; - memcpy(ctx->buf + pos, buf, num); - buf += num; + t = ctx->bytecount & 0x3f; - for (;;) { - PREFETCH64(buf + 64); + /* Handle any leading odd-sized chunks */ + if (t) { + unsigned char *p = ctx->buf + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); sha256_transform(ctx, ctx->buf); - if (len < 64) - break; - len -= 64; - memcpy(ctx->buf, buf, 64); - buf += 64; + buf += t; + len -= t; } - if (len != 0) - memcpy(ctx->buf, buf, len); + /* Process data in 64-byte chunks */ + while (len >= 64) { + PREFETCH64(buf + 64); + sha256_transform(ctx, buf); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->buf, buf, len); } /* Update the message digest with the contents of the buffer (MD5) */ @@ -515,10 +529,10 @@ static void md5_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) { size_t t; - /* Update bitcount */ - ctx->bitcount += (len << 3); + /* Update bytecount */ + ctx->bytecount += len; - t = (ctx->bitcount >> 3) & 0x3f; + t = ctx->bytecount & 0x3f; /* Handle any leading odd-sized chunks */ if (t) { @@ -538,8 +552,7 @@ static void md5_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) /* Process data in 64-byte chunks */ while (len >= 64) { PREFETCH64(buf + 64); - memcpy(ctx->buf, buf, 64); - md5_transform(ctx, ctx->buf); + md5_transform(ctx, buf); buf += 64; len -= 64; } @@ -551,31 +564,29 @@ static void md5_write(SUM_CONTEXT *ctx, const unsigned char *buf, size_t len) /* Finalize the computation and write the digest in ctx->state[] (SHA-1) */ static void sha1_final(SUM_CONTEXT *ctx) { + uint64_t bitcount = ctx->bytecount << 3; + size_t pos = ((size_t)ctx->bytecount) & 0x3F; unsigned char *p; - sha1_write(ctx, NULL, 0); /* flush */; + ctx->buf[pos++] = 0x80; - if (ctx->bytecount < 56) { /* enough room */ - ctx->buf[ctx->bytecount++] = 0x80; /* pad */ - while (ctx->bytecount < 56) - ctx->buf[ctx->bytecount++] = 0; /* pad */ - } else { /* need one extra block */ - ctx->buf[ctx->bytecount++] = 0x80; /* pad character */ - while (ctx->bytecount < 64) - ctx->buf[ctx->bytecount++] = 0; - sha1_write(ctx, NULL, 0); /* flush */; - memset(ctx->buf, 0, 56); /* fill next block with zeroes */ + /* Pad whatever data is left in the buffer */ + while (pos != (64 - 8)) { + pos &= 0x3F; + if (pos == 0) + sha1_transform(ctx, ctx->buf); + ctx->buf[pos++] = 0; } - /* append the 64 bit count (big-endian) */ - ctx->buf[56] = (unsigned char) (ctx->bitcount >> 56); - ctx->buf[57] = (unsigned char) (ctx->bitcount >> 48); - ctx->buf[58] = (unsigned char) (ctx->bitcount >> 40); - ctx->buf[59] = (unsigned char) (ctx->bitcount >> 32); - ctx->buf[60] = (unsigned char) (ctx->bitcount >> 24); - ctx->buf[61] = (unsigned char) (ctx->bitcount >> 16); - ctx->buf[62] = (unsigned char) (ctx->bitcount >> 8); - ctx->buf[63] = (unsigned char) ctx->bitcount; + /* Append to the padding the total message's length in bits and transform */ + ctx->buf[63] = (unsigned char) bitcount; + ctx->buf[62] = (unsigned char) (bitcount >> 8); + ctx->buf[61] = (unsigned char) (bitcount >> 16); + ctx->buf[60] = (unsigned char) (bitcount >> 24); + ctx->buf[59] = (unsigned char) (bitcount >> 32); + ctx->buf[58] = (unsigned char) (bitcount >> 40); + ctx->buf[57] = (unsigned char) (bitcount >> 48); + ctx->buf[56] = (unsigned char) (bitcount >> 56); sha1_transform(ctx, ctx->buf); @@ -596,7 +607,8 @@ static void sha1_final(SUM_CONTEXT *ctx) /* Finalize the computation and write the digest in ctx->state[] (SHA-256) */ static void sha256_final(SUM_CONTEXT *ctx) { - size_t pos = ctx->bytecount & 0x3F; + uint64_t bitcount = ctx->bytecount << 3; + size_t pos = ((size_t)ctx->bytecount) & 0x3F; unsigned char *p; ctx->buf[pos++] = 0x80; @@ -610,15 +622,14 @@ static void sha256_final(SUM_CONTEXT *ctx) } /* Append to the padding the total message's length in bits and transform */ - ctx->bitcount = ctx->bytecount << 3; - ctx->buf[63] = (unsigned char) (ctx->bitcount); - ctx->buf[62] = (unsigned char) (ctx->bitcount >> 8); - ctx->buf[61] = (unsigned char) (ctx->bitcount >> 16); - ctx->buf[60] = (unsigned char) (ctx->bitcount >> 24); - ctx->buf[59] = (unsigned char) (ctx->bitcount >> 32); - ctx->buf[58] = (unsigned char) (ctx->bitcount >> 40); - ctx->buf[57] = (unsigned char) (ctx->bitcount >> 48); - ctx->buf[56] = (unsigned char) (ctx->bitcount >> 56); + ctx->buf[63] = (unsigned char) bitcount; + ctx->buf[62] = (unsigned char) (bitcount >> 8); + ctx->buf[61] = (unsigned char) (bitcount >> 16); + ctx->buf[60] = (unsigned char) (bitcount >> 24); + ctx->buf[59] = (unsigned char) (bitcount >> 32); + ctx->buf[58] = (unsigned char) (bitcount >> 40); + ctx->buf[57] = (unsigned char) (bitcount >> 48); + ctx->buf[56] = (unsigned char) (bitcount >> 56); sha256_transform(ctx, ctx->buf); @@ -642,12 +653,10 @@ static void sha256_final(SUM_CONTEXT *ctx) /* Finalize the computation and write the digest in ctx->state[] (MD5) */ static void md5_final(SUM_CONTEXT *ctx) { - size_t count; + size_t count = ((size_t)ctx->bytecount) & 0x3F; + uint64_t bitcount = ctx->bytecount << 3; unsigned char *p; - /* Compute number of bytes mod 64 */ - count = (ctx->bitcount >> 3) & 0x3F; - /* Set the first char of padding to 0x80. * This is safe since there is always at least one byte free */ @@ -671,14 +680,14 @@ static void md5_final(SUM_CONTEXT *ctx) } /* append the 64 bit count (little endian) */ - ctx->buf[56] = (unsigned char) ctx->bitcount; - ctx->buf[57] = (unsigned char) (ctx->bitcount >> 8); - ctx->buf[58] = (unsigned char) (ctx->bitcount >> 16); - ctx->buf[59] = (unsigned char) (ctx->bitcount >> 24); - ctx->buf[60] = (unsigned char) (ctx->bitcount >> 32); - ctx->buf[61] = (unsigned char) (ctx->bitcount >> 40); - ctx->buf[62] = (unsigned char) (ctx->bitcount >> 48); - ctx->buf[63] = (unsigned char) (ctx->bitcount >> 56); + ctx->buf[56] = (unsigned char) bitcount; + ctx->buf[57] = (unsigned char) (bitcount >> 8); + ctx->buf[58] = (unsigned char) (bitcount >> 16); + ctx->buf[59] = (unsigned char) (bitcount >> 24); + ctx->buf[60] = (unsigned char) (bitcount >> 32); + ctx->buf[61] = (unsigned char) (bitcount >> 40); + ctx->buf[62] = (unsigned char) (bitcount >> 48); + ctx->buf[63] = (unsigned char) (bitcount >> 56); md5_transform(ctx, ctx->buf); @@ -695,7 +704,6 @@ static void md5_final(SUM_CONTEXT *ctx) #undef X } - //#define NULL_TEST #ifdef NULL_TEST // These 'null' calls are useful for testing load balancing and individual algorithm speed diff --git a/src/rufus.rc b/src/rufus.rc index 4a48866c..07f719d8 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.878" +CAPTION "Rufus 2.8.879" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,878,0 - PRODUCTVERSION 2,8,878,0 + FILEVERSION 2,8,879,0 + PRODUCTVERSION 2,8,879,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.878" + VALUE "FileVersion", "2.8.879" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.878" + VALUE "ProductVersion", "2.8.879" END END BLOCK "VarFileInfo" diff --git a/src/stdfn.c b/src/stdfn.c index a8989bf3..cdca1180 100644 --- a/src/stdfn.c +++ b/src/stdfn.c @@ -820,7 +820,6 @@ BOOL SetLGP(BOOL bRestore, BOOL* bExistingKey, const char* szPath, const char* s */ BOOL SetThreadAffinity(DWORD_PTR* thread_affinity, size_t num_threads) { - size_t i, j, pc; DWORD_PTR affinity, dummy; From 1cc7fca4c5b378d98ede3a70bb61981993ff3f7a Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 7 Mar 2016 16:15:18 +0000 Subject: [PATCH 50/91] [ui] disable BIOS boot when MBR for UEFI is selected in dual UEFI/BIOS mode * Closes #708 --- src/format.c | 2 +- src/rufus.rc | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/format.c b/src/format.c index 45421753..6e38e176 100644 --- a/src/format.c +++ b/src/format.c @@ -908,7 +908,7 @@ static BOOL WriteMBR(HANDLE hPhysicalDrive) // What follows is really a case statement with complex conditions listed // by order of preference - if (allow_dual_uefi_bios) + if ((allow_dual_uefi_bios) && (tt == TT_BIOS)) goto windows_mbr; // Forced UEFI (by zeroing the MBR) diff --git a/src/rufus.rc b/src/rufus.rc index 07f719d8..1871c692 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.879" +CAPTION "Rufus 2.8.880" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,879,0 - PRODUCTVERSION 2,8,879,0 + FILEVERSION 2,8,880,0 + PRODUCTVERSION 2,8,880,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.879" + VALUE "FileVersion", "2.8.880" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.879" + VALUE "ProductVersion", "2.8.880" END END BLOCK "VarFileInfo" From a10a207790a27b372d01f580d93f0fa937128c33 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 8 Mar 2016 17:28:45 +0000 Subject: [PATCH 51/91] [syslinux] fallback to embedded on version match if download fails * Could be useful for current tails user (6.03 based, same as ours) who want to create an UFD without downloading files. * Also improve the buffer overflow check in syslinux/libinstaller/syslxmod.c --- src/rufus.c | 9 +++++++-- src/rufus.rc | 10 +++++----- src/syslinux/libinstaller/syslxmod.c | 10 +++++----- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/rufus.c b/src/rufus.c index ef5c507f..3e33c2b8 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -1468,8 +1468,13 @@ static BOOL BootCheck(void) } } if (syslinux_ldlinux_len[i] == 0) { - uprintf("Could not download the file - cancelling\n"); - return FALSE; + // If the version matches our embedded one, try to use that as a last ditch effort + if (img_report.sl_version == embedded_sl_version[1]) { + uprintf("Could not download the file - will try to use embedded %s version instead", img_report.sl_version_str); + } else { + uprintf("Could not download the file - cancelling\n"); + return FALSE; + } } } } diff --git a/src/rufus.rc b/src/rufus.rc index 1871c692..16f49f29 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.880" +CAPTION "Rufus 2.8.881" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,880,0 - PRODUCTVERSION 2,8,880,0 + FILEVERSION 2,8,881,0 + PRODUCTVERSION 2,8,881,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.880" + VALUE "FileVersion", "2.8.881" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.880" + VALUE "ProductVersion", "2.8.881" END END BLOCK "VarFileInfo" diff --git a/src/syslinux/libinstaller/syslxmod.c b/src/syslinux/libinstaller/syslxmod.c index 581f9fce..80d0b430 100644 --- a/src/syslinux/libinstaller/syslxmod.c +++ b/src/syslinux/libinstaller/syslxmod.c @@ -122,11 +122,11 @@ int syslinux_patch(const sector_t *sectp, int nsectors, return -1; /* The actual file is too small for content */ /* Search for LDLINUX_MAGIC to find the patch area */ - for (wp = (const uint32_t _slimg *)boot_image; - (get_32_sl(wp) != LDLINUX_MAGIC) && (((uintptr_t)wp) < ((uintptr_t)boot_image + boot_image_len)); - wp++) - ; - if (((uintptr_t)wp) >= ((uintptr_t)boot_image + boot_image_len)) + dw = (boot_image_len - sizeof(struct patch_area)) >> 2; + for (i = 0, wp = (const uint32_t _slimg *)boot_image; + (i <= dw) && ((get_32_sl(wp) != LDLINUX_MAGIC)); + i++, wp++) + if (i > dw) /* Not found */ return -1; patcharea = (struct patch_area _slimg *)wp; epa = slptr(boot_image, &patcharea->epaoffset); From b82462bb7d4c58e5a22359a3b424812927a8997b Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 10 Mar 2016 16:13:16 +0000 Subject: [PATCH 52/91] [ui] improve progress bar refresh * Closes #699 --- src/checksum.c | 2 +- src/format.c | 8 ++++---- src/localization.c | 8 +++----- src/rufus.c | 9 +++++++-- src/rufus.h | 1 + src/rufus.rc | 10 +++++----- 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/checksum.c b/src/checksum.c index ab896d29..9347524f 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -873,7 +873,7 @@ DWORD WINAPI SumThread(void* param) read_size[0] = 1; // Don't trigger the first loop break for (rb = 0; ;rb += read_size[_bufnum]) { // Update the progress and check for cancel - if (_GetTickCount64() > LastRefresh + 25) { + if (_GetTickCount64() > LastRefresh + MAX_REFRESH) { LastRefresh = _GetTickCount64(); format_percent = (100.0f*rb) / (1.0f*img_report.projected_size); PrintInfo(0, MSG_271, format_percent); diff --git a/src/format.c b/src/format.c index 6e38e176..eadde70b 100644 --- a/src/format.c +++ b/src/format.c @@ -612,7 +612,7 @@ static BOOL FormatFAT32(DWORD DriveIndex) format_percent = 0.0f; for (i=0; i<(SystemAreaSize+BurstSize-1); i+=BurstSize) { - if (_GetTickCount64() > LastRefresh + 25) { + if (_GetTickCount64() > LastRefresh + MAX_REFRESH) { LastRefresh = _GetTickCount64(); format_percent = (100.0f*i)/(1.0f*(SystemAreaSize+BurstSize)); PrintInfo(0, MSG_217, format_percent); @@ -1449,7 +1449,7 @@ static DWORD WINAPI CloseFormatPromptThread(LPVOID param) { static void update_progress(const uint64_t processed_bytes) { - if (_GetTickCount64() > LastRefresh + 25) { + if (_GetTickCount64() > LastRefresh + MAX_REFRESH) { LastRefresh = _GetTickCount64(); format_percent = (100.0f*processed_bytes)/(1.0f*img_report.projected_size); PrintInfo(0, MSG_261, format_percent); @@ -1497,7 +1497,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage) // will be as fast, if not faster, than whatever async scheme you can come up with. rSize = BufSize; for (wb = 0, wSize = 0; wb < (uint64_t)SelectedDrive.DiskSize; wb += wSize) { - if (_GetTickCount64() > LastRefresh + 25) { + 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); @@ -2043,7 +2043,7 @@ DWORD WINAPI SaveImageThread(void* param) } if (rSize == 0) break; - if (_GetTickCount64() > LastRefresh + 25) { + if (_GetTickCount64() > LastRefresh + MAX_REFRESH) { LastRefresh = _GetTickCount64(); format_percent = (100.0f*wb)/(1.0f*SelectedDrive.DiskSize); PrintInfo(0, MSG_261, format_percent); diff --git a/src/localization.c b/src/localization.c index 6e14957f..6a7f45cf 100644 --- a/src/localization.c +++ b/src/localization.c @@ -418,8 +418,6 @@ char* lmprintf(uint32_t msg_id, ...) #define MSG_INFO 1 #define MSG_LOW_PRI 0 #define MSG_HIGH_PRI 1 -// Minimum delay between Info and Status message refreshes, in ms -#define MSG_DELAY 50 char szMessage[2][2][MSG_LEN] = { {"", ""}, {"", ""} }; char* szStatusMessage = szMessage[MSG_STATUS][MSG_HIGH_PRI]; static BOOL bStatusTimerArmed = FALSE, bOutputTimerArmed[2] = { FALSE, FALSE }; @@ -436,7 +434,7 @@ typedef void PRINT_FUNCTION(char*); PRINT_FUNCTION *PrintMessage[2] = { PrintInfoMessage, PrintStatusMessage }; /* - * The following timer call is used, along with MSG_DELAY, to prevent obnoxious flicker + * The following timer call is used, along with MAX_REFRESH, to prevent obnoxious flicker * on the Info and Status fields due to messages being updated too quickly. */ static void CALLBACK OutputMessageTimeout(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) @@ -460,10 +458,10 @@ static void OutputMessage(BOOL info, char* msg) } else { // Find if we need to arm a timer delta = _GetTickCount64() - last_msg_time[i]; - if (delta < MSG_DELAY) { + if (delta < (2 * MAX_REFRESH)) { // Not enough time has elapsed since our last output => arm a timer output_msg[i] = msg; - SetTimer(hMainDialog, TID_OUTPUT_INFO + i, (UINT)(MSG_DELAY - delta), OutputMessageTimeout); + SetTimer(hMainDialog, TID_OUTPUT_INFO + i, (UINT)((2 * MAX_REFRESH) - delta), OutputMessageTimeout); bOutputTimerArmed[i] = TRUE; } else { PrintMessage[i](msg); diff --git a/src/rufus.c b/src/rufus.c index 3e33c2b8..0d3e83d8 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -763,6 +763,7 @@ static void InitProgress(BOOL bOnlyFormat) void UpdateProgress(int op, float percent) { int pos; + static uint64_t LastRefresh = 0; if ((op < 0) || (op >= OP_MAX)) { duprintf("UpdateProgress: invalid op %d\n", op); @@ -794,8 +795,12 @@ void UpdateProgress(int op, float percent) pos = MAX_PROGRESS; } - SendMessage(hProgress, PBM_SETPOS, (WPARAM)pos, 0); - SetTaskbarProgressValue(pos, MAX_PROGRESS); + // Reduce the refresh rate, to avoid weird effects on the sliding part of progress bar + if (_GetTickCount64() > LastRefresh + (2 * MAX_REFRESH)) { + LastRefresh = _GetTickCount64(); + SendMessage(hProgress, PBM_SETPOS, (WPARAM)pos, 0); + SetTaskbarProgressValue(pos, MAX_PROGRESS); + } } /* diff --git a/src/rufus.h b/src/rufus.h index 3979eaf1..bbf8f9ee 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -55,6 +55,7 @@ #define MAX_CLUSTER_SIZES 18 #define MAX_PROGRESS (0xFFFF-1) // leave room for 1 more for insta-progress workaround #define MAX_LOG_SIZE 0x7FFFFFFE +#define MAX_REFRESH 25 // How long we should wait to refresh UI elements (in ms) #define MAX_GUID_STRING_LENGTH 40 #define MAX_GPT_PARTITIONS 128 #define MAX_SECTORS_TO_CLEAR 128 // nb sectors to zap when clearing the MBR/GPT (must be >34) diff --git a/src/rufus.rc b/src/rufus.rc index 16f49f29..fc5bc990 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.881" +CAPTION "Rufus 2.8.882" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,881,0 - PRODUCTVERSION 2,8,881,0 + FILEVERSION 2,8,882,0 + PRODUCTVERSION 2,8,882,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.881" + VALUE "FileVersion", "2.8.882" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.881" + VALUE "ProductVersion", "2.8.882" END END BLOCK "VarFileInfo" From 03a97ee2617e41a6a72285018d30188552040968 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 14 Mar 2016 13:41:20 +0000 Subject: [PATCH 53/91] [misc] improve genericity of registry functions * Ensure that we can also handle non app specific keys --- ChangeLog.txt | 9 +++++++ src/registry.h | 70 ++++++++++++++++++++++++++++++++++++++------------ src/rufus.rc | 10 ++++---- 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 445d6868..a741868e 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,12 @@ +o Version 2.8 (2016.03.??) + Enable listing of non-USB card readers (EXPERIMENTAL) + Major speed improvements for checksum computation + Fix UI flicker during progress report + Fix computation of FAT size for Large FAT32 (with thanks to Ady) + Syslinux improvements + Update GRUB to 2.02~beta3 + Switch to https when downloading updates + o Version 2.7 (2016.02.14) Add Thai translation, courtesy of Sippapas Wangsri Add Drag and Drop support, courtesy of SeymourApps diff --git a/src/registry.h b/src/registry.h index 24df9244..b6458f4b 100644 --- a/src/registry.h +++ b/src/registry.h @@ -54,13 +54,14 @@ static __inline BOOL DeleteRegistryKey(HKEY key_root, const char* key_name) the application and create the app subkey if required */ static __inline BOOL _GetRegistryKey(HKEY key_root, const char* key_name, DWORD reg_type, LPBYTE dest, DWORD dest_size) { + const char software_prefix[] = "SOFTWARE\\"; + char long_key_name[MAX_PATH] = { 0 }; BOOL r = FALSE; - size_t i = 0; + size_t i; LONG s; HKEY hSoftware = NULL, hApp = NULL; DWORD dwDisp, dwType = -1, dwSize = dest_size; - // VS Code Analysis complains if we don't break our initialization into chars - char long_key_name[256] = { 0 }; + memset(dest, 0, dest_size); if (key_name == NULL) @@ -72,9 +73,15 @@ static __inline BOOL _GetRegistryKey(HKEY key_root, const char* key_name, DWORD } if (i != 0) { - strcpy(long_key_name, "SOFTWARE\\"); - safe_strcat(long_key_name, sizeof(long_key_name), key_name); - long_key_name[sizeof("SOFTWARE\\") + i-1] = 0; + // Prefix with "SOFTWARE" if needed + if (_strnicmp(key_name, software_prefix, sizeof(software_prefix) - 1) != 0) { + strcpy(long_key_name, software_prefix); + safe_strcat(long_key_name, sizeof(long_key_name), key_name); + long_key_name[sizeof(software_prefix) + i - 1] = 0; + } else { + safe_strcpy(long_key_name, sizeof(long_key_name), key_name); + long_key_name[i] = 0; + } i++; if (RegOpenKeyExA(key_root, long_key_name, 0, KEY_READ, &hApp) != ERROR_SUCCESS) { hApp = NULL; @@ -108,25 +115,54 @@ out: /* Write a generic registry key value (create the key if it doesn't exist) */ static __inline BOOL _SetRegistryKey(HKEY key_root, const char* key_name, DWORD reg_type, LPBYTE src, DWORD src_size) { + const char software_prefix[] = "SOFTWARE\\"; + char long_key_name[MAX_PATH] = { 0 }; BOOL r = FALSE; - HKEY hSoftware = NULL, hApp = NULL; + size_t i; + HKEY hRoot = NULL, hApp = NULL; DWORD dwDisp, dwType = reg_type; - if (RegOpenKeyExA(key_root, "SOFTWARE", 0, KEY_READ|KEY_CREATE_SUB_KEY, &hSoftware) != ERROR_SUCCESS) { - hSoftware = NULL; - goto out; - } - if (RegCreateKeyExA(hSoftware, COMPANY_NAME "\\" APPLICATION_NAME, 0, NULL, 0, - KEY_SET_VALUE|KEY_QUERY_VALUE|KEY_CREATE_SUB_KEY, NULL, &hApp, &dwDisp) != ERROR_SUCCESS) { - hApp = NULL; + if (RegOpenKeyExA(key_root, NULL, 0, KEY_READ|KEY_CREATE_SUB_KEY, &hRoot) != ERROR_SUCCESS) { + hRoot = NULL; goto out; } - r = (RegSetValueExA(hApp, key_name, 0, dwType, src, src_size) == ERROR_SUCCESS); + // Find if we're dealing with a short key + for (i = safe_strlen(key_name); i>0; i--) { + if (key_name[i] == '\\') + break; + } + + if (i == 0) { + // If this is a short key name, store the value under our app sub-hive + if (RegCreateKeyExA(hRoot, "SOFTWARE\\" COMPANY_NAME "\\" APPLICATION_NAME, 0, NULL, 0, + KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_CREATE_SUB_KEY, NULL, &hApp, &dwDisp) != ERROR_SUCCESS) { + hApp = NULL; + goto out; + } + } else { + // Prefix with "SOFTWARE" if needed + if (_strnicmp(key_name, software_prefix, sizeof(software_prefix) - 1) != 0) { + strcpy(long_key_name, software_prefix); + safe_strcat(long_key_name, sizeof(long_key_name), key_name); + long_key_name[sizeof(software_prefix) + i - 1] = 0; + } else { + safe_strcpy(long_key_name, sizeof(long_key_name), key_name); + long_key_name[i] = 0; + } + i++; + if (RegCreateKeyExA(hRoot, long_key_name, 0, NULL, 0, + KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_CREATE_SUB_KEY, NULL, &hApp, &dwDisp) != ERROR_SUCCESS) { + hApp = NULL; + goto out; + } + } + + r = (RegSetValueExA(hApp, &key_name[i], 0, dwType, src, src_size) == ERROR_SUCCESS); out: - if (hSoftware != NULL) - RegCloseKey(hSoftware); + if (hRoot != NULL) + RegCloseKey(hRoot); if (hApp != NULL) RegCloseKey(hApp); return r; diff --git a/src/rufus.rc b/src/rufus.rc index fc5bc990..b9b75900 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.882" +CAPTION "Rufus 2.8.883" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,882,0 - PRODUCTVERSION 2,8,882,0 + FILEVERSION 2,8,883,0 + PRODUCTVERSION 2,8,883,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.882" + VALUE "FileVersion", "2.8.883" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.882" + VALUE "ProductVersion", "2.8.883" END END BLOCK "VarFileInfo" From b1c5545205952dc8776bf1d6da8a7c530d27bfa8 Mon Sep 17 00:00:00 2001 From: Na Jiyoun Date: Thu, 17 Mar 2016 21:48:37 +0000 Subject: [PATCH 54/91] [loc] update Korean translation to latest --- res/localization/rufus.loc | 7 ++++++- src/rufus.rc | 10 +++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 6033b66b..6e99eedf 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -8230,7 +8230,7 @@ t MSG_286 "'0'をドライブへ書き込み初期化中: %0.1f%% 完了" ################################################################################ l "ko-KR" "Korean (한국어)" 0x0412 -v 1.0.18 +v 1.0.19 b "en-US" # Main dialog @@ -8660,6 +8660,11 @@ t MSG_278 "부팅 유형" t MSG_279 "부팅 안 됨" t MSG_280 "이미지 선택" t MSG_281 "(이미지를 선택하세요)" +t MSG_282 "전용 USB 드라이브 잠김" +t MSG_283 "유효하지 않은 디지털 서명" +t MSG_284 "다운로드 한 실행 파일에 디지털 서명이 없습니다." +t MSG_285 "다운로드 한 실행 파일은 '%s'에 의해 서명됩니다..\n이 파일은 정상적인 서명이 아니며 악성코드가 포함되어 있을 수 있습니다.\n" + "그래도 이 파일을 실행하시겠습니까?" ################################################################################ l "lv-LV" "Latvian (Latviešu)" 0x0426 diff --git a/src/rufus.rc b/src/rufus.rc index b9b75900..5ab01cab 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.883" +CAPTION "Rufus 2.8.884" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,883,0 - PRODUCTVERSION 2,8,883,0 + FILEVERSION 2,8,884,0 + PRODUCTVERSION 2,8,884,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.883" + VALUE "FileVersion", "2.8.884" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.883" + VALUE "ProductVersion", "2.8.884" END END BLOCK "VarFileInfo" From 3fe6894f8beff09ea4ffeb565b66c23a089770d7 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 17 Mar 2016 21:56:36 +0000 Subject: [PATCH 55/91] [misc] increase SetLGP thread wait delay * Someone running Rufus in a VirtualBox environment, where their CPU was also seeing 100% usage, reported getting the following message: "SetLGP: Killing stuck thread!" --- ChangeLog.txt | 1 - src/rufus.rc | 10 +++++----- src/stdfn.c | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index a741868e..ddbf7d31 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -5,7 +5,6 @@ o Version 2.8 (2016.03.??) Fix computation of FAT size for Large FAT32 (with thanks to Ady) Syslinux improvements Update GRUB to 2.02~beta3 - Switch to https when downloading updates o Version 2.7 (2016.02.14) Add Thai translation, courtesy of Sippapas Wangsri diff --git a/src/rufus.rc b/src/rufus.rc index 5ab01cab..2aaadc80 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.884" +CAPTION "Rufus 2.8.885" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,884,0 - PRODUCTVERSION 2,8,884,0 + FILEVERSION 2,8,885,0 + PRODUCTVERSION 2,8,885,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.884" + VALUE "FileVersion", "2.8.885" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.884" + VALUE "ProductVersion", "2.8.885" END END BLOCK "VarFileInfo" diff --git a/src/stdfn.c b/src/stdfn.c index cdca1180..47648b43 100644 --- a/src/stdfn.c +++ b/src/stdfn.c @@ -803,7 +803,7 @@ BOOL SetLGP(BOOL bRestore, BOOL* bExistingKey, const char* szPath, const char* s uprintf("SetLGP: Unable to start thread"); return FALSE; } - if (WaitForSingleObject(thread_id, 2500) != WAIT_OBJECT_0) { + if (WaitForSingleObject(thread_id, 5000) != WAIT_OBJECT_0) { uprintf("SetLGP: Killing stuck thread!"); TerminateThread(thread_id, 0); CloseHandle(thread_id); From cbf1a60365443378534bdaab70bedf5e33b43a2f Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 22 Mar 2016 16:03:18 +0000 Subject: [PATCH 56/91] v2.8 (build 886) --- ChangeLog.txt | 6 +++--- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index ddbf7d31..a2bbd4fc 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,7 +1,7 @@ -o Version 2.8 (2016.03.??) +o Version 2.8 (2016.03.22) Enable listing of non-USB card readers (EXPERIMENTAL) - Major speed improvements for checksum computation - Fix UI flicker during progress report + Major speed improvement for checksum computation + Fix UI flicker during progress actualization Fix computation of FAT size for Large FAT32 (with thanks to Ady) Syslinux improvements Update GRUB to 2.02~beta3 diff --git a/src/rufus.rc b/src/rufus.rc index 2aaadc80..8b8c33d5 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.885" +CAPTION "Rufus 2.8.886" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,885,0 - PRODUCTVERSION 2,8,885,0 + FILEVERSION 2,8,886,0 + PRODUCTVERSION 2,8,886,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.885" + VALUE "FileVersion", "2.8.886" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.885" + VALUE "ProductVersion", "2.8.886" END END BLOCK "VarFileInfo" From 2c90a06668b5fc7252688578fe765649c956bac1 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 23 Mar 2016 16:56:49 +0000 Subject: [PATCH 57/91] use IFileDialog when running on Vista or later * When compiled with MinGW, this was always disabled due to forcing XP as the lowest common denominator and using #ifdefs * This should also help with OFN_NOCHANGEDIR seemingly being ignored * Sadly, this change also adds ~20KB to our *compressed* size... :( --- src/Makefile.am | 2 +- src/Makefile.in | 2 +- src/missing.h | 304 ++++++++++++++++++++++++++++++++++++++++++++++++ src/rufus.rc | 10 +- src/stdlg.c | 292 +++++++++++++++++++++++----------------------- 5 files changed, 454 insertions(+), 156 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index d2fe6359..da1937ce 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,4 +15,4 @@ rufus_SOURCES = badblocks.c checksum.c dos.c dos_locale.c drive.c format.c icon. rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS) rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \ - libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust + libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -luuid diff --git a/src/Makefile.in b/src/Makefile.in index 137a8a86..401d576f 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -276,7 +276,7 @@ rufus_SOURCES = badblocks.c checksum.c dos.c dos_locale.c drive.c format.c icon. rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS) rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \ - libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust + libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -luuid all: all-recursive diff --git a/src/missing.h b/src/missing.h index 62a96ab8..3dada756 100644 --- a/src/missing.h +++ b/src/missing.h @@ -272,3 +272,307 @@ typedef unsigned __int64 uintptr_t; typedef unsigned int uintptr_t; #endif #endif + +/* + * IFile[Open]Dialog interface for Vista and later (from MinGW headers) + */ +#ifdef DDKBUILD +typedef struct _COMDLG_FILTERSPEC { + LPCWSTR pszName; + LPCWSTR pszSpec; +} COMDLG_FILTERSPEC; +#endif + +#ifndef __IFileDialog_INTERFACE_DEFINED__ +#define __IFileDialog_INTERFACE_DEFINED__ + +enum _FILEOPENDIALOGOPTIONS { + FOS_OVERWRITEPROMPT = 0x2, + FOS_STRICTFILETYPES = 0x4, + FOS_NOCHANGEDIR = 0x8, + FOS_PICKFOLDERS = 0x20, + FOS_FORCEFILESYSTEM = 0x40, + FOS_ALLNONSTORAGEITEMS = 0x80, + FOS_NOVALIDATE = 0x100, + FOS_ALLOWMULTISELECT = 0x200, + FOS_PATHMUSTEXIST = 0x800, + FOS_FILEMUSTEXIST = 0x1000, + FOS_CREATEPROMPT = 0x2000, + FOS_SHAREAWARE = 0x4000, + FOS_NOREADONLYRETURN = 0x8000, + FOS_NOTESTFILECREATE = 0x10000, + FOS_HIDEMRUPLACES = 0x20000, + FOS_HIDEPINNEDPLACES = 0x40000, + FOS_NODEREFERENCELINKS = 0x100000, + FOS_DONTADDTORECENT = 0x2000000, + FOS_FORCESHOWHIDDEN = 0x10000000, + FOS_DEFAULTNOMINIMODE = 0x20000000, + FOS_FORCEPREVIEWPANEON = 0x40000000 +}; + +typedef enum FDAP { + FDAP_BOTTOM = 0, + FDAP_TOP = 1 +} FDAP; + +typedef DWORD FILEOPENDIALOGOPTIONS; + +DEFINE_GUID(IID_IFileDialog, 0x42f85136, 0xdb7e, 0x439c, 0x85, 0xf1, 0xe4, 0x07, 0x5d, 0x13, 0x5f, 0xc8); + +typedef struct IFileDialogVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT(STDMETHODCALLTYPE *QueryInterface)( + IFileDialog* This, + REFIID riid, + void **ppvObject); + + ULONG(STDMETHODCALLTYPE *AddRef)( + IFileDialog* This); + + ULONG(STDMETHODCALLTYPE *Release)( + IFileDialog* This); + + /*** IModalWindow methods ***/ + HRESULT(STDMETHODCALLTYPE *Show)( + IFileDialog* This, + HWND hwndOwner); + + /*** IFileDialog methods ***/ + HRESULT(STDMETHODCALLTYPE *SetFileTypes)( + IFileDialog* This, + UINT cFileTypes, + const COMDLG_FILTERSPEC *rgFilterSpec); + + HRESULT(STDMETHODCALLTYPE *SetFileTypeIndex)( + IFileDialog* This, + UINT iFileType); + + HRESULT(STDMETHODCALLTYPE *GetFileTypeIndex)( + IFileDialog* This, + UINT *piFileType); + + HRESULT(STDMETHODCALLTYPE *Advise)( + IFileDialog* This, + IFileDialogEvents *pfde, + DWORD *pdwCookie); + + HRESULT(STDMETHODCALLTYPE *Unadvise)( + IFileDialog* This, + DWORD dwCookie); + + HRESULT(STDMETHODCALLTYPE *SetOptions)( + IFileDialog* This, + FILEOPENDIALOGOPTIONS fos); + + HRESULT(STDMETHODCALLTYPE *GetOptions)( + IFileDialog* This, + FILEOPENDIALOGOPTIONS *pfos); + + HRESULT(STDMETHODCALLTYPE *SetDefaultFolder)( + IFileDialog* This, + IShellItem *psi); + + HRESULT(STDMETHODCALLTYPE *SetFolder)( + IFileDialog* This, + IShellItem *psi); + + HRESULT(STDMETHODCALLTYPE *GetFolder)( + IFileDialog* This, + IShellItem **ppsi); + + HRESULT(STDMETHODCALLTYPE *GetCurrentSelection)( + IFileDialog* This, + IShellItem **ppsi); + + HRESULT(STDMETHODCALLTYPE *SetFileName)( + IFileDialog* This, + LPCWSTR pszName); + + HRESULT(STDMETHODCALLTYPE *GetFileName)( + IFileDialog* This, + LPWSTR *pszName); + + HRESULT(STDMETHODCALLTYPE *SetTitle)( + IFileDialog* This, + LPCWSTR pszTitle); + + HRESULT(STDMETHODCALLTYPE *SetOkButtonLabel)( + IFileDialog* This, + LPCWSTR pszText); + + HRESULT(STDMETHODCALLTYPE *SetFileNameLabel)( + IFileDialog* This, + LPCWSTR pszLabel); + + HRESULT(STDMETHODCALLTYPE *GetResult)( + IFileDialog* This, + IShellItem **ppsi); + + HRESULT(STDMETHODCALLTYPE *AddPlace)( + IFileDialog* This, + IShellItem *psi, + FDAP fdap); + + HRESULT(STDMETHODCALLTYPE *SetDefaultExtension)( + IFileDialog* This, + LPCWSTR pszDefaultExtension); + + HRESULT(STDMETHODCALLTYPE *Close)( + IFileDialog* This, + HRESULT hr); + + HRESULT(STDMETHODCALLTYPE *SetClientGuid)( + IFileDialog* This, + REFGUID guid); + + HRESULT(STDMETHODCALLTYPE *ClearClientData)( + IFileDialog* This); + + HRESULT(STDMETHODCALLTYPE *SetFilter)( + IFileDialog* This, + IShellItemFilter *pFilter); + + END_INTERFACE +} IFileDialogVtbl; +interface IFileDialog { + CONST_VTBL IFileDialogVtbl* lpVtbl; +}; +#endif + +#ifndef __IFileOpenDialog_INTERFACE_DEFINED__ +#define __IFileOpenDialog_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IFileOpenDialog, 0xd57c7288, 0xd4ad, 0x4768, 0xbe, 0x02, 0x9d, 0x96, 0x95, 0x32, 0xd9, 0x60); + +typedef struct IFileOpenDialogVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT(STDMETHODCALLTYPE *QueryInterface)( + IFileOpenDialog* This, + REFIID riid, + void **ppvObject); + + ULONG(STDMETHODCALLTYPE *AddRef)( + IFileOpenDialog* This); + + ULONG(STDMETHODCALLTYPE *Release)( + IFileOpenDialog* This); + + /*** IModalWindow methods ***/ + HRESULT(STDMETHODCALLTYPE *Show)( + IFileOpenDialog* This, + HWND hwndOwner); + + /*** IFileDialog methods ***/ + HRESULT(STDMETHODCALLTYPE *SetFileTypes)( + IFileOpenDialog* This, + UINT cFileTypes, + const COMDLG_FILTERSPEC *rgFilterSpec); + + HRESULT(STDMETHODCALLTYPE *SetFileTypeIndex)( + IFileOpenDialog* This, + UINT iFileType); + + HRESULT(STDMETHODCALLTYPE *GetFileTypeIndex)( + IFileOpenDialog* This, + UINT *piFileType); + + HRESULT(STDMETHODCALLTYPE *Advise)( + IFileOpenDialog* This, + IFileDialogEvents *pfde, + DWORD *pdwCookie); + + HRESULT(STDMETHODCALLTYPE *Unadvise)( + IFileOpenDialog* This, + DWORD dwCookie); + + HRESULT(STDMETHODCALLTYPE *SetOptions)( + IFileOpenDialog* This, + FILEOPENDIALOGOPTIONS fos); + + HRESULT(STDMETHODCALLTYPE *GetOptions)( + IFileOpenDialog* This, + FILEOPENDIALOGOPTIONS *pfos); + + HRESULT(STDMETHODCALLTYPE *SetDefaultFolder)( + IFileOpenDialog* This, + IShellItem *psi); + + HRESULT(STDMETHODCALLTYPE *SetFolder)( + IFileOpenDialog* This, + IShellItem *psi); + + HRESULT(STDMETHODCALLTYPE *GetFolder)( + IFileOpenDialog* This, + IShellItem **ppsi); + + HRESULT(STDMETHODCALLTYPE *GetCurrentSelection)( + IFileOpenDialog* This, + IShellItem **ppsi); + + HRESULT(STDMETHODCALLTYPE *SetFileName)( + IFileOpenDialog* This, + LPCWSTR pszName); + + HRESULT(STDMETHODCALLTYPE *GetFileName)( + IFileOpenDialog* This, + LPWSTR *pszName); + + HRESULT(STDMETHODCALLTYPE *SetTitle)( + IFileOpenDialog* This, + LPCWSTR pszTitle); + + HRESULT(STDMETHODCALLTYPE *SetOkButtonLabel)( + IFileOpenDialog* This, + LPCWSTR pszText); + + HRESULT(STDMETHODCALLTYPE *SetFileNameLabel)( + IFileOpenDialog* This, + LPCWSTR pszLabel); + + HRESULT(STDMETHODCALLTYPE *GetResult)( + IFileOpenDialog* This, + IShellItem **ppsi); + + HRESULT(STDMETHODCALLTYPE *AddPlace)( + IFileOpenDialog* This, + IShellItem *psi, + FDAP fdap); + + HRESULT(STDMETHODCALLTYPE *SetDefaultExtension)( + IFileOpenDialog* This, + LPCWSTR pszDefaultExtension); + + HRESULT(STDMETHODCALLTYPE *Close)( + IFileOpenDialog* This, + HRESULT hr); + + HRESULT(STDMETHODCALLTYPE *SetClientGuid)( + IFileOpenDialog* This, + REFGUID guid); + + HRESULT(STDMETHODCALLTYPE *ClearClientData)( + IFileOpenDialog* This); + + HRESULT(STDMETHODCALLTYPE *SetFilter)( + IFileOpenDialog* This, + IShellItemFilter *pFilter); + + /*** IFileOpenDialog methods ***/ + HRESULT(STDMETHODCALLTYPE *GetResults)( + IFileOpenDialog* This, + IShellItemArray **ppenum); + + HRESULT(STDMETHODCALLTYPE *GetSelectedItems)( + IFileOpenDialog* This, + IShellItemArray **ppsai); + + END_INTERFACE +} IFileOpenDialogVtbl; +interface IFileOpenDialog { + CONST_VTBL IFileOpenDialogVtbl* lpVtbl; +}; +#endif diff --git a/src/rufus.rc b/src/rufus.rc index 8b8c33d5..f710d079 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.886" +CAPTION "Rufus 2.8.887" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,886,0 - PRODUCTVERSION 2,8,886,0 + FILEVERSION 2,8,887,0 + PRODUCTVERSION 2,8,887,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.886" + VALUE "FileVersion", "2.8.887" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.886" + VALUE "ProductVersion", "2.8.887" END END BLOCK "VarFileInfo" diff --git a/src/stdlg.c b/src/stdlg.c index e530c7dc..69098919 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -44,9 +44,7 @@ #include "settings.h" #include "license.h" -#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) PF_TYPE_DECL(WINAPI, HRESULT, SHCreateItemFromParsingName, (PCWSTR, IBindCtx*, REFIID, void **)); -#endif PF_TYPE_DECL(WINAPI, LPITEMIDLIST, SHSimpleIDListFromPath, (PCWSTR pszPath)); #define INIT_VISTA_SHELL32 PF_INIT(SHCreateItemFromParsingName, Shell32) #define INIT_XP_SHELL32 PF_INIT(SHSimpleIDListFromPath, Shell32) @@ -135,8 +133,6 @@ void BrowseForFolder(void) { BROWSEINFOW bi; LPITEMIDLIST pidl; - -#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) WCHAR *wpath; size_t i; HRESULT hr; @@ -147,79 +143,79 @@ void BrowseForFolder(void) { char* tmp_path = NULL; dialog_showing++; - // Even if we have Vista support with the compiler, - // it does not mean we have the Vista API available - INIT_VISTA_SHELL32; - if (IS_VISTA_SHELL32_AVAILABLE) { - hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC, - &IID_IFileOpenDialog, (LPVOID)&pfod); - if (FAILED(hr)) { - uprintf("CoCreateInstance for FileOpenDialog failed: error %X\n", hr); - pfod = NULL; // Just in case - goto fallback; - } - hr = pfod->lpVtbl->SetOptions(pfod, FOS_PICKFOLDERS); - if (FAILED(hr)) { - uprintf("Failed to set folder option for FileOpenDialog: error %X\n", hr); - goto fallback; - } - // Set the initial folder (if the path is invalid, will simply use last) - wpath = utf8_to_wchar(szFolderPath); - // The new IFileOpenDialog makes us split the path - fname = NULL; - if ((wpath != NULL) && (wcslen(wpath) >= 1)) { - for (i=wcslen(wpath)-1; i!=0; i--) { - if (wpath[i] == L'\\') { - wpath[i] = 0; - fname = &wpath[i+1]; - break; - } +#ifndef DDKBUILD // WDK being uncooperative yet again... + if (nWindowsVersion >= WINDOWS_VISTA) { + INIT_VISTA_SHELL32; + if (IS_VISTA_SHELL32_AVAILABLE) { + hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC, + &IID_IFileOpenDialog, (LPVOID)&pfod); + if (FAILED(hr)) { + uprintf("CoCreateInstance for FileOpenDialog failed: error %X\n", hr); + pfod = NULL; // Just in case + goto fallback; } - } - - hr = (*pfSHCreateItemFromParsingName)(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path); - if (SUCCEEDED(hr)) { - if (wpath != NULL) { - hr = pfod->lpVtbl->SetFolder(pfod, si_path); - } - if (fname != NULL) { - hr = pfod->lpVtbl->SetFileName(pfod, fname); - } - } - safe_free(wpath); - - hr = pfod->lpVtbl->Show(pfod, hMainDialog); - if (SUCCEEDED(hr)) { - hr = pfod->lpVtbl->GetResult(pfod, &psi); - if (SUCCEEDED(hr)) { - psi->lpVtbl->GetDisplayName(psi, SIGDN_FILESYSPATH, &wpath); - tmp_path = wchar_to_utf8(wpath); - CoTaskMemFree(wpath); - if (tmp_path == NULL) { - uprintf("Could not convert path\n"); - } else { - safe_strcpy(szFolderPath, MAX_PATH, tmp_path); - safe_free(tmp_path); - } - } else { + hr = pfod->lpVtbl->SetOptions(pfod, FOS_PICKFOLDERS); + if (FAILED(hr)) { uprintf("Failed to set folder option for FileOpenDialog: error %X\n", hr); + goto fallback; } - } else if ((hr & 0xFFFF) != ERROR_CANCELLED) { - // If it's not a user cancel, assume the dialog didn't show and fallback - uprintf("Could not show FileOpenDialog: error %X\n", hr); - goto fallback; + // Set the initial folder (if the path is invalid, will simply use last) + wpath = utf8_to_wchar(szFolderPath); + // The new IFileOpenDialog makes us split the path + fname = NULL; + if ((wpath != NULL) && (wcslen(wpath) >= 1)) { + for (i = wcslen(wpath) - 1; i != 0; i--) { + if (wpath[i] == L'\\') { + wpath[i] = 0; + fname = &wpath[i + 1]; + break; + } + } + } + + hr = (*pfSHCreateItemFromParsingName)(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path); + if (SUCCEEDED(hr)) { + if (wpath != NULL) { + hr = pfod->lpVtbl->SetFolder(pfod, si_path); + } + if (fname != NULL) { + hr = pfod->lpVtbl->SetFileName(pfod, fname); + } + } + safe_free(wpath); + + hr = pfod->lpVtbl->Show(pfod, hMainDialog); + if (SUCCEEDED(hr)) { + hr = pfod->lpVtbl->GetResult(pfod, &psi); + if (SUCCEEDED(hr)) { + psi->lpVtbl->GetDisplayName(psi, SIGDN_FILESYSPATH, &wpath); + tmp_path = wchar_to_utf8(wpath); + CoTaskMemFree(wpath); + if (tmp_path == NULL) { + uprintf("Could not convert path\n"); + } else { + safe_strcpy(szFolderPath, MAX_PATH, tmp_path); + safe_free(tmp_path); + } + } else { + uprintf("Failed to set folder option for FileOpenDialog: error %X\n", hr); + } + } else if ((hr & 0xFFFF) != ERROR_CANCELLED) { + // If it's not a user cancel, assume the dialog didn't show and fallback + uprintf("Could not show FileOpenDialog: error %X\n", hr); + goto fallback; + } + pfod->lpVtbl->Release(pfod); + dialog_showing--; + return; } - pfod->lpVtbl->Release(pfod); - dialog_showing--; - return; - } fallback: - if (pfod != NULL) { - pfod->lpVtbl->Release(pfod); + if (pfod != NULL) { + pfod->lpVtbl->Release(pfod); + } } -#else - dialog_showing++; #endif + INIT_XP_SHELL32; memset(&bi, 0, sizeof(BROWSEINFOW)); bi.hwndOwner = hMainDialog; @@ -253,99 +249,97 @@ char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options) size_t i, j, ext_strlen; BOOL r; char* filepath = NULL; - -#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) HRESULT hr = FALSE; IFileDialog *pfd = NULL; IShellItem *psiResult; COMDLG_FILTERSPEC* filter_spec; wchar_t *wpath = NULL, *wfilename = NULL; IShellItem *si_path = NULL; // Automatically freed -#endif if ((ext == NULL) || (ext->count == 0) || (ext->extension == NULL) || (ext->description == NULL)) return NULL; dialog_showing++; -#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) - INIT_VISTA_SHELL32; - filter_spec = (COMDLG_FILTERSPEC*)calloc(ext->count + 1, sizeof(COMDLG_FILTERSPEC)); - if ((IS_VISTA_SHELL32_AVAILABLE) && (filter_spec != NULL)) { - // Setup the file extension filter table - for (i=0; icount; i++) { - filter_spec[i].pszSpec = utf8_to_wchar(ext->extension[i]); - filter_spec[i].pszName = utf8_to_wchar(ext->description[i]); - } - filter_spec[i].pszSpec = L"*.*"; - filter_spec[i].pszName = utf8_to_wchar(lmprintf(MSG_107)); - - hr = CoCreateInstance(save?&CLSID_FileSaveDialog:&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC, - &IID_IFileDialog, (LPVOID)&pfd); - - if (FAILED(hr)) { - SetLastError(hr); - uprintf("CoCreateInstance for FileOpenDialog failed: %s\n", WindowsErrorString()); - pfd = NULL; // Just in case - goto fallback; - } - - // Set the file extension filters - pfd->lpVtbl->SetFileTypes(pfd, (UINT)ext->count+1, filter_spec); - - // Set the default directory - wpath = utf8_to_wchar(path); - hr = (*pfSHCreateItemFromParsingName)(wpath, NULL, &IID_IShellItem, (LPVOID) &si_path); - if (SUCCEEDED(hr)) { - pfd->lpVtbl->SetFolder(pfd, si_path); - } - safe_free(wpath); - - // Set the default filename - wfilename = utf8_to_wchar((ext->filename == NULL)?"":ext->filename); - if (wfilename != NULL) { - pfd->lpVtbl->SetFileName(pfd, wfilename); - } - - // Display the dialog - hr = pfd->lpVtbl->Show(pfd, hMainDialog); - - // Cleanup - safe_free(wfilename); - for (i=0; icount; i++) { - safe_free(filter_spec[i].pszSpec); - safe_free(filter_spec[i].pszName); - } - safe_free(filter_spec[i].pszName); - safe_free(filter_spec); - - if (SUCCEEDED(hr)) { - // Obtain the result of the user's interaction with the dialog. - hr = pfd->lpVtbl->GetResult(pfd, &psiResult); - if (SUCCEEDED(hr)) { - hr = psiResult->lpVtbl->GetDisplayName(psiResult, SIGDN_FILESYSPATH, &wpath); - if (SUCCEEDED(hr)) { - filepath = wchar_to_utf8(wpath); - CoTaskMemFree(wpath); - } else { - SetLastError(hr); - uprintf("Unable to access file path: %s\n", WindowsErrorString()); - } - psiResult->lpVtbl->Release(psiResult); +#ifndef DDKBUILD + if (nWindowsVersion >= WINDOWS_VISTA) { + INIT_VISTA_SHELL32; + filter_spec = (COMDLG_FILTERSPEC*)calloc(ext->count + 1, sizeof(COMDLG_FILTERSPEC)); + if ((IS_VISTA_SHELL32_AVAILABLE) && (filter_spec != NULL)) { + // Setup the file extension filter table + for (i = 0; i < ext->count; i++) { + filter_spec[i].pszSpec = utf8_to_wchar(ext->extension[i]); + filter_spec[i].pszName = utf8_to_wchar(ext->description[i]); } - } else if ((hr & 0xFFFF) != ERROR_CANCELLED) { - // If it's not a user cancel, assume the dialog didn't show and fallback - SetLastError(hr); - uprintf("Could not show FileOpenDialog: %s\n", WindowsErrorString()); - goto fallback; - } - pfd->lpVtbl->Release(pfd); - dialog_showing--; - return filepath; - } + filter_spec[i].pszSpec = L"*.*"; + filter_spec[i].pszName = utf8_to_wchar(lmprintf(MSG_107)); + hr = CoCreateInstance(save ? &CLSID_FileSaveDialog : &CLSID_FileOpenDialog, NULL, CLSCTX_INPROC, + &IID_IFileDialog, (LPVOID)&pfd); + + if (FAILED(hr)) { + SetLastError(hr); + uprintf("CoCreateInstance for FileOpenDialog failed: %s\n", WindowsErrorString()); + pfd = NULL; // Just in case + goto fallback; + } + + // Set the file extension filters + pfd->lpVtbl->SetFileTypes(pfd, (UINT)ext->count + 1, filter_spec); + + // Set the default directory + wpath = utf8_to_wchar(path); + hr = (*pfSHCreateItemFromParsingName)(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path); + if (SUCCEEDED(hr)) { + pfd->lpVtbl->SetFolder(pfd, si_path); + } + safe_free(wpath); + + // Set the default filename + wfilename = utf8_to_wchar((ext->filename == NULL) ? "" : ext->filename); + if (wfilename != NULL) { + pfd->lpVtbl->SetFileName(pfd, wfilename); + } + + // Display the dialog + hr = pfd->lpVtbl->Show(pfd, hMainDialog); + + // Cleanup + safe_free(wfilename); + for (i = 0; i < ext->count; i++) { + safe_free(filter_spec[i].pszSpec); + safe_free(filter_spec[i].pszName); + } + safe_free(filter_spec[i].pszName); + safe_free(filter_spec); + + if (SUCCEEDED(hr)) { + // Obtain the result of the user's interaction with the dialog. + hr = pfd->lpVtbl->GetResult(pfd, &psiResult); + if (SUCCEEDED(hr)) { + hr = psiResult->lpVtbl->GetDisplayName(psiResult, SIGDN_FILESYSPATH, &wpath); + if (SUCCEEDED(hr)) { + filepath = wchar_to_utf8(wpath); + CoTaskMemFree(wpath); + } else { + SetLastError(hr); + uprintf("Unable to access file path: %s\n", WindowsErrorString()); + } + psiResult->lpVtbl->Release(psiResult); + } + } else if ((hr & 0xFFFF) != ERROR_CANCELLED) { + // If it's not a user cancel, assume the dialog didn't show and fallback + SetLastError(hr); + uprintf("Could not show FileOpenDialog: %s\n", WindowsErrorString()); + goto fallback; + } + pfd->lpVtbl->Release(pfd); + dialog_showing--; + return filepath; + } fallback: - if (pfd != NULL) { - pfd->lpVtbl->Release(pfd); + if (pfd != NULL) { + pfd->lpVtbl->Release(pfd); + } } #endif From e4bb1a6eb88d7fbb59882fa8e8054e12218d4983 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 24 Mar 2016 12:46:44 +0000 Subject: [PATCH 58/91] drop support for WDK's Windows XP targets * Die, XP, die!!! * Also fix a Coverity warning in checksum.c --- src/checksum.c | 2 +- src/libcdio/config.h | 15 +-------------- src/missing.h | 7 ------- src/rufus.c | 2 -- src/rufus.h | 6 ++++++ src/rufus.rc | 10 +++++----- src/stdlg.c | 4 ---- 7 files changed, 13 insertions(+), 33 deletions(-) diff --git a/src/checksum.c b/src/checksum.c index 9347524f..397c59c4 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -847,7 +847,7 @@ DWORD WINAPI SumThread(void* param) // gets into its next wait loop data_ready[i] = CreateEvent(NULL, FALSE, FALSE, NULL); thread_ready[i] = CreateEvent(NULL, FALSE, FALSE, NULL); - if ((data_ready == NULL) || (thread_ready[i] == NULL)) { + if ((data_ready[i] == NULL) || (thread_ready[i] == NULL)) { uprintf("Unable to create checksum thread event: %s", WindowsErrorString()); goto out; } diff --git a/src/libcdio/config.h b/src/libcdio/config.h index d5218aac..0aacce4a 100644 --- a/src/libcdio/config.h +++ b/src/libcdio/config.h @@ -39,21 +39,8 @@ /* Define to 1 if you have the `fseeko64' function. */ #define HAVE_FSEEKO64 1 -#if defined(_MSC_VER) -/* The equivalent of fseeko64 for MSVC is _fseeki64, however this */ -/* is not available on XP when build with WDK (but _lseeki64 is) */ -#if defined(DDKBUILD) -#include -#include -#include -static __inline int fseeko64(FILE *stream, __int64 offset, int origin) { - fflush(stream); /* VERY IMPORTANT! */ - return (lseek64(_fileno(stream), offset, origin) == -1LL)?-1:0; -} -#else +/* The equivalent of fseeko64 for MSVC is _fseeki64 */ #define fseeko64 _fseeki64 -#endif -#endif /* Define to 1 if you have the `ftruncate' function. */ /* #undef HAVE_FTRUNCATE */ diff --git a/src/missing.h b/src/missing.h index 3dada756..f6a5ac13 100644 --- a/src/missing.h +++ b/src/missing.h @@ -276,13 +276,6 @@ typedef unsigned int uintptr_t; /* * IFile[Open]Dialog interface for Vista and later (from MinGW headers) */ -#ifdef DDKBUILD -typedef struct _COMDLG_FILTERSPEC { - LPCWSTR pszName; - LPCWSTR pszSpec; -} COMDLG_FILTERSPEC; -#endif - #ifndef __IFileDialog_INTERFACE_DEFINED__ #define __IFileDialog_INTERFACE_DEFINED__ diff --git a/src/rufus.c b/src/rufus.c index 0d3e83d8..e2af2f71 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -2798,9 +2798,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine }; // Disable loading system DLLs from the current directory (sideloading mitigation) -#ifndef DDKBUILD // WDK doesn't know about that one SetDllDirectoryA(""); -#endif uprintf("*** " APPLICATION_NAME " init ***\n"); PF_INIT(GetTickCount64, kernel32); diff --git a/src/rufus.h b/src/rufus.h index bbf8f9ee..8c149470 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -24,6 +24,12 @@ #pragma warning(disable: 4996) // Ignore deprecated (eg. GetVersionEx()), as we have to contend with XP #pragma warning(disable: 28159) // We use GetTickCount64() where possible, but it's not available on XP #pragma warning(disable: 6258) // I know what I'm using TerminateThread for +// Burn in HELL Windows XP!!! +#ifdef DDKBUILD +#if (_WIN32_WINNT < _WIN32_WINNT_VISTA) +#error The Windows XP target is no longer supported for WDK compilation. +#endif +#endif #endif #pragma once diff --git a/src/rufus.rc b/src/rufus.rc index f710d079..25e67d5f 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.887" +CAPTION "Rufus 2.8.888" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,887,0 - PRODUCTVERSION 2,8,887,0 + FILEVERSION 2,8,888,0 + PRODUCTVERSION 2,8,888,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.887" + VALUE "FileVersion", "2.8.888" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.887" + VALUE "ProductVersion", "2.8.888" END END BLOCK "VarFileInfo" diff --git a/src/stdlg.c b/src/stdlg.c index 69098919..9df22c6a 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -143,7 +143,6 @@ void BrowseForFolder(void) { char* tmp_path = NULL; dialog_showing++; -#ifndef DDKBUILD // WDK being uncooperative yet again... if (nWindowsVersion >= WINDOWS_VISTA) { INIT_VISTA_SHELL32; if (IS_VISTA_SHELL32_AVAILABLE) { @@ -214,7 +213,6 @@ fallback: pfod->lpVtbl->Release(pfod); } } -#endif INIT_XP_SHELL32; memset(&bi, 0, sizeof(BROWSEINFOW)); @@ -260,7 +258,6 @@ char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options) return NULL; dialog_showing++; -#ifndef DDKBUILD if (nWindowsVersion >= WINDOWS_VISTA) { INIT_VISTA_SHELL32; filter_spec = (COMDLG_FILTERSPEC*)calloc(ext->count + 1, sizeof(COMDLG_FILTERSPEC)); @@ -341,7 +338,6 @@ fallback: pfd->lpVtbl->Release(pfd); } } -#endif memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); From 0d310d1c6bcb6f962af4e269271a4d8ca0b8d165 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 25 Mar 2016 16:38:01 +0000 Subject: [PATCH 59/91] [misc] fix Coverity warnings --- _coverity.cmd | 2 +- src/registry.h | 3 +++ src/rufus.rc | 10 +++++----- src/stdlg.c | 9 +++++---- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/_coverity.cmd b/_coverity.cmd index b80d58aa..c55d133a 100644 --- a/_coverity.cmd +++ b/_coverity.cmd @@ -1,5 +1,5 @@ @echo off -set COV_DIR=E:\cov-analysis-win32-7.7.0 +set COV_DIR=E:\cov-analysis-win32-7.7.0.4 set PATH=%PATH%;%COV_DIR%\bin set PWD=%~dp0 rmdir cov-int /s /q >NUL 2>NUL diff --git a/src/registry.h b/src/registry.h index b6458f4b..01f686c7 100644 --- a/src/registry.h +++ b/src/registry.h @@ -122,6 +122,9 @@ static __inline BOOL _SetRegistryKey(HKEY key_root, const char* key_name, DWORD HKEY hRoot = NULL, hApp = NULL; DWORD dwDisp, dwType = reg_type; + if (key_name == NULL) + return FALSE; + if (RegOpenKeyExA(key_root, NULL, 0, KEY_READ|KEY_CREATE_SUB_KEY, &hRoot) != ERROR_SUCCESS) { hRoot = NULL; goto out; diff --git a/src/rufus.rc b/src/rufus.rc index 25e67d5f..5b66613e 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.888" +CAPTION "Rufus 2.8.889" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,888,0 - PRODUCTVERSION 2,8,888,0 + FILEVERSION 2,8,889,0 + PRODUCTVERSION 2,8,889,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.888" + VALUE "FileVersion", "2.8.889" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.888" + VALUE "ProductVersion", "2.8.889" END END BLOCK "VarFileInfo" diff --git a/src/stdlg.c b/src/stdlg.c index 9df22c6a..9676575c 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -175,10 +175,10 @@ void BrowseForFolder(void) { hr = (*pfSHCreateItemFromParsingName)(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path); if (SUCCEEDED(hr)) { if (wpath != NULL) { - hr = pfod->lpVtbl->SetFolder(pfod, si_path); + pfod->lpVtbl->SetFolder(pfod, si_path); } if (fname != NULL) { - hr = pfod->lpVtbl->SetFileName(pfod, fname); + pfod->lpVtbl->SetFileName(pfod, fname); } } safe_free(wpath); @@ -250,7 +250,7 @@ char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options) HRESULT hr = FALSE; IFileDialog *pfd = NULL; IShellItem *psiResult; - COMDLG_FILTERSPEC* filter_spec; + COMDLG_FILTERSPEC* filter_spec = NULL; wchar_t *wpath = NULL, *wfilename = NULL; IShellItem *si_path = NULL; // Automatically freed @@ -333,7 +333,8 @@ char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options) dialog_showing--; return filepath; } -fallback: + fallback: + safe_free(filter_spec); if (pfd != NULL) { pfd->lpVtbl->Release(pfd); } From 99046919a52b9ac2ec4ab4b0a712a19291c00391 Mon Sep 17 00:00:00 2001 From: VGPlayer Date: Sun, 24 Apr 2016 11:28:28 +0200 Subject: [PATCH 60/91] [loc] update Malay translation to latest --- res/localization/rufus.loc | 35 ++++++++++++++++++++++++++++------- src/rufus.rc | 10 +++++----- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 6e99eedf..4d1e3d07 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -9596,7 +9596,7 @@ t MSG_285 "Atsiųstą vykdomąjį failą pasirašė '%s'.\nŠio parašo mes neat ################################################################################ l "ms-MY" "Malay (Bahasa Malaysia)" 0x043e, 0x083e -v 1.0.18 +v 1.0.19 b "en-US" # Main dialog @@ -9827,9 +9827,17 @@ t MSG_093 "PENTING: PERANTI INI MEMPUNYAI BEBERAPA PARTISYEN!!\n\n" "Jika anda mahu meneruskannya, anda bertanggungjawab ke atas kehilangan data dalam partisyen tersebut." t MSG_094 "Beberapa partisyen dikesan" t MSG_095 "DD Imej" -#t MSG_096 "Sistem fail yang dipilih tidak boleh digunakan dengan jenis ISO ini (...)" +t MSG_096 "Sistem fail yang sedang dipilih tidak boleh digunakan dengan jenis ISO ini. " + "Sila pilih sistem fail berlainan atau gunakan ISO berlainan." t MSG_097 "'Windows To Go' hanya boleh digunakan jika sistem fail adalah NTFS." -#t MSG_098 "PENTING: Anda cuba memasang 'Windows To Go', tetapi pemacu sasaran anda tidak (...)" +t MSG_098 "PENTING: Anda cuba memasang 'Windows To Go', tetapi " + "pemacu sasaran anda tidak mempunyai atribut 'FIXED'. Disebabkan " + "ini Windows akan berkemungkinan besar sangkut sepanjang but, kerana Microsoft " + "tidak merekanya untuk berfungsi dengan pemacu yang sebaliknya mempunyai " + "atribut 'REMOVABLE'.\n\nAdakah anda masih mahu teruskan?\n\n" + "Nota: Atribut 'FIXED/REMOVABLE'adalah sifat perkakasan yang " + "hanya boleh ditukar menggunakan alatan tersuai daripada pengilang pemacu. " + "Bagaimanapun alatan tersebut adalah HAMPIR TIDAK AKAN diberikan kepada umum..." t MSG_099 "Had sistem fail" t MSG_100 "Imej ISO ini mengandungi fail yang lebih besar daripada 4GB " "iaitu saiz maksima yang dibenarkan untuk sistem fail FAT/FAT32." @@ -9869,7 +9877,15 @@ t MSG_114 "Imej ini menggunakan Syslinux %s%s tetapi aplikasi ini hanya mempunya "NOTA:Fail akan dimuat turun ke dalam direktori aplikasi ini dan akan digunakan semula" "secara automatik sekiranya sedia ada.\n" t MSG_115 "Muat turun diperlukan" -#t MSG_116 "Imej ini menggunakan Grub %s tetapi penggunaan hanya termasuk fail pemasangan untuk (...)" +t MSG_116 "Imej ini menggunakan Grub %s tetapi aplikasi hanya termasuk fail pemasangan untuk Grub %s.\n\n" + "Sepertimana versi Grub berlainan mungkin tidak sesuai antara satu sama lain, dan ianya tidak " + "mungkin untuk memasukkan mereka semua, Rufus akan cuba mengesan versi fail pemasangan Grub " + "('core.img') yang sepadan dengan salah satu daripada imej anda:\n" + "- Pilih 'Ya' untuk bersambung ke Internet dan cuba memuat turunnya\n" + "- Pilih 'Tidak' untuk menggunakan versi lalai dari Rufus\n" + "- Pilih 'Batal' untuk membatalkan operasi\n\n" + "Nota: Fail akan dimuat turun dalam direktori aplikasi semasa dan akan digunakan semula secara automatik " + "jika ada. Jika tiada padanan boleh dijumpai dalam talian, versi lalai akan digunakan." # Tooltips # Partition Scheme and Target Type @@ -9931,10 +9947,15 @@ t MSG_192 "Melepasi bacaan" t MSG_193 "Muat turun %s" t MSG_194 "Tidak boleh muat turun %s" t MSG_195 "Menggunakan %s fail versi dibenam" -#t MSG_196 "PENTING: PEMACU INI MENGGUNAKAN SAIZ SEKTOR BUKAN STANDARD!! (...)" +t MSG_196 "PENTING: PEMACU INI MENGGUNAKAN SAIZ SEKTOR BUKAN PIAWAIAN!\n\n" + "Pemacu konvensional mengunakan saiz sektor 512 bait tetapi pemacu ini menggunakan " + "%d bait. Dalam banyak kes, ini bermaksud anda TIDAK akan mampu untuk but dari pemacu ini.\n" + "Rufus boleh cuba untuk mencipta pemacu boleh but, tetapi TIDAK ADA JAMINAN ianya akan berfungsi." t MSG_197 "Saiz sektor bukan standard dikesan" -#t MSG_198 "'Windows To Go' hanya boleh dipasang di pemacu dibahagi GPT jika ia ada (...)" -#t MSG_199 "Pilih ini jika anda merancang untuk memasang Windows, ke cakera lain, menggunakan (...)" +t MSG_198 "'Windows To Go' hanya boleh dipasang dalam pemacu berpartisyen GPT jika ia mempunyai " + "set atribut 'FIXED'. Pemacu semasa tidak dikesan sebagai 'FIXED'." +t MSG_199 "Pilih ini jika anda merancang untuk memasang Windows, ke cakera lain, " + "menggunakan peranti dipilih sebagai media pemasangan." t MSG_200 "Pilih ini jika anda mahu untuk menjalankan Windows secara langsung dari peranti dipilih." # Status messages - these messages will appear on the status bar diff --git a/src/rufus.rc b/src/rufus.rc index 5b66613e..d61e5f9d 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.889" +CAPTION "Rufus 2.8.890" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,889,0 - PRODUCTVERSION 2,8,889,0 + FILEVERSION 2,8,890,0 + PRODUCTVERSION 2,8,890,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.889" + VALUE "FileVersion", "2.8.890" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.889" + VALUE "ProductVersion", "2.8.890" END END BLOCK "VarFileInfo" From fc5d64618a4d7d90b7f310bc5e934c7d3f477fa2 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Sun, 24 Apr 2016 14:19:19 +0200 Subject: [PATCH 61/91] update UEFI:NTFS to latest * This introduces ARM boot support * Also set rufus-next to 2.9 and add ARM64 UEFI detection --- configure | 20 ++++++++++---------- configure.ac | 2 +- res/uefi/readme.txt | 6 +++--- res/uefi/uefi-ntfs.img | Bin 262144 -> 524288 bytes src/iso.c | 2 +- src/rufus.rc | 10 +++++----- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/configure b/configure index 62ee0102..760bb77e 100644 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for rufus 2.8. +# Generated by GNU Autoconf 2.69 for rufus 2.9. # # Report bugs to . # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='rufus' PACKAGE_TARNAME='rufus' -PACKAGE_VERSION='2.8' -PACKAGE_STRING='rufus 2.8' +PACKAGE_VERSION='2.9' +PACKAGE_STRING='rufus 2.9' PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues' PACKAGE_URL='http://rufus.akeo.ie' @@ -1228,7 +1228,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures rufus 2.8 to adapt to many kinds of systems. +\`configure' configures rufus 2.9 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1294,7 +1294,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of rufus 2.8:";; + short | recursive ) echo "Configuration of rufus 2.9:";; esac cat <<\_ACEOF @@ -1385,7 +1385,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -rufus configure 2.8 +rufus configure 2.9 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1440,7 +1440,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by rufus $as_me 2.8, which was +It was created by rufus $as_me 2.9, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2303,7 +2303,7 @@ fi # Define the identity of the package. PACKAGE='rufus' - VERSION='2.8' + VERSION='2.9' cat >>confdefs.h <<_ACEOF @@ -4482,7 +4482,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by rufus $as_me 2.8, which was +This file was extended by rufus $as_me 2.9, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4536,7 +4536,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -rufus config.status 2.8 +rufus config.status 2.9 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index f80c281b..441fc784 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([rufus], [2.8], [https://github.com/pbatard/rufus/issues], [rufus], [http://rufus.akeo.ie]) +AC_INIT([rufus], [2.9], [https://github.com/pbatard/rufus/issues], [rufus], [http://rufus.akeo.ie]) AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies]) AC_CONFIG_SRCDIR([src/rufus.c]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/res/uefi/readme.txt b/res/uefi/readme.txt index 5d3f40da..a0456b2f 100644 --- a/res/uefi/readme.txt +++ b/res/uefi/readme.txt @@ -5,12 +5,12 @@ This image, which you can mount as FAT filesystem or open in 7-zip, contains the following data: o The NTFS UEFI drivers from efifs (https://github.com/pbatard/efifs) which were compiled, with compression disabled, using Visual Studio 2015 Community Edition. - These are the \EFI\Rufus\ntfs_[ia32|x64].efi files. + These are the \EFI\Rufus\ntfs_[ia32|x64|arm].efi files. o The UEFI:NTFS binaries (https://github.com/pbatard/uefi-ntfs), which were also compiled using Visual Studio 2015 Community Edition. - These are the \EFI\Boot\boot[ia32|x64].efi files. + These are the \EFI\Boot\boot[ia32|x64|arm].efi files. The FAT partition was created on Debian GNU/Linux using the following commands - dd if=/dev/zero of=uefi-ntfs.img bs=512 count=512 + dd if=/dev/zero of=uefi-ntfs.img bs=512 count=1024 mkfs.vfat -n UEFI_NTFS uefi-ntfs.img and then mounting the uefi-ntfs.img image and copying the relevant files. diff --git a/res/uefi/uefi-ntfs.img b/res/uefi/uefi-ntfs.img index 78db98c8b5e13f9587d6bb1ec79e7f020018e9d7..2fd68705bb6b44553654640dbcf0b91db5639c21 100644 GIT binary patch literal 524288 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

D% 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⋘ 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%0ArtQEgaP*6j;Ii|vYYvia8|B{n!r%1gM; z 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 zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ yAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAO!x$68JynYw9Tg literal 262144 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 Date: Tue, 26 Apr 2016 14:57:07 +0200 Subject: [PATCH 62/91] [core] don't list non-USB removable devices by default * Unless specifically requested with Ctrl-Alt-H * Closes #727 * Also rename usb.c to dev.c, since we may be listing more than USB devices --- src/.msvc/rufus.vcxproj | 4 ++-- src/.msvc/rufus.vcxproj.filters | 12 ++++++------ src/.msvc/rufus_sources | 2 +- src/Makefile.am | 4 ++-- src/Makefile.in | 28 ++++++++++++++-------------- src/{usb.c => dev.c} | 16 ++++++++++------ src/{usb.h => dev.h} | 2 +- src/rufus.c | 22 +++++++++++----------- src/rufus.h | 2 +- src/rufus.rc | 10 +++++----- 10 files changed, 53 insertions(+), 49 deletions(-) rename src/{usb.c => dev.c} (98%) rename src/{usb.h => dev.h} (99%) diff --git a/src/.msvc/rufus.vcxproj b/src/.msvc/rufus.vcxproj index 82fc4a9c..6d337200 100644 --- a/src/.msvc/rufus.vcxproj +++ b/src/.msvc/rufus.vcxproj @@ -200,7 +200,7 @@ - + @@ -224,7 +224,7 @@ - + diff --git a/src/.msvc/rufus.vcxproj.filters b/src/.msvc/rufus.vcxproj.filters index 41f2ae8a..2ccf6621 100644 --- a/src/.msvc/rufus.vcxproj.filters +++ b/src/.msvc/rufus.vcxproj.filters @@ -66,15 +66,15 @@ Source Files - - Source Files - Source Files Source Files + + Source Files + @@ -128,9 +128,6 @@ Header Files - - Header Files - Header Files @@ -140,6 +137,9 @@ Header Files + + Header Files + diff --git a/src/.msvc/rufus_sources b/src/.msvc/rufus_sources index 46ab8b7f..86409c87 100644 --- a/src/.msvc/rufus_sources +++ b/src/.msvc/rufus_sources @@ -36,6 +36,7 @@ SXS_APPLICATION_MANIFEST=..\rufus.manifest SOURCES=badblocks.c \ checksum.c \ + dev.c \ dos.c \ dos_locale.c \ drive.c \ @@ -52,6 +53,5 @@ SOURCES=badblocks.c \ stdio.c \ stdlg.c \ syslinux.c \ - usb.c \ vhd.c \ rufus.rc diff --git a/src/Makefile.am b/src/Makefile.am index da1937ce..a46a084c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,8 +10,8 @@ AM_V_WINDRES = $(AM_V_WINDRES_$(V)) %_rc.o: %.rc ../res/localization/embedded.loc $(AM_V_WINDRES) $(AM_RCFLAGS) -i $< -o $@ -rufus_SOURCES = badblocks.c checksum.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c net.c parser.c \ - pki.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c usb.c vhd.c +rufus_SOURCES = badblocks.c checksum.c dev.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c \ + net.c parser.c pki.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c vhd.c rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS) rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \ diff --git a/src/Makefile.in b/src/Makefile.in index 401d576f..c306667e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -88,15 +88,15 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) am_rufus_OBJECTS = rufus-badblocks.$(OBJEXT) rufus-checksum.$(OBJEXT) \ - rufus-dos.$(OBJEXT) rufus-dos_locale.$(OBJEXT) \ - rufus-drive.$(OBJEXT) rufus-format.$(OBJEXT) \ - rufus-icon.$(OBJEXT) rufus-iso.$(OBJEXT) \ - rufus-localization.$(OBJEXT) rufus-net.$(OBJEXT) \ - rufus-parser.$(OBJEXT) rufus-pki.$(OBJEXT) \ + rufus-dev.$(OBJEXT) rufus-dos.$(OBJEXT) \ + rufus-dos_locale.$(OBJEXT) rufus-drive.$(OBJEXT) \ + rufus-format.$(OBJEXT) rufus-icon.$(OBJEXT) \ + rufus-iso.$(OBJEXT) rufus-localization.$(OBJEXT) \ + rufus-net.$(OBJEXT) rufus-parser.$(OBJEXT) rufus-pki.$(OBJEXT) \ rufus-rufus.$(OBJEXT) rufus-smart.$(OBJEXT) \ rufus-stdfn.$(OBJEXT) rufus-stdio.$(OBJEXT) \ rufus-stdlg.$(OBJEXT) rufus-syslinux.$(OBJEXT) \ - rufus-usb.$(OBJEXT) rufus-vhd.$(OBJEXT) + rufus-vhd.$(OBJEXT) rufus_OBJECTS = $(am_rufus_OBJECTS) rufus_DEPENDENCIES = rufus_rc.o bled/libbled.a ms-sys/libmssys.a \ syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \ @@ -270,8 +270,8 @@ AM_V_WINDRES_0 = @echo " RC $@";$(WINDRES) AM_V_WINDRES_1 = $(WINDRES) AM_V_WINDRES_ = $(AM_V_WINDRES_$(AM_DEFAULT_VERBOSITY)) AM_V_WINDRES = $(AM_V_WINDRES_$(V)) -rufus_SOURCES = badblocks.c checksum.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c net.c parser.c \ - pki.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c usb.c vhd.c +rufus_SOURCES = badblocks.c checksum.c dev.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c \ + net.c parser.c pki.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c vhd.c rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS) rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows @@ -344,6 +344,12 @@ rufus-checksum.o: checksum.c rufus-checksum.obj: checksum.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-checksum.obj `if test -f 'checksum.c'; then $(CYGPATH_W) 'checksum.c'; else $(CYGPATH_W) '$(srcdir)/checksum.c'; fi` +rufus-dev.o: dev.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-dev.o `test -f 'dev.c' || echo '$(srcdir)/'`dev.c + +rufus-dev.obj: dev.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-dev.obj `if test -f 'dev.c'; then $(CYGPATH_W) 'dev.c'; else $(CYGPATH_W) '$(srcdir)/dev.c'; fi` + rufus-dos.o: dos.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-dos.o `test -f 'dos.c' || echo '$(srcdir)/'`dos.c @@ -440,12 +446,6 @@ rufus-syslinux.o: syslinux.c rufus-syslinux.obj: syslinux.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-syslinux.obj `if test -f 'syslinux.c'; then $(CYGPATH_W) 'syslinux.c'; else $(CYGPATH_W) '$(srcdir)/syslinux.c'; fi` -rufus-usb.o: usb.c - $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-usb.o `test -f 'usb.c' || echo '$(srcdir)/'`usb.c - -rufus-usb.obj: usb.c - $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-usb.obj `if test -f 'usb.c'; then $(CYGPATH_W) 'usb.c'; else $(CYGPATH_W) '$(srcdir)/usb.c'; fi` - rufus-vhd.o: vhd.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-vhd.o `test -f 'vhd.c' || echo '$(srcdir)/'`vhd.c diff --git a/src/usb.c b/src/dev.c similarity index 98% rename from src/usb.c rename to src/dev.c index 05fa769a..0ae8cd31 100644 --- a/src/usb.c +++ b/src/dev.c @@ -1,6 +1,6 @@ /* * Rufus: The Reliable USB Formatting Utility - * USB device listing + * Device detection and enumeration * Copyright 2014-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify @@ -40,7 +40,7 @@ #include "localization.h" #include "drive.h" -#include "usb.h" +#include "dev.h" extern StrArray DriveID, DriveLabel; extern BOOL enable_HDDs, use_fake_units, enable_vmdk, usb_debug, list_non_usb_removable_drives; @@ -157,7 +157,7 @@ static __inline BOOL IsRemovable(const char* buffer) /* * Refresh the list of USB devices */ -BOOL GetUSBDevices(DWORD devnum) +BOOL GetDevices(DWORD devnum) { // List of USB storage drivers we know - list may be incomplete! const char* usbstor_name[] = { @@ -461,14 +461,18 @@ BOOL GetUSBDevices(DWORD devnum) uprintf("Found VHD device '%s'", buffer); } else if ((props.is_CARD) && ((!props.is_USB) || ((props.vid == 0) && (props.pid == 0)))) { uprintf("Found card reader device '%s'", buffer); - } else if ((!props.is_USB) && (props.is_Removable) && (!props.is_UASP)) { - uprintf("Found non-USB removable device '%s'", buffer); + } else if ((!props.is_USB) && (!props.is_UASP) && (props.is_Removable)) { + uprintf("Found non-USB removable device '%s' => Eliminated", buffer); + if (!list_non_usb_removable_drives) { + uuprintf("If you *REALLY* need, you can enable listing of this device with "); + continue; + } } else { if ((props.vid == 0) && (props.pid == 0)) { if (!props.is_USB) { // If we have a non removable SCSI drive and couldn't get a VID:PID, // we are most likely dealing with a system drive => eliminate it! - uuprintf(" Non-USB or non-removable => Eliminated"); + uuprintf("Found non-USB non-removable device '%s' => Eliminated", buffer); continue; } safe_strcpy(str, sizeof(str), "????:????"); // Couldn't figure VID:PID diff --git a/src/usb.h b/src/dev.h similarity index 99% rename from src/usb.h rename to src/dev.h index d67e018c..a3787cb1 100644 --- a/src/usb.h +++ b/src/dev.h @@ -1,6 +1,6 @@ /* * Rufus: The Reliable USB Formatting Utility - * USB device listing + * Device listing * Copyright 2014-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify diff --git a/src/rufus.c b/src/rufus.c index e2af2f71..aea4a480 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -2093,7 +2093,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA case DBT_CUSTOMEVENT: // Sent by our timer refresh function or for card reader media change LastRefresh = _GetTickCount64(); KillTimer(hMainDialog, TID_REFRESH_TIMER); - GetUSBDevices((DWORD)ComboBox_GetItemData(hDeviceList, ComboBox_GetCurSel(hDeviceList))); + GetDevices((DWORD)ComboBox_GetItemData(hDeviceList, ComboBox_GetCurSel(hDeviceList))); user_changed_label = FALSE; return (INT_PTR)TRUE; case DBT_DEVNODES_CHANGED: @@ -2124,7 +2124,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA log_displayed = FALSE; hLogDlg = MyCreateDialog(hMainInstance, IDD_LOG, hDlg, (DLGPROC)LogProc); InitDialog(hDlg); - GetUSBDevices(0); + GetDevices(0); CheckForUpdates(FALSE); // Register MEDIA_INSERTED/MEDIA_REMOVED notifications for card readers if ((pfSHChangeNotifyRegister != NULL) && (SUCCEEDED(SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &pidlDesktop)))) { @@ -2429,7 +2429,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA if ((HIWORD(wParam)) == BN_CLICKED) { enable_HDDs = !enable_HDDs; PrintStatus2000(lmprintf(MSG_253), enable_HDDs); - GetUSBDevices(0); + GetDevices(0); } break; case IDC_START: @@ -2669,7 +2669,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA EnableControls(TRUE); if (wParam) { uprintf("\r\n"); - GetUSBDevices(DeviceNum); + GetDevices(DeviceNum); } if (!IS_ERROR(FormatStatus)) { // This is the only way to achieve instantaneous progress transition to 100% @@ -3073,7 +3073,7 @@ relaunch: usb_debug = !usb_debug; WriteSettingBool(SETTING_ENABLE_USB_DEBUG, usb_debug); PrintStatus2000(lmprintf(MSG_270), usb_debug); - GetUSBDevices(0); + GetDevices(0); continue; } // Alt-, => Disable physical drive locking @@ -3123,7 +3123,7 @@ relaunch: if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'F')) { enable_HDDs = !enable_HDDs; PrintStatus2000(lmprintf(MSG_253), enable_HDDs); - GetUSBDevices(0); + GetDevices(0); CheckDlgButton(hMainDialog, IDC_ENABLE_FIXED_DISKS, enable_HDDs?BST_CHECKED:BST_UNCHECKED); continue; } @@ -3160,7 +3160,7 @@ relaunch: force_large_fat32 = !force_large_fat32; WriteSettingBool(SETTING_FORCE_LARGE_FAT32_FORMAT, force_large_fat32); PrintStatus2000(lmprintf(MSG_254), force_large_fat32); - GetUSBDevices(0); + GetDevices(0); continue; } // Alt N => Enable NTFS compression @@ -3182,7 +3182,7 @@ relaunch: if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'S')) { size_check = !size_check; PrintStatus2000(lmprintf(MSG_252), size_check); - GetUSBDevices(0); + GetDevices(0); continue; } // Alt-T => Preserve timestamps when extracting ISO files @@ -3197,7 +3197,7 @@ relaunch: use_fake_units = !use_fake_units; WriteSettingBool(SETTING_USE_PROPER_SIZE_UNITS, !use_fake_units); PrintStatus2000(lmprintf(MSG_263), !use_fake_units); - GetUSBDevices(0); + GetDevices(0); continue; } // Alt-V => Save selected device to *UNCOMPRESSED* VHD @@ -3210,7 +3210,7 @@ relaunch: enable_vmdk = !enable_vmdk; WriteSettingBool(SETTING_ENABLE_VMDK_DETECTION, enable_vmdk); PrintStatus2000(lmprintf(MSG_265), enable_vmdk); - GetUSBDevices(0); + GetDevices(0); continue; } // Alt-X => Delete the 'rufus_files' subdirectory @@ -3243,7 +3243,7 @@ relaunch: uprintf("NOTE: Listing of non-USB removable drives has been %s.", (list_non_usb_removable_drives)?"enabled (CAUTION!)":"disabled"); if (list_non_usb_removable_drives) uprintf("By using this unofficial cheat mode you forfeit ANY RIGHT to complain if you lose valuable data!"); - GetUSBDevices(0); + GetDevices(0); continue; } diff --git a/src/rufus.h b/src/rufus.h index 8c149470..18ac48a7 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -421,7 +421,7 @@ extern unsigned char* GetResource(HMODULE module, char* name, char* type, const extern DWORD GetResourceSize(HMODULE module, char* name, char* type, const char* desc); extern DWORD RunCommand(const char* cmdline, const char* dir, BOOL log); extern BOOL CompareGUID(const GUID *guid1, const GUID *guid2); -extern BOOL GetUSBDevices(DWORD devnum); +extern BOOL GetDevices(DWORD devnum); extern BOOL SetLGP(BOOL bRestore, BOOL* bExistingKey, const char* szPath, const char* szPolicy, DWORD dwValue); extern LONG GetEntryWidth(HWND hDropDown, const char* entry); extern DWORD DownloadFile(const char* url, const char* file, HWND hProgressDialog); diff --git a/src/rufus.rc b/src/rufus.rc index 4f04b228..f3526e25 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.891" +CAPTION "Rufus 2.9.892" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,891,0 - PRODUCTVERSION 2,9,891,0 + FILEVERSION 2,9,892,0 + PRODUCTVERSION 2,9,892,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.891" + VALUE "FileVersion", "2.9.892" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.891" + VALUE "ProductVersion", "2.9.892" END END BLOCK "VarFileInfo" From d4c518a4aea43ee101f8ea1776ce56f416dd3802 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 28 Apr 2016 10:09:43 +0200 Subject: [PATCH 63/91] [misc] update UEFI:NTFS partition detection --- src/drive.c | 9 +++------ src/rufus.c | 2 +- src/rufus.rc | 10 +++++----- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/drive.c b/src/drive.c index 95ce1b49..55c08124 100644 --- a/src/drive.c +++ b/src/drive.c @@ -57,7 +57,6 @@ const GUID PARTITION_SYSTEM_GUID = * Globals */ RUFUS_DRIVE_INFO SelectedDrive; -size_t uefi_ntfs_size = 0; /* * The following methods get or set the AutoMount setting (which is different from AutoRun) @@ -684,9 +683,6 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys if (hPhysical == INVALID_HANDLE_VALUE) return 0; - if (uefi_ntfs_size == 0) - uefi_ntfs_size = GetResourceSize(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_NTFS), _RT_RCDATA, "uefi-ntfs.img"); - r = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, geometry, sizeof(geometry), &size, NULL); if (!r || size <= 0) { @@ -734,7 +730,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) { part_type = DriveLayout->PartitionEntry[i].Mbr.PartitionType; isUefiNtfs = (i == 1) && (part_type == 0xef) && - (DriveLayout->PartitionEntry[i].PartitionLength.QuadPart == uefi_ntfs_size); + (DriveLayout->PartitionEntry[i].PartitionLength.QuadPart <= 1*MB); suprintf("Partition %d%s:\n", i+1, isUefiNtfs?" (UEFI:NTFS)":""); for (j=0; j Date: Thu, 28 Apr 2016 22:40:16 +0200 Subject: [PATCH 64/91] [core] update UEFI:NTFS to latest * Should fix the long-standing HP firmware compatibility as per #615, #549 and others * See https://github.com/pbatard/uefi-ntfs/commit/22370067f546e400da719633cba272ee77ae3464 for details --- res/uefi/uefi-ntfs.img | Bin 524288 -> 524288 bytes src/rufus.rc | 10 +++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/res/uefi/uefi-ntfs.img b/res/uefi/uefi-ntfs.img index 2fd68705bb6b44553654640dbcf0b91db5639c21..b85943ed87bc5ae5e9f17cfcbba00dbe507f44f4 100644 GIT binary patch delta 21725 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 oaiFp1T521 diff --git a/src/rufus.rc b/src/rufus.rc index 6816193a..78023b18 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.893" +CAPTION "Rufus 2.9.894" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,893,0 - PRODUCTVERSION 2,9,893,0 + FILEVERSION 2,9,894,0 + PRODUCTVERSION 2,9,894,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.893" + VALUE "FileVersion", "2.9.894" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.893" + VALUE "ProductVersion", "2.9.894" END END BLOCK "VarFileInfo" From b6c0dd1b23c4a1c631c465252090a6d2806d6389 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 2 May 2016 11:11:22 +0100 Subject: [PATCH 65/91] [core] fix a typo in exFAT cluster selection for >32GB drives * Closes #745 --- src/rufus.c | 6 +++--- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/rufus.c b/src/rufus.c index 767ae697..65199eca 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -268,11 +268,11 @@ static BOOL DefineClusterSizes(void) if (nWindowsVersion > WINDOWS_XP) { SelectedDrive.ClusterSize[FS_EXFAT].Allowed = 0x03FFFE00; if (SelectedDrive.DiskSize < 256*MB) // < 256 MB - SelectedDrive.ClusterSize[FS_EXFAT].Default = 4*1024; + SelectedDrive.ClusterSize[FS_EXFAT].Default = 4*KB; else if (SelectedDrive.DiskSize < 32*GB) // < 32 GB - SelectedDrive.ClusterSize[FS_EXFAT].Default = 32*1024; + SelectedDrive.ClusterSize[FS_EXFAT].Default = 32*KB; else - SelectedDrive.ClusterSize[FS_EXFAT].Default = 28*1024; + SelectedDrive.ClusterSize[FS_EXFAT].Default = 128*KB; } // UDF (only supported for Vista and later) diff --git a/src/rufus.rc b/src/rufus.rc index 78023b18..e9cd6b45 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.894" +CAPTION "Rufus 2.9.895" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,894,0 - PRODUCTVERSION 2,9,894,0 + FILEVERSION 2,9,895,0 + PRODUCTVERSION 2,9,895,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.894" + VALUE "FileVersion", "2.9.895" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.894" + VALUE "ProductVersion", "2.9.895" END END BLOCK "VarFileInfo" From 8bd9055d6c602b5f3fda8be8a8f0e8ae5882372f Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 2 May 2016 12:06:38 +0100 Subject: [PATCH 66/91] [misc] add a retry on commandline hogger deletion * Trying to delete the hogger could result in access denied on first attempt, which would leave a rufus.com behind * Part of #714 --- src/rufus.c | 13 +++++++------ src/rufus.rc | 10 +++++----- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/rufus.c b/src/rufus.c index 65199eca..32a2bdf2 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -242,7 +242,7 @@ static BOOL DefineClusterSizes(void) if ((SelectedDrive.DiskSize >= 256*MB) && (SelectedDrive.DiskSize < 32*GB)) { for (i=8; i<=32; i<<=1) { // 256 MB -> 32 GB if (SelectedDrive.DiskSize*1.0f < i*GB*FAT32_CLUSTER_THRESHOLD) { - SelectedDrive.ClusterSize[FS_FAT32].Default = ((ULONG)i/2)*1024; + SelectedDrive.ClusterSize[FS_FAT32].Default = ((ULONG)i/2)*KB; break; } } @@ -259,7 +259,7 @@ static BOOL DefineClusterSizes(void) SelectedDrive.ClusterSize[FS_NTFS].Allowed = 0x0001FE00; for (i=16; i<=256; i<<=1) { // 7 MB -> 256 TB if (SelectedDrive.DiskSize < i*TB) { - SelectedDrive.ClusterSize[FS_NTFS].Default = ((ULONG)i/4)*1024; + SelectedDrive.ClusterSize[FS_NTFS].Default = ((ULONG)i/4)*KB; break; } } @@ -3282,14 +3282,15 @@ out: SetLGP(TRUE, &existing_key, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", "NoDriveTypeAutorun", 0); if ((nWindowsVersion > WINDOWS_XP) && (!automount) && (!SetAutoMount(FALSE))) uprintf("Failed to restore AutoMount to disabled"); + // Unconditional delete with retry, just in case... + for (i = 0; (!DeleteFileA(cmdline_hogger)) && (i <= 10); i++) + Sleep(200); + CloseHandle(mutex); + CLOSE_OPENED_LIBRARIES; if (attached_console) { SetWindowPos(GetConsoleWindow(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); FreeConsole(); } - // Unconditional delete, just in case... - DeleteFileA(cmdline_hogger); - CloseHandle(mutex); - CLOSE_OPENED_LIBRARIES; uprintf("*** " APPLICATION_NAME " exit ***\n"); #ifdef _CRTDBG_MAP_ALLOC _CrtDumpMemoryLeaks(); diff --git a/src/rufus.rc b/src/rufus.rc index e9cd6b45..60e5b44b 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.895" +CAPTION "Rufus 2.9.896" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,895,0 - PRODUCTVERSION 2,9,895,0 + FILEVERSION 2,9,896,0 + PRODUCTVERSION 2,9,896,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.895" + VALUE "FileVersion", "2.9.896" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.895" + VALUE "ProductVersion", "2.9.896" END END BLOCK "VarFileInfo" From f65dbb11c057b42d64a19957a6c08c1bcc9145ce Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 9 May 2016 13:40:54 +0100 Subject: [PATCH 67/91] [loc] add new message for listing of non-USB removable drives * Also increase status display timeout for cheat modes --- res/localization/ChangeLog.txt | 5 +++++ res/localization/rufus.loc | 6 +++-- src/rufus.c | 41 +++++++++++++++++----------------- src/rufus.h | 1 + src/rufus.rc | 10 ++++----- 5 files changed, 36 insertions(+), 27 deletions(-) diff --git a/res/localization/ChangeLog.txt b/res/localization/ChangeLog.txt index f05ad82a..d8a0e30e 100644 --- a/res/localization/ChangeLog.txt +++ b/res/localization/ChangeLog.txt @@ -15,6 +15,11 @@ content. PLEASE, do not just look at this Changelog when updating your translation, but always use the English section of rufus.loc as your base. For instance, MSG_114, that was introduced in v1.0.8 is MORE than one line! +o Version 1.0.20 (2016.05.09) + - *NEW* MSG_287 "Detection of non-USB removable drives" + Note, this message is followed by either "enabled"/"disabled" (see MSG_250/251) and is similar to MSG_253 + The message appears on the status bar and can be tested with Ctrl-Alt-F. + o Version 1.0.19 (2015.10.15) Note: The following message can be tested by pressing Alt-, (That's the 'Alt' and 'comma' keys on your keyboard) In case the message below is not clear, you can consider that it says "Exclusive locking of the USB drive" diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 4d1e3d07..d4670038 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -92,7 +92,7 @@ # http://download.microsoft.com/download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5BMS-LCID%5D.pdf # for the LCID (0x####) codes you should use l "en-US" "English (English)" 0x0409, 0x0809, 0x0c09, 0x1009, 0x1409, 0x1809, 0x1c09, 0x2009, 0x2409, 0x2809, 0x2c09, 0x3009, 0x3409, 0x3809, 0x3c09, 0x4009, 0x4409, 0x4809 -v 1.0.19 +v 1.0.20 # Main dialog g IDD_DIALOG @@ -548,6 +548,7 @@ t MSG_284 "The downloaded executable is missing a digital signature." t MSG_285 "The downloaded executable is signed by '%s'.\nThis is not a signature we recognize and could " "indicate some form of malicious activity...\nAre you sure you want to run this file?" t MSG_286 "Zeroing drive: %0.1f%% completed" +t MSG_287 "Detection of non-USB removable drives" ################################################################################ ############################# TRANSLATOR END COPY ############################## @@ -5033,7 +5034,7 @@ t MSG_285 "Ladatun tiedoston on allekirjoittanut '%s'.\nEmme tunnista kyseistä ################################################################################ l "fr-FR" "French (Français)" 0x040c, 0x080c, 0x0c0c, 0x100c, 0x140c, 0x180c, 0x1c0c, 0x200c, 0x240c, 0x280c, 0x2c0c, 0x300c, 0x340c, 0x380c, 0xe40c -v 1.0.19 +v 1.0.20 b "en-US" g IDD_DIALOG @@ -5449,6 +5450,7 @@ t MSG_283 "Signature invalide" t MSG_284 "L'exécutable téléchargé ne possède pas de signature digitale." t MSG_285 "L'exécutable téléchargé est signé par '%s'.\nCe n’est pas une signature que nous reconnaissons et " "pourrait indiquer une activité malicieuse...\nÊtes-vous certain de vouloir lancer ce fichier?" +t MSG_287 "Détection disques non-USB détachables" ################################################################################ l "de-DE" "German (Deutsch)" 0x0407, 0x0807, 0x0c07, 0x1007, 0x1407 diff --git a/src/rufus.c b/src/rufus.c index 32a2bdf2..5acdad77 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -1889,9 +1889,9 @@ void InitDialog(HWND hDlg) PrintInfo(0, MSG_210); } -static void PrintStatus2000(const char* str, BOOL val) +static void PrintStatusTimeout(const char* str, BOOL val) { - PrintStatus(2000, (val)?MSG_250:MSG_251, str); + PrintStatus(STATUS_MSG_TIMEOUT, (val)?MSG_250:MSG_251, str); } void ShowLanguageMenu(RECT rcExclude) @@ -2428,7 +2428,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA case IDC_ENABLE_FIXED_DISKS: if ((HIWORD(wParam)) == BN_CLICKED) { enable_HDDs = !enable_HDDs; - PrintStatus2000(lmprintf(MSG_253), enable_HDDs); + PrintStatusTimeout(lmprintf(MSG_253), enable_HDDs); GetDevices(0); } break; @@ -3072,14 +3072,14 @@ relaunch: if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == VK_OEM_PERIOD)) { usb_debug = !usb_debug; WriteSettingBool(SETTING_ENABLE_USB_DEBUG, usb_debug); - PrintStatus2000(lmprintf(MSG_270), usb_debug); + PrintStatusTimeout(lmprintf(MSG_270), usb_debug); GetDevices(0); continue; } // Alt-, => Disable physical drive locking if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == VK_OEM_COMMA)) { lock_drive = !lock_drive; - PrintStatus2000(lmprintf(MSG_282), lock_drive); + PrintStatusTimeout(lmprintf(MSG_282), lock_drive); continue; } // Alt-B => Toggle fake drive detection during bad blocks check @@ -3090,7 +3090,7 @@ relaunch: if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'B')) { detect_fakes = !detect_fakes; WriteSettingBool(SETTING_DISABLE_FAKE_DRIVES_CHECK, !detect_fakes); - PrintStatus2000(lmprintf(MSG_256), detect_fakes); + PrintStatusTimeout(lmprintf(MSG_256), detect_fakes); continue; } // Alt C => Force the update check to be successful @@ -3098,7 +3098,7 @@ relaunch: // check, so that it always succeeds. This is useful for translators. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'C')) { force_update = !force_update; - PrintStatus2000(lmprintf(MSG_259), force_update); + PrintStatusTimeout(lmprintf(MSG_259), force_update); continue; } // Alt-D => Delete the NoDriveTypeAutorun key on exit (useful if the app crashed) @@ -3112,7 +3112,7 @@ relaunch: if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'E')) { allow_dual_uefi_bios = !allow_dual_uefi_bios; WriteSettingBool(SETTING_ENABLE_WIN_DUAL_EFI_BIOS, allow_dual_uefi_bios); - PrintStatus2000(lmprintf(MSG_266), allow_dual_uefi_bios); + PrintStatusTimeout(lmprintf(MSG_266), allow_dual_uefi_bios); SetMBRForUEFI(TRUE); continue; } @@ -3122,7 +3122,7 @@ relaunch: // When enabled, Rufus will list and allow the formatting of USB HDDs. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'F')) { enable_HDDs = !enable_HDDs; - PrintStatus2000(lmprintf(MSG_253), enable_HDDs); + PrintStatusTimeout(lmprintf(MSG_253), enable_HDDs); GetDevices(0); CheckDlgButton(hMainDialog, IDC_ENABLE_FIXED_DISKS, enable_HDDs?BST_CHECKED:BST_UNCHECKED); continue; @@ -3132,7 +3132,7 @@ relaunch: // DD-mode when writing the data. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'I')) { enable_iso = !enable_iso; - PrintStatus2000(lmprintf(MSG_262), enable_iso); + PrintStatusTimeout(lmprintf(MSG_262), enable_iso); if (image_path != NULL) { iso_provided = TRUE; dont_display_image_name = TRUE; @@ -3146,27 +3146,27 @@ relaunch: // a file name). This option allows users to ignore Joliet when using such images. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'J')) { enable_joliet = !enable_joliet; - PrintStatus2000(lmprintf(MSG_257), enable_joliet); + PrintStatusTimeout(lmprintf(MSG_257), enable_joliet); continue; } // Alt K => Toggle Rock Ridge support for ISO9660 images if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'K')) { enable_rockridge = !enable_rockridge; - PrintStatus2000(lmprintf(MSG_258), enable_rockridge); + PrintStatusTimeout(lmprintf(MSG_258), enable_rockridge); 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; WriteSettingBool(SETTING_FORCE_LARGE_FAT32_FORMAT, force_large_fat32); - PrintStatus2000(lmprintf(MSG_254), force_large_fat32); + PrintStatusTimeout(lmprintf(MSG_254), force_large_fat32); GetDevices(0); continue; } // Alt N => Enable NTFS compression if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'N')) { enable_ntfs_compression = !enable_ntfs_compression; - PrintStatus2000(lmprintf(MSG_260), enable_ntfs_compression); + PrintStatusTimeout(lmprintf(MSG_260), enable_ntfs_compression); continue; } // Alt-R => Remove all the registry keys that may have been created by Rufus @@ -3181,7 +3181,7 @@ relaunch: // the target USB drive. If this is enabled, the size check is disabled. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'S')) { size_check = !size_check; - PrintStatus2000(lmprintf(MSG_252), size_check); + PrintStatusTimeout(lmprintf(MSG_252), size_check); GetDevices(0); continue; } @@ -3189,14 +3189,14 @@ relaunch: if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'T')) { preserve_timestamps = !preserve_timestamps; WriteSettingBool(SETTING_PRESERVE_TIMESTAMPS, preserve_timestamps); - PrintStatus2000(lmprintf(MSG_269), preserve_timestamps); + PrintStatusTimeout(lmprintf(MSG_269), preserve_timestamps); continue; } // Alt-U => Use PROPER size units, instead of this whole Kibi/Gibi nonsense if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'U')) { use_fake_units = !use_fake_units; WriteSettingBool(SETTING_USE_PROPER_SIZE_UNITS, !use_fake_units); - PrintStatus2000(lmprintf(MSG_263), !use_fake_units); + PrintStatusTimeout(lmprintf(MSG_263), !use_fake_units); GetDevices(0); continue; } @@ -3209,7 +3209,7 @@ relaunch: if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'W')) { enable_vmdk = !enable_vmdk; WriteSettingBool(SETTING_ENABLE_VMDK_DETECTION, enable_vmdk); - PrintStatus2000(lmprintf(MSG_265), enable_vmdk); + PrintStatusTimeout(lmprintf(MSG_265), enable_vmdk); GetDevices(0); continue; } @@ -3239,8 +3239,9 @@ relaunch: enable_HDDs = previous_enable_HDDs; } CheckDlgButton(hMainDialog, IDC_ENABLE_FIXED_DISKS, enable_HDDs ? BST_CHECKED : BST_UNCHECKED); - PrintStatus2000("Listing of non-USB removable drives", list_non_usb_removable_drives); - uprintf("NOTE: Listing of non-USB removable drives has been %s.", (list_non_usb_removable_drives)?"enabled (CAUTION!)":"disabled"); + PrintStatusTimeout(lmprintf(MSG_287), list_non_usb_removable_drives); + uprintf("%sListing of non-USB removable drives %s", + (list_non_usb_removable_drives)?"CAUTION: ":"", (list_non_usb_removable_drives)?"enabled":"disabled"); if (list_non_usb_removable_drives) uprintf("By using this unofficial cheat mode you forfeit ANY RIGHT to complain if you lose valuable data!"); GetDevices(0); diff --git a/src/rufus.h b/src/rufus.h index 18ac48a7..186e1980 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -66,6 +66,7 @@ #define MAX_GPT_PARTITIONS 128 #define MAX_SECTORS_TO_CLEAR 128 // nb sectors to zap when clearing the MBR/GPT (must be >34) #define MBR_UEFI_MARKER 0x49464555 // 'U', 'E', 'F', 'I', as a 32 bit little endian longword +#define STATUS_MSG_TIMEOUT 3500 // How long should cheat mode messages appear for on the status bar #define WRITE_RETRIES 3 #define NUM_CHECKSUMS 3 // Number of checksum algorithms we support (MD5, SHA1, SHA256) #define FS_DEFAULT FS_FAT32 diff --git a/src/rufus.rc b/src/rufus.rc index 60e5b44b..07e84269 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.896" +CAPTION "Rufus 2.9.897" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,896,0 - PRODUCTVERSION 2,9,896,0 + FILEVERSION 2,9,897,0 + PRODUCTVERSION 2,9,897,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.896" + VALUE "FileVersion", "2.9.897" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.896" + VALUE "ProductVersion", "2.9.897" END END BLOCK "VarFileInfo" From d79264846e1369792d6458e14b0bc6e20aeade27 Mon Sep 17 00:00:00 2001 From: Tmp341 Date: Mon, 9 May 2016 16:12:33 +0300 Subject: [PATCH 68/91] [loc] update Turkish translation to latest * Added and translated two lines. But i don't know, whether or not Turkish localization is 100% synchronized with English. * Closes #750 --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index d4670038..86a6d1d6 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -16081,7 +16081,7 @@ t MSG_286 "Zeroing drive: %0.1f%%" ################################################################################ l "tr-TR" "Turkish (Türkçe)" 0x041F -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -16557,6 +16557,8 @@ t MSG_283 "Geçersiz imza" t MSG_284 "İndirilen yürütülebilir dosyanın dijital imzası eksik." t MSG_285 "İndirilen yürütülebilir dosya '%s' tarafından imzalanmış.\nBu tanımlayabildiğimiz ve kötü niyetli " "etkinliğini belirtebileceğimiz bir imza değil...\nBu dosyayı çalıştırmak istediğinize emin misiniz?" +t MSG_286 "Sürücü sıfırlanıyor: %0.1f%% tamamlandı" +t MSG_287 "USB olmayan çıkarılabilir aygıtlar taranıyor" ################################################################################ l "uk-UA" "Ukrainian (Українська)" 0x0422 diff --git a/src/rufus.rc b/src/rufus.rc index 07e84269..16a60d45 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.897" +CAPTION "Rufus 2.9.898" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,897,0 - PRODUCTVERSION 2,9,897,0 + FILEVERSION 2,9,898,0 + PRODUCTVERSION 2,9,898,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.897" + VALUE "FileVersion", "2.9.898" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.897" + VALUE "ProductVersion", "2.9.898" END END BLOCK "VarFileInfo" From 2aac7729745b4f7166f2c95efb21c350ad5803ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=AErlea=20Alexandru?= Date: Mon, 9 May 2016 17:33:22 +0100 Subject: [PATCH 69/91] [loc] update Romanian translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 86a6d1d6..decb940f 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -12469,7 +12469,7 @@ t MSG_285 "O executável transferido está assinado por '%s'.\nNão é uma assin ################################################################################ l "ro-RO" "Romanian (Română)" 0x0418, 0x0818 -v 1.0.19 +v 1.0.20 b "en-US" g IDD_DIALOG @@ -12881,6 +12881,8 @@ t MSG_283 "Semnătură invalidă" t MSG_284 "Executabilul descărcat nu este semnat." t MSG_285 "Executabilul descărcat este semnat de către '%s'.\nAceasta nu este o semnătură recunoscută și ar putea " "indica o anumită formă de activitate dăunătoare...\nSunteți sigur că doriți să executați acest fișier?" +t MSG_286 "Unitatea zero: %0.1f%% finisat" +t MSG_287 "Detectarea unităților mobile de bază non-USB" ################################################################################ l "ru-RU" "Russian (Русский)" 0x0419, 0x0819 diff --git a/src/rufus.rc b/src/rufus.rc index 16a60d45..95f39e1d 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.898" +CAPTION "Rufus 2.9.899" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,898,0 - PRODUCTVERSION 2,9,898,0 + FILEVERSION 2,9,899,0 + PRODUCTVERSION 2,9,899,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.898" + VALUE "FileVersion", "2.9.899" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.898" + VALUE "ProductVersion", "2.9.899" END END BLOCK "VarFileInfo" From f08afb4492ea5ff9d4f6f9afb300af92dd937d7e Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 9 May 2016 17:40:28 +0100 Subject: [PATCH 70/91] [loc] add missing MSG_286 to translation ChangeLog * Also fix some spacing issues with French translation --- res/localization/ChangeLog.txt | 3 +++ res/localization/rufus.loc | 15 ++++++++------- src/rufus.rc | 10 +++++----- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/res/localization/ChangeLog.txt b/res/localization/ChangeLog.txt index d8a0e30e..e41efbac 100644 --- a/res/localization/ChangeLog.txt +++ b/res/localization/ChangeLog.txt @@ -16,6 +16,9 @@ translation, but always use the English section of rufus.loc as your base. For instance, MSG_114, that was introduced in v1.0.8 is MORE than one line! o Version 1.0.20 (2016.05.09) + - *NEW* MSG_286 "Zeroing drive: %0.1f%% completed" + Used when filling a whole drive with zero bytes, to display progress in percent (e.g. "Zeroing drive: 12.3% completed") + Can be tested with Alt-Z (CAUTION: THIS WILL COMPLETELY ERASE THE SELECTED DRIVE!!) - *NEW* MSG_287 "Detection of non-USB removable drives" Note, this message is followed by either "enabled"/"disabled" (see MSG_250/251) and is similar to MSG_253 The message appears on the status bar and can be tested with Ctrl-Alt-F. diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index decb940f..5f2458f5 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -5237,11 +5237,11 @@ t MSG_095 "Image DD" t MSG_096 "Le système de fichiers sélectionné ne peut pas être utilisé avec ce type d'image ISO. " "Veuillez sélectionner un système de fichiers different file ou une autre ISO." t MSG_097 "'%s' peut seulement être appliqué pour un système de fichiers NTFS." -t MSG_098 "IMPORTANT: Vous essayez d'installer 'Windows To Go', mais votre périphérique de destination ne possède pas " +t MSG_098 "IMPORTANT : Vous essayez d'installer 'Windows To Go', mais votre périphérique de destination ne possède pas " "l'attribut 'FIXE'. A cause de cela, Windows va très probablement geler lors du démarrage, car Microsoft ne l'a pas " "conçu pour fonctionner avec des périphériques qui possèdent l'attribut 'AMOVIBLE'.\n\n" "Voulez vous continuer malgré celà?\n\n" - "Note: L'attribut 'FIXE/AMOVIBLE' est une propriété matérielle qui peut uniquement être changée avec des outils " + "Note : L'attribut 'FIXE/AMOVIBLE' est une propriété matérielle qui peut uniquement être changée avec des outils " "propriétaires, que les fabriquants de périphériques ne fournissent PRESQUE JAMAIS au public..." t MSG_099 "Limitation du système de fichiers" t MSG_100 "Cette image ISO contient un fichier de plus de 4 Go, ce qui est plus que la taille maximum " @@ -5347,7 +5347,7 @@ t MSG_192 "Phase de lecture" t MSG_193 "Téléchargement completé pour %s " t MSG_194 "Impossible de télécharger %s" t MSG_195 "La version par défaut du fichier %s sera utilisée" -t MSG_196 "IMPORTANT: CE PÉRIPHÉRIQUE UTILISE UNE TAILLE DE SECTEUR NON STANDARD !\n\n" +t MSG_196 "IMPORTANT : CE PÉRIPHÉRIQUE UTILISE UNE TAILLE DE SECTEUR NON STANDARD !\n\n" "La majorité des disques utilisent une taille de secteur de 512 octets, mais celui ci utilise une taille de %d octets. " "Dans la majorité des cas, cela veut dire que vous ne POUVEZ PAS démarrer un oridinateur depusi ce disque.\n" "Rufus peut toujours essayer de créer un disque démarrable, mais il n'y a AUCUNE guarantie que cela marchera." @@ -5377,7 +5377,7 @@ t MSG_215 "%s ouvert" t MSG_216 "%s sauvegardé" t MSG_217 "Formatage : %0.1f%% complété" t MSG_218 "Système de fichiers : Tâche %d/%d complétée" -t MSG_219 "Finalisation NTFS: %d%% complété" +t MSG_219 "Finalisation NTFS : %d%% complété" t MSG_220 "Formatage (%s) - durée estimée %d :%02d..." t MSG_221 "Ecriture du label (peut prendre du temps)..." t MSG_222 "Formatage (%s)..." @@ -5399,7 +5399,7 @@ t MSG_237 "Test de défauts : Test avec motif 0x%02X" t MSG_238 "Partitionage (%s)..." t MSG_239 "Effacement des partitions..." t MSG_240 "Téléchargement de %s : Connexion..." -t MSG_241 "Téléchargement: %0.1f%%" +t MSG_241 "Téléchargement : %0.1f%%" t MSG_242 "Echec de téléchargement du fichier" t MSG_243 "Recherche des mises à jour..." t MSG_244 "Mises à jour : Impossible de se connecter" @@ -5425,11 +5425,11 @@ t MSG_263 "Affichage de tailles avec de VRAIES unités" t MSG_264 "Suppression du dossier '%s'" t MSG_265 "Détection de disque VMWare" t MSG_266 "Mode dual UEFI/BIOS" -t MSG_267 "Application de l'image Windows: %0.1f%% complété" +t MSG_267 "Application de l'image Windows : %0.1f%% complété" t MSG_268 "Application de l'image Windows..." t MSG_269 "Préservation des dates de fichiers" t MSG_270 "Debug USB" -t MSG_271 "Calculation des checksums de l'image: %0.1f%% complété" +t MSG_271 "Calculation des checksums de l'image : %0.1f%% complété" t MSG_272 "Calcule les checksums MD5, SHA1 et SHA256 pour l'image sélectionée" t MSG_273 "Change la langue de l'application" t MSG_274 "Image ISOHybrid détectée" @@ -5450,6 +5450,7 @@ t MSG_283 "Signature invalide" t MSG_284 "L'exécutable téléchargé ne possède pas de signature digitale." t MSG_285 "L'exécutable téléchargé est signé par '%s'.\nCe n’est pas une signature que nous reconnaissons et " "pourrait indiquer une activité malicieuse...\nÊtes-vous certain de vouloir lancer ce fichier?" +t MSG_286 "Effacement à zéro : %0.1f%% complété" t MSG_287 "Détection disques non-USB détachables" ################################################################################ diff --git a/src/rufus.rc b/src/rufus.rc index 95f39e1d..62847715 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.899" +CAPTION "Rufus 2.9.900" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,899,0 - PRODUCTVERSION 2,9,899,0 + FILEVERSION 2,9,900,0 + PRODUCTVERSION 2,9,900,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.899" + VALUE "FileVersion", "2.9.900" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.899" + VALUE "ProductVersion", "2.9.900" END END BLOCK "VarFileInfo" From 3227e2e5d1d917e0da6807560356aa3d6fb0a8b7 Mon Sep 17 00:00:00 2001 From: Tiago Rinaldi Date: Tue, 10 May 2016 10:51:02 +0100 Subject: [PATCH 71/91] [loc] update Brazilian Portuguese translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 5f2458f5..a840cf92 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -11575,7 +11575,7 @@ t MSG_285 "Pobrany plik wykonywalny jest podpisany przez '%s'.\nTo nie jest rozp ################################################################################ l "pt-BR" "Portuguese Brazilian (Português do Brasil)" 0x0416 -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -12007,6 +12007,8 @@ t MSG_283 "Assinatura digital inválida" t MSG_284 "O executável baixado não contém uma assinatura digital." t MSG_285 "O executável baixado é assinado por '%s'.\nEsta assinatura não é reconhecida e pode " "indicar alguma forma de atividade maliciosa...\nVocê tem certeza que deseja executar este arquivo?" +t MSG_286 "Zerando HD: %0.1f%% concluído" +t MSG_287 "Detecção de drives não USB removíveis" ################################################################################ l "pt-PT" "Portuguese Standard (Português)" 0x0816 diff --git a/src/rufus.rc b/src/rufus.rc index 62847715..7733d4e2 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.900" +CAPTION "Rufus 2.9.901" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,900,0 - PRODUCTVERSION 2,9,900,0 + FILEVERSION 2,9,901,0 + PRODUCTVERSION 2,9,901,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.900" + VALUE "FileVersion", "2.9.901" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.900" + VALUE "ProductVersion", "2.9.901" END END BLOCK "VarFileInfo" From 7387d891f118a17958321e950952b7f75abd4d2a Mon Sep 17 00:00:00 2001 From: MaKK Date: Tue, 10 May 2016 11:18:33 +0100 Subject: [PATCH 72/91] [loc] update Spanish translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index a840cf92..2d6475fc 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -14693,7 +14693,7 @@ t MSG_285 "Oseba, ki je podpisala preneseno datoteko, je '%s'.\nTa podpis se ne ################################################################################ l "es-ES" "Spanish (Español)" 0x040a, 0x080a, 0x0c0a, 0x100a, 0x140a, 0x180a, 0x1c0a, 0x200a, 0x240a, 0x280a, 0x2c0a, 0x300a, 0x340a, 0x380a, 0x3c0a, 0x400a, 0x440a, 0x480a, 0x4c0a, 0x500a, 0x540a, 0x580a -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -15159,6 +15159,8 @@ t MSG_283 "Firma no válida" t MSG_284 "El ejecutable descargado carece de firma digital." t MSG_285 "El ejecutable descargado está firmado por '%s'.\nNo reconocemos este tipo de firma y podría " "indicar alguna forma de actividad maliciosa...\n¿Está seguro de que quieres ejecutar este fichero?" +t MSG_286 "Borrando a ceros la unidad: %0.1f%% completado" +t MSG_287 "Detección de unidades extraibles no USB" ################################################################################ l "sv-SE" "Swedish (Svenska)" 0x041d, 0x081d diff --git a/src/rufus.rc b/src/rufus.rc index 7733d4e2..92cb7a0b 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.901" +CAPTION "Rufus 2.9.902" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,901,0 - PRODUCTVERSION 2,9,901,0 + FILEVERSION 2,9,902,0 + PRODUCTVERSION 2,9,902,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.901" + VALUE "FileVersion", "2.9.902" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.901" + VALUE "ProductVersion", "2.9.902" END END BLOCK "VarFileInfo" From 887ce483e8d3eb7772f564131143519050b9dec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=BE=D0=BD=D1=81=D1=82=D0=B0=D0=BD=D1=82=D0=B8?= =?UTF-8?q?=D0=BD=20=D0=92?= Date: Tue, 10 May 2016 11:24:31 +0100 Subject: [PATCH 73/91] [loc] update Ukrainian translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 2d6475fc..afbd3dbc 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -16569,7 +16569,7 @@ t MSG_287 "USB olmayan çıkarılabilir aygıtlar taranıyor" ################################################################################ l "uk-UA" "Ukrainian (Українська)" 0x0422 -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -17021,6 +17021,8 @@ t MSG_283 "Невірний підпис" t MSG_284 "У завантаженого файлу відсутній цифровий підпис." t MSG_285 "Завантажений файл підписаний '%s'.\nЦе не той підпис, який визнається, " "що вказує на деякі форми шкідливих дій...\nВи впевнені, що хочете запустити цей файл?" +t MSG_286 "Обнуління диска: %0.1f%% завершено" +t MSG_287 "Виявлення знімних не-USB носіїв" ################################################################################ l "vi-VN" "Vietnamese (Tiếng Việt)" 0x042A diff --git a/src/rufus.rc b/src/rufus.rc index 92cb7a0b..17d8ae18 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.902" +CAPTION "Rufus 2.9.903" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,902,0 - PRODUCTVERSION 2,9,902,0 + FILEVERSION 2,9,903,0 + PRODUCTVERSION 2,9,903,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.902" + VALUE "FileVersion", "2.9.903" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.902" + VALUE "ProductVersion", "2.9.903" END END BLOCK "VarFileInfo" From 5fd158d50b28faa8fd9e292f489f446436a1c4cc Mon Sep 17 00:00:00 2001 From: Aldis Tutins Date: Tue, 10 May 2016 11:26:45 +0100 Subject: [PATCH 74/91] [loc] update Latvian translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index afbd3dbc..2c570d35 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -8671,7 +8671,7 @@ t MSG_285 "다운로드 한 실행 파일은 '%s'에 의해 서명됩니다..\n ################################################################################ l "lv-LV" "Latvian (Latviešu)" 0x0426 -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -9135,6 +9135,8 @@ t MSG_283 "Nederīgs paraksts" t MSG_284 "Ielādētajam izpildfailam ir kļūdains ciparu paraksts." t MSG_285 "Ielādētais izpildfails parakstīts kā '%s'.\nTas ir neatpazīts paraksts un iespējams, " "var radīt aizdomīgas aktivitātes...\nVai tiešām vēlaties izpildīt šo failu?" +t MSG_286 "Nulles disks: %0.1f%% paveikts" +t MSG_287 "neUSB disku noteikšana" ################################################################################ l "lt-LT" "Lithuanian (Lietuvių)" 0x0427 diff --git a/src/rufus.rc b/src/rufus.rc index 17d8ae18..34ebbbb3 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.903" +CAPTION "Rufus 2.9.904" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,903,0 - PRODUCTVERSION 2,9,903,0 + FILEVERSION 2,9,904,0 + PRODUCTVERSION 2,9,904,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.903" + VALUE "FileVersion", "2.9.904" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.903" + VALUE "ProductVersion", "2.9.904" END END BLOCK "VarFileInfo" From 2ecaed9d1d833269fa374b1eb9f74575f0214e4b Mon Sep 17 00:00:00 2001 From: Riku Brander Date: Tue, 10 May 2016 11:29:57 +0100 Subject: [PATCH 75/91] [loc] update Finnish translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 2c570d35..88b5ad2b 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -4585,7 +4585,7 @@ t MSG_286 "Nullen schrijven : %0.1f%% voltooid" ################################################################################ l "fi-FI" "Finnish (Suomi)" 0x040B -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -5031,6 +5031,8 @@ t MSG_283 "Epäkelpo allekirjoitus" t MSG_284 "Ladatusta tiedostosta puuttuu digitaalinen allekirjoitus." t MSG_285 "Ladatun tiedoston on allekirjoittanut '%s'.\nEmme tunnista kyseistä allekirjoitusta, mikä " "saattaa viitata haitalliseen toimintaan...\nHaluatko varmasti suorittaa tämän tiedoston?" +t MSG_286 "Nollataan asemaa: %0.1f%% suoritettu" +t MSG_287 "Ei-USB-liitäntäisten irroitettavien asemien tunnistus" ################################################################################ l "fr-FR" "French (Français)" 0x040c, 0x080c, 0x0c0c, 0x100c, 0x140c, 0x180c, 0x1c0c, 0x200c, 0x240c, 0x280c, 0x2c0c, 0x300c, 0x340c, 0x380c, 0xe40c diff --git a/src/rufus.rc b/src/rufus.rc index 34ebbbb3..457c21ed 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.904" +CAPTION "Rufus 2.9.905" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,904,0 - PRODUCTVERSION 2,9,904,0 + FILEVERSION 2,9,905,0 + PRODUCTVERSION 2,9,905,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.904" + VALUE "FileVersion", "2.9.905" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.904" + VALUE "ProductVersion", "2.9.905" END END BLOCK "VarFileInfo" From e1cd763dd210f2f4e8d089ddef81251b37faee92 Mon Sep 17 00:00:00 2001 From: Thilo Langbein Date: Tue, 10 May 2016 11:31:50 +0100 Subject: [PATCH 76/91] [loc] update German translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 88b5ad2b..7fd3a30c 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -5457,7 +5457,7 @@ t MSG_287 "Détection disques non-USB détachables" ################################################################################ l "de-DE" "German (Deutsch)" 0x0407, 0x0807, 0x0c07, 0x1007, 0x1407 -v 1.0.19 +v 1.0.20 b "en-US" g IDD_DIALOG @@ -5899,6 +5899,8 @@ t MSG_283 "Ungültige Signatur" t MSG_284 "Die heruntergeladene ausführbare Datei verfügt über keine Signatur." t MSG_285 "Die heruntergeladene ausführbare Datei ist von '%s' signiert.\nDiese Signatur ist nicht akzeptiert und könnte " "auf eine böswillige Aktivität hindeuten...\nSind Sie sicher, dass Sie diese Datei ausführen wollen?" +t MSG_286 "Überschreiben mit Nullen: %0.1f%% fertiggestellt" +t MSG_287 "Erkennung nicht wechselbarer USB-Laufwerke" ################################################################################ l "el-GR" "Greek (Ελληνικά)" 0x0408 diff --git a/src/rufus.rc b/src/rufus.rc index 457c21ed..5cd3a669 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.905" +CAPTION "Rufus 2.9.906" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,905,0 - PRODUCTVERSION 2,9,905,0 + FILEVERSION 2,9,906,0 + PRODUCTVERSION 2,9,906,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.905" + VALUE "FileVersion", "2.9.906" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.905" + VALUE "ProductVersion", "2.9.906" END END BLOCK "VarFileInfo" From 55b01502ffa69bc1a350ba34c3f01d04d546a3b7 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 10 May 2016 11:33:31 +0100 Subject: [PATCH 77/91] [misc] update ChangeLog --- ChangeLog.txt | 8 ++++++++ src/rufus.rc | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index a2bbd4fc..93e817c6 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,11 @@ +o Version 2.9 (2016.05.??) + Add ARM support for UEFI:NTFS + Fix UEFI:NTFS support for HP and Gigabyte firmwares (with thanks to Rod Smith and linnaea) + Fix unwanted listing of some internal removable drives + Fix missing default cluster size default on exFAT for >32GB drives + Fix the non-removal of the commandline hogger in some corner cases + Use "modern" file selection dialog on Vista or later (if you can spot the difference, good for you...) + o Version 2.8 (2016.03.22) Enable listing of non-USB card readers (EXPERIMENTAL) Major speed improvement for checksum computation diff --git a/src/rufus.rc b/src/rufus.rc index 5cd3a669..1c94f0fd 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.906" +CAPTION "Rufus 2.9.907" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,906,0 - PRODUCTVERSION 2,9,906,0 + FILEVERSION 2,9,907,0 + PRODUCTVERSION 2,9,907,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.906" + VALUE "FileVersion", "2.9.907" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.906" + VALUE "ProductVersion", "2.9.907" END END BLOCK "VarFileInfo" From 0915370cc8ea9db07385f5927f5def4afd576ae3 Mon Sep 17 00:00:00 2001 From: Dinis Medeiros Date: Tue, 10 May 2016 11:36:01 +0100 Subject: [PATCH 78/91] [loc] update Portuguese (Standard) translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 7fd3a30c..e9ed0b1a 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -12018,7 +12018,7 @@ t MSG_287 "Detecção de drives não USB removíveis" ################################################################################ l "pt-PT" "Portuguese Standard (Português)" 0x0816 -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -12475,6 +12475,8 @@ t MSG_283 "Assinatura inválida" t MSG_284 "No executável transferido está a faltar uma assinatura digital." t MSG_285 "O executável transferido está assinado por '%s'.\nNão é uma assinatura reconhecida e " "poderá indicar algum tipo de actividade mal intencionada...\nTem certeza de que deseja executar este ficheiro?" +t MSG_286 "A limpar disco: %0.1f%% concluído" +t MSG_287 "Detecção de unidades removíveis não-USB" ################################################################################ l "ro-RO" "Romanian (Română)" 0x0418, 0x0818 diff --git a/src/rufus.rc b/src/rufus.rc index 1c94f0fd..2d544cdc 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.907" +CAPTION "Rufus 2.9.908" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,907,0 - PRODUCTVERSION 2,9,907,0 + FILEVERSION 2,9,908,0 + PRODUCTVERSION 2,9,908,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.907" + VALUE "FileVersion", "2.9.908" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.907" + VALUE "ProductVersion", "2.9.908" END END BLOCK "VarFileInfo" From e34d2ab1260647acc23f562d6888c89655979b92 Mon Sep 17 00:00:00 2001 From: Sopor Date: Tue, 10 May 2016 11:38:27 +0100 Subject: [PATCH 79/91] [loc] update Swedish translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index e9ed0b1a..d8ca5624 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -15172,7 +15172,7 @@ t MSG_287 "Detección de unidades extraibles no USB" ################################################################################ l "sv-SE" "Swedish (Svenska)" 0x041d, 0x081d -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -15634,6 +15634,8 @@ t MSG_283 "Ogiltig signatur" t MSG_284 "Den nedladdade körbara filen saknar digital signatur." t MSG_285 "Den nedladdade körbara filen är signerad av '%s'.\nDetta är inte en signatur vi känner igen och " "detta kan tyda på någon form av skadlig aktivitet...\nÄr du säker på att du vill köra filen?" +t MSG_286 "Nollställer enheten: %0.1f%% klart" +t MSG_287 "Visar även icke flyttbara USB-enheter" ################################################################################ l "th-TH" "Thai (ไทย)" 0x041e diff --git a/src/rufus.rc b/src/rufus.rc index 2d544cdc..6db608c4 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.908" +CAPTION "Rufus 2.9.909" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,908,0 - PRODUCTVERSION 2,9,908,0 + FILEVERSION 2,9,909,0 + PRODUCTVERSION 2,9,909,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.908" + VALUE "FileVersion", "2.9.909" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.908" + VALUE "ProductVersion", "2.9.909" END END BLOCK "VarFileInfo" From 7c2088fee6f660822ef0e6cc24385e5e16729897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=98=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2?= Date: Tue, 10 May 2016 11:40:04 +0100 Subject: [PATCH 80/91] [loc] update Russian translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index d8ca5624..8f2be9e2 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -12897,7 +12897,7 @@ t MSG_287 "Detectarea unităților mobile de bază non-USB" ################################################################################ l "ru-RU" "Russian (Русский)" 0x0419, 0x0819 -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -13330,6 +13330,8 @@ t MSG_283 "Неверная подпись" t MSG_284 "У загруженного файла отсутствует цифровая подпись." t MSG_285 "Загруженный файл подписан '%s'.\nЭто не та подпись, которая признается, что " "указывает на некоторые формы вредоносных действий...\nВы уверены, что хотите запустить этот файл?" +t MSG_286 "Обнуление диска: %0.1f%% выполнено" +t MSG_287 "Выявление не-USB съемных дисков" ################################################################################ l "sr-SP" "Serbian (Srpski)" 0x241a, 0x081a, 0x181a, 0x2c1a, 0x701a, 0x7c1a diff --git a/src/rufus.rc b/src/rufus.rc index 6db608c4..53c9d63e 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.909" +CAPTION "Rufus 2.9.910" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,909,0 - PRODUCTVERSION 2,9,909,0 + FILEVERSION 2,9,910,0 + PRODUCTVERSION 2,9,910,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.909" + VALUE "FileVersion", "2.9.910" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.909" + VALUE "ProductVersion", "2.9.910" END END BLOCK "VarFileInfo" From dc1b8bd94d7581f58d828f2bfd90a184ec7c930f Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Tue, 10 May 2016 14:41:05 +0800 Subject: [PATCH 81/91] [loc] update Chinese (Traditional) translation to latest * Closes #751 --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 8f2be9e2..38e4bd0c 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -2388,7 +2388,7 @@ t MSG_285 "已下载的可执行文件是由 '%s' 签署的。\n这个不是我 ################################################################################ l "zh-TW" "Chinese Traditional (正體中文)" 0x0404, 0x0c04, 0x1404, 0x7c04 -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -2798,6 +2798,8 @@ t MSG_282 "鎖定 USB 磁碟" t MSG_283 "無效簽章" t MSG_284 "下載的檔案缺少數位簽章。" t MSG_285 "下載的檔案簽章者為: '%s'.\n本軟體未使用此簽章,代表檔案可能已遭受病毒感染...\n是否要執行檔案?" +t MSG_286 "寫入零: 已完成 %0.1f%%" +t MSG_287 "偵測非USB可移除磁碟" ################################################################################ l "hr-HR" "Croatian (Hrvatski)" 0x041a, 0x081a, 0x101a diff --git a/src/rufus.rc b/src/rufus.rc index 53c9d63e..e43f999e 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.910" +CAPTION "Rufus 2.9.911" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,910,0 - PRODUCTVERSION 2,9,910,0 + FILEVERSION 2,9,911,0 + PRODUCTVERSION 2,9,911,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.910" + VALUE "FileVersion", "2.9.911" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.910" + VALUE "ProductVersion", "2.9.911" END END BLOCK "VarFileInfo" From 7d5d95efbfb99467b208acf571ad10c323aee207 Mon Sep 17 00:00:00 2001 From: Sippapas Wangsri Date: Tue, 10 May 2016 11:45:29 +0100 Subject: [PATCH 82/91] [loc] update Thai translation to latest --- res/localization/rufus.loc | 5 +++-- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 38e4bd0c..00cec61e 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -15643,7 +15643,7 @@ t MSG_287 "Visar även icke flyttbara USB-enheter" ################################################################################ l "th-TH" "Thai (ไทย)" 0x041e -v 1.0.19 +v 1.0.20 # Main dialog g IDD_DIALOG @@ -16098,7 +16098,8 @@ t MSG_283 "ใบรับรองผิดพลาด" t MSG_284 "ไฟล์ที่ดาวน์โหลดมาไม่มีการรับรองดิจิทัล" t MSG_285 "ไฟล์ที่ดาวน์โหลดมาถูกรับรองโดย '%s'.\nซึ่งไม่ใช่การรับรองที่เรารู้จัก ซึ่งอาจ" "ทำให้เกิดกิจกรรมที่เกิดภัยคุกคามได้...\nคุณต้องการจะเปิดไฟล์นี้หรือไม่?" -t MSG_286 "Zeroing drive: %0.1f%%" +t MSG_286 "กำลังเขียนไดร์ฟด้วย zero byte: %0.1f%%" +t MSG_287 "กำลังตรวจสอบไดร์ฟที่ไม่ใช่ USB" ################################################################################ l "tr-TR" "Turkish (Türkçe)" 0x041F diff --git a/src/rufus.rc b/src/rufus.rc index e43f999e..5f3d40bf 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.911" +CAPTION "Rufus 2.9.912" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,911,0 - PRODUCTVERSION 2,9,911,0 + FILEVERSION 2,9,912,0 + PRODUCTVERSION 2,9,912,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.911" + VALUE "FileVersion", "2.9.912" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.911" + VALUE "ProductVersion", "2.9.912" END END BLOCK "VarFileInfo" From 16690df5cb920fe7b04885bc4e75f5b08fe64069 Mon Sep 17 00:00:00 2001 From: Zia Azimi Date: Tue, 10 May 2016 13:54:57 +0430 Subject: [PATCH 83/91] [loc] update Persian translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 00cec61e..6b528798 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -10562,7 +10562,7 @@ t MSG_285 "Den nedlastede programfil er signert av '%s'.\nDette er en signatur v ################################################################################ l "fa-IR" "Persian (فارسی)" 0x0429 a "r" -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -11105,6 +11105,8 @@ t MSG_283 "امضای نامعتبر" t MSG_284 "فایل اجرایی دانلود شده امضای دیجیتال ندارد." t MSG_285 "این فایل اجرایی دانلود شده، توسط '%s' امضا شده است.\n ما این امضا را نمی‌شناسیم و " "ناشناس بودن آن ممکن است نشانه نوعی فعالیت خرابکارانه باشد...\nآیا مطمئن هستید می‌خواهید این فایل را اجرا کنید؟" +t MSG_286 "درحال بازنويسي درايو با داده صفر؛ درصد پيشرفت: %0.1f%%" +t MSG_287 "شناسايي درايوهاي غير USB" ################################################################################ l "pl-PL" "Polish (Polski)" 0x0415 diff --git a/src/rufus.rc b/src/rufus.rc index 5f3d40bf..5b8b7671 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.912" +CAPTION "Rufus 2.9.913" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,912,0 - PRODUCTVERSION 2,9,912,0 + FILEVERSION 2,9,913,0 + PRODUCTVERSION 2,9,913,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.912" + VALUE "FileVersion", "2.9.913" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.912" + VALUE "ProductVersion", "2.9.913" END END BLOCK "VarFileInfo" From bf73a6c451e0ac765fea594bf26c018b10af878c Mon Sep 17 00:00:00 2001 From: Roberto Boriotti Date: Tue, 10 May 2016 11:51:45 +0100 Subject: [PATCH 84/91] [loc] update Italian translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 6b528798..56babc34 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -7312,7 +7312,7 @@ t MSG_285 "Berkas exe yang diunduh ditandatangani oleh '%s'.\nTanda tangan ini " ################################################################################ l "it-IT" "Italian (Italiano)" 0x0410, 0x0810 -v 1.0.19 +v 1.0.20 b "en-US" g IDD_DIALOG @@ -7740,6 +7740,8 @@ t MSG_283 "Firma non valida" t MSG_284 "L'eseguibile scaricato non ha una firma digitale." t MSG_285 "L'eseguibile scaricato è firmato da '%s'.\nQuesta non è una firma riconosciuta e potrebbe " "indicare qualche forma di attività malevola.\nSei sicuro di voler eseguire questo file?" +t MSG_286 "Azzeramento disco: %0.1f%% completato" +t MSG_287 "Rilevamento di unità rimuovibili non USB" ###################################################################### l "ja-JP" "Japanese (日本語)" 0x0411 diff --git a/src/rufus.rc b/src/rufus.rc index 5b8b7671..ee1634e9 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.913" +CAPTION "Rufus 2.9.914" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,913,0 - PRODUCTVERSION 2,9,913,0 + FILEVERSION 2,9,914,0 + PRODUCTVERSION 2,9,914,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.913" + VALUE "FileVersion", "2.9.914" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.913" + VALUE "ProductVersion", "2.9.914" END END BLOCK "VarFileInfo" From 1747df09d9023f29a50a8f88741e2e0ffb3a056f Mon Sep 17 00:00:00 2001 From: Sippapas Wangsri Date: Tue, 10 May 2016 11:59:37 +0100 Subject: [PATCH 85/91] [loc] additional Thai translation updates --- res/localization/rufus.loc | 6 +++--- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 56babc34..f65a86b6 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -15782,8 +15782,8 @@ t MSG_045 "USB Storage Device (Generic)" t MSG_046 "%s (Disk %d) [%s]" # Used when a drive is detected that contains more than one partition t MSG_047 "พบหลายพาร์ทิชั่น" -t MSG_048 "Rufus - Flushing buffers" -t MSG_049 "Rufus - Cancellation" +t MSG_048 "Rufus - กำลังล้างบัฟเฟอร์" +t MSG_049 "Rufus - กำลังยกเลิกการดำเนินการ" # Error messages t MSG_050 "สำเร็จ" @@ -16070,7 +16070,7 @@ t MSG_262 "การรองรับ ISO" t MSG_263 "ใช้หน่วยของขนาดตามจริง (เช่น 1KB คือ 1024 bytes)" t MSG_264 "กำลังลบไดเรคทอรี่ '%s'" t MSG_265 "กำลังตรวจหาดิสก์ VMWare" -t MSG_266 "Dual UEFI/BIOS mode" +t MSG_266 "ระบบบูตคู่ UEFI/BIOS" t MSG_267 "กำลังใช้อิมเมจ Windows: %0.1f%%" t MSG_268 "กำลังใช้อิมเมจ Windows..." t MSG_269 "Preserve timestamps" diff --git a/src/rufus.rc b/src/rufus.rc index ee1634e9..b0d3f1c2 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.914" +CAPTION "Rufus 2.9.915" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,914,0 - PRODUCTVERSION 2,9,914,0 + FILEVERSION 2,9,915,0 + PRODUCTVERSION 2,9,915,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.914" + VALUE "FileVersion", "2.9.915" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.914" + VALUE "ProductVersion", "2.9.915" END END BLOCK "VarFileInfo" From e44c35613a5e01378f08df0c4245a86e2e8ff4f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elvin=20M=C9=99likov?= Date: Tue, 10 May 2016 19:41:10 +0100 Subject: [PATCH 86/91] [loc] update Azerbaijani translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index f65a86b6..06cc74dd 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -989,7 +989,7 @@ t MSG_281 "(فضلا اختر صورة)" ################################################################################ l "az-AZ" "Azerbaijani (Azərbaycanca)" 0x042c, 0x782c -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -1465,6 +1465,8 @@ t MSG_283 "Keçərsiz imza" t MSG_284 "Yüklənən aparıla faylın rəqəmsal imzası çatmır." t MSG_285 "Yüklənən aparıla bilən fayl '%s' tərəfindən imzalanmışdır.\nBu tərifə və pis niyyətli " "səmərəliliyini qeyd edəcəyimiz bir imza deyil...\nBu faylı işlətmək istədiyinizə əminsiniz?" +t MSG_286 "Sürücü sıfırlama: %0.1f%% tamamlandı" +t MSG_287 "Olmayan çıxarılabilən USB sürücülər" ###################################################################### l "bg-BG" "Bulgarian (Български)" 0x0402 diff --git a/src/rufus.rc b/src/rufus.rc index b0d3f1c2..90cda0a7 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.915" +CAPTION "Rufus 2.9.916" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,915,0 - PRODUCTVERSION 2,9,915,0 + FILEVERSION 2,9,916,0 + PRODUCTVERSION 2,9,916,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.915" + VALUE "FileVersion", "2.9.916" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.915" + VALUE "ProductVersion", "2.9.916" END END BLOCK "VarFileInfo" From ddd019f2e68fbd8ef5079e02a54302f859edfdb7 Mon Sep 17 00:00:00 2001 From: Arif Budiman Date: Tue, 10 May 2016 19:42:21 +0100 Subject: [PATCH 87/91] [loc] update Indonesian translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 06cc74dd..ae4e1d10 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -6829,7 +6829,7 @@ t MSG_286 "Meghajtó kinullázása: %0.1f%% kész" ################################################################################ l "id-ID" "Indonesian (Bahasa Indonesia)" 0x0421 -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -7311,6 +7311,8 @@ t MSG_284 "Berkas exe yang diunduh memiliki tanda tangan digital yang salah." t MSG_285 "Berkas exe yang diunduh ditandatangani oleh '%s'.\nTanda tangan ini " "tidak kami kenali dan bisa menjadi pertanda dari aktivitas berbahaya...\n" "Apakah Anda yakin ingin menjalankan berkas ini?" +t MSG_286 "Mengosongkan perangkat: %0.1f%% selesai" +t MSG_287 "Deteksi selain perangkat USB yang dapat dilepas" ################################################################################ l "it-IT" "Italian (Italiano)" 0x0410, 0x0810 diff --git a/src/rufus.rc b/src/rufus.rc index 90cda0a7..2aa25d06 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.916" +CAPTION "Rufus 2.9.917" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,916,0 - PRODUCTVERSION 2,9,916,0 + FILEVERSION 2,9,917,0 + PRODUCTVERSION 2,9,917,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.916" + VALUE "FileVersion", "2.9.917" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.916" + VALUE "ProductVersion", "2.9.917" END END BLOCK "VarFileInfo" From 387ae477cbb7227fda0ec01af6d8e747c379f7c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Erik=20Drangev=C3=A5g?= Date: Wed, 11 May 2016 11:31:49 +0100 Subject: [PATCH 88/91] [loc] update Norwegian translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index ae4e1d10..9e00e646 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -10094,7 +10094,7 @@ t MSG_286 "Mensifarkan pemacu: %0.1f%% selesai" ################################################################################ l "nb-NO" "Norwegian (Norsk)" 0x0414 -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -10564,6 +10564,8 @@ t MSG_283 "Ugyldig signatur" t MSG_284 "Den nedlastede programfil mangler en digital signatur." t MSG_285 "Den nedlastede programfil er signert av '%s'.\nDette er en signatur vi ikke gjenkjenner, og kan " "indikere en form for skadelig aktivitet...\nEr du sikker på at du vil kjøre denne filen?" +t MSG_286 "Skriver 0-er til stasjon: %0.1f%% ferdig" +t MSG_287 "Oppdagelse av ikke-USB flyttbare stasjoner" ################################################################################ l "fa-IR" "Persian (فارسی)" 0x0429 diff --git a/src/rufus.rc b/src/rufus.rc index 2aa25d06..6fe70999 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.917" +CAPTION "Rufus 2.9.918" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,917,0 - PRODUCTVERSION 2,9,917,0 + FILEVERSION 2,9,918,0 + PRODUCTVERSION 2,9,918,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.917" + VALUE "FileVersion", "2.9.918" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.917" + VALUE "ProductVersion", "2.9.918" END END BLOCK "VarFileInfo" From a05d0a5ac2392d6bc6e66169b0a6caf56483c324 Mon Sep 17 00:00:00 2001 From: Gintaras Venslovas Date: Thu, 12 May 2016 13:03:55 +0100 Subject: [PATCH 89/91] [loc] update Lithuanian translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 9e00e646..e6a09456 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -9152,7 +9152,7 @@ t MSG_287 "neUSB disku noteikšana" ################################################################################ l "lt-LT" "Lithuanian (Lietuvių)" 0x0427 -v 1.0.19 +v 1.0.20 b "en-US" # Main dialog @@ -9610,6 +9610,8 @@ t MSG_283 "Negaliojantis parašas" t MSG_284 "Atsiųstas vykdomasis failas neturi skaitmeninio parašo." t MSG_285 "Atsiųstą vykdomąjį failą pasirašė '%s'.\nŠio parašo mes neatpažįstame ir tai gali " "būti tam tikros kenkėjiškos veiklos požymis...\nAr jūs tikrai norite vykdyti šį failą?" +t MSG_286 "Nulinamas diskas: %0.1f%% baigta" +t MSG_287 "Ne USB keičiamų diskų aptikimas" ################################################################################ l "ms-MY" "Malay (Bahasa Malaysia)" 0x043e, 0x083e diff --git a/src/rufus.rc b/src/rufus.rc index 6fe70999..26bac0e4 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.918" +CAPTION "Rufus 2.9.919" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,918,0 - PRODUCTVERSION 2,9,918,0 + FILEVERSION 2,9,919,0 + PRODUCTVERSION 2,9,919,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.918" + VALUE "FileVersion", "2.9.919" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.918" + VALUE "ProductVersion", "2.9.919" END END BLOCK "VarFileInfo" From 0bfce8655e97125e117721760a735880a26d4f77 Mon Sep 17 00:00:00 2001 From: Piotr Halama Date: Thu, 12 May 2016 13:05:06 +0100 Subject: [PATCH 90/91] [loc] update Polish translation to latest --- res/localization/rufus.loc | 4 +++- src/rufus.rc | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index e6a09456..21471c87 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -11120,7 +11120,7 @@ t MSG_287 "شناسايي درايوهاي غير USB" ################################################################################ l "pl-PL" "Polish (Polski)" 0x0415 -v 1.0.19 +v 1.0.20 b "en-US" # my info: 6.9.2015,22:39 @@ -11592,6 +11592,8 @@ t MSG_283 "Nieprawidłowa sygnatura" t MSG_284 "Pobrany plik wykonywalny nie posiada cyfrowej sygnatury." t MSG_285 "Pobrany plik wykonywalny jest podpisany przez '%s'.\nTo nie jest rozpoznawana przez nas sygnatura i może " "wskazywać na pewne formy złośliwych zachowań...\nCzy na pewno chcesz uruchomić ten plik?" +t MSG_286 "Zerowanie dysku: ukończono %0.1f%%" +t MSG_287 "Wykrywanie dysków wymiennych nie-USB" ################################################################################ l "pt-BR" "Portuguese Brazilian (Português do Brasil)" 0x0416 diff --git a/src/rufus.rc b/src/rufus.rc index 26bac0e4..3b64c156 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.919" +CAPTION "Rufus 2.9.920" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,919,0 - PRODUCTVERSION 2,9,919,0 + FILEVERSION 2,9,920,0 + PRODUCTVERSION 2,9,920,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.919" + VALUE "FileVersion", "2.9.920" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.919" + VALUE "ProductVersion", "2.9.920" END END BLOCK "VarFileInfo" From 2c3745f459b45198c96e0ba1b0bf0555f8c792f3 Mon Sep 17 00:00:00 2001 From: Matej Horvat Date: Thu, 12 May 2016 13:11:26 +0100 Subject: [PATCH 91/91] [loc] update Slovenian translation to latest --- res/localization/rufus.loc | 8 +++++--- src/rufus.rc | 10 +++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 21471c87..dde86e8d 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -77,7 +77,7 @@ # l "ru-RU" "Russian (Русский)" 0x0419 # l "sr-SP" "Serbian (Latin)" 0x241a # l "sk-SK" "Slovak (Slovensky)" 0x041B -# l "sl-SI" "Slovene (Slovenščina)" 0x0424 +# l "sl-SI" "Slovenian (Slovenščina)" 0x0424 # l "es-ES" "Spanish (Español)" 0x040a # l "sv-SE" "Swedish (Svenska)" 0x041d # l "th-TH" "Thai (ไทย)" 0x041e @@ -14277,8 +14277,8 @@ t MSG_285 "Stiahnutý inštalátor podpísal '%s'.\nTento podpis nebol rozoznan "nejakú formu škodlivej aktivity...\nSte si istý, že chcete spustiť tento súbor?" ################################################################################ -l "sl-SI" "Slovene (Slovenščina)" 0x0424 -v 1.0.19 +l "sl-SI" "Slovenian (Slovenščina)" 0x0424 +v 1.0.20 b "en-US" # Main dialog @@ -14716,6 +14716,8 @@ t MSG_283 "Neveljaven podpis" t MSG_284 "Prenesena datoteka nima digitalnega podpisa." t MSG_285 "Oseba, ki je podpisala preneseno datoteko, je '%s'.\nTa podpis se ne ujema s pričakovanim, kar lahko pomeni, " "da je to zlonamerna datoteka, ki jo vam je nekdo podtaknil.\nAli ste prepričani, da jo želite zagnati?" +t MSG_286 "Zapolnjujem nosilec z ničlami: %0.1f%%" +t MSG_287 "Zaznava neodstranljivih nosilcev" ################################################################################ l "es-ES" "Spanish (Español)" 0x040a, 0x080a, 0x0c0a, 0x100a, 0x140a, 0x180a, 0x1c0a, 0x200a, 0x240a, 0x280a, 0x2c0a, 0x300a, 0x340a, 0x380a, 0x3c0a, 0x400a, 0x440a, 0x480a, 0x4c0a, 0x500a, 0x540a, 0x580a diff --git a/src/rufus.rc b/src/rufus.rc index 3b64c156..9fb533f5 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.9.920" +CAPTION "Rufus 2.9.921" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,9,920,0 - PRODUCTVERSION 2,9,920,0 + FILEVERSION 2,9,921,0 + PRODUCTVERSION 2,9,921,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.9.920" + VALUE "FileVersion", "2.9.921" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.9.920" + VALUE "ProductVersion", "2.9.921" END END BLOCK "VarFileInfo"