/* * Rufus: The Reliable USB Formatting Utility * Standard User I/O Routines (logging, status, etc.) * Copyright © 2011-2017 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef _CRTDBG_MAP_ALLOC #include #include #endif #include #include #include #include #include #include #include #include "rufus.h" #include "resource.h" #include "msapi_utf8.h" #include "localization.h" /* * Globals */ HWND hStatus; size_t ubuffer_pos = 0; char ubuffer[UBUFFER_SIZE]; // Buffer for ubpushf() messages we don't log right away #ifdef RUFUS_LOGGING void _uprintf(const char *format, ...) { static char buf[4096]; char* p = buf; wchar_t* wbuf; va_list args; int n; va_start(args, format); n = safe_vsnprintf(p, sizeof(buf)-3, format, args); // buf-3 is room for CR/LF/NUL va_end(args); p += (n < 0)?sizeof(buf)-3:n; while((p>buf) && (isspaceU(p[-1]))) *--p = '\0'; *p++ = '\r'; *p++ = '\n'; *p = '\0'; // Yay, Windows 10 *FINALLY* added actual Unicode support for OutputDebugStringW()! wbuf = utf8_to_wchar(buf); // Send output to Windows debug facility OutputDebugStringW(wbuf); if ((hLog != NULL) && (hLog != INVALID_HANDLE_VALUE)) { // Send output to our log Window Edit_SetSel(hLog, MAX_LOG_SIZE, MAX_LOG_SIZE); Edit_ReplaceSel(hLog, wbuf); // Make sure the message scrolls into view // (Or see code commented in LogProc:WM_SHOWWINDOW for a less forceful scroll) Edit_Scroll(hLog, 0, Edit_GetLineCount(hLog)); } free(wbuf); } #endif // Prints a bitstring of a number of any size, with or without leading zeroes. // See also the printbits() and printbitslz() helper macros in rufus.h char *_printbits(size_t const size, void const * const ptr, int leading_zeroes) { // sizeof(uintmax_t) so that we have enough space to store whatever is thrown at us static char str[sizeof(uintmax_t) * 8 + 3]; size_t i; uint8_t* b = (uint8_t*)ptr; uintmax_t mask, lzmask = 0, val = 0; // Little endian, the SCOURGE of any rational computing for (i = 0; i < size; i++) val |= ((uintmax_t)b[i]) << (8 * i); str[0] = '0'; str[1] = 'b'; if (leading_zeroes) lzmask = 1ULL << (size * 8 - 1); for (i = 2, mask = 1ULL << (sizeof(uintmax_t) * 8 - 1); mask != 0; mask >>= 1) { if ((i > 2) || (lzmask & mask)) str[i++] = (val & mask) ? '1' : '0'; else if (val & mask) str[i++] = '1'; } str[i] = '\0'; return str; } // Display an hex dump of buffer 'buf' void DumpBufferHex(void *buf, size_t size) { unsigned char* buffer = (unsigned char*)buf; size_t i, j, k; char line[80] = ""; for (i=0; i 126)) { sprintf(&line[strlen(line)], "."); } else { sprintf(&line[strlen(line)], "%c", buffer[i+j]); } } } } uprintf("%s\n", line); } // Convert a windows error to human readable string const char *WindowsErrorString(void) { static char err_string[256] = {0}; DWORD size; DWORD error_code, format_error; error_code = GetLastError(); static_sprintf(err_string, "[0x%08lX] ", error_code); size = FormatMessageU(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, HRESULT_CODE(error_code), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &err_string[strlen(err_string)], sizeof(err_string)-(DWORD)strlen(err_string), NULL); if (size == 0) { format_error = GetLastError(); if ((format_error) && (format_error != 0x13D)) // 0x13D, decode error, is returned for unknown codes static_sprintf(err_string, "Windows error code 0x%08lX (FormatMessage error code 0x%08lX)", error_code, format_error); else static_sprintf(err_string, "Unknown error 0x%08lX", error_code); } SetLastError(error_code); // Make sure we don't change the errorcode on exit return err_string; } char* GuidToString(const GUID* guid) { static char guid_string[MAX_GUID_STRING_LENGTH]; if (guid == NULL) return NULL; sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", (unsigned int)guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); return guid_string; } // Find upper power of 2 static __inline uint16_t upo2(uint16_t v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v++; return v; } // Convert a size to human readable char* SizeToHumanReadable(uint64_t size, BOOL copy_to_log, BOOL fake_units) { int suffix; static char str_size[32]; const char* dir = ((right_to_left_mode)&&(!copy_to_log))?RIGHT_TO_LEFT_MARK:""; double hr_size = (double)size; double t; uint16_t i_size; char **_msg_table = copy_to_log?default_msg_table:msg_table; const double divider = fake_units?1000.0:1024.0; for (suffix=0; suffix 1) && (!SetFilePointerEx(hFile, liFilePointer, NULL, FILE_BEGIN))) { uprintf(" Could not set file pointer - aborting"); break; } if (WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL)) { if (nNumberOfBytesToWrite == *lpNumberOfBytesWritten) return TRUE; // Some large drives return 0, even though all the data was written - See github #787 */ if (large_drive && (*lpNumberOfBytesWritten == 0)) { uprintf("Warning: Possible short write"); return TRUE; } uprintf(" Wrote %d bytes but requested %d%s", *lpNumberOfBytesWritten, nNumberOfBytesToWrite, nTry < nNumRetries ? retry_msg : ""); } else { uprintf(" Write error [0x%08X]%s", GetLastError(), nTry < nNumRetries ? retry_msg : ""); } // If we can't reposition for the next run, just abort if (!readFilePointer) break; Sleep(200); } if (SCODE_CODE(GetLastError()) == ERROR_SUCCESS) SetLastError(ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT); return FALSE; } // A WaitForSingleObject() equivalent that doesn't block Windows messages // This is needed, for instance, if you are waiting for a thread that may issue uprintf's DWORD WaitForSingleObjectWithMessages(HANDLE hHandle, DWORD dwMilliseconds) { DWORD res, dwCurTime, dwEndTime = GetTickCount() + dwMilliseconds; MSG msg; do { // Read all of the messages in this next loop, removing each message as we read it. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if ((msg.message == WM_QUIT) || (msg.message == WM_CLOSE)) { SetLastError(ERROR_CANCELLED); return WAIT_FAILED; } else { DispatchMessage(&msg); } } // Wait for any message sent or posted to this queue or for the handle to signaled. res = MsgWaitForMultipleObjects(1, &hHandle, FALSE, dwMilliseconds, QS_ALLINPUT); if (dwMilliseconds != INFINITE) { dwCurTime = GetTickCount(); // Account for the case where we may reach the timeout condition while // processing timestamps if (dwCurTime < dwEndTime) dwMilliseconds = dwEndTime - dwCurTime; else res = WAIT_TIMEOUT; } } while (res == (WAIT_OBJECT_0 + 1)); return res; }