diff --git a/_sign.cmd b/_sign.cmd index 2b9dbbef..b876207d 100644 --- a/_sign.cmd +++ b/_sign.cmd @@ -1,6 +1,6 @@ :retry @set /p password=Please enter PFX password: -@E:\WinDDK\7600.16385.0\bin\amd64\signtool sign /v /f D:\Secured\akeo\akeo.p12 /p %password% /tr http://timestamp.comodoca.com/rfc3161 %1 %2 %3 %4 +@"C:\Program Files (x86)\Windows Kits\8.0\bin\x64\signtool" sign /v /f D:\Secured\akeo\akeo.p12 /p %password% /tr http://timestamp.comodoca.com/rfc3161 %1 %2 %3 %4 @if ERRORLEVEL 1 goto retry @set password= @exit diff --git a/src/net.c b/src/net.c index f5a0cea5..7cb3e58d 100644 --- a/src/net.c +++ b/src/net.c @@ -273,7 +273,7 @@ BOOL DownloadFile(const char* url, const char* file) uprintf("Network is unavailable: %s\n", WinInetErrorString()); goto out; } - _snprintf(agent, ARRAYSIZE(agent), "Rufus/%d.%d.%d.%d", rufus_version[0], rufus_version[1], rufus_version[2], rufus_version[3]); + _snprintf(agent, ARRAYSIZE(agent), APPLICATION_NAME "/%d.%d.%d.%d", rufus_version[0], rufus_version[1], rufus_version[2], rufus_version[3]); hSession = InternetOpenA(agent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (hSession == NULL) { uprintf("Could not open internet session: %s\n", WinInetErrorString()); @@ -364,26 +364,32 @@ out: return r; } -#define uuprintf if(verbose) uprintf -#define uuuprintf if(verbose>1) uprintf -// TODO: call this from a thread that will launch the download if successful -BOOL CheckForUpdates(const char* url) +// TODO: check that no format operation is occurring +DWORD WINAPI CheckForUpdatesThread(LPVOID param) { + const char* server_url = RUFUS_URL "/"; BOOL r = FALSE; - int verbose = 2; + int i, j, verbose = 2, verpos[4]; + static char* archname[] = {"win_x86", "win_x64"}; DWORD dwFlags, dwSize, dwDownloaded, dwTotalSize, dwStatus; char* buf = NULL; char agent[64], hostname[64], urlpath[128], 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, hostname, sizeof(hostname), 0, NULL, 1, urlpath, sizeof(urlpath), NULL, 1}; SYSTEMTIME ServerTime, LocalTime; FILETIME FileTime; int64_t local_time, reg_time, server_time, update_interval; + BOOL is_x64 = FALSE, (__stdcall *pIsWow64Process)(HANDLE, PBOOL) = NULL; - verbose = ReadRegistryKey32(REGKEY_VERBOSE_UPDATES); + // Wait a while before checking for updates + // TODO: start the thread in sleep mode and only wake it on user inactivity? +// Sleep(15000); + +// verbose = ReadRegistryKey32(REGKEY_VERBOSE_UPDATES); if (GetRegistryKeyBool(REGKEY_DISABLE_UPDATES)) { - uuprintf("Check for updates disabled, as per registry settings.\n"); + vuprintf("Check for updates disabled, as per registry settings.\n"); return FALSE; } reg_time = ReadRegistryKey64(REGKEY_LAST_UPDATE); @@ -396,18 +402,35 @@ BOOL CheckForUpdates(const char* url) if (!SystemTimeToFileTime(&LocalTime, &FileTime)) goto out; local_time = ((((int64_t)FileTime.dwHighDateTime)<<32) + FileTime.dwLowDateTime) / 10000000; - uuuprintf("Local time: %" PRId64 "\n", local_time); + vvuprintf("Local time: %" PRId64 "\n", local_time); if (local_time < reg_time + update_interval) { - uuprintf("Next update check in %" PRId64 " seconds.\n", reg_time + update_interval - local_time); + vuprintf("Next update check in %" PRId64 " seconds.\n", reg_time + update_interval - local_time); return FALSE; } - PrintStatus(3000, FALSE, "Checking for Rufus updates...\n"); + PrintStatus(3000, FALSE, "Checking for " APPLICATION_NAME " updates...\n"); - if ((!InternetCrackUrlA(url, safe_strlen(url), 0, &UrlParts)) || (!InternetGetConnectedState(&dwFlags, 0))) + if (!GetVersionExA(&os_version)) { + vuprintf("Could not read Windows version - Check for updates cancelled.\n"); + return FALSE; + } + + // Detect if the OS is 64 bit, without relying on external libs + if (sizeof(uintptr_t) < 8) { + // This application is not 64 bit, but it might be 32 bit running in WOW64 + pIsWow64Process = (BOOL (__stdcall *)(HANDLE, PBOOL)) + GetProcAddress(GetModuleHandleA("KERNEL32"), "IsWow64Process"); + if (pIsWow64Process != NULL) { + (*pIsWow64Process)(GetCurrentProcess(), &is_x64); + } + } else { + is_x64 = TRUE; + } + + if ((!InternetCrackUrlA(server_url, safe_strlen(server_url), 0, &UrlParts)) || (!InternetGetConnectedState(&dwFlags, 0))) goto out; - _snprintf(agent, ARRAYSIZE(agent), "Rufus/%d.%d.%d.%d", rufus_version[0], rufus_version[1], rufus_version[2], rufus_version[3]); + _snprintf(agent, ARRAYSIZE(agent), APPLICATION_NAME "/%d.%d.%d.%d", rufus_version[0], rufus_version[1], rufus_version[2], rufus_version[3]); hSession = InternetOpenA(agent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (hSession == NULL) goto out; @@ -415,17 +438,52 @@ BOOL CheckForUpdates(const char* url) if (hConnection == NULL) goto out; - hRequest = HttpOpenRequestA(hConnection, "GET", UrlParts.lpszUrlPath, NULL, NULL, (const char**)"*/*\0", - INTERNET_FLAG_HYPERLINK|INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP|INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS|INTERNET_FLAG_NO_COOKIES| - INTERNET_FLAG_NO_UI|INTERNET_FLAG_NO_CACHE_WRITE, (DWORD_PTR)NULL); - if ((hRequest == NULL) || (!HttpSendRequest(hRequest, NULL, 0, NULL, 0))) - goto out; + // At this stage we can query the server for various update version files. + // We first try to lookup for "___.ver" + // and then remove each each of the components until we find our match. For instance, we may first + // look for rufus_win_x64_6.2.ver (Win8 x64) but only get a match for rufus_win_x64_6.ver (Vista x64 or later) + // This allows sunsetting OS versions (eg XP) or providing different downloads for different archs/groups. + + safe_sprintf(urlpath, sizeof(urlpath), "%s_%s_%d.%d.ver", APPLICATION_NAME, + archname[is_x64?1:0], os_version.dwMajorVersion, os_version.dwMinorVersion); + uprintf("Base update check: %s\n", urlpath); + for (i=0, j=safe_strlen(urlpath)-5; (j>0)&&(i(){}[].,:;#@'/?|~"; rufus_update update; + if ((buf == NULL) || (len < 2) || (len > 65536) || (buf[len-1] != 0)) + return; // Sanitize the data - Of course not a silver bullet, but it helps - for (i=0; i #include +#include "rufus.h" #pragma once @@ -25,14 +26,9 @@ extern "C" { #endif -/* - * Application root subkey, under HKCU\Software - * Typically "\" - */ -#define REGKEY_APPLICATION "Akeo Systems\\Rufus" - /* * List of registry keys used by this application + * These keys go into HKCU\Software\COMPANY_NAME\APPLICATION_NAME\ */ #define REGKEY_VERBOSE_UPDATES "VerboseUpdateCheck" #define REGKEY_DISABLE_UPDATES "DisableUpdateCheck" @@ -40,8 +36,29 @@ extern "C" { #define REGKEY_UPDATE_INTERVAL "UpdateCheckInterval" #define REGKEY_LAST_VERSION_SEEN "LastVersionSeen" +/* Delete a registry key from HKCU\Software and all its subkeys + If the key has subkeys, this call will fail. */ +static __inline BOOL DeleteRegistryKey(const char* key_name) +{ + HKEY hSoftware = NULL; + LSTATUS s; -/* Read a generic registry key value (create the app key if it doesn't exist) */ + if (RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE", 0, KEY_READ|KEY_CREATE_SUB_KEY, &hSoftware) != ERROR_SUCCESS) { + return FALSE; + } + ERROR_SUCCESS; + + s = RegDeleteKeyA(hSoftware, key_name); + if ((s != ERROR_SUCCESS) && (s != ERROR_FILE_NOT_FOUND)) { + SetLastError(s); + uprintf("Failed to delete registry key HKCU\\Software\\%s: %s", key_name, + (s == ERROR_ACCESS_DENIED)?"Key is not empty":WindowsErrorString()); + } + RegCloseKey(hSoftware); + return ((s == ERROR_SUCCESS) || (s == ERROR_FILE_NOT_FOUND)); +} + +/* Read a generic registry key value (create the key if it doesn't exist) */ static __inline BOOL _GetRegistryKey(const char* key_name, DWORD reg_type, LPBYTE dest, DWORD dest_size) { BOOL r = FALSE; @@ -51,7 +68,7 @@ static __inline BOOL _GetRegistryKey(const char* key_name, DWORD reg_type, LPBYT memset(dest, 0, dest_size); if ( (RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE", 0, KEY_READ|KEY_CREATE_SUB_KEY, &hSoftware) != ERROR_SUCCESS) - || (RegCreateKeyExA(hSoftware, REGKEY_APPLICATION, 0, NULL, 0, + || (RegCreateKeyExA(hSoftware, COMPANY_NAME "\\" APPLICATION_NAME, 0, NULL, 0, KEY_SET_VALUE|KEY_QUERY_VALUE|KEY_CREATE_SUB_KEY, NULL, &hApp, &dwDisp) != ERROR_SUCCESS) ) { goto out; } @@ -67,7 +84,7 @@ out: return r; } -/* Write a generic registry key value (create the app if it doesn't exist) */ +/* Write a generic registry key value (create the key if it doesn't exist) */ static __inline BOOL _SetRegistryKey(const char* key_name, DWORD reg_type, LPBYTE src, DWORD src_size) { BOOL r = FALSE; @@ -75,7 +92,7 @@ static __inline BOOL _SetRegistryKey(const char* key_name, DWORD reg_type, LPBYT DWORD dwDisp, dwType = reg_type; if ( (RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE", 0, KEY_READ|KEY_CREATE_SUB_KEY, &hSoftware) != ERROR_SUCCESS) - || (RegCreateKeyExA(hSoftware, REGKEY_APPLICATION, 0, NULL, 0, + || (RegCreateKeyExA(hSoftware, COMPANY_NAME "\\" APPLICATION_NAME, 0, NULL, 0, KEY_SET_VALUE|KEY_QUERY_VALUE|KEY_CREATE_SUB_KEY, NULL, &hApp, &dwDisp) != ERROR_SUCCESS) ) { goto out; } diff --git a/src/rufus.c b/src/rufus.c index bc1460bd..a9969786 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -38,6 +38,7 @@ #include "resource.h" #include "rufus.h" #include "sys_types.h" +#include "registry.h" /* Redefinitions for the WDK */ #ifndef PBM_SETSTATE @@ -1625,7 +1626,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA break; #ifdef RUFUS_TEST case IDC_TEST: - CheckForUpdates("http://rufus.akeo.ie/rufus.ver"); + CheckForUpdates(); /* InitProgress(); if (!IsWindow(hISOProgressDlg)) { @@ -1956,13 +1957,18 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine while(GetMessage(&msg, NULL, 0, 0)) { // The following ensures the processing of the ISO progress window messages if (!IsWindow(hISOProgressDlg) || !IsDialogMessage(hISOProgressDlg, &msg)) { - // Alt-S => Disable size limit + // Alt-S => Disable size limit for ISOs + // By default, Rufus will not copy ISOs that are larger than in size than + // the target USB drive. If this is enabled, the size check is disabled. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'S')) { iso_size_check = !iso_size_check; PrintStatus(2000, FALSE, "ISO size check %s.", iso_size_check?"enabled":"disabled"); continue; } - // Alt-F => toggle detection of fixed disks + // Alt-F => Toggle detection of fixed disks + // By default Rufus does not allow formatting USB fixed disk drives, such as USB HDDs + // This is a safety feature, to avoid someone unintentionally formatting a backup + // drive instead of an USB key. If this is enabled, Rufus will allow fixed disk formatting. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'F')) { enable_fixed_disks = !enable_fixed_disks; PrintStatus(2000, FALSE, "Fixed disks detection %s.", enable_fixed_disks?"enabled":"disabled"); @@ -1970,17 +1976,30 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine continue; } // Alt-D => Delete the NoDriveTypeAutorun key on exit (useful if the app crashed) + // This key is used to disable Windows popup messages when an USB drive is plugged in. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'D')) { PrintStatus(2000, FALSE, "NoDriveTypeAutorun will be deleted on exit."); existing_key = FALSE; continue; } - // Alt K => Toggle fake drive detection during bad blocks check (enabled by default) + // Alt K => Toggle fake drive detection during bad blocks check + // By default, Rufus will check for fake USB flash drives that mistakenly present + // more capacity than they already have by looping over the flash. This check which + // is enabled by default is performed by writing the block number sequence and reading + // it back during the bad block check. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'K')) { detect_fakes = !detect_fakes; PrintStatus(2000, FALSE, "Fake drive detection %s.", detect_fakes?"enabled":"disabled"); continue; } + // Alt-R => Remove all the registry settings created by Rufus by deleting the registry key + if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'R')) { + PrintStatus(2000, FALSE, "Application registry key %s deleted.", + DeleteRegistryKey(COMPANY_NAME "\\" APPLICATION_NAME)?"successfully":"could not be"); + // Also try to delete the upper key (company name) if it's empty (don't care about the result) + DeleteRegistryKey(COMPANY_NAME); + continue; + } TranslateMessage(&msg); DispatchMessage(&msg); } diff --git a/src/rufus.h b/src/rufus.h index f0ce1351..80b2ccff 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -26,6 +26,8 @@ /* Features not ready for prime time and that may *DESTROY* your data - USE AT YOUR OWN RISKS! */ #define RUFUS_TEST +#define APPLICATION_NAME "Rufus" +#define COMPANY_NAME "Akeo Consulting" #define STR_NO_LABEL "NO_LABEL" #define RUFUS_CANCELBOX_TITLE "Rufus - Cancellation" #define RUFUS_BLOCKING_IO_TITLE "Rufus - Flushing buffers" @@ -75,6 +77,8 @@ #ifdef RUFUS_DEBUG extern void _uprintf(const char *format, ...); #define uprintf(...) _uprintf(__VA_ARGS__) +#define vuprintf(...) if (verbose) _uprintf(__VA_ARGS__) +#define vvuprintf(...) if (verbose > 1) _uprintf(__VA_ARGS__) #else #define uprintf(...) #endif @@ -238,13 +242,13 @@ extern char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* extern BOOL FileIO(BOOL save, char* path, char** buffer, DWORD* size); extern LONG GetEntryWidth(HWND hDropDown, const char* entry); extern BOOL DownloadFile(const char* url, const char* file); -extern BOOL CheckForUpdates(const char* url); +extern BOOL CheckForUpdates(void); extern BOOL IsShown(HWND hDlg); extern char* get_token_data_file(const char* token, const char* filename); extern char* get_token_data_buffer(const char* token, unsigned int n, const char* buffer, size_t buffer_size); extern char* insert_section_data(const char* filename, const char* section, const char* data, BOOL dos2unix); extern char* replace_in_token_data(const char* filename, const char* token, const char* src, const char* rep, BOOL dos2unix); -extern void parse_update(char* buf); +extern void parse_update(char* buf, size_t len); __inline static BOOL UnlockDrive(HANDLE hDrive) { diff --git a/src/rufus.rc b/src/rufus.rc index bb7b1b6d..67848e9d 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -30,7 +30,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 206, 316 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_APPWINDOW -CAPTION "Rufus v1.2.1.194" +CAPTION "Rufus v1.2.1.195" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "Start",IDC_START,94,278,50,14 @@ -77,7 +77,7 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,231,175,50,14,WS_GROUP CONTROL "http://rufus.akeo.ie",IDC_ABOUT_RUFUS_URL, "SysLink",WS_TABSTOP,46,47,114,9 - LTEXT "Version 1.2.1 (Build 194)",IDC_STATIC,46,19,78,8 + LTEXT "Version 1.2.1 (Build 195)",IDC_STATIC,46,19,78,8 PUSHBUTTON "License...",IDC_ABOUT_LICENSE,46,175,50,14,WS_GROUP CONTROL "",IDC_ABOUT_COPYRIGHTS,"RichEdit20W",ES_MULTILINE | ES_READONLY | WS_VSCROLL,46,107,235,63,WS_EX_STATICEDGE LTEXT "Report bugs or request enhancements at:",IDC_STATIC,46,66,187,8 @@ -237,8 +237,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,2,1,194 - PRODUCTVERSION 1,2,1,194 + FILEVERSION 1,2,1,195 + PRODUCTVERSION 1,2,1,195 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -255,13 +255,13 @@ BEGIN BEGIN VALUE "CompanyName", "akeo.ie" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "1.2.1.194" + VALUE "FileVersion", "1.2.1.195" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "1.2.1.194" + VALUE "ProductVersion", "1.2.1.195" END END BLOCK "VarFileInfo"