2011-12-01 16:34:42 +00:00
|
|
|
/*
|
2011-12-05 11:36:02 +00:00
|
|
|
* Rufus: The Reliable USB Formatting Utility
|
2013-01-24 21:30:11 +00:00
|
|
|
* Standard User I/O Routines (logging, status, etc.)
|
2017-04-01 16:29:42 +00:00
|
|
|
* Copyright © 2011-2017 Pete Batard <pete@akeo.ie>
|
2011-12-01 16:34:42 +00:00
|
|
|
*
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2011-12-01 17:20:52 +00:00
|
|
|
#ifdef _CRTDBG_MAP_ALLOC
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <crtdbg.h>
|
|
|
|
#endif
|
2011-12-01 16:34:42 +00:00
|
|
|
|
|
|
|
#include <windows.h>
|
2012-05-30 23:32:25 +00:00
|
|
|
#include <windowsx.h>
|
2011-12-01 16:34:42 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ctype.h>
|
2014-03-01 00:09:40 +00:00
|
|
|
#include <math.h>
|
2011-12-01 16:34:42 +00:00
|
|
|
|
|
|
|
#include "rufus.h"
|
|
|
|
#include "resource.h"
|
2016-02-20 22:52:32 +00:00
|
|
|
#include "msapi_utf8.h"
|
2013-10-15 21:58:27 +00:00
|
|
|
#include "localization.h"
|
2011-12-01 16:34:42 +00:00
|
|
|
|
2011-12-01 17:54:35 +00:00
|
|
|
/*
|
|
|
|
* Globals
|
|
|
|
*/
|
|
|
|
HWND hStatus;
|
2017-04-25 13:32:19 +00:00
|
|
|
size_t ubuffer_pos = 0;
|
|
|
|
char ubuffer[UBUFFER_SIZE]; // Buffer for ubpushf() messages we don't log right away
|
2011-12-01 17:54:35 +00:00
|
|
|
|
2017-04-25 19:25:50 +00:00
|
|
|
#ifdef RUFUS_LOGGING
|
2011-12-01 16:34:42 +00:00
|
|
|
void _uprintf(const char *format, ...)
|
|
|
|
{
|
2013-10-15 21:58:27 +00:00
|
|
|
static char buf[4096];
|
|
|
|
char* p = buf;
|
2017-07-22 14:17:24 +00:00
|
|
|
wchar_t* wbuf;
|
2011-12-01 16:34:42 +00:00
|
|
|
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;
|
|
|
|
|
2013-10-15 21:58:27 +00:00
|
|
|
while((p>buf) && (isspaceU(p[-1])))
|
2011-12-01 16:34:42 +00:00
|
|
|
*--p = '\0';
|
|
|
|
|
|
|
|
*p++ = '\r';
|
|
|
|
*p++ = '\n';
|
|
|
|
*p = '\0';
|
|
|
|
|
2017-07-22 14:17:24 +00:00
|
|
|
// Yay, Windows 10 *FINALLY* added actual Unicode support for OutputDebugStringW()!
|
|
|
|
wbuf = utf8_to_wchar(buf);
|
2012-05-30 23:32:25 +00:00
|
|
|
// Send output to Windows debug facility
|
2017-07-22 14:17:24 +00:00
|
|
|
OutputDebugStringW(wbuf);
|
2016-01-15 12:26:31 +00:00
|
|
|
if ((hLog != NULL) && (hLog != INVALID_HANDLE_VALUE)) {
|
|
|
|
// Send output to our log Window
|
|
|
|
Edit_SetSel(hLog, MAX_LOG_SIZE, MAX_LOG_SIZE);
|
2017-07-24 10:36:06 +00:00
|
|
|
Edit_ReplaceSel(hLog, wbuf);
|
2016-01-15 12:26:31 +00:00
|
|
|
// Make sure the message scrolls into view
|
|
|
|
// (Or see code commented in LogProc:WM_SHOWWINDOW for a less forceful scroll)
|
2017-08-11 10:47:27 +00:00
|
|
|
Edit_Scroll(hLog, Edit_GetLineCount(hLog), 0);
|
2016-01-15 12:26:31 +00:00
|
|
|
}
|
2017-07-22 14:17:24 +00:00
|
|
|
free(wbuf);
|
2011-12-01 16:34:42 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-03-01 17:13:37 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2017-04-01 16:29:42 +00:00
|
|
|
// Display an hex dump of buffer 'buf'
|
2011-12-01 16:34:42 +00:00
|
|
|
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<size; i+=16) {
|
|
|
|
if (i!=0)
|
|
|
|
uprintf("%s\n", line);
|
|
|
|
line[0] = 0;
|
|
|
|
sprintf(&line[strlen(line)], " %08x ", (unsigned int)i);
|
|
|
|
for(j=0,k=0; k<16; j++,k++) {
|
|
|
|
if (i+j < size) {
|
|
|
|
sprintf(&line[strlen(line)], "%02x", buffer[i+j]);
|
|
|
|
} else {
|
|
|
|
sprintf(&line[strlen(line)], " ");
|
|
|
|
}
|
|
|
|
sprintf(&line[strlen(line)], " ");
|
|
|
|
}
|
|
|
|
sprintf(&line[strlen(line)], " ");
|
|
|
|
for(j=0,k=0; k<16; j++,k++) {
|
|
|
|
if (i+j < size) {
|
|
|
|
if ((buffer[i+j] < 32) || (buffer[i+j] > 126)) {
|
|
|
|
sprintf(&line[strlen(line)], ".");
|
|
|
|
} else {
|
|
|
|
sprintf(&line[strlen(line)], "%c", buffer[i+j]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
uprintf("%s\n", line);
|
|
|
|
}
|
|
|
|
|
2017-04-01 16:29:42 +00:00
|
|
|
// Convert a windows error to human readable string
|
2011-12-04 19:47:27 +00:00
|
|
|
const char *WindowsErrorString(void)
|
2011-12-01 16:34:42 +00:00
|
|
|
{
|
2013-01-09 21:54:28 +00:00
|
|
|
static char err_string[256] = {0};
|
2011-12-01 16:34:42 +00:00
|
|
|
|
|
|
|
DWORD size;
|
|
|
|
DWORD error_code, format_error;
|
|
|
|
|
|
|
|
error_code = GetLastError();
|
|
|
|
|
2017-08-10 18:43:04 +00:00
|
|
|
static_sprintf(err_string, "[0x%08lX] ", error_code);
|
2011-12-01 16:34:42 +00:00
|
|
|
|
2013-11-30 17:39:38 +00:00
|
|
|
size = FormatMessageU(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, HRESULT_CODE(error_code),
|
2011-12-01 16:34:42 +00:00
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &err_string[strlen(err_string)],
|
|
|
|
sizeof(err_string)-(DWORD)strlen(err_string), NULL);
|
|
|
|
if (size == 0) {
|
|
|
|
format_error = GetLastError();
|
2011-12-04 19:47:27 +00:00
|
|
|
if ((format_error) && (format_error != 0x13D)) // 0x13D, decode error, is returned for unknown codes
|
2017-08-10 18:43:04 +00:00
|
|
|
static_sprintf(err_string, "Windows error code 0x%08lX (FormatMessage error code 0x%08lX)",
|
|
|
|
error_code, format_error);
|
2011-12-01 16:34:42 +00:00
|
|
|
else
|
2017-08-10 18:43:04 +00:00
|
|
|
static_sprintf(err_string, "Unknown error 0x%08lX", error_code);
|
2011-12-01 16:34:42 +00:00
|
|
|
}
|
2013-11-13 01:07:32 +00:00
|
|
|
|
|
|
|
SetLastError(error_code); // Make sure we don't change the errorcode on exit
|
2011-12-01 16:34:42 +00:00
|
|
|
return err_string;
|
|
|
|
}
|
|
|
|
|
2013-01-18 01:39:24 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-04-01 16:29:42 +00:00
|
|
|
// Find upper power of 2
|
2014-03-01 00:09:40 +00:00
|
|
|
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
|
2015-01-28 23:22:11 +00:00
|
|
|
char* SizeToHumanReadable(uint64_t size, BOOL copy_to_log, BOOL fake_units)
|
2013-01-22 02:40:43 +00:00
|
|
|
{
|
2014-04-10 21:01:48 +00:00
|
|
|
int suffix;
|
2013-10-15 21:58:27 +00:00
|
|
|
static char str_size[32];
|
2015-01-28 23:22:11 +00:00
|
|
|
const char* dir = ((right_to_left_mode)&&(!copy_to_log))?RIGHT_TO_LEFT_MARK:"";
|
2014-02-17 22:41:04 +00:00
|
|
|
double hr_size = (double)size;
|
2014-03-01 00:09:40 +00:00
|
|
|
double t;
|
|
|
|
uint16_t i_size;
|
2015-01-28 23:22:11 +00:00
|
|
|
char **_msg_table = copy_to_log?default_msg_table:msg_table;
|
2014-03-01 00:09:40 +00:00
|
|
|
const double divider = fake_units?1000.0:1024.0;
|
|
|
|
|
2014-04-10 21:01:48 +00:00
|
|
|
for (suffix=0; suffix<MAX_SIZE_SUFFIXES-1; suffix++) {
|
|
|
|
if (hr_size < divider)
|
2014-03-01 00:09:40 +00:00
|
|
|
break;
|
2014-04-10 21:01:48 +00:00
|
|
|
hr_size /= divider;
|
2013-01-22 02:40:43 +00:00
|
|
|
}
|
|
|
|
if (suffix == 0) {
|
2014-05-15 22:51:33 +00:00
|
|
|
static_sprintf(str_size, "%s%d%s %s", dir, (int)hr_size, dir, _msg_table[MSG_020-MSG_000]);
|
2014-03-01 00:09:40 +00:00
|
|
|
} else if (fake_units) {
|
|
|
|
if (hr_size < 8) {
|
2014-05-15 22:51:33 +00:00
|
|
|
static_sprintf(str_size, (fabs((hr_size*10.0)-(floor(hr_size + 0.5)*10.0)) < 0.5)?"%0.0f%s":"%0.1f%s",
|
2015-01-20 02:56:17 +00:00
|
|
|
hr_size, _msg_table[MSG_020+suffix-MSG_000]);
|
2014-03-01 00:09:40 +00:00
|
|
|
} else {
|
|
|
|
t = (double)upo2((uint16_t)hr_size);
|
|
|
|
i_size = (uint16_t)((fabs(1.0f-(hr_size / t)) < 0.05f)?t:hr_size);
|
2018-08-18 16:38:23 +00:00
|
|
|
static_sprintf(str_size, "%s%d%s %s", dir, i_size, dir, _msg_table[MSG_020+suffix-MSG_000]);
|
2014-03-01 00:09:40 +00:00
|
|
|
}
|
2013-01-22 02:40:43 +00:00
|
|
|
} else {
|
2014-05-15 22:51:33 +00:00
|
|
|
static_sprintf(str_size, (hr_size * 10.0 - (floor(hr_size) * 10.0)) < 0.5?
|
|
|
|
"%s%0.0f%s %s":"%s%0.1f%s %s", dir, hr_size, dir, _msg_table[MSG_020+suffix-MSG_000]);
|
2013-01-22 02:40:43 +00:00
|
|
|
}
|
|
|
|
return str_size;
|
|
|
|
}
|
|
|
|
|
2017-09-03 12:54:07 +00:00
|
|
|
// Convert a YYYYMMDDHHMMSS UTC timestamp to a more human readable version
|
|
|
|
char* TimestampToHumanReadable(uint64_t ts)
|
|
|
|
{
|
|
|
|
uint64_t rem = ts, divisor = 10000000000ULL;
|
|
|
|
uint16_t data[6];
|
|
|
|
int i;
|
|
|
|
static char str[64];
|
|
|
|
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
data[i] = (uint16_t) ((divisor == 0)?rem:(rem / divisor));
|
|
|
|
rem %= divisor;
|
|
|
|
divisor /= 100ULL;
|
|
|
|
}
|
|
|
|
static_sprintf(str, "%04d.%02d.%02d %02d:%02d:%02d (UTC)", data[0], data[1], data[2], data[3], data[4], data[5]);
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2017-04-01 16:29:42 +00:00
|
|
|
// Convert custom error code to messages
|
2013-12-19 23:56:40 +00:00
|
|
|
const char* _StrError(DWORD error_code)
|
2011-12-04 19:47:27 +00:00
|
|
|
{
|
|
|
|
if ( (!IS_ERROR(error_code)) || (SCODE_CODE(error_code) == ERROR_SUCCESS)) {
|
2014-05-19 22:25:00 +00:00
|
|
|
return lmprintf(MSG_050);
|
2011-12-04 19:47:27 +00:00
|
|
|
}
|
|
|
|
if (SCODE_FACILITY(error_code) != FACILITY_STORAGE) {
|
|
|
|
uprintf("StrError: non storage - %08X (%X)\n", error_code, SCODE_FACILITY(error_code));
|
|
|
|
SetLastError(error_code);
|
|
|
|
return WindowsErrorString();
|
|
|
|
}
|
|
|
|
switch (SCODE_CODE(error_code)) {
|
|
|
|
case ERROR_GEN_FAILURE:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_051);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_INCOMPATIBLE_FS:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_052);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_ACCESS_DENIED:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_053);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_WRITE_PROTECT:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_054);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_DEVICE_IN_USE:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_055);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_CANT_QUICK_FORMAT:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_056);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_LABEL_TOO_LONG:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_057);
|
2013-06-25 01:55:25 +00:00
|
|
|
case ERROR_INVALID_HANDLE:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_058);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_INVALID_CLUSTER_SIZE:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_059);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_INVALID_VOLUME_SIZE:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_060);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_NO_MEDIA_IN_DRIVE:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_061);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_NOT_SUPPORTED:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_062);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_063);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_READ_FAULT:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_064);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_WRITE_FAULT:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_065);
|
2013-07-05 22:58:04 +00:00
|
|
|
case ERROR_INSTALL_FAILURE:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_066);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_OPEN_FAILED:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_067);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_PARTITION_FAILURE:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_068);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_CANNOT_COPY:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_069);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_CANCELLED:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_070);
|
2011-12-04 19:47:27 +00:00
|
|
|
case ERROR_CANT_START_THREAD:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_071);
|
2011-12-06 23:35:55 +00:00
|
|
|
case ERROR_BADBLOCKS_FAILURE:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_072);
|
2012-02-01 14:26:36 +00:00
|
|
|
case ERROR_ISO_SCAN:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_073);
|
2012-02-01 14:26:36 +00:00
|
|
|
case ERROR_ISO_EXTRACT:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_074);
|
2012-02-07 02:05:58 +00:00
|
|
|
case ERROR_CANT_REMOUNT_VOLUME:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_075);
|
2012-03-27 19:31:15 +00:00
|
|
|
case ERROR_CANT_PATCH:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_076);
|
2013-04-07 23:10:58 +00:00
|
|
|
case ERROR_CANT_ASSIGN_LETTER:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_077);
|
2013-04-07 23:10:58 +00:00
|
|
|
case ERROR_CANT_MOUNT_VOLUME:
|
2013-10-15 21:58:27 +00:00
|
|
|
return lmprintf(MSG_078);
|
2014-05-19 22:25:00 +00:00
|
|
|
case ERROR_NOT_READY:
|
|
|
|
return lmprintf(MSG_079);
|
2018-06-30 21:45:15 +00:00
|
|
|
case ERROR_BAD_SIGNATURE:
|
|
|
|
return lmprintf(MSG_172);
|
2011-12-04 19:47:27 +00:00
|
|
|
default:
|
|
|
|
SetLastError(error_code);
|
|
|
|
return WindowsErrorString();
|
|
|
|
}
|
|
|
|
}
|
2013-12-19 23:56:40 +00:00
|
|
|
|
|
|
|
const char* StrError(DWORD error_code, BOOL use_default_locale)
|
|
|
|
{
|
|
|
|
const char* ret;
|
|
|
|
if (use_default_locale)
|
|
|
|
toggle_default_locale();
|
|
|
|
ret = _StrError(error_code);
|
|
|
|
if (use_default_locale)
|
|
|
|
toggle_default_locale();
|
|
|
|
return ret;
|
|
|
|
}
|
2016-01-15 12:26:31 +00:00
|
|
|
|
2017-04-01 16:29:42 +00:00
|
|
|
// A WriteFile() equivalent, with up to nNumRetries write attempts on error.
|
2016-01-15 12:26:31 +00:00
|
|
|
BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
|
|
|
LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries)
|
|
|
|
{
|
|
|
|
DWORD nTry;
|
|
|
|
BOOL readFilePointer;
|
|
|
|
LARGE_INTEGER liFilePointer, liZero = { { 0,0 } };
|
|
|
|
|
|
|
|
// Need to get the current file pointer in case we need to retry
|
|
|
|
readFilePointer = SetFilePointerEx(hFile, liZero, &liFilePointer, FILE_CURRENT);
|
|
|
|
if (!readFilePointer)
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Warning: Could not read file pointer: %s", WindowsErrorString());
|
2016-01-15 12:26:31 +00:00
|
|
|
|
|
|
|
if (nNumRetries == 0)
|
|
|
|
nNumRetries = 1;
|
|
|
|
for (nTry = 1; nTry <= nNumRetries; nTry++) {
|
|
|
|
// Need to rewind our file position on retry - if we can't even do that, just give up
|
|
|
|
if ((nTry > 1) && (!SetFilePointerEx(hFile, liFilePointer, NULL, FILE_BEGIN))) {
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Could not set file pointer - Aborting");
|
2016-01-15 12:26:31 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL)) {
|
|
|
|
if (nNumberOfBytesToWrite == *lpNumberOfBytesWritten)
|
|
|
|
return TRUE;
|
2016-09-06 16:56:36 +00:00
|
|
|
// 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;
|
|
|
|
}
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Wrote %d bytes but requested %d", *lpNumberOfBytesWritten, nNumberOfBytesToWrite);
|
2016-09-06 16:56:36 +00:00
|
|
|
} else {
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Write error [0x%08X]", GetLastError());
|
2016-01-15 12:26:31 +00:00
|
|
|
}
|
|
|
|
// If we can't reposition for the next run, just abort
|
|
|
|
if (!readFilePointer)
|
|
|
|
break;
|
2018-06-13 18:23:24 +00:00
|
|
|
if (nTry < nNumRetries) {
|
|
|
|
uprintf("Retrying in %d seconds...", WRITE_TIMEOUT / 1000);
|
|
|
|
Sleep(WRITE_TIMEOUT);
|
|
|
|
}
|
2016-01-15 12:26:31 +00:00
|
|
|
}
|
|
|
|
if (SCODE_CODE(GetLastError()) == ERROR_SUCCESS)
|
|
|
|
SetLastError(ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2017-07-24 10:36:06 +00:00
|
|
|
|
|
|
|
// 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)
|
|
|
|
{
|
2017-11-13 14:29:48 +00:00
|
|
|
uint64_t CurTime, EndTime = GetTickCount64() + dwMilliseconds;
|
|
|
|
DWORD res;
|
2017-07-24 10:36:06 +00:00
|
|
|
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) {
|
2017-11-13 14:29:48 +00:00
|
|
|
CurTime = GetTickCount64();
|
2017-07-24 10:36:06 +00:00
|
|
|
// Account for the case where we may reach the timeout condition while
|
|
|
|
// processing timestamps
|
2017-11-13 14:29:48 +00:00
|
|
|
if (CurTime < EndTime)
|
|
|
|
dwMilliseconds = (DWORD) (EndTime - CurTime);
|
2017-07-24 10:36:06 +00:00
|
|
|
else
|
|
|
|
res = WAIT_TIMEOUT;
|
|
|
|
}
|
|
|
|
} while (res == (WAIT_OBJECT_0 + 1));
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|