diff --git a/configure b/configure index 6fb9a9ef..284af7b2 100755 --- 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 3.1. +# Generated by GNU Autoconf 2.69 for rufus 3.2. # # Report bugs to . # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='rufus' PACKAGE_TARNAME='rufus' -PACKAGE_VERSION='3.1' -PACKAGE_STRING='rufus 3.1' +PACKAGE_VERSION='3.2' +PACKAGE_STRING='rufus 3.2' PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues' PACKAGE_URL='https://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 3.1 to adapt to many kinds of systems. +\`configure' configures rufus 3.2 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 3.1:";; + short | recursive ) echo "Configuration of rufus 3.2:";; 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 3.1 +rufus configure 3.2 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 3.1, which was +It was created by rufus $as_me 3.2, 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='3.1' + VERSION='3.2' cat >>confdefs.h <<_ACEOF @@ -4481,7 +4481,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 3.1, which was +This file was extended by rufus $as_me 3.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4535,7 +4535,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 3.1 +rufus config.status 3.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 259f1bd6..5cca5391 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([rufus], [3.1], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.akeo.ie]) +AC_INIT([rufus], [3.2], [https://github.com/pbatard/rufus/issues], [rufus], [https://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/appstore/AppxManifest.xml b/res/appstore/AppxManifest.xml index 995d3f74..50ba0f02 100644 --- a/res/appstore/AppxManifest.xml +++ b/res/appstore/AppxManifest.xml @@ -8,7 +8,7 @@ for an interesting struggle, when you also happen to have a comma in one of the fields... --> diff --git a/res/appstore/packme.cmd b/res/appstore/packme.cmd index 57020955..66a8345f 100644 --- a/res/appstore/packme.cmd +++ b/res/appstore/packme.cmd @@ -1,5 +1,5 @@ @echo off -set VERSION=3.1 +set VERSION=3.2 rem Make sure you don't have anything you don't want included in the package, as anything residing in the rem current directory will be included, including any previous .appx, which makes for nice recursion... diff --git a/res/localization/ChangeLog.txt b/res/localization/ChangeLog.txt index b088e23a..d432b8aa 100644 --- a/res/localization/ChangeLog.txt +++ b/res/localization/ChangeLog.txt @@ -15,7 +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.23 (2018.??.??) +o Version 1.0.24 (2018.??.??) + - *NEW* MSG_087 + - *NEW* MSG_172 + +o Version 1.0.23 (2018.03.27) - All positioning ('m', 's') has now been removed as well as some controls, for the 3.0 UI redesign - *NEW* IDS_DRIVE_PROPERTIES_TXT "Drive Properties" - *NEW* IDS_BOOT_SELECTION_TXT "Boot selection" diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index 00fd8bdb..386e3324 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -208,7 +208,7 @@ t MSG_032 "UEFI (non CSM)" t MSG_033 "BIOS or UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d pass" -t MSG_035 "%d passes" +t MSG_035 "%d passes %s" t MSG_036 "ISO Image" t MSG_037 "Application" t MSG_038 "Abort" @@ -277,6 +277,7 @@ t MSG_084 "This ISO image seems to use an obsolete version of '%s'.\n" "'%s' exists there, it will be reused automatically." t MSG_085 "Downloading '%s'" t MSG_086 "No image selected" +t MSG_087 "for %s devices" t MSG_088 "Image is too big" t MSG_089 "The image is too big for the selected target." t MSG_090 "Unsupported ISO" @@ -386,6 +387,7 @@ t MSG_169 "Create an extra hidden partition and try to align partitions boundari "This can improve boot detection for older BIOSes" t MSG_170 "Enable the listing of USB Hard Drive enclosures. USE AT YOUR OWN RISKS!!!" t MSG_171 "Start the formatting operation.\nThis will DESTROY any data on the target!" +t MSG_172 "Invalid download signature" t MSG_173 "Click to select..." # The following will appear in the about dialog t MSG_174 "Rufus - The Reliable USB Formatting Utility" @@ -684,7 +686,7 @@ t MSG_032 "UEFI (بدون CSM)" t MSG_033 "BIOS أو UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d تجاوز" -t MSG_035 "%d تجاوزات" +t MSG_035 "%d تجاوزات %s" t MSG_036 "ISO صورة" t MSG_037 "تطبيق" t MSG_038 "توقف" @@ -1136,7 +1138,7 @@ t MSG_032 "UEFI (yox CSM)" t MSG_033 "BIOS və ya UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d Keçid" -t MSG_035 "%d Keçid" +t MSG_035 "%d Keçid %s" t MSG_036 "ISO Əksi" t MSG_037 "Proqram" t MSG_038 "İmtina et" @@ -1583,7 +1585,7 @@ t MSG_030 "%s (Стандартно)" #t MSG_033 "%s дялова схема за UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d Пробег" -t MSG_035 "%d Пробега" +t MSG_035 "%d Пробега %s" t MSG_036 "ISO образ" t MSG_037 "Приложение" t MSG_038 "Прекрати" @@ -2028,7 +2030,7 @@ t MSG_032 "UEFI (非 CSM)" t MSG_033 "BIOS 或 UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d 遍" -t MSG_035 "%d 遍" +t MSG_035 "%d 遍 %s" t MSG_036 "ISO 镜像" t MSG_037 "程序" t MSG_038 "中止" @@ -2471,7 +2473,7 @@ t MSG_032 "UEFI (無 CSM)" t MSG_033 "BIOS 或 UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d 回" -t MSG_035 "%d 回" +t MSG_035 "%d 回 %s" t MSG_036 "ISO 映像" t MSG_037 "程式" t MSG_038 "終止" @@ -2885,7 +2887,7 @@ t MSG_032 "UEFI (bez CSM)" t MSG_033 "BIOS ili UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d prolaz" -t MSG_035 "%d prolaza" +t MSG_035 "%d prolaza %s" t MSG_036 "ISO slika" t MSG_037 "Aplikacija" t MSG_038 "Prekini" @@ -3340,7 +3342,7 @@ t MSG_032 "UEFI (ne CSM)" t MSG_033 "BIOS nebo UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d pokus" -t MSG_035 "%d pokusy" +t MSG_035 "%d pokusy %s" t MSG_036 "Obraz ISO" t MSG_037 "Aplikace" t MSG_038 "Přerušit" @@ -3792,7 +3794,7 @@ t MSG_032 "UEFI (ikke CSM)" t MSG_033 "BIOS eller UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d gennemløb" -t MSG_035 "%d gennemløb" +t MSG_035 "%d gennemløb %s" t MSG_036 "ISO-image" t MSG_037 "Applikation" t MSG_038 "Annuller" @@ -4228,7 +4230,7 @@ t MSG_032 "UEFI (geen CSM)" t MSG_033 "BIOS of UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d Ronde" -t MSG_035 "%d Rondes" +t MSG_035 "%d Rondes %s" t MSG_036 "ISO image" t MSG_037 "Applicatie" t MSG_038 "Afbreken" @@ -4667,7 +4669,7 @@ t MSG_032 "UEFI (ei-CSM)" t MSG_033 "BIOS tai UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d testi" -t MSG_035 "%d testiä" +t MSG_035 "%d testiä %s" t MSG_036 "ISO-kuva" t MSG_037 "Sovellus" t MSG_038 "Keskeytä" @@ -5105,7 +5107,7 @@ t MSG_031 "BIOS (ou UEFI-CSM)" t MSG_032 "UEFI (non CSM)" t MSG_033 "BIOS ou UEFI" t MSG_034 "%d passe" -t MSG_035 "%d passes" +t MSG_035 "%d passes %s" t MSG_036 "Image ISO" t MSG_037 "Application" t MSG_038 "Annuler" @@ -5528,7 +5530,7 @@ t MSG_032 "UEFI (ohne CSM)" t MSG_033 "BIOS oder UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d Durchgang" -t MSG_035 "%d Durchgänge" +t MSG_035 "%d Durchgänge %s" t MSG_036 "ISO-Abbild" t MSG_037 "Programm" t MSG_038 "Abbruch" @@ -5956,7 +5958,7 @@ t MSG_032 "UEFI (εκτός από CSM)" t MSG_033 "BIOS ή UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d Πέρασμα" -t MSG_035 "%d Περάσματα" +t MSG_035 "%d Περάσματα %s" t MSG_036 "Είδωλο ISO" t MSG_037 "Εφαρμογή" t MSG_038 "Τερματισμός" @@ -6412,7 +6414,7 @@ t MSG_032 "UEFI (שאינו CSM)" t MSG_033 "BIOS או UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "מעבר אחד" -t MSG_035 "%d מעברים" +t MSG_035 "%d מעברים %s" t MSG_036 "קובץ ISO" t MSG_037 "יישום" t MSG_038 "ביטול" @@ -6889,7 +6891,7 @@ t MSG_032 "UEFI (nem CSM)" t MSG_033 "BIOS vagy UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d vizsgálva" -t MSG_035 "%d vizsgálva" +t MSG_035 "%d vizsgálva %s" t MSG_036 "ISO kép" t MSG_037 "Alkalmazás" t MSG_038 "Megszakít" @@ -7341,7 +7343,7 @@ t MSG_032 "UEFI (non CSM)" t MSG_033 "BIOS atau UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d kali uji" -t MSG_035 "%d kali uji" +t MSG_035 "%d kali uji %s" t MSG_036 "ISO Image" t MSG_037 "Aplikasi" t MSG_038 "Batal" @@ -7789,7 +7791,7 @@ t MSG_031 "BIOS (o UEFI CSM)" t MSG_032 "UEFI (non CSM)" t MSG_033 "BIOS o UEFI" t MSG_034 "%d test" -t MSG_035 "%d test" +t MSG_035 "%d test %s" t MSG_036 "Immagine ISO" t MSG_037 "Applicazione" t MSG_038 "Annulla" @@ -8229,7 +8231,7 @@ t MSG_032 "UEFI (CSM無効)" t MSG_033 "BIOSまたはUEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d パス" -t MSG_035 "%d パス" +t MSG_035 "%d パス %s" t MSG_036 "ISOイメージ" t MSG_037 "アプリケーション" t MSG_038 "中止" @@ -8698,7 +8700,7 @@ t MSG_032 "UEFI (CSM 지원 안 됨)" t MSG_033 "BIOS 또는 UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "한번만 검사" -t MSG_035 "%d회 검사" +t MSG_035 "%d회 검사 %s" t MSG_036 "ISO 이미지" t MSG_037 "프로그램" t MSG_038 "취소" @@ -9146,7 +9148,7 @@ t MSG_032 "BIOS (bez CSM)" t MSG_033 "BIOS vai UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d mēģ." -t MSG_035 "%d mēģ." +t MSG_035 "%d mēģ. %s" t MSG_036 "ISO virtuālais attēls" t MSG_037 "Programma" t MSG_038 "Pārtraukt" @@ -9596,7 +9598,7 @@ t MSG_032 "UEFI (ne CSM)" t MSG_033 "BIOS arba UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d bandymas" -t MSG_035 "%d bandymai" +t MSG_035 "%d bandymai %s" t MSG_036 "ISO atvaizdas" t MSG_037 "Programa" t MSG_038 "Nutraukti" @@ -10051,7 +10053,7 @@ t MSG_030 "%s (Lalai)" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d kali lulus" -t MSG_035 "%d kali lulus" +t MSG_035 "%d kali lulus %s" t MSG_036 "Imej ISO" t MSG_037 "Aplikasi" t MSG_038 "Batal" @@ -10480,7 +10482,7 @@ t MSG_032 "UEFI (ikke CSM)" t MSG_033 "BIOS eller UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d Passering" -t MSG_035 "%d Passeringer" +t MSG_035 "%d Passeringer %s" t MSG_036 "ISO-bilde" t MSG_037 "Applikasjon" t MSG_038 "Avbryt" @@ -10959,7 +10961,7 @@ t MSG_032 "UEFI (non CSM)" t MSG_033 "BIOS یا UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d گذره" -t MSG_035 "%d گذره" +t MSG_035 "%d گذره %s" t MSG_036 "ایمیج ISO" t MSG_037 "برنامه" t MSG_038 "لغو" @@ -11427,7 +11429,7 @@ t MSG_032 "UEFI (bez CSM)" t MSG_033 "BIOS lub UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d Przebieg" -t MSG_035 "%d Przebiegi" +t MSG_035 "%d Przebiegi %s" t MSG_036 "Obraz ISO" t MSG_037 "Aplikacja" t MSG_038 "Przerwij" @@ -11891,7 +11893,7 @@ t MSG_032 "UEFI (não CSM)" t MSG_033 "BIOS ou UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d passo" -t MSG_035 "%d passos" +t MSG_035 "%d passos %s" t MSG_036 "Imagem ISO" t MSG_037 "Aplicativo" t MSG_038 "Abortar" @@ -12364,7 +12366,7 @@ t MSG_032 "UEFI (não CSM)" t MSG_033 "BIOS ou UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d passo" -t MSG_035 "%d passos" +t MSG_035 "%d passos %s" t MSG_036 "Imagem ISO" t MSG_037 "Aplicação" t MSG_038 "Abortar" @@ -12808,7 +12810,7 @@ t MSG_031 "BIOS (sau UEFI-CSM)" t MSG_032 "UEFI (non CSM)" t MSG_033 "BIOS sau UEFI" t MSG_034 "%d pas" -t MSG_035 "%d pași" +t MSG_035 "%d pași %s" t MSG_036 "Imagine ISO" t MSG_037 "Cerere" t MSG_038 "Anulează" @@ -13233,7 +13235,7 @@ t MSG_032 "UEFI (non-CSM)" t MSG_033 "BIOS или UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d проход" -t MSG_035 "%d прохода" +t MSG_035 "%d прохода %s" t MSG_036 "ISO-образ" t MSG_037 "Приложение" t MSG_038 "Отменить" @@ -13675,7 +13677,7 @@ t MSG_030 "%s (Uobičajeno)" #t MSG_033 "%s particijska šema za UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d sekvenca" -t MSG_035 "%d sekvence" +t MSG_035 "%d sekvence %s" t MSG_036 "ISO datoteke" t MSG_037 "Aplikacija" t MSG_038 "Prekini" @@ -14122,7 +14124,7 @@ t MSG_032 "UEFI (bez CSM)" t MSG_033 "BIOS alebo UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d pokus" -t MSG_035 "%d pokusy" +t MSG_035 "%d pokusy %s" t MSG_036 "Obraz ISO" t MSG_037 "Aplikácia" t MSG_038 "Ukončiť" @@ -14576,7 +14578,7 @@ t MSG_032 "UEFI (brez CSM)" t MSG_033 "BIOS ali UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d prehod" -t MSG_035 "%d prehoda/-i" +t MSG_035 "%d prehoda/-i %s" t MSG_036 "sliko ISO" t MSG_037 "Aplikacija" t MSG_038 "Prekini" @@ -15010,7 +15012,7 @@ t MSG_032 "UEFI (no CSM)" t MSG_033 "BIOS o UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d paso" -t MSG_035 "%d pasos" +t MSG_035 "%d pasos %s" t MSG_036 "Imagen ISO" t MSG_037 "Aplicación" t MSG_038 "Abortar" @@ -15467,7 +15469,7 @@ t MSG_032 "UEFI (icke CSM)" t MSG_033 "BIOS eller UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d gång" -t MSG_035 "%d gånger" +t MSG_035 "%d gånger %s" t MSG_036 "ISO-avbild" t MSG_037 "Program" t MSG_038 "Avbryt" @@ -15926,7 +15928,7 @@ t MSG_032 "UEFI (ที่ไม่ใช่ CSM)" t MSG_033 "BIOS หรือ UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d รอบ" -t MSG_035 "%d รอบ" +t MSG_035 "%d รอบ %s" t MSG_036 "อิมเมจ ISO" t MSG_037 "แอพพลิเคชั่น" t MSG_038 "ยกเลิก" @@ -16393,7 +16395,7 @@ t MSG_032 "UEFI (CSM yok)" t MSG_033 "BIOS ya da UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d Geçiş" -t MSG_035 "%d Geçiş" +t MSG_035 "%d Geçiş %s" t MSG_036 "ISO Yansıması" t MSG_037 "Uygulama" t MSG_038 "Vazgeç" @@ -16847,7 +16849,7 @@ t MSG_032 "UEFI (без CSM)" t MSG_033 "BIOS чи UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "%d прохід" -t MSG_035 "%d проходи" +t MSG_035 "%d проходи %s" t MSG_036 "ISO-образ" t MSG_037 "Додаток" t MSG_038 "Відмінити" @@ -17283,7 +17285,7 @@ t MSG_030 "%s (Mặc định)" #t MSG_033 "Sắp xếp phân vùng %s cho UEFI" # Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) t MSG_034 "Qua %d lần" -t MSG_035 "Qua %d lần" +t MSG_035 "Qua %d lần %s" t MSG_036 "Ảnh ISO" t MSG_037 "Ứng dụng" t MSG_038 "Huỷ bỏ" diff --git a/src/badblocks.c b/src/badblocks.c index 4f7bc9b0..268cdabd 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-2016 by Pete Batard + * Copyright 2011-2018 by Pete Batard * * This file is based on the minix file system programs fsck and mkfs * written and copyrighted by Linus Torvalds @@ -350,13 +350,14 @@ static void pattern_fill(unsigned char *buffer, unsigned int pattern, unsigned char bpattern[sizeof(pattern)], *ptr; if (pattern == (unsigned int) ~0) { + PrintInfo(3500, MSG_236); srand((unsigned int)GetTickCount64()); for (ptr = buffer; ptr < buffer + n; ptr++) { // coverity[dont_call] (*ptr) = rand() % (1 << (8 * sizeof(char))); } - PrintInfo(3500, MSG_236); } else { + PrintInfo(3500, MSG_237, pattern); bpattern[0] = 0; for (i = 0; i < sizeof(bpattern); i++) { if (pattern == 0) @@ -372,7 +373,6 @@ static void pattern_fill(unsigned char *buffer, unsigned int pattern, else i--; } - PrintInfo(3500, MSG_237, bpattern[i]); cur_pattern++; } } @@ -422,16 +422,22 @@ static int64_t do_write(HANDLE hDrive, unsigned char * buffer, uint64_t tryout, } static unsigned int test_rw(HANDLE hDrive, blk_t last_block, size_t block_size, blk_t first_block, - size_t blocks_at_once, int nb_passes) + size_t blocks_at_once, int pattern_type, int nb_passes) { + const unsigned int pattern[BADLOCKS_PATTERN_TYPES][BADBLOCK_PATTERN_COUNT] = + { BADBLOCK_PATTERN_SLC, BADCLOCK_PATTERN_MLC, BADBLOCK_PATTERN_TLC }; unsigned char *buffer = NULL, *read_buffer; - const unsigned int pattern[] = BADBLOCK_PATTERNS; int i, pat_idx; unsigned int bb_count = 0; blk_t got, tryout, recover_block = ~0, *blk_id; - size_t id_offset; + size_t id_offset = 0; - if ((nb_passes < 1) || (nb_passes > 4)) { + if ((pattern_type < 0) || (pattern_type >= BADLOCKS_PATTERN_TYPES)) { + uprintf("%sInvalid pattern type\n", bb_prefix); + cancel_ops = -1; + return 0; + } + if ((nb_passes < 1) || (nb_passes > BADBLOCK_PATTERN_COUNT)) { uprintf("%sInvalid number of passes\n", bb_prefix); cancel_ops = -1; return 0; @@ -446,26 +452,31 @@ static unsigned int test_rw(HANDLE hDrive, blk_t last_block, size_t block_size, return 0; } - uprintf("%sChecking from block %lu to %lu\n", bb_prefix, - (unsigned long) first_block, (unsigned long) last_block - 1); + uprintf("%sChecking from block %lu to %lu (1 block = %s)\n", bb_prefix, + (unsigned long) first_block, (unsigned long) last_block - 1, + SizeToHumanReadable(BADBLOCK_BLOCK_SIZE, FALSE, FALSE)); nr_pattern = nb_passes; cur_pattern = 0; for (pat_idx = 0; pat_idx < nb_passes; pat_idx++) { - srand((unsigned int)GetTickCount64()); - if (cancel_ops) goto out; + if (cancel_ops) + goto out; + if (detect_fakes && (pat_idx == 0)) { + srand((unsigned int)GetTickCount64()); + id_offset = rand() * (block_size - sizeof(blk_t)) / RAND_MAX; + uprintf("%sUsing offset %d for fake device check\n", bb_prefix, id_offset); + } // coverity[dont_call] - id_offset = rand() * (block_size-sizeof(blk_t)) / RAND_MAX; - pattern_fill(buffer, pattern[pat_idx], blocks_at_once * block_size); - uprintf("%sUsing offset %d for fake device check\n", bb_prefix, id_offset); + pattern_fill(buffer, pattern[pattern_type][pat_idx], blocks_at_once * block_size); num_blocks = last_block - 1; currently_testing = first_block; if (s_flag | v_flag) - uprintf("%sWriting test pattern 0x%02X\n", bb_prefix, pattern[pat_idx]); + uprintf("%sWriting test pattern 0x%02X\n", bb_prefix, pattern[pattern_type][pat_idx]); cur_op = OP_WRITE; tryout = blocks_at_once; while (currently_testing < last_block) { - if (cancel_ops) goto out; + if (cancel_ops) + goto out; if (max_bb && bb_count >= max_bb) { if (s_flag || v_flag) { uprintf(abort_msg); @@ -477,7 +488,7 @@ static unsigned int test_rw(HANDLE hDrive, blk_t last_block, size_t block_size, } if (currently_testing + tryout > last_block) tryout = last_block - currently_testing; - if (detect_fakes) { + if (detect_fakes && (pat_idx == 0)) { /* Add the block number at a fixed (random) offset during each pass to allow for the detection of 'fake' media (eg. 2GB USB masquerading as 16GB) */ for (i=0; i<(int)blocks_at_once; i++) { @@ -525,7 +536,7 @@ static unsigned int test_rw(HANDLE hDrive, blk_t last_block, size_t block_size, } if (currently_testing + tryout > last_block) tryout = last_block - currently_testing; - if (detect_fakes) { + if (detect_fakes && (pat_idx == 0)) { for (i=0; i<(int)blocks_at_once; i++) { blk_id = (blk_t*)(intptr_t)(buffer + id_offset+ i*block_size); *blk_id = (blk_t)(currently_testing + i); @@ -563,11 +574,11 @@ out: return bb_count; } -BOOL BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, size_t block_size, - int nb_passes, badblocks_report *report, FILE* fd) +BOOL BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, int nb_passes, + int flash_type, badblocks_report *report, FILE* fd) { errcode_t error_code; - blk_t first_block = 0, last_block = disk_size/block_size; + blk_t last_block = disk_size / BADBLOCK_BLOCK_SIZE; if (report == NULL) return FALSE; num_read_errors = 0; @@ -589,7 +600,7 @@ BOOL BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, size_t block_size, cancel_ops = 0; /* use a timer to update status every second */ SetTimer(hMainDialog, TID_BADBLOCKS_UPDATE, 1000, alarm_intr); - report->bb_count = test_rw(hPhysicalDrive, last_block, block_size, first_block, BB_BLOCKS_AT_ONCE, nb_passes); + report->bb_count = test_rw(hPhysicalDrive, last_block, BADBLOCK_BLOCK_SIZE, 0, BB_BLOCKS_AT_ONCE, flash_type, nb_passes); KillTimer(hMainDialog, TID_BADBLOCKS_UPDATE); free(bb_list->list); free(bb_list); diff --git a/src/badblocks.h b/src/badblocks.h index 9bd502b7..45f6a303 100644 --- a/src/badblocks.h +++ b/src/badblocks.h @@ -7,7 +7,7 @@ * * Copyright 1995, 1996, 1997, 1998, 1999 by Theodore Ts'o * Copyright 1999 by David Beattie - * Copyright 2011-2013 by Pete Batard + * Copyright 2011-2018 by Pete Batard * * This file is based on the minix file system programs fsck and mkfs * written and copyrighted by Linus Torvalds @@ -55,5 +55,5 @@ typedef struct { /* * Shared prototypes */ -BOOL BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, size_t block_size, - int test_type, badblocks_report *report, FILE* fd); +BOOL BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, int nb_passes, + int flash_type, badblocks_report *report, FILE* fd); diff --git a/src/dev.c b/src/dev.c index 94eef03e..d11129a5 100644 --- a/src/dev.c +++ b/src/dev.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "rufus.h" #include "missing.h" @@ -452,16 +453,12 @@ BOOL GetDevices(DWORD devnum) if (strcmp(genstor_name[s], "SD") == 0) card_start = s; } - // Overkill, but better safe than sorry. And yeah, we could have used - // arrays of arrays to avoid this, but it's more readable this way. - if ((uasp_start <= 0) || (uasp_start >= 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; - } + + // Better safe than sorry. And yeah, we could have used arrays of + // arrays to avoid this, but it's more readable this way. + assert((uasp_start > 0) && (uasp_start < ARRAYSIZE(usbstor_name))); + assert((card_start > 0) && (card_start < ARRAYSIZE(genstor_name))); + devid_list = NULL; if (full_list_size != 0) { full_list_size += 1; // add extra NUL terminator diff --git a/src/dos_locale.c b/src/dos_locale.c index 53bad108..e524d2ab 100644 --- a/src/dos_locale.c +++ b/src/dos_locale.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "rufus.h" @@ -288,8 +289,8 @@ static const char* kb_to_hr(const char* kb) } } // Should never happen, so let's try to get some attention here - MessageBoxA(hMainDialog, "YO BNLA #1", "UHAHAHHA?", MB_OKCANCEL|MB_ICONWARNING); - return "Someone missed a keyboard!"; + assert(i < ARRAYSIZE(kb_hr_list)); + return NULL; } typedef struct { @@ -425,8 +426,8 @@ static const char* cp_to_hr(ULONG cp) } } // Should never happen, so this oughta get some attention - MessageBoxA(hMainDialog, "YO BNLA #2", "UHAHAHHA?", MB_OKCANCEL|MB_ICONWARNING); - return "Someone missed a codepage!"; + assert(i < ARRAYSIZE(cp_hr_list)); + return NULL; } // http://blogs.msdn.com/b/michkap/archive/2004/12/05/275231.aspx diff --git a/src/drive.c b/src/drive.c index 22ed314f..22a28bb3 100644 --- a/src/drive.c +++ b/src/drive.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "rufus.h" #include "missing.h" @@ -109,11 +110,9 @@ BOOL GetAutoMount(BOOL* enabled) * clear the MBR of!), so we mitigate the risk by forcing our indexes to belong to * the specific range [DRIVE_INDEX_MIN; DRIVE_INDEX_MAX]. */ -#define CheckDriveIndex(DriveIndex) do { \ - if ((DriveIndex < DRIVE_INDEX_MIN) || (DriveIndex > DRIVE_INDEX_MAX)) { \ - uprintf("ERROR: Bad index value %d. Please check the code!", DriveIndex); \ - goto out; \ - } \ +#define CheckDriveIndex(DriveIndex) do { \ + assert((DriveIndex >= DRIVE_INDEX_MIN) && (DriveIndex <= DRIVE_INDEX_MAX)); \ + if ((DriveIndex < DRIVE_INDEX_MIN) || (DriveIndex > DRIVE_INDEX_MAX)) goto out; \ DriveIndex -= DRIVE_INDEX_MIN; } while (0) /* diff --git a/src/format.c b/src/format.c index 264d2af0..63e4bd31 100644 --- a/src/format.c +++ b/src/format.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "rufus.h" #include "missing.h" @@ -1856,6 +1857,7 @@ DWORD WINAPI FormatThread(void* param) if (IsChecked(IDC_BAD_BLOCKS)) { do { + int sel = ComboBox_GetCurSel(hNBPasses); // create a log file for bad blocks report. Since %USERPROFILE% may // have localized characters, we use the UTF-8 API. userdir = getenvU("USERPROFILE"); @@ -1874,8 +1876,8 @@ DWORD WINAPI FormatThread(void* param) fflush(log_fd); } - if (!BadBlocks(hPhysicalDrive, SelectedDrive.DiskSize, SelectedDrive.SectorSize, - ComboBox_GetCurSel(hNBPasses)+1, &report, log_fd)) { + if (!BadBlocks(hPhysicalDrive, SelectedDrive.DiskSize, (sel >= 2) ? 4 : sel +1, + (sel < 2) ? 0 : sel - 2, &report, log_fd)) { uprintf("Bad blocks: Check failed.\n"); if (!IS_ERROR(FormatStatus)) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_BADBLOCKS_FAILURE); @@ -2029,8 +2031,8 @@ DWORD WINAPI FormatThread(void* param) // All good } else if (tt == TT_UEFI) { // For once, no need to do anything - just check our sanity + assert((bt == BT_IMAGE) && IS_EFI_BOOTABLE(img_report) && (fs <= FS_NTFS)); if ( (bt != BT_IMAGE) || !IS_EFI_BOOTABLE(img_report) || (fs > FS_NTFS) ) { - 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/msapi_utf8.h b/src/msapi_utf8.h index ecc86040..388fdfd2 100644 --- a/src/msapi_utf8.h +++ b/src/msapi_utf8.h @@ -512,6 +512,22 @@ static __inline int PathGetDriveNumberU(char* lpPath) return ret; } +// This one is tricky since we can't blindly convert a +// UTF-16 position to a UTF-8 one. So we do it manually. +static __inline const char* PathFindFileNameU(const char* szPath) +{ + size_t i; + if (szPath == NULL) + return NULL; + for (i = strlen(szPath); i != 0; i--) { + if ((szPath[i] == '/') || (szPath[i] == '\\')) { + i++; + break; + } + } + return &szPath[i]; +} + // This function differs from regular GetTextExtentPoint in that it uses a zero terminated string static __inline BOOL GetTextExtentPointU(HDC hdc, const char* lpString, LPSIZE lpSize) { diff --git a/src/net.c b/src/net.c index 3e867cf7..e1da8f27 100644 --- a/src/net.c +++ b/src/net.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "rufus.h" #include "missing.h" @@ -44,7 +45,6 @@ #define DEFAULT_UPDATE_INTERVAL (24*3600) DWORD DownloadStatus; -BOOL PromptOnError = TRUE; extern BOOL force_update; static DWORD error_code; @@ -216,13 +216,14 @@ const char* WinInetErrorString(void) } /* - * Download a file from an URL + * Download a file or fill a buffer from an URL * Mostly taken from http://support.microsoft.com/kb/234913 + * If file is NULL, a buffer is allocated for the download (that needs to be freed by the caller) * If hProgressDialog is not NULL, this function will send INIT and EXIT messages * to the dialog in question, with WPARAM being set to nonzero for EXIT on success * and also attempt to indicate progress using an IDC_PROGRESS control */ -DWORD DownloadFile(const char* url, const char* file, HWND hProgressDialog) +static DWORD DownloadToFileOrBuffer(const char* url, const char* file, BYTE** buffer, HWND hProgressDialog) { HWND hProgressBar = NULL; BOOL r = FALSE; @@ -234,8 +235,8 @@ DWORD DownloadFile(const char* url, const char* file, HWND hProgressDialog) HINTERNET hSession = NULL, hConnection = NULL, hRequest = NULL; URL_COMPONENTSA UrlParts = {sizeof(URL_COMPONENTSA), NULL, 1, (INTERNET_SCHEME)0, hostname, sizeof(hostname), 0, NULL, 1, urlpath, sizeof(urlpath), NULL, 1}; - size_t last_slash; - int i; + const char* short_name; + size_t i; // Can't link with wininet.lib because of sideloading issues PF_TYPE_DECL(WINAPI, BOOL, InternetCrackUrlA, (LPCSTR, DWORD, DWORD, LPURL_COMPONENTSA)); @@ -257,7 +258,8 @@ DWORD DownloadFile(const char* url, const char* file, HWND hProgressDialog) PF_INIT_OR_OUT(HttpSendRequestA, WinInet); PF_INIT_OR_OUT(HttpQueryInfoA, WinInet); - DownloadStatus = 0; + FormatStatus = 0; + DownloadStatus = 404; if (hProgressDialog != NULL) { // Use the progress control provided, if any hProgressBar = GetDlgItem(hProgressDialog, IDC_PROGRESS); @@ -268,22 +270,18 @@ DWORD DownloadFile(const char* url, const char* file, HWND hProgressDialog) SendMessage(hProgressDialog, UM_PROGRESS_INIT, 0, 0); } - if (file == NULL) - goto out; + assert(url != NULL); - for (last_slash = safe_strlen(file); last_slash != 0; last_slash--) { - if ((file[last_slash] == '/') || (file[last_slash] == '\\')) { - last_slash++; - break; - } + short_name = (file != NULL) ? PathFindFileNameU(file) : PathFindFileNameU(url); + + if (hProgressDialog != NULL) { + PrintInfo(0, MSG_085, short_name); + uprintf("Downloading %s", url); } - PrintInfo(0, MSG_085, &file[last_slash]); - uprintf("Downloading '%s' from %s\n", &file[last_slash], url); - if ( (!pfInternetCrackUrlA(url, (DWORD)safe_strlen(url), 0, &UrlParts)) || (UrlParts.lpszHostName == NULL) || (UrlParts.lpszUrlPath == NULL)) { - uprintf("Unable to decode URL: %s\n", WinInetErrorString()); + uprintf("Unable to decode URL: %s", WinInetErrorString()); goto out; } hostname[sizeof(hostname)-1] = 0; @@ -295,7 +293,7 @@ DWORD DownloadFile(const char* url, const char* file, HWND hProgressDialog) if (i <= 0) { // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384702.aspx is wrong... SetLastError(ERROR_INTERNET_NOT_INITIALIZED); - uprintf("Network is unavailable: %s\n", WinInetErrorString()); + uprintf("Network is unavailable: %s", WinInetErrorString()); goto out; } static_sprintf(agent, APPLICATION_NAME "/%d.%d.%d (Windows NT %d.%d%s)", @@ -303,13 +301,13 @@ DWORD DownloadFile(const char* url, const char* file, HWND hProgressDialog) nWindowsVersion>>4, nWindowsVersion&0x0F, is_x64()?"; WOW64":""); hSession = pfInternetOpenA(agent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (hSession == NULL) { - uprintf("Could not open Internet session: %s\n", WinInetErrorString()); + uprintf("Could not open Internet session: %s", WinInetErrorString()); goto out; } hConnection = pfInternetConnectA(hSession, UrlParts.lpszHostName, UrlParts.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)NULL); if (hConnection == NULL) { - uprintf("Could not connect to server %s:%d: %s\n", UrlParts.lpszHostName, UrlParts.nPort, WinInetErrorString()); + uprintf("Could not connect to server %s:%d: %s", UrlParts.lpszHostName, UrlParts.nPort, WinInetErrorString()); goto out; } @@ -318,84 +316,97 @@ DWORD DownloadFile(const char* url, const char* file, HWND hProgressDialog) INTERNET_FLAG_NO_COOKIES|INTERNET_FLAG_NO_UI|INTERNET_FLAG_NO_CACHE_WRITE|INTERNET_FLAG_HYPERLINK| ((UrlParts.nScheme==INTERNET_SCHEME_HTTPS)?INTERNET_FLAG_SECURE:0), (DWORD_PTR)NULL); if (hRequest == NULL) { - uprintf("Could not open URL %s: %s\n", url, WinInetErrorString()); + uprintf("Could not open URL %s: %s", url, WinInetErrorString()); goto out; } if (!pfHttpSendRequestA(hRequest, NULL, 0, NULL, 0)) { - uprintf("Unable to send request: %s\n", WinInetErrorString()); + uprintf("Unable to send request: %s", WinInetErrorString()); goto out; } // Get the file size dwSize = sizeof(DownloadStatus); - DownloadStatus = 404; pfHttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, (LPVOID)&DownloadStatus, &dwSize, NULL); if (DownloadStatus != 200) { error_code = ERROR_INTERNET_ITEM_NOT_FOUND; - uprintf("Unable to access file: %d\n", DownloadStatus); + uprintf("Unable to access file: %d", DownloadStatus); goto out; } dwSize = sizeof(dwTotalSize); if (!pfHttpQueryInfoA(hRequest, HTTP_QUERY_CONTENT_LENGTH|HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwTotalSize, &dwSize, NULL)) { - uprintf("Unable to retrieve file length: %s\n", WinInetErrorString()); + uprintf("Unable to retrieve file length: %s", WinInetErrorString()); goto out; } - uprintf("File length: %d bytes\n", dwTotalSize); + if (hProgressDialog != NULL) + uprintf("File length: %d bytes", dwTotalSize); - hFile = CreateFileU(file, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - uprintf("Unable to create file '%s': %s\n", &file[last_slash], WinInetErrorString()); - goto out; + if (file != NULL) { + hFile = CreateFileU(file, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + uprintf("Unable to create file '%s': %s", short_name, WinInetErrorString()); + goto out; + } + } else { + if (buffer == NULL) { + uprintf("No buffer pointer provided for download"); + goto out; + } + *buffer = malloc(dwTotalSize); + if (*buffer == NULL) { + uprintf("Could not allocate buffer for download"); + goto out; + } } // Keep checking for data until there is nothing left. dwSize = 0; while (1) { + // User may have cancelled the download if (IS_ERROR(FormatStatus)) goto out; - if (!pfInternetReadFile(hRequest, buf, sizeof(buf), &dwDownloaded) || (dwDownloaded == 0)) break; - dwSize += dwDownloaded; - SendMessage(hProgressBar, PBM_SETPOS, (WPARAM)(MAX_PROGRESS*((1.0f*dwSize)/(1.0f*dwTotalSize))), 0); - PrintInfo(0, MSG_241, (100.0f*dwSize)/(1.0f*dwTotalSize)); - if (!WriteFile(hFile, buf, dwDownloaded, &dwWritten, NULL)) { - uprintf("Error writing file '%s': %s\n", &file[last_slash], WinInetErrorString()); - goto out; - } else if (dwDownloaded != dwWritten) { - uprintf("Error writing file '%s': Only %d/%d bytes written\n", dwWritten, dwDownloaded); - goto out; + if (hProgressDialog != NULL) { + SendMessage(hProgressBar, PBM_SETPOS, (WPARAM)(MAX_PROGRESS*((1.0f*dwSize) / (1.0f*dwTotalSize))), 0); + PrintInfo(0, MSG_241, (100.0f*dwSize) / (1.0f*dwTotalSize)); } + if (file != NULL) { + if (!WriteFile(hFile, buf, dwDownloaded, &dwWritten, NULL)) { + uprintf("Error writing file '%s': %s", short_name, WinInetErrorString()); + goto out; + } else if (dwDownloaded != dwWritten) { + uprintf("Error writing file '%s': Only %d/%d bytes written", short_name, dwWritten, dwDownloaded); + goto out; + } + } else { + memcpy(&(*buffer)[dwSize], buf, dwDownloaded); + } + dwSize += dwDownloaded; } if (dwSize != dwTotalSize) { - uprintf("Could not download complete file - read: %d bytes, expected: %d bytes\n", dwSize, dwTotalSize); + uprintf("Could not download complete file - read: %d bytes, expected: %d bytes", dwSize, dwTotalSize); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; goto out; } else { + DownloadStatus = 200; r = TRUE; - uprintf("Successfully downloaded '%s'\n", &file[last_slash]); + if (hProgressDialog != NULL) { + uprintf("Successfully downloaded '%s'", short_name); + SendMessage(hProgressBar, PBM_SETPOS, (WPARAM)MAX_PROGRESS, 0); + PrintInfo(0, MSG_241, 100.0f); + } } out: - if (hProgressDialog != NULL) - SendMessage(hProgressDialog, UM_PROGRESS_EXIT, (WPARAM)r, 0); if (hFile != INVALID_HANDLE_VALUE) { // Force a flush - May help with the PKI API trying to process downloaded updates too early... FlushFileBuffers(hFile); CloseHandle(hFile); } - if (!r) { - if (file != NULL) - _unlinkU(file); - if (PromptOnError) { - PrintInfo(0, MSG_242); - SetLastError(error_code); - MessageBoxExU(hMainDialog, IS_ERROR(FormatStatus)?StrError(FormatStatus, FALSE):WinInetErrorString(), - lmprintf(MSG_044), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); - } - } + if ((!r) && (file != NULL)) + _unlinkU(file); if (hRequest) pfInternetCloseHandle(hRequest); if (hConnection) @@ -403,23 +414,95 @@ out: if (hSession) pfInternetCloseHandle(hSession); - return r?dwSize:0; + return r ? dwSize : 0; +} + +// Download and validate a signed file. The file must have a corresponding '.sig' on the server. +DWORD DownloadSignedFile(const char* url, const char* file, HWND hProgressDialog, BOOL bPromptOnError) +{ + char* url_sig = NULL; + BYTE *buf = NULL, *sig = NULL; + DWORD buf_len = 0, sig_len = 0; + DWORD ret = 0; + HANDLE hFile = INVALID_HANDLE_VALUE; + + assert(url != NULL); + + url_sig = malloc(strlen(url) + 5); + if (url_sig == NULL) { + uprintf("Could not allocate signature URL"); + goto out; + } + strcpy(url_sig, url); + strcat(url_sig, ".sig"); + + buf_len = DownloadToFileOrBuffer(url, NULL, &buf, hProgressDialog); + if (buf_len == 0) + goto out; + sig_len = DownloadToFileOrBuffer(url_sig, NULL, &sig, NULL); + if ((sig_len != RSA_SIGNATURE_SIZE) || (!ValidateOpensslSignature(buf, buf_len, sig, sig_len))) { + uprintf("FATAL: Download signature is invalid ✗"); + DownloadStatus = 403; // Forbidden + FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_BAD_SIGNATURE); + goto out; + } + + uprintf("Download signature is valid ✓"); + DownloadStatus = 206; // Partial content + hFile = CreateFileU(file, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + uprintf("Unable to create file '%s': %s", PathFindFileNameU(file), WinInetErrorString()); + goto out; + } + if (!WriteFile(hFile, buf, buf_len, &ret, NULL)) { + uprintf("Error writing file '%s': %s", PathFindFileNameU(file), WinInetErrorString()); + ret = 0; + goto out; + } else if (ret != buf_len) { + uprintf("Error writing file '%s': Only %d/%d bytes written", PathFindFileNameU(file), ret, buf_len); + ret = 0; + goto out; + } + DownloadStatus = 200; // Full content + +out: + if (hProgressDialog != NULL) + SendMessage(hProgressDialog, UM_PROGRESS_EXIT, (WPARAM)ret, 0); + if ((bPromptOnError) && (DownloadStatus != 200)) { + PrintInfo(0, MSG_242); + SetLastError(error_code); + MessageBoxExU(hMainDialog, IS_ERROR(FormatStatus) ? StrError(FormatStatus, FALSE) : WinInetErrorString(), + lmprintf(MSG_044), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid); + } + safe_closehandle(hFile); + free(url_sig); + free(buf); + free(sig); + return ret; } /* Threaded download */ -static const char *_url, *_file; -static HWND _hProgressDialog; -static DWORD WINAPI _DownloadFileThread(LPVOID param) +typedef struct { + const char* url; + const char* file; + HWND hProgressDialog; + BOOL bPromptOnError; +} DownloadSignedFileThreadArgs; + +static DWORD WINAPI DownloadSignedFileThread(LPVOID param) { - ExitThread(DownloadFile(_url, _file, _hProgressDialog) != 0); + DownloadSignedFileThreadArgs* args = (DownloadSignedFileThreadArgs*)param; + ExitThread(DownloadSignedFile(args->url, args->file, args->hProgressDialog, args->bPromptOnError)); } -HANDLE DownloadFileThreaded(const char* url, const char* file, HWND hProgressDialog) +HANDLE DownloadSignedFileThreaded(const char* url, const char* file, HWND hProgressDialog, BOOL bPromptOnError) { - _url = url; - _file = file; - _hProgressDialog = hProgressDialog; - return CreateThread(NULL, 0, _DownloadFileThread, NULL, 0, NULL); + static DownloadSignedFileThreadArgs args; + args.url = url; + args.file = file; + args.hProgressDialog = hProgressDialog; + args.bPromptOnError = bPromptOnError; + return CreateThread(NULL, 0, DownloadSignedFileThread, &args, 0, NULL); } static __inline uint64_t to_uint64_t(uint16_t x[4]) { @@ -443,8 +526,9 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) static const char* channel[] = {"release", "beta", "test"}; // release channel const char* accept_types[] = {"*/*\0", NULL}; DWORD dwFlags, dwSize, dwDownloaded, dwTotalSize, dwStatus; + BYTE *sig = NULL; char* buf = NULL; - char agent[64], hostname[64], urlpath[128], mime[32]; + char agent[64], hostname[64], urlpath[128], sigpath[256], mime[32]; OSVERSIONINFOA os_version = {sizeof(OSVERSIONINFOA), 0, 0, 0, 0, ""}; HINTERNET hSession = NULL, hConnection = NULL, hRequest = NULL; URL_COMPONENTSA UrlParts = {sizeof(URL_COMPONENTSA), NULL, 1, (INTERNET_SCHEME)0, @@ -487,7 +571,7 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) } while ((!force_update_check) && ((iso_op_in_progress || format_op_in_progress || (dialog_showing>0)))); if (!force_update_check) { if ((ReadSetting32(SETTING_UPDATE_INTERVAL) == -1)) { - vuprintf("Check for updates disabled, as per settings.\n"); + vuprintf("Check for updates disabled, as per settings."); goto out; } reg_time = ReadSetting64(SETTING_LAST_UPDATE); @@ -500,9 +584,9 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) if (!SystemTimeToFileTime(&LocalTime, &FileTime)) goto out; local_time = ((((int64_t)FileTime.dwHighDateTime)<<32) + FileTime.dwLowDateTime) / 10000000; - vvuprintf("Local time: %" PRId64 "\n", local_time); + vvuprintf("Local time: %" PRId64, local_time); if (local_time < reg_time + update_interval) { - vuprintf("Next update check in %" PRId64 " seconds.\n", reg_time + update_interval - local_time); + vuprintf("Next update check in %" PRId64 " seconds.", reg_time + update_interval - local_time); goto out; } } @@ -512,7 +596,7 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) status++; // 1 if (!GetVersionExA(&os_version)) { - uprintf("Could not read Windows version - Check for updates cancelled.\n"); + uprintf("Could not read Windows version - Check for updates cancelled."); goto out; } @@ -540,7 +624,7 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) max_channel = releases_only ? 1 : (int)ARRAYSIZE(channel) - 1; #endif for (k=0; (k___.ver" // and then remove each each of the components until we find our match. For instance, we may first @@ -548,21 +632,18 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) // This allows sunsetting OS versions (eg XP) or providing different downloads for different archs/groups. static_sprintf(urlpath, "%s%s%s_%s_%lu.%lu.ver", APPLICATION_NAME, (k==0)?"":"_", (k==0)?"":channel[k], archname[is_x64()?1:0], os_version.dwMajorVersion, os_version.dwMinorVersion); - vuprintf("Base update check: %s\n", urlpath); + vuprintf("Base update check: %s", urlpath); for (i=0, j=(int)safe_strlen(urlpath)-5; (j>0)&&(i to_uint64_t(rufus_version)) || (force_update)) && ( (os_version.dwMajorVersion > update.platform_min[0]) || ( (os_version.dwMajorVersion == update.platform_min[0]) && (os_version.dwMinorVersion >= update.platform_min[1])) ); - uprintf("N%sew %s version found%c\n", found_new_version?"":"o n", channel[k], found_new_version?'!':'.'); + uprintf("N%sew %s version found%c", found_new_version?"":"o n", channel[k], found_new_version?'!':'.'); } out: safe_free(buf); + safe_free(sig); if (hRequest) pfInternetCloseHandle(hRequest); if (hConnection) diff --git a/src/pki.c b/src/pki.c index 07cf065c..328adf50 100644 --- a/src/pki.c +++ b/src/pki.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "rufus.h" #include "resource.h" @@ -52,6 +53,63 @@ typedef struct { LPWSTR lpszMoreInfoLink; } SPROG_PUBLISHERINFO, *PSPROG_PUBLISHERINFO; +// https://msdn.microsoft.com/en-us/library/ee442238.aspx +typedef struct { + BLOBHEADER BlobHeader; + RSAPUBKEY RsaHeader; + BYTE Modulus[256]; // 2048 bit modulus +} RSA_2048_PUBKEY; + +// The RSA public key modulus for the private key we use to sign the files on the server. +// NOTE 1: This openssl modulus must be *REVERSED* to be usable with Microsoft APIs +// NOTE 2: Also, this modulus is 2052 bits, and not 2048, because openssl adds an extra +// 0x00 at the beginning to force an integer sign. These extra 8 bits *MUST* be removed. +static uint8_t rsa_pubkey_modulus[] = { + /* + $ openssl genrsa -aes256 -out private.pem 2048 + $ openssl rsa -in private.pem -pubout -out public.pem + $ openssl rsa -pubin -inform PEM -text -noout < public.pem + Public-Key: (2048 bit) + Modulus: + 00:b6:40:7d:d1:98:7b:81:9e:be:23:0f:32:5d:55: + 60:c6:bf:b4:41:bb:43:1b:f1:e1:e6:f9:2b:d6:dd: + 11:50:e8:b9:3f:19:97:5e:a7:8b:4a:30:c6:76:58: + 72:1c:ac:ff:a1:f8:96:6c:51:5d:13:11:e3:5b:11: + 82:f5:9a:69:e4:28:97:0f:ca:1f:02:ea:1f:7d:dc: + f9:fc:79:2f:61:ff:8e:45:60:65:ba:37:9b:de:49: + 05:6a:a8:fd:70:d0:0c:79:b6:d7:81:aa:54:c3:c6: + 4a:87:a0:45:ee:ca:d5:d5:c5:c2:ac:86:42:b3:58: + 27:d2:43:b9:37:f2:e6:75:66:17:53:d0:38:d0:c6: + 57:c2:55:36:a2:43:87:ea:24:f0:96:ec:34:dd:79: + 4d:80:54:9d:84:81:a7:cf:0c:a5:7c:d6:63:fa:7a: + 66:30:a9:50:ee:f0:e5:f8:a2:2d:ac:fc:24:21:fe: + ef:e8:d3:6f:0e:27:b0:64:22:95:3e:6d:a6:66:97: + c6:98:c2:47:b3:98:69:4d:b1:b5:d3:6f:43:f5:d7: + a5:13:5e:8c:28:4f:62:4e:01:48:0a:63:89:e7:ca: + 34:aa:7d:2f:bb:70:e0:31:bb:39:49:a3:d2:c9:2e: + a6:30:54:9a:5c:4d:58:17:d9:fc:3a:43:e6:8e:2a: + 18:e9 + Exponent: 65537 (0x10001) + */ + 0x00, 0xb6, 0x40, 0x7d, 0xd1, 0x98, 0x7b, 0x81, 0x9e, 0xbe, 0x23, 0x0f, 0x32, 0x5d, 0x55, + 0x60, 0xc6, 0xbf, 0xb4, 0x41, 0xbb, 0x43, 0x1b, 0xf1, 0xe1, 0xe6, 0xf9, 0x2b, 0xd6, 0xdd, + 0x11, 0x50, 0xe8, 0xb9, 0x3f, 0x19, 0x97, 0x5e, 0xa7, 0x8b, 0x4a, 0x30, 0xc6, 0x76, 0x58, + 0x72, 0x1c, 0xac, 0xff, 0xa1, 0xf8, 0x96, 0x6c, 0x51, 0x5d, 0x13, 0x11, 0xe3, 0x5b, 0x11, + 0x82, 0xf5, 0x9a, 0x69, 0xe4, 0x28, 0x97, 0x0f, 0xca, 0x1f, 0x02, 0xea, 0x1f, 0x7d, 0xdc, + 0xf9, 0xfc, 0x79, 0x2f, 0x61, 0xff, 0x8e, 0x45, 0x60, 0x65, 0xba, 0x37, 0x9b, 0xde, 0x49, + 0x05, 0x6a, 0xa8, 0xfd, 0x70, 0xd0, 0x0c, 0x79, 0xb6, 0xd7, 0x81, 0xaa, 0x54, 0xc3, 0xc6, + 0x4a, 0x87, 0xa0, 0x45, 0xee, 0xca, 0xd5, 0xd5, 0xc5, 0xc2, 0xac, 0x86, 0x42, 0xb3, 0x58, + 0x27, 0xd2, 0x43, 0xb9, 0x37, 0xf2, 0xe6, 0x75, 0x66, 0x17, 0x53, 0xd0, 0x38, 0xd0, 0xc6, + 0x57, 0xc2, 0x55, 0x36, 0xa2, 0x43, 0x87, 0xea, 0x24, 0xf0, 0x96, 0xec, 0x34, 0xdd, 0x79, + 0x4d, 0x80, 0x54, 0x9d, 0x84, 0x81, 0xa7, 0xcf, 0x0c, 0xa5, 0x7c, 0xd6, 0x63, 0xfa, 0x7a, + 0x66, 0x30, 0xa9, 0x50, 0xee, 0xf0, 0xe5, 0xf8, 0xa2, 0x2d, 0xac, 0xfc, 0x24, 0x21, 0xfe, + 0xef, 0xe8, 0xd3, 0x6f, 0x0e, 0x27, 0xb0, 0x64, 0x22, 0x95, 0x3e, 0x6d, 0xa6, 0x66, 0x97, + 0xc6, 0x98, 0xc2, 0x47, 0xb3, 0x98, 0x69, 0x4d, 0xb1, 0xb5, 0xd3, 0x6f, 0x43, 0xf5, 0xd7, + 0xa5, 0x13, 0x5e, 0x8c, 0x28, 0x4f, 0x62, 0x4e, 0x01, 0x48, 0x0a, 0x63, 0x89, 0xe7, 0xca, + 0x34, 0xaa, 0x7d, 0x2f, 0xbb, 0x70, 0xe0, 0x31, 0xbb, 0x39, 0x49, 0xa3, 0xd2, 0xc9, 0x2e, + 0xa6, 0x30, 0x54, 0x9a, 0x5c, 0x4d, 0x58, 0x17, 0xd9, 0xfc, 0x3a, 0x43, 0xe6, 0x8e, 0x2a, + 0x18, 0xe9 +}; /* * FormatMessage does not handle PKI errors @@ -65,8 +123,19 @@ const char* WinPKIErrorString(void) return WindowsErrorString(); switch (error_code) { + // See also https://docs.microsoft.com/en-gb/windows/desktop/com/com-error-codes-4 case NTE_BAD_UID: return "Bad UID."; + case NTE_NO_KEY: + return "Key does not exist."; + case NTE_BAD_KEYSET: + return "Keyset does not exist."; + case NTE_BAD_ALGID: + return "Invalid algorithm specified."; + case NTE_BAD_VER: + return "Bad version of provider."; + case NTE_BAD_SIGNATURE: + return "Invalid Signature."; case CRYPT_E_MSG_ERROR: return "An error occurred while performing an operation on a cryptographic message."; case CRYPT_E_UNKNOWN_ALGO: @@ -581,3 +650,80 @@ LONG ValidateSignature(HWND hDlg, const char* path) return r; } + +// Why-oh-why am I the only one on github doing this openssl vs MS signature validation?!? +// For once, I'd like to find code samples from *OTHER PEOPLE* who went through this ordeal first... +BOOL ValidateOpensslSignature(BYTE* pbBuffer, DWORD dwBufferLen, BYTE* pbSignature, DWORD dwSigLen) +{ + HCRYPTPROV hProv = 0; + HCRYPTHASH hHash = 0; + HCRYPTKEY hPubKey; + // We could load and convert an openssl PEM, but since we know what we need... + RSA_2048_PUBKEY pbMyPubKey = { + { PUBLICKEYBLOB, CUR_BLOB_VERSION, 0, CALG_RSA_KEYX }, + // $ openssl genrsa -aes256 -out private.pem 2048 + // Generating RSA private key, 2048 bit long modulus + // e is 65537 (0x010001) + // => 0x010001 below. Also 0x31415352 = "RSA1" + { 0x31415352, sizeof(pbMyPubKey.Modulus) * 8, 0x010001 }, + { 0 } // Modulus is initialized below + }; + USHORT dwMyPubKeyLen = sizeof(pbMyPubKey); + BOOL r; + BYTE t; + int i, j; + + // Get a handle to the default PROV_RSA_AES provider (AES so we get SHA-256 support). + // 2 passes in case we need to create a new container. + r = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT); + if (!r) { + uprintf("PKI: Could not create the default key container: %s", WinPKIErrorString()); + goto out; + } + + // Reverse the modulus bytes from openssl (and also remove the extra unwanted 0x00) + assert(sizeof(rsa_pubkey_modulus) >= sizeof(pbMyPubKey.Modulus)); + for (i = 0; i < sizeof(pbMyPubKey.Modulus); i++) + pbMyPubKey.Modulus[i] = rsa_pubkey_modulus[sizeof(rsa_pubkey_modulus) -1 - i]; + + // Import our RSA public key so that the MS API can use it + r = CryptImportKey(hProv, (BYTE*)&pbMyPubKey.BlobHeader, dwMyPubKeyLen, 0, 0, &hPubKey); + if (!r) { + uprintf("Could not import public key: %s", WinPKIErrorString()); + goto out; + } + + // Create the hash object. + r = CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash); + if (!r) { + uprintf("Could not create empty hash: %s", WinPKIErrorString()); + goto out; + } + + // Compute the cryptographic hash of the buffer. + r = CryptHashData(hHash, pbBuffer, dwBufferLen, 0); + if (!r) { + uprintf("Could not hash data: %s", WinPKIErrorString()); + goto out; + } + + // Reverse the signature bytes + for (i = 0, j = dwSigLen - 1; i < j; i++, j--) { + t = pbSignature[i]; + pbSignature[i] = pbSignature[j]; + pbSignature[j] = t; + } + + // Now that we have all of the public key, hash and signature data in a + // format that Microsoft can handle, we can call CryptVerifySignature(). + r = CryptVerifySignature(hHash, pbSignature, dwSigLen, hPubKey, NULL, 0); + if (!r) + uprintf("Signature validation failed: %s", WinPKIErrorString()); + +out: + if (hHash) + CryptDestroyHash(hHash); + if (hProv) + CryptReleaseContext(hProv, 0); + return r; +} diff --git a/src/rufus.c b/src/rufus.c index a040df2d..9d0356de 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "rufus.h" #include "missing.h" @@ -51,6 +52,7 @@ static const char* cmdline_hogger = "rufus.com"; static const char* FileSystemLabel[FS_MAX] = { "FAT", "FAT32", "NTFS", "UDF", "exFAT", "ReFS" }; +static const char* flash_type[BADLOCKS_PATTERN_TYPES] = { "SLC", "MLC", "TLC" }; static const char* ep_reg = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"; static const char* vs_reg = "Software\\Microsoft\\VisualStudio"; // Number of steps for each FS for FCC_STRUCTURE_PROGRESS @@ -1165,9 +1167,12 @@ static __inline void MoveCtrlY(HWND hDlg, int nID, int vertical_shift) { static void SetPassesTooltip(void) { - const unsigned char pattern[] = BADBLOCK_PATTERNS; - CreateTooltip(hNBPasses, lmprintf(MSG_153 + ComboBox_GetCurSel(hNBPasses), - pattern[0], pattern[1], pattern[2], pattern[3]), -1); + const unsigned int pattern[BADLOCKS_PATTERN_TYPES][BADBLOCK_PATTERN_COUNT] = + { BADBLOCK_PATTERN_SLC, BADCLOCK_PATTERN_MLC, BADBLOCK_PATTERN_TLC }; + int sel = ComboBox_GetCurSel(hNBPasses); + int type = (sel < 2) ? 0 : sel - 2; + CreateTooltip(hNBPasses, lmprintf(MSG_153 + ((sel >= 2) ? 3 : sel), + pattern[type][0], pattern[type][1], pattern[type][2], pattern[type][3]), -1); } static void ResizeDialogs(int shift) @@ -1341,14 +1346,13 @@ static void UpdateImage(void) } } - if (image_path != NULL) { - ComboBox_DeleteString(hBootType, index); - ComboBox_InsertStringU(hBootType, index, short_image_path); - ComboBox_SetItemData(hBootType, index, BT_IMAGE); - IGNORE_RETVAL(ComboBox_SetCurSel(hBootType, index)); - bt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType)); - SetBootTypeDropdownWidth(); - } + ComboBox_DeleteString(hBootType, index); + ComboBox_InsertStringU(hBootType, index, + (image_path == NULL) ? lmprintf(MSG_281, lmprintf(MSG_280)) : short_image_path); + ComboBox_SetItemData(hBootType, index, BT_IMAGE); + IGNORE_RETVAL(ComboBox_SetCurSel(hBootType, index)); + bt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType)); + SetBootTypeDropdownWidth(); } // The scanning process can be blocking for message processing => use a thread @@ -1358,6 +1362,7 @@ DWORD WINAPI ISOScanThread(LPVOID param) if (image_path == NULL) goto out; + format_op_in_progress = TRUE; PrintInfoDebug(0, MSG_202); user_notified = FALSE; EnableControls(FALSE); @@ -1365,15 +1370,16 @@ 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.image_size == 0) || (!img_report.is_iso && !img_report.is_bootable_img)) { + if (IS_ERROR(FormatStatus) || (img_report.image_size == 0) || (!img_report.is_iso && !img_report.is_bootable_img)) { // Failed to scan image SendMessage(hMainDialog, UM_PROGRESS_EXIT, 0, 0); safe_free(image_path); - EnableControls(TRUE); + UpdateImage(); SetMBRProps(); PopulateProperties(); PrintInfoDebug(0, MSG_203); PrintStatus(0, MSG_203); + EnableControls(TRUE); goto out; } @@ -1435,15 +1441,18 @@ DWORD WINAPI ISOScanThread(LPVOID param) out: dont_display_image_name = FALSE; + format_op_in_progress = FALSE; PrintInfo(0, MSG_210); ExitThread(0); } -static BOOL BootCheck(void) +// Likewise, boot check will block message processing => use a thread +static DWORD WINAPI BootCheckThread(LPVOID param) { int i, r; FILE *fd; DWORD len; + WPARAM ret = -1; BOOL in_files_dir = FALSE; const char* grub = "grub"; const char* core_img = "core.img"; @@ -1454,34 +1463,42 @@ static BOOL BootCheck(void) syslinux_ldlinux_len[0] = 0; syslinux_ldlinux_len[1] = 0; safe_free(grub2_buf); + + if (ComboBox_GetCurSel(hDeviceList) == CB_ERR) + goto out; + + if ((zero_drive) || (bt == BT_NON_BOOTABLE)) { + // Nothing to check + ret = 0; + goto out; + } + if (bt == BT_IMAGE) { - // We should never be there - if (image_path == NULL) { - uprintf("Spock gone crazy error in %s:%d", __FILE__, __LINE__); - MessageBoxExU(hMainDialog, "image_path is NULL. Please report this error to the author of this application", "Logic error", MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); - return FALSE; - } + assert(image_path != NULL); + if (image_path == NULL) + goto out; if ((size_check) && (img_report.projected_size > (uint64_t)SelectedDrive.DiskSize)) { // This ISO image is too big for the selected target MessageBoxExU(hMainDialog, lmprintf(MSG_089), lmprintf(MSG_088), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); - return FALSE; + goto out; } if (IS_DD_BOOTABLE(img_report) && !img_report.is_iso) { // Pure DD images are fine at this stage - return TRUE; + ret = 0; + goto out; } if ((display_togo_option) && (ComboBox_GetCurSel(GetDlgItem(hMainDialog, IDC_IMAGE_OPTION)) == 1)) { if (fs != FS_NTFS) { // Windows To Go only works for NTFS MessageBoxExU(hMainDialog, lmprintf(MSG_097, "Windows To Go"), lmprintf(MSG_092), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); - return FALSE; + goto out; } if (SelectedDrive.MediaType != FixedMedia) { if ((tt == TT_UEFI) && (pt == PARTITION_STYLE_GPT) && (nWindowsBuildNumber < 15000)) { // Up to Windows 10 Creators Update, we were screwed, since we need access to 2 partitions at the same time. // Thankfully, the newer Windows allow mounting multiple partitions on the same REMOVABLE drive. MessageBoxExU(hMainDialog, lmprintf(MSG_198), lmprintf(MSG_190), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); - return FALSE; + goto out; } } // If multiple versions are available, asks the user to select one before we commit to format the drive @@ -1490,7 +1507,7 @@ static BOOL BootCheck(void) MessageBoxExU(hMainDialog, lmprintf(MSG_073), lmprintf(MSG_291), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid); // fall through case -2: - return FALSE; + goto out; default: break; } @@ -1498,13 +1515,13 @@ static BOOL BootCheck(void) if (!IS_EFI_BOOTABLE(img_report)) { // Unsupported ISO MessageBoxExU(hMainDialog, lmprintf(MSG_091), lmprintf(MSG_090), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); - return FALSE; + goto out; } if (HAS_WIN7_EFI(img_report) && (!WimExtractCheck())) { // Your platform cannot extract files from WIM archives => download 7-zip? if (MessageBoxExU(hMainDialog, lmprintf(MSG_102), lmprintf(MSG_101), MB_YESNO|MB_ICONERROR|MB_IS_RTL, selected_langid) == IDYES) ShellExecuteA(hMainDialog, "open", SEVENZIP_URL, NULL, NULL, SW_SHOWNORMAL); - return FALSE; + goto out; } } else if ( ((fs == FS_NTFS) && !HAS_WINDOWS(img_report) && !HAS_GRUB(img_report) && (!HAS_SYSLINUX(img_report) || (SL_MAJOR(img_report.sl_version) <= 5))) @@ -1513,16 +1530,16 @@ static BOOL BootCheck(void) || ((IS_FAT(fs)) && (HAS_WINDOWS(img_report) || HAS_INSTALL_WIM(img_report)) && (!allow_dual_uefi_bios)) ) { // Incompatible FS and ISO MessageBoxExU(hMainDialog, lmprintf(MSG_096), lmprintf(MSG_092), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); - return FALSE; + goto out; } else if ((fs == FS_FAT16) && HAS_KOLIBRIOS(img_report)) { // KolibriOS doesn't support FAT16 MessageBoxExU(hMainDialog, lmprintf(MSG_189), lmprintf(MSG_099), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); - return FALSE; + goto out; } if ((IS_FAT(fs)) && (img_report.has_4GB_file)) { // This ISO image contains a file larger than 4GB file (FAT32) MessageBoxExU(hMainDialog, lmprintf(MSG_100), lmprintf(MSG_099), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); - return FALSE; + goto out; } // If the selected target doesn't include include BIOS, skip file downloads for GRUB/Syslinux @@ -1557,15 +1574,13 @@ static BOOL BootCheck(void) r = MessageBoxExU(hMainDialog, lmprintf(MSG_116, img_report.grub2_version, GRUB2_PACKAGE_VERSION), lmprintf(MSG_115), MB_YESNOCANCEL|MB_ICONWARNING|MB_IS_RTL, selected_langid); if (r == IDCANCEL) - return FALSE; + goto out; else if (r == IDYES) { static_sprintf(tmp, "%s-%s", grub, img_report.grub2_version); IGNORE_RETVAL(_mkdir(tmp)); IGNORE_RETVAL(_chdir(tmp)); static_sprintf(tmp, "%s/%s-%s/%s", FILES_URL, grub, img_report.grub2_version, core_img); - PromptOnError = FALSE; - grub2_len = (long)DownloadFile(tmp, core_img, hMainDialog); - PromptOnError = TRUE; + grub2_len = (long)DownloadSignedFile(tmp, core_img, hMainDialog, FALSE); if ((grub2_len == 0) && (DownloadStatus == 404)) { // Couldn't locate the file on the server => try to download without the version extra uprintf("Extended version was not found, trying main version..."); @@ -1574,9 +1589,7 @@ static BOOL BootCheck(void) for (i = 0; ((tmp2[i] >= '0') && (tmp2[i] <= '9')) || (tmp2[i] == '.'); i++); tmp2[i] = 0; static_sprintf(tmp, "%s/%s-%s/%s", FILES_URL, grub, tmp2, core_img); - PromptOnError = FALSE; - grub2_len = (long)DownloadFile(tmp, core_img, hMainDialog); - PromptOnError = TRUE; + grub2_len = (long)DownloadSignedFile(tmp, core_img, hMainDialog, FALSE); static_sprintf(tmp, "%s/%s-%s/%s", FILES_URL, grub, img_report.grub2_version, core_img); } if (grub2_len <= 0) { @@ -1621,10 +1634,10 @@ static BOOL BootCheck(void) static_sprintf(tmp, "%s-%s", syslinux, embedded_sl_version_str[0]); IGNORE_RETVAL(_mkdir(tmp)); static_sprintf(tmp, "%s/%s-%s/%s", FILES_URL, syslinux, embedded_sl_version_str[0], old_c32_name[i]); - len = DownloadFile(tmp, &tmp[sizeof(FILES_URL)], hMainDialog); + len = DownloadSignedFile(tmp, &tmp[sizeof(FILES_URL)], hMainDialog, TRUE); if (len == 0) { uprintf("Could not download file - cancelling"); - return FALSE; + goto out; } use_own_c32[i] = TRUE; } @@ -1657,7 +1670,7 @@ static BOOL BootCheck(void) embedded_sl_version_str[1], embedded_sl_version_ext[1]), lmprintf(MSG_115), MB_YESNO|MB_ICONWARNING|MB_IS_RTL, selected_langid); if (r != IDYES) - return FALSE; + goto out; for (i=0; i<2; i++) { static_sprintf(tmp, "%s-%s", syslinux, img_report.sl_version_str); IGNORE_RETVAL(_mkdir(tmp)); @@ -1668,15 +1681,15 @@ static BOOL BootCheck(void) } static_sprintf(tmp, "%s/%s-%s%s/%s.%s", FILES_URL, syslinux, img_report.sl_version_str, img_report.sl_version_ext, ldlinux, ldlinux_ext[i]); - PromptOnError = (*img_report.sl_version_ext == 0); - syslinux_ldlinux_len[i] = DownloadFile(tmp, &tmp[sizeof(FILES_URL)], hMainDialog); - PromptOnError = TRUE; + syslinux_ldlinux_len[i] = DownloadSignedFile(tmp, &tmp[sizeof(FILES_URL)], + hMainDialog, (*img_report.sl_version_ext == 0)); if ((syslinux_ldlinux_len[i] == 0) && (DownloadStatus == 404) && (*img_report.sl_version_ext != 0)) { // Couldn't locate the file on the server => try to download without the version extra uprintf("Extended version was not found, trying main version..."); static_sprintf(tmp, "%s/%s-%s/%s.%s", FILES_URL, syslinux, img_report.sl_version_str, ldlinux, ldlinux_ext[i]); - syslinux_ldlinux_len[i] = DownloadFile(tmp, &tmp[sizeof(FILES_URL)], hMainDialog); + syslinux_ldlinux_len[i] = DownloadSignedFile(tmp, &tmp[sizeof(FILES_URL)], + hMainDialog, (*img_report.sl_version_ext == 0)); if (syslinux_ldlinux_len[i] != 0) { // Duplicate the file so that the user won't be prompted to download again static_sprintf(tmp, "%s-%s\\%s.%s", syslinux, img_report.sl_version_str, ldlinux, ldlinux_ext[i]); @@ -1691,7 +1704,7 @@ static BOOL BootCheck(void) 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"); - return FALSE; + goto out; } } } @@ -1714,20 +1727,20 @@ static BOOL BootCheck(void) r = MessageBoxExU(hMainDialog, lmprintf(MSG_104, "Syslinux v5.0", tmp, "Syslinux v5+", tmp), lmprintf(MSG_103, tmp), MB_YESNOCANCEL|MB_ICONWARNING|MB_IS_RTL, selected_langid); if (r == IDCANCEL) - return FALSE; + goto out; if (r == IDYES) { static_sprintf(tmp, "%s-%s", syslinux, embedded_sl_version_str[1]); IGNORE_RETVAL(_mkdir(tmp)); static_sprintf(tmp, "%s/%s-%s/%s.%s", FILES_URL, syslinux, embedded_sl_version_str[1], ldlinux, ldlinux_ext[2]); - if (DownloadFile(tmp, &tmp[sizeof(FILES_URL)], hMainDialog) == 0) - return FALSE; + if (DownloadSignedFile(tmp, &tmp[sizeof(FILES_URL)], hMainDialog, TRUE) == 0) + goto out; } } } else if (bt == BT_MSDOS) { if ((size_check) && (ComboBox_GetItemData(hClusterSize, ComboBox_GetCurSel(hClusterSize)) >= 65536)) { // MS-DOS cannot boot from a drive using a 64 kilobytes Cluster size MessageBoxExU(hMainDialog, lmprintf(MSG_110), lmprintf(MSG_111), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); - return FALSE; + goto out; } } else if (bt == BT_GRUB4DOS) { IGNORE_RETVAL(_chdirU(app_dir)); @@ -1744,13 +1757,13 @@ static BOOL BootCheck(void) r = MessageBoxExU(hMainDialog, lmprintf(MSG_104, "Grub4DOS 0.4", tmp, "Grub4DOS", tmp), lmprintf(MSG_103, tmp), MB_YESNOCANCEL|MB_ICONWARNING|MB_IS_RTL, selected_langid); if (r == IDCANCEL) - return FALSE; + goto out; if (r == IDYES) { static_sprintf(tmp, "grub4dos-%s", GRUB4DOS_VERSION); IGNORE_RETVAL(_mkdir(tmp)); static_sprintf(tmp, "%s/grub4dos-%s/grldr", FILES_URL, GRUB4DOS_VERSION); - if (DownloadFile(tmp, &tmp[sizeof(FILES_URL)], hMainDialog) == 0) - return FALSE; + if (DownloadSignedFile(tmp, &tmp[sizeof(FILES_URL)], hMainDialog, TRUE) == 0) + goto out; } } } @@ -1760,10 +1773,14 @@ uefi_target: fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem)); if (fs != FS_NTFS) { MessageBoxExU(hMainDialog, lmprintf(MSG_097, "UEFI:NTFS"), lmprintf(MSG_092), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); - return FALSE; + goto out; } } - return TRUE; + ret = 0; + +out: + PostMessage(hMainDialog, UM_FORMAT_START, ret, 0); + ExitThread((DWORD)ret); } static __inline const char* IsAlphaOrBeta(void) @@ -2197,9 +2214,10 @@ static void GetHalfDropwdownWidth(HWND hDlg) hw = max(hw, GetTextSize(GetDlgItem(hDlg, IDC_TARGET_SYSTEM), lmprintf(msg_id)).cx); // Just in case, we also do the number of passes - for (i = 1; i <= 4; i++) - hw = max(hw, GetTextSize(GetDlgItem(hDlg, IDC_TARGET_SYSTEM), - lmprintf((i == 1) ? MSG_034 : MSG_035, i)).cx); + for (i = 1; i <= 5; i++) { + char* msg = (i == 1) ? lmprintf(MSG_034, 1) : lmprintf(MSG_035, (i == 2) ? 2 : 4, (i == 2) ? "" : lmprintf(MSG_087, flash_type[i - 3])); + hw = max(hw, GetTextSize(GetDlgItem(hDlg, IDC_TARGET_SYSTEM), msg).cx); + } // Finally, we must ensure that we'll have enough space for the 2 checkbox controls // that end up with a half dropdown @@ -2529,7 +2547,7 @@ static void InitDialog(HWND hDlg) DWORD len; HDC hDC; int i, lfHeight; - char tmp[128], *token, *buf, *ext; + char tmp[128], *token, *buf, *ext, *msg; static char* resource[2] = { MAKEINTRESOURCEA(IDR_SL_LDLINUX_V4_SYS), MAKEINTRESOURCEA(IDR_SL_LDLINUX_V6_SYS) }; #ifdef RUFUS_TEST @@ -2635,8 +2653,9 @@ static void InitDialog(HWND hDlg) SendMessage(hProgress, PBM_SETRANGE, 0, (MAX_PROGRESS<<16) & 0xFFFF0000); // Fill up the passes - for (i=0; i<4; i++) { - IGNORE_RETVAL(ComboBox_AddStringU(hNBPasses, lmprintf((i==0)?MSG_034:MSG_035, i+1))); + for (i = 1; i <= 5; i++) { + msg = (i == 1) ? lmprintf(MSG_034, 1) : lmprintf(MSG_035, (i == 2) ? 2 : 4, (i == 2) ? "" : lmprintf(MSG_087, flash_type[i - 3])); + IGNORE_RETVAL(ComboBox_AddStringU(hNBPasses, msg)); } IGNORE_RETVAL(ComboBox_SetCurSel(hNBPasses, 0)); SetPassesTooltip(); @@ -2973,7 +2992,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA case WM_COMMAND: #ifdef RUFUS_TEST if (LOWORD(wParam) == IDC_TEST) { - Notification(MSG_ERROR, NULL, lmprintf(MSG_042), lmprintf(MSG_043, lmprintf(MSG_055))); + DownloadSignedFile(FILES_URL "/gendb.sh", "C:\\Downloads\\gendb.sh", hProgress); break; } #endif @@ -3020,6 +3039,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA // User might be trying to cancel during preliminary checks FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED; PrintInfo(0, MSG_201); + EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE); return (INT_PTR)TRUE; } if (ulRegister != 0) @@ -3217,6 +3237,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA } } FormatStatus = 0; + format_op_in_progress = FALSE; if (CreateThread(NULL, 0, ISOScanThread, NULL, 0, NULL) == NULL) { uprintf("Unable to start ISO scanning thread"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_START_THREAD); @@ -3254,86 +3275,13 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA SetTaskbarProgressValue(0, MAX_PROGRESS); SendMessage(hProgress, PBM_SETPOS, 0, 0); selection_default = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType)); - nDeviceIndex = ComboBox_GetCurSel(hDeviceList); - if (nDeviceIndex != CB_ERR) { - if (!zero_drive) { - if ((bt != BT_NON_BOOTABLE) && (!BootCheck())) - goto aborted_start; - - // Display a warning about UDF formatting times - if (fs == FS_UDF) { - dur_secs = (uint32_t)(((double)SelectedDrive.DiskSize) / 1073741824.0f / UDF_FORMAT_SPEED); - if (dur_secs > UDF_FORMAT_WARN) { - dur_mins = dur_secs / 60; - dur_secs -= dur_mins * 60; - MessageBoxExU(hMainDialog, lmprintf(MSG_112, dur_mins, dur_secs), lmprintf(MSG_113), - MB_OK | MB_ICONASTERISK | MB_IS_RTL, selected_langid); - } else { - dur_secs = 0; - dur_mins = 0; - } - } - - if ((bt == BT_IMAGE) && IS_DD_BOOTABLE(img_report)) { - if (img_report.is_iso) { - // Ask users how they want to write ISOHybrid images - char* iso_image = lmprintf(MSG_036); - char* dd_image = lmprintf(MSG_095); - char* choices[2] = { lmprintf(MSG_276, iso_image), lmprintf(MSG_277, dd_image) }; - i = SelectionDialog(lmprintf(MSG_274), lmprintf(MSG_275, iso_image, dd_image, iso_image, dd_image), - choices, 2); - if (i < 0) // Cancel - goto aborted_start; - else if (i == 2) - write_as_image = TRUE; - } else { - write_as_image = TRUE; - } - } - } - - if (!CheckDriveAccess(2000)) - goto aborted_start; - - GetWindowTextU(hDeviceList, tmp, ARRAYSIZE(tmp)); - if (MessageBoxExU(hMainDialog, lmprintf(MSG_003, tmp), - APPLICATION_NAME, MB_OKCANCEL|MB_ICONWARNING|MB_IS_RTL, selected_langid) == IDCANCEL) - goto aborted_start; - if ((SelectedDrive.nPartitions > 1) && (MessageBoxExU(hMainDialog, lmprintf(MSG_093), - lmprintf(MSG_094), MB_OKCANCEL|MB_ICONWARNING|MB_IS_RTL, selected_langid) == IDCANCEL)) - goto aborted_start; - if ((!zero_drive) && (bt != BT_NON_BOOTABLE) && (SelectedDrive.SectorSize != 512) && - (MessageBoxExU(hMainDialog, lmprintf(MSG_196, SelectedDrive.SectorSize), - lmprintf(MSG_197), MB_OKCANCEL|MB_ICONWARNING|MB_IS_RTL, selected_langid) == IDCANCEL)) - goto aborted_start; - - DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex); - InitProgress(zero_drive || write_as_image); - format_thid = CreateThread(NULL, 0, FormatThread, (LPVOID)(uintptr_t)DeviceNum, 0, NULL); - if (format_thid == NULL) { - uprintf("Unable to start formatting thread"); - FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_START_THREAD); - PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0); - } else { - uprintf("\r\nFormat operation started"); - PrintInfo(0, -1); - timer = 0; - static_sprintf(szTimer, "00:00:00"); - SendMessageA(hStatus, SB_SETTEXTA, SBT_OWNERDRAW | SB_SECTION_RIGHT, (LPARAM)szTimer); - SetTimer(hMainDialog, TID_APP_TIMER, 1000, ClockTimer); - // Set focus to the Cancel button - SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hMainDialog, IDCANCEL), TRUE); - } + // Create a thread to validate options and download files as needed (so that we can update the UI). + // On exit, this thread sends message UM_FORMAT_START back to this dialog. + if (CreateThread(NULL, 0, BootCheckThread, NULL, 0, NULL) == NULL) { + uprintf("Unable to start boot check thread"); + FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD); + PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0); } - if (format_thid != NULL) - break; - aborted_start: - format_op_in_progress = FALSE; - EnableControls(TRUE); - zero_drive = FALSE; - if (queued_hotplug_event) - SendMessage(hDlg, UM_MEDIA_CHANGE, 0, 0); - EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE); break; case IDC_LANG: // Show the language menu such that it doesn't overlap the button @@ -3610,6 +3558,87 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA SendMessage(hUpdatesDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hUpdatesDlg, IDC_CHECK_NOW), TRUE); break; + case UM_FORMAT_START: + if (wParam != 0) + goto aborted_start; + + if (!zero_drive) { + // Display a warning about UDF formatting times + if (fs == FS_UDF) { + dur_secs = (uint32_t)(((double)SelectedDrive.DiskSize) / 1073741824.0f / UDF_FORMAT_SPEED); + if (dur_secs > UDF_FORMAT_WARN) { + dur_mins = dur_secs / 60; + dur_secs -= dur_mins * 60; + MessageBoxExU(hMainDialog, lmprintf(MSG_112, dur_mins, dur_secs), lmprintf(MSG_113), + MB_OK | MB_ICONASTERISK | MB_IS_RTL, selected_langid); + } else { + dur_secs = 0; + dur_mins = 0; + } + } + + if ((bt == BT_IMAGE) && IS_DD_BOOTABLE(img_report)) { + if (img_report.is_iso) { + // Ask users how they want to write ISOHybrid images + char* iso_image = lmprintf(MSG_036); + char* dd_image = lmprintf(MSG_095); + char* choices[2] = { lmprintf(MSG_276, iso_image), lmprintf(MSG_277, dd_image) }; + i = SelectionDialog(lmprintf(MSG_274), lmprintf(MSG_275, iso_image, dd_image, iso_image, dd_image), + choices, 2); + if (i < 0) // Cancel + goto aborted_start; + else if (i == 2) + write_as_image = TRUE; + } else { + write_as_image = TRUE; + } + } + } + + if (!CheckDriveAccess(2000)) + goto aborted_start; + + GetWindowTextU(hDeviceList, tmp, ARRAYSIZE(tmp)); + if (MessageBoxExU(hMainDialog, lmprintf(MSG_003, tmp), + APPLICATION_NAME, MB_OKCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid) == IDCANCEL) + goto aborted_start; + if ((SelectedDrive.nPartitions > 1) && (MessageBoxExU(hMainDialog, lmprintf(MSG_093), + lmprintf(MSG_094), MB_OKCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid) == IDCANCEL)) + goto aborted_start; + if ((!zero_drive) && (bt != BT_NON_BOOTABLE) && (SelectedDrive.SectorSize != 512) && + (MessageBoxExU(hMainDialog, lmprintf(MSG_196, SelectedDrive.SectorSize), + lmprintf(MSG_197), MB_OKCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid) == IDCANCEL)) + goto aborted_start; + + nDeviceIndex = ComboBox_GetCurSel(hDeviceList); + DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex); + InitProgress(zero_drive || write_as_image); + format_thid = CreateThread(NULL, 0, FormatThread, (LPVOID)(uintptr_t)DeviceNum, 0, NULL); + if (format_thid == NULL) { + uprintf("Unable to start formatting thread"); + FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD); + PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0); + } else { + uprintf("\r\nFormat operation started"); + PrintInfo(0, -1); + timer = 0; + static_sprintf(szTimer, "00:00:00"); + SendMessageA(hStatus, SB_SETTEXTA, SBT_OWNERDRAW | SB_SECTION_RIGHT, (LPARAM)szTimer); + SetTimer(hMainDialog, TID_APP_TIMER, 1000, ClockTimer); + // Set focus to the Cancel button + SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hMainDialog, IDCANCEL), TRUE); + } + if (format_thid != NULL) + break; + aborted_start: + format_op_in_progress = FALSE; + EnableControls(TRUE); + zero_drive = FALSE; + if (queued_hotplug_event) + SendMessage(hDlg, UM_MEDIA_CHANGE, 0, 0); + EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE); + break; + case UM_FORMAT_COMPLETED: format_thid = NULL; // Stop the timer diff --git a/src/rufus.h b/src/rufus.h index 04c70a75..62651b56 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -67,7 +67,12 @@ #define MARQUEE_TIMER_REFRESH 10 // Time between progress bar marquee refreshes, in ms #define FS_DEFAULT FS_FAT32 #define SINGLE_CLUSTERSIZE_DEFAULT 0x00000100 -#define BADBLOCK_PATTERNS {0xaa, 0x55, 0xff, 0x00} +#define BADLOCKS_PATTERN_TYPES 3 +#define BADBLOCK_PATTERN_COUNT 4 +#define BADBLOCK_PATTERN_SLC {0x00, 0xff, 0x55, 0xaa} +#define BADCLOCK_PATTERN_MLC {0x00, 0xff, 0x33, 0xcc} +#define BADBLOCK_PATTERN_TLC {0x00, 0xff, 0x1c71c7, 0xe38e38} +#define BADBLOCK_BLOCK_SIZE (128 * 1024) #define LARGE_FAT32_SIZE (32*1073741824LL) // Size at which we need to use fat32format #define UDF_FORMAT_SPEED 3.1f // Speed estimate at which we expect UDF drives to be formatted (GB/s) #define UDF_FORMAT_WARN 20 // Duration (in seconds) above which we warn about long UDF formatting times @@ -75,6 +80,7 @@ #define FAT32_CLUSTER_THRESHOLD 1.011f // For FAT32, cluster size changes don't occur at power of 2 boundaries but sligthly above #define DD_BUFFER_SIZE 65536 // Minimum size of the buffer we use for DD operations #define UBUFFER_SIZE 2048 +#define RSA_SIGNATURE_SIZE 256 #define CBN_SELCHANGE_INTERNAL (CBN_SELCHANGE + 256) #define RUFUS_URL "https://rufus.ie" #define DOWNLOAD_URL RUFUS_URL "/downloads" @@ -157,6 +163,7 @@ enum user_message_type { UM_NO_UPDATE, UM_UPDATE_CSM_TOOLTIP, UM_RESIZE_BUTTONS, + UM_FORMAT_START, // Start of the WM IDs for the language menu items UM_LANGUAGE_MENU = WM_APP + 0x100 }; @@ -394,7 +401,6 @@ extern float fScale; extern char szFolderPath[MAX_PATH], app_dir[MAX_PATH], temp_dir[MAX_PATH], system_dir[MAX_PATH], sysnative_dir[MAX_PATH]; extern char* image_path; extern DWORD FormatStatus, DownloadStatus, MainThreadId; -extern BOOL PromptOnError; extern unsigned long syslinux_ldlinux_len[2]; 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; @@ -470,8 +476,8 @@ extern BOOL ResetDevice(int index); extern BOOL GetOpticalMedia(IMG_SAVE* img_save); 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); -extern HANDLE DownloadFileThreaded(const char* url, const char* file, HWND hProgressDialog); +extern DWORD DownloadSignedFile(const char* url, const char* file, HWND hProgressDialog, BOOL PromptOnError); +extern HANDLE DownloadSignedFileThreaded(const char* url, const char* file, HWND hProgressDialog, BOOL bPromptOnError); extern INT_PTR CALLBACK UpdateCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); extern BOOL SetUpdateCheck(void); extern BOOL CheckForUpdates(BOOL force); @@ -498,6 +504,7 @@ extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid extern char* GetSignatureName(const char* path, const char* country_code); extern uint64_t GetSignatureTimeStamp(const char* path); extern LONG ValidateSignature(HWND hDlg, const char* path); +extern BOOL ValidateOpensslSignature(BYTE* pbBuffer, DWORD dwBufferLen, BYTE* pbSignature, DWORD dwSigLen); extern BOOL IsFontAvailable(const char* font_name); extern BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries); @@ -607,3 +614,4 @@ static __inline HMODULE GetLibraryHandle(char* szLibraryName) { #define ERROR_CANT_PATCH 0x120A #define ERROR_CANT_ASSIGN_LETTER 0x120B #define ERROR_CANT_MOUNT_VOLUME 0x120C +#define ERROR_BAD_SIGNATURE 0x120D diff --git a/src/rufus.rc b/src/rufus.rc index 06a27776..9e76b862 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 3.1.1323" +CAPTION "Rufus 3.2.1328" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -389,8 +389,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,1,1323,0 - PRODUCTVERSION 3,1,1323,0 + FILEVERSION 3,2,1328,0 + PRODUCTVERSION 3,2,1328,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -407,13 +407,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.1.1323" + VALUE "FileVersion", "3.2.1328" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2018 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.1.1323" + VALUE "ProductVersion", "3.2.1328" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index 1fc4116d..4353d6a4 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -315,6 +315,8 @@ const char* _StrError(DWORD error_code) return lmprintf(MSG_078); case ERROR_NOT_READY: return lmprintf(MSG_079); + case ERROR_BAD_SIGNATURE: + return lmprintf(MSG_172); default: SetLastError(error_code); return WindowsErrorString(); diff --git a/src/stdlg.c b/src/stdlg.c index 234074f8..6032f1f2 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -1558,8 +1558,9 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR static char* filepath = NULL; static int download_status = 0; static HFONT hyperlink_font = NULL; - LONG i; + static HANDLE hThread = NULL; HWND hNotes; + DWORD exit_code; STARTUPINFOA si; PROCESS_INFORMATION pi; EXT_DECL(dl_ext, NULL, __VA_GROUP__("*.exe"), __VA_GROUP__(lmprintf(MSG_037))); @@ -1614,8 +1615,16 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR case 1: // Abort FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED; download_status = 0; + hThread = NULL; break; case 2: // Launch newer version and close this one + if ((hThread == NULL) || (!GetExitCodeThread(hThread, &exit_code)) || (exit_code == 0)) { + hThread = NULL; + EnableWindow(GetDlgItem(hDlg, IDC_DOWNLOAD), FALSE); + break; + } + + hThread = NULL; Sleep(1000); // Add a delay on account of antivirus scanners if (ValidateSignature(hDlg, filepath) != NO_ERROR) { @@ -1630,7 +1639,7 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR si.cb = sizeof(si); if (!CreateProcessU(filepath, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { PrintInfo(0, MSG_214); - uprintf("Failed to launch new application: %s\n", WindowsErrorString()); + uprintf("Failed to launch new application: %s", WindowsErrorString()); } else { PrintInfo(0, MSG_213); PostMessage(hDlg, WM_COMMAND, (WPARAM)IDCLOSE, 0); @@ -1639,19 +1648,18 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR break; default: // Download if (update.download_url == NULL) { - uprintf("Could not get download URL\n"); + uprintf("Could not get download URL"); break; } - for (i=(int)strlen(update.download_url); (i>0)&&(update.download_url[i]!='/'); i--); - dl_ext.filename = &update.download_url[i+1]; + dl_ext.filename = PathFindFileNameU(update.download_url); filepath = FileDialog(TRUE, app_dir, &dl_ext, OFN_NOCHANGEDIR); if (filepath == NULL) { - uprintf("Could not get save path\n"); + uprintf("Could not get save path"); break; } // Opening the File Dialog will make us lose tabbing focus - set it back SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDC_DOWNLOAD), TRUE); - DownloadFileThreaded(update.download_url, filepath, hDlg); + hThread = DownloadSignedFileThreaded(update.download_url, filepath, hDlg, TRUE); break; } return (INT_PTR)TRUE; @@ -1665,11 +1673,14 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR return (INT_PTR)TRUE; case UM_PROGRESS_EXIT: EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE); - if (wParam) { + if (wParam != 0) { SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD), lmprintf(MSG_039)); download_status = 2; } else { SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD), lmprintf(MSG_040)); + // Disable the download button if we found an invalid signature + EnableWindow(GetDlgItem(hDlg, IDC_DOWNLOAD), + FormatStatus != (ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_BAD_SIGNATURE))); download_status = 0; } return (INT_PTR)TRUE;