mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
21351b9fbe
* Remove unused iso_op_in_progress and use a single op_in_progress that gets set when we disable the controls. * Also fix an issue where Ctrl-L was being processed as Alt-L due yet another completely backwards Windows behaviour where the message that is meant to indicating whether Alt is pressed is also sometimes used to indicate that another key is being pressed if the dialog doesn't have keyboard focus...
869 lines
36 KiB
C
869 lines
36 KiB
C
/*
|
|
* Rufus: The Reliable USB Formatting Utility
|
|
* Standard User I/O Routines (logging, status, error, etc.)
|
|
* Copyright © 2011-2019 Pete Batard <pete@akeo.ie>
|
|
*
|
|
* 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/>.
|
|
*/
|
|
#ifdef _CRTDBG_MAP_ALLOC
|
|
#include <stdlib.h>
|
|
#include <crtdbg.h>
|
|
#endif
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
|
|
#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
|
|
|
|
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, Edit_GetLineCount(hLog), 0);
|
|
}
|
|
free(wbuf);
|
|
}
|
|
|
|
void _uprintfs(const char* str)
|
|
{
|
|
wchar_t* wstr;
|
|
wstr = utf8_to_wchar(str);
|
|
OutputDebugStringW(wstr);
|
|
if ((hLog != NULL) && (hLog != INVALID_HANDLE_VALUE)) {
|
|
Edit_SetSel(hLog, MAX_LOG_SIZE, MAX_LOG_SIZE);
|
|
Edit_ReplaceSel(hLog, wstr);
|
|
Edit_Scroll(hLog, Edit_GetLineCount(hLog), 0);
|
|
}
|
|
free(wstr);
|
|
}
|
|
|
|
// 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<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);
|
|
}
|
|
|
|
// Count on Microsoft to add a new API while not bothering updating the existing error facilities,
|
|
// so that the new error messages have to be handled manually. Now, since I don't have all day:
|
|
// 1. Copy text from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-vds/5102cc53-3143-4268-ba4c-6ea39e999ab4
|
|
// 2. awk '{l[NR%7]=$0} {if (NR%7==0) printf "\tcase %s:\t// %s\n\t\treturn \"%s\";\n", l[1], l[3], l[6]}' vds.txt
|
|
// 3. Filter out the crap we don't need.
|
|
static const char *GetVdsError(DWORD error_code)
|
|
{
|
|
switch (error_code) {
|
|
case 0x80042400: // VDS_E_NOT_SUPPORTED
|
|
return "The operation is not supported by the object.";
|
|
case 0x80042401: // VDS_E_INITIALIZED_FAILED
|
|
return "VDS or the provider failed to initialize.";
|
|
case 0x80042402: // VDS_E_INITIALIZE_NOT_CALLED
|
|
return "VDS did not call the hardware provider's initialization method.";
|
|
case 0x80042403: // VDS_E_ALREADY_REGISTERED
|
|
return "The provider is already registered.";
|
|
case 0x80042404: // VDS_E_ANOTHER_CALL_IN_PROGRESS
|
|
return "A concurrent second call is made on an object before the first call is completed.";
|
|
case 0x80042405: // VDS_E_OBJECT_NOT_FOUND
|
|
return "The specified object was not found.";
|
|
case 0x80042406: // VDS_E_INVALID_SPACE
|
|
return "The specified space is neither free nor valid.";
|
|
case 0x80042407: // VDS_E_PARTITION_LIMIT_REACHED
|
|
return "No more partitions can be created on the specified disk.";
|
|
case 0x80042408: // VDS_E_PARTITION_NOT_EMPTY
|
|
return "The extended partition is not empty.";
|
|
case 0x80042409: // VDS_E_OPERATION_PENDING
|
|
return "The operation is still in progress.";
|
|
case 0x8004240A: // VDS_E_OPERATION_DENIED
|
|
return "The operation is not permitted on the specified disk, partition, or volume.";
|
|
case 0x8004240B: // VDS_E_OBJECT_DELETED
|
|
return "The object no longer exists.";
|
|
case 0x8004240C: // VDS_E_CANCEL_TOO_LATE
|
|
return "The operation can no longer be canceled.";
|
|
case 0x8004240D: // VDS_E_OPERATION_CANCELED
|
|
return "The operation has already been canceled.";
|
|
case 0x8004240E: // VDS_E_CANNOT_EXTEND
|
|
return "The file system does not support extending this volume.";
|
|
case 0x8004240F: // VDS_E_NOT_ENOUGH_SPACE
|
|
return "There is not enough space to complete the operation.";
|
|
case 0x80042410: // VDS_E_NOT_ENOUGH_DRIVE
|
|
return "There are not enough free disk drives in the subsystem to complete the operation.";
|
|
case 0x80042411: // VDS_E_BAD_COOKIE
|
|
return "The cookie was not found.";
|
|
case 0x80042412: // VDS_E_NO_MEDIA
|
|
return "There is no removable media in the drive.";
|
|
case 0x80042413: // VDS_E_DEVICE_IN_USE
|
|
return "The device is currently in use.";
|
|
case 0x80042414: // VDS_E_DISK_NOT_EMPTY
|
|
return "The disk contains partitions or volumes.";
|
|
case 0x80042415: // VDS_E_INVALID_OPERATION
|
|
return "The specified operation is not valid.";
|
|
case 0x80042416: // VDS_E_PATH_NOT_FOUND
|
|
return "The specified path was not found.";
|
|
case 0x80042417: // VDS_E_DISK_NOT_INITIALIZED
|
|
return "The specified disk has not been initialized.";
|
|
case 0x80042418: // VDS_E_NOT_AN_UNALLOCATED_DISK
|
|
return "The specified disk is not an unallocated disk.";
|
|
case 0x80042419: // VDS_E_UNRECOVERABLE_ERROR
|
|
return "An unrecoverable error occurred. The service MUST shut down.";
|
|
case 0x0004241A: // VDS_S_DISK_PARTIALLY_CLEANED
|
|
return "The clean operation was not a full clean or was canceled before it could be completed.";
|
|
case 0x8004241B: // VDS_E_DMADMIN_SERVICE_CONNECTION_FAILED
|
|
return "The provider failed to connect to the LDMA service.";
|
|
case 0x8004241C: // VDS_E_PROVIDER_INITIALIZATION_FAILED
|
|
return "The provider failed to initialize.";
|
|
case 0x8004241D: // VDS_E_OBJECT_EXISTS
|
|
return "The object already exists.";
|
|
case 0x8004241E: // VDS_E_NO_DISKS_FOUND
|
|
return "No disks were found on the target machine.";
|
|
case 0x8004241F: // VDS_E_PROVIDER_CACHE_CORRUPT
|
|
return "The cache for a provider is corrupt.";
|
|
case 0x80042420: // VDS_E_DMADMIN_METHOD_CALL_FAILED
|
|
return "A method call to the LDMA service failed.";
|
|
case 0x00042421: // VDS_S_PROVIDER_ERROR_LOADING_CACHE
|
|
return "The provider encountered errors while loading the cache.";
|
|
case 0x80042422: // VDS_E_PROVIDER_VOL_DEVICE_NAME_NOT_FOUND
|
|
return "The device form of the volume pathname could not be retrieved.";
|
|
case 0x80042423: // VDS_E_PROVIDER_VOL_OPEN
|
|
return "Failed to open the volume device";
|
|
case 0x80042424: // VDS_E_DMADMIN_CORRUPT_NOTIFICATION
|
|
return "A corrupt notification was sent from the LDMA service.";
|
|
case 0x80042425: // VDS_E_INCOMPATIBLE_FILE_SYSTEM
|
|
return "The file system is incompatible with the specified operation.";
|
|
case 0x80042426: // VDS_E_INCOMPATIBLE_MEDIA
|
|
return "The media is incompatible with the specified operation.";
|
|
case 0x80042427: // VDS_E_ACCESS_DENIED
|
|
return "Access is denied. A VDS operation MUST run elevated.";
|
|
case 0x80042428: // VDS_E_MEDIA_WRITE_PROTECTED
|
|
return "The media is write-protected.";
|
|
case 0x80042429: // VDS_E_BAD_LABEL
|
|
return "The volume label is not valid.";
|
|
case 0x8004242A: // VDS_E_CANT_QUICK_FORMAT
|
|
return "The volume cannot be quick-formatted.";
|
|
case 0x8004242B: // VDS_E_IO_ERROR
|
|
return "An I/O error occurred during the operation.";
|
|
case 0x8004242C: // VDS_E_VOLUME_TOO_SMALL
|
|
return "The volume size is too small.";
|
|
case 0x8004242D: // VDS_E_VOLUME_TOO_BIG
|
|
return "The volume size is too large.";
|
|
case 0x8004242E: // VDS_E_CLUSTER_SIZE_TOO_SMALL
|
|
return "The cluster size is too small.";
|
|
case 0x8004242F: // VDS_E_CLUSTER_SIZE_TOO_BIG
|
|
return "The cluster size is too large.";
|
|
case 0x80042430: // VDS_E_CLUSTER_COUNT_BEYOND_32BITS
|
|
return "The number of clusters is too large to be represented as a 32-bit integer.";
|
|
case 0x80042431: // VDS_E_OBJECT_STATUS_FAILED
|
|
return "The component that the object represents has failed.";
|
|
case 0x80042432: // VDS_E_VOLUME_INCOMPLETE
|
|
return "The volume is incomplete.";
|
|
case 0x80042433: // VDS_E_EXTENT_SIZE_LESS_THAN_MIN
|
|
return "The specified extent size is too small.";
|
|
case 0x00042434: // VDS_S_UPDATE_BOOTFILE_FAILED
|
|
return "The operation was successful, but VDS failed to update the boot options.";
|
|
case 0x00042436: // VDS_S_BOOT_PARTITION_NUMBER_CHANGE
|
|
case 0x80042436: // VDS_E_BOOT_PARTITION_NUMBER_CHANGE
|
|
return "The boot partition's partition number will change as a result of the operation.";
|
|
case 0x80042437: // VDS_E_NO_FREE_SPACE
|
|
return "The specified disk does not have enough free space to complete the operation.";
|
|
case 0x80042438: // VDS_E_ACTIVE_PARTITION
|
|
return "An active partition was detected on the selected disk.";
|
|
case 0x80042439: // VDS_E_PARTITION_OF_UNKNOWN_TYPE
|
|
return "The partition information cannot be read.";
|
|
case 0x8004243A: // VDS_E_LEGACY_VOLUME_FORMAT
|
|
return "A partition with an unknown type was detected on the specified disk.";
|
|
case 0x8004243C: // VDS_E_MIGRATE_OPEN_VOLUME
|
|
return "A volume on the specified disk could not be opened.";
|
|
case 0x8004243D: // VDS_E_VOLUME_NOT_ONLINE
|
|
return "The volume is not online.";
|
|
case 0x8004243E: // VDS_E_VOLUME_NOT_HEALTHY
|
|
return "The volume is failing or has failed.";
|
|
case 0x8004243F: // VDS_E_VOLUME_SPANS_DISKS
|
|
return "The volume spans multiple disks.";
|
|
case 0x80042440: // VDS_E_REQUIRES_CONTIGUOUS_DISK_SPACE
|
|
return "The volume does not consist of a single disk extent.";
|
|
case 0x80042441: // VDS_E_BAD_PROVIDER_DATA
|
|
return "A provider returned bad data.";
|
|
case 0x80042442: // VDS_E_PROVIDER_FAILURE
|
|
return "A provider failed to complete an operation.";
|
|
case 0x00042443: // VDS_S_VOLUME_COMPRESS_FAILED
|
|
return "The file system was formatted successfully but could not be compressed.";
|
|
case 0x80042444: // VDS_E_PACK_OFFLINE
|
|
return "The pack is offline.";
|
|
case 0x80042445: // VDS_E_VOLUME_NOT_A_MIRROR
|
|
return "The volume is not a mirror.";
|
|
case 0x80042446: // VDS_E_NO_EXTENTS_FOR_VOLUME
|
|
return "No extents were found for the volume.";
|
|
case 0x80042447: // VDS_E_DISK_NOT_LOADED_TO_CACHE
|
|
return "The migrated disk failed to load to the cache.";
|
|
case 0x80042448: // VDS_E_INTERNAL_ERROR
|
|
return "VDS encountered an internal error.";
|
|
case 0x8004244A: // VDS_E_PROVIDER_TYPE_NOT_SUPPORTED
|
|
return "The method call is not supported for the specified provider type.";
|
|
case 0x8004244B: // VDS_E_DISK_NOT_ONLINE
|
|
return "One or more of the specified disks are not online.";
|
|
case 0x8004244C: // VDS_E_DISK_IN_USE_BY_VOLUME
|
|
return "One or more extents of the disk are already being used by the volume.";
|
|
case 0x0004244D: // VDS_S_IN_PROGRESS
|
|
return "The asynchronous operation is in progress.";
|
|
case 0x8004244E: // VDS_E_ASYNC_OBJECT_FAILURE
|
|
return "Failure initializing the asynchronous object.";
|
|
case 0x8004244F: // VDS_E_VOLUME_NOT_MOUNTED
|
|
return "The volume is not mounted.";
|
|
case 0x80042450: // VDS_E_PACK_NOT_FOUND
|
|
return "The pack was not found.";
|
|
case 0x80042453: // VDS_E_OBJECT_OUT_OF_SYNC
|
|
return "The reference to the object might be stale.";
|
|
case 0x80042454: // VDS_E_MISSING_DISK
|
|
return "The specified disk could not be found.";
|
|
case 0x80042455: // VDS_E_DISK_PNP_REG_CORRUPT
|
|
return "The provider's list of PnP registered disks has become corrupted.";
|
|
case 0x80042457: // VDS_E_NO_DRIVELETTER_FLAG
|
|
return "The provider does not support the VDS_VF_NO DRIVELETTER volume flag.";
|
|
case 0x80042459: // VDS_E_REVERT_ON_CLOSE_SET
|
|
return "Some volume flags are already set.";
|
|
case 0x0004245B: // VDS_S_UNABLE_TO_GET_GPT_ATTRIBUTES
|
|
return "Unable to retrieve the GPT attributes for this volume.";
|
|
case 0x8004245C: // VDS_E_VOLUME_TEMPORARILY_DISMOUNTED
|
|
return "The volume is already dismounted temporarily.";
|
|
case 0x8004245D: // VDS_E_VOLUME_PERMANENTLY_DISMOUNTED
|
|
return "The volume is already permanently dismounted.";
|
|
case 0x8004245E: // VDS_E_VOLUME_HAS_PATH
|
|
return "The volume cannot be dismounted permanently because it still has an access path.";
|
|
case 0x8004245F: // VDS_E_TIMEOUT
|
|
return "The operation timed out.";
|
|
case 0x80042461: // VDS_E_LDM_TIMEOUT
|
|
return "The operation timed out in the LDMA service. Retry the operation.";
|
|
case 0x80042462: // VDS_E_REVERT_ON_CLOSE_MISMATCH
|
|
return "The flags to be cleared do not match the flags that were set previously.";
|
|
case 0x80042463: // VDS_E_RETRY
|
|
return "The operation failed. Retry the operation.";
|
|
case 0x80042464: // VDS_E_ONLINE_PACK_EXISTS
|
|
return "The operation failed, because an online pack object already exists.";
|
|
case 0x80042468: // VDS_E_MAX_USABLE_MBR
|
|
return "Only the first 2TB are usable on large MBR disks.";
|
|
case 0x80042500: // VDS_E_NO_SOFTWARE_PROVIDERS_LOADED
|
|
return "There are no software providers loaded.";
|
|
case 0x80042501: // VDS_E_DISK_NOT_MISSING
|
|
return "The disk is not missing.";
|
|
case 0x80042502: // VDS_E_NO_VOLUME_LAYOUT
|
|
return "The volume's layout could not be retrieved.";
|
|
case 0x80042503: // VDS_E_CORRUPT_VOLUME_INFO
|
|
return "The volume's driver information is corrupted.";
|
|
case 0x80042504: // VDS_E_INVALID_ENUMERATOR
|
|
return "The enumerator is corrupted";
|
|
case 0x80042505: // VDS_E_DRIVER_INTERNAL_ERROR
|
|
return "An internal error occurred in the volume management driver.";
|
|
case 0x80042507: // VDS_E_VOLUME_INVALID_NAME
|
|
return "The volume name is not valid.";
|
|
case 0x00042508: // VDS_S_DISK_IS_MISSING
|
|
return "The disk is missing and not all information could be returned.";
|
|
case 0x80042509: // VDS_E_CORRUPT_PARTITION_INFO
|
|
return "The disk's partition information is corrupted.";
|
|
case 0x0004250A: // VDS_S_NONCONFORMANT_PARTITION_INFO
|
|
return "The disk's partition information does not conform to what is expected on a dynamic disk.";
|
|
case 0x8004250B: // VDS_E_CORRUPT_EXTENT_INFO
|
|
return "The disk's extent information is corrupted.";
|
|
case 0x0004250E: // VDS_S_SYSTEM_PARTITION
|
|
return "Warning: There was a failure while checking for the system partition.";
|
|
case 0x8004250F: // VDS_E_BAD_PNP_MESSAGE
|
|
return "The PNP service sent a corrupted notification to the provider.";
|
|
case 0x80042510: // VDS_E_NO_PNP_DISK_ARRIVE
|
|
case 0x80042511: // VDS_E_NO_PNP_VOLUME_ARRIVE
|
|
return "No disk/volume arrival notification was received.";
|
|
case 0x80042512: // VDS_E_NO_PNP_DISK_REMOVE
|
|
case 0x80042513: // VDS_E_NO_PNP_VOLUME_REMOVE
|
|
return "No disk/volume removal notification was received.";
|
|
case 0x80042514: // VDS_E_PROVIDER_EXITING
|
|
return "The provider is exiting.";
|
|
case 0x00042517: // VDS_S_NO_NOTIFICATION
|
|
return "No volume arrival notification was received.";
|
|
case 0x80042519: // VDS_E_INVALID_DISK
|
|
return "The specified disk is not valid.";
|
|
case 0x8004251A: // VDS_E_INVALID_PACK
|
|
return "The specified disk pack is not valid.";
|
|
case 0x8004251B: // VDS_E_VOLUME_ON_DISK
|
|
return "This operation is not allowed on disks with volumes.";
|
|
case 0x8004251C: // VDS_E_DRIVER_INVALID_PARAM
|
|
return "The driver returned an invalid parameter error.";
|
|
case 0x8004253D: // VDS_E_DRIVER_OBJECT_NOT_FOUND
|
|
return "The object was not found in the driver cache.";
|
|
case 0x8004253E: // VDS_E_PARTITION_NOT_CYLINDER_ALIGNED
|
|
return "The disk layout contains partitions which are not cylinder aligned.";
|
|
case 0x8004253F: // VDS_E_DISK_LAYOUT_PARTITIONS_TOO_SMALL
|
|
return "The disk layout contains partitions which are less than the minimum required size.";
|
|
case 0x80042540: // VDS_E_DISK_IO_FAILING
|
|
return "The I/O to the disk is failing.";
|
|
case 0x80042543: // VDS_E_GPT_ATTRIBUTES_INVALID
|
|
return "Invalid GPT attributes were specified.";
|
|
case 0x8004254D: // VDS_E_UNEXPECTED_DISK_LAYOUT_CHANGE
|
|
return "An unexpected layout change occurred external to the volume manager.";
|
|
case 0x8004254E: // VDS_E_INVALID_VOLUME_LENGTH
|
|
return "The volume length is invalid.";
|
|
case 0x8004254F: // VDS_E_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE
|
|
return "The volume length is not a multiple of the sector size.";
|
|
case 0x80042550: // VDS_E_VOLUME_NOT_RETAINED
|
|
return "The volume does not have a retained partition association.";
|
|
case 0x80042551: // VDS_E_VOLUME_RETAINED
|
|
return "The volume already has a retained partition association.";
|
|
case 0x80042553: // VDS_E_ALIGN_BEYOND_FIRST_CYLINDER
|
|
return "The specified alignment is beyond the first cylinder.";
|
|
case 0x80042554: // VDS_E_ALIGN_NOT_SECTOR_SIZE_MULTIPLE
|
|
return "The specified alignment is not a multiple of the sector size.";
|
|
case 0x80042555: // VDS_E_ALIGN_NOT_ZERO
|
|
return "The specified partition type cannot be created with a non-zero alignment.";
|
|
case 0x80042556: // VDS_E_CACHE_CORRUPT
|
|
return "The service's cache has become corrupt.";
|
|
case 0x80042557: // VDS_E_CANNOT_CLEAR_VOLUME_FLAG
|
|
return "The specified volume flag cannot be cleared.";
|
|
case 0x80042558: // VDS_E_DISK_BEING_CLEANED
|
|
return "The operation is not allowed on a disk that is in the process of being cleaned.";
|
|
case 0x8004255A: // VDS_E_DISK_REMOVEABLE
|
|
return "The operation is not supported on removable media.";
|
|
case 0x8004255B: // VDS_E_DISK_REMOVEABLE_NOT_EMPTY
|
|
return "The operation is not supported on a non-empty removable disk.";
|
|
case 0x8004255C: // VDS_E_DRIVE_LETTER_NOT_FREE
|
|
return "The specified drive letter is not free to be assigned.";
|
|
case 0x8004255E: // VDS_E_INVALID_DRIVE_LETTER
|
|
return "The specified drive letter is not valid.";
|
|
case 0x8004255F: // VDS_E_INVALID_DRIVE_LETTER_COUNT
|
|
return "The specified number of drive letters to retrieve is not valid.";
|
|
case 0x80042560: // VDS_E_INVALID_FS_FLAG
|
|
return "The specified file system flag is not valid.";
|
|
case 0x80042561: // VDS_E_INVALID_FS_TYPE
|
|
return "The specified file system is not valid.";
|
|
case 0x80042562: // VDS_E_INVALID_OBJECT_TYPE
|
|
return "The specified object type is not valid.";
|
|
case 0x80042563: // VDS_E_INVALID_PARTITION_LAYOUT
|
|
return "The specified partition layout is invalid.";
|
|
case 0x80042564: // VDS_E_INVALID_PARTITION_STYLE
|
|
return "VDS only supports MBR or GPT partition style disks.";
|
|
case 0x80042565: // VDS_E_INVALID_PARTITION_TYPE
|
|
return "The specified partition type is not valid for this operation.";
|
|
case 0x80042566: // VDS_E_INVALID_PROVIDER_CLSID
|
|
case 0x80042567: // VDS_E_INVALID_PROVIDER_ID
|
|
case 0x8004256A: // VDS_E_INVALID_PROVIDER_VERSION_GUID
|
|
return "A NULL GUID was passed to the provider.";
|
|
case 0x80042568: // VDS_E_INVALID_PROVIDER_NAME
|
|
return "The specified provider name is invalid.";
|
|
case 0x80042569: // VDS_E_INVALID_PROVIDER_TYPE
|
|
return "The specified provider type is invalid.";
|
|
case 0x8004256B: // VDS_E_INVALID_PROVIDER_VERSION_STRING
|
|
return "The specified provider version string is invalid.";
|
|
case 0x8004256C: // VDS_E_INVALID_QUERY_PROVIDER_FLAG
|
|
return "The specified query provider flag is invalid.";
|
|
case 0x8004256D: // VDS_E_INVALID_SERVICE_FLAG
|
|
return "The specified service flag is invalid.";
|
|
case 0x8004256E: // VDS_E_INVALID_VOLUME_FLAG
|
|
return "The specified volume flag is invalid.";
|
|
case 0x8004256F: // VDS_E_PARTITION_NOT_OEM
|
|
return "The operation is only supported on an OEM, ESP, or unknown partition.";
|
|
case 0x80042570: // VDS_E_PARTITION_PROTECTED
|
|
return "Cannot delete a protected partition without the force protected parameter set.";
|
|
case 0x80042571: // VDS_E_PARTITION_STYLE_MISMATCH
|
|
return "The specified partition style is not the same as the disk's partition style.";
|
|
case 0x80042572: // VDS_E_PROVIDER_INTERNAL_ERROR
|
|
return "An internal error has occurred in the provider.";
|
|
case 0x80042575: // VDS_E_UNRECOVERABLE_PROVIDER_ERROR
|
|
return "An unrecoverable error occurred in the provider.";
|
|
case 0x80042576: // VDS_E_VOLUME_HIDDEN
|
|
return "Cannot assign a mount point to a hidden volume.";
|
|
case 0x00042577: // VDS_S_DISMOUNT_FAILED
|
|
case 0x00042578: // VDS_S_REMOUNT_FAILED
|
|
return "Failed to dismount/remount the volume after setting the volume flags.";
|
|
case 0x80042579: // VDS_E_FLAG_ALREADY_SET
|
|
return "Cannot set the specified flag as revert-on-close because it is already set.";
|
|
case 0x8004257B: // VDS_E_DISTINCT_VOLUME
|
|
return "The input volume id cannot be the id of the volume that is the target of the operation.";
|
|
case 0x00042583: // VDS_S_FS_LOCK
|
|
return "Failed to obtain a file system lock.";
|
|
case 0x80042584: // VDS_E_READONLY
|
|
return "The volume is read only.";
|
|
case 0x80042585: // VDS_E_INVALID_VOLUME_TYPE
|
|
return "The volume type is invalid for this operation.";
|
|
case 0x80042588: // VDS_E_VOLUME_MIRRORED
|
|
return "This operation is not supported on a mirrored volume.";
|
|
case 0x80042589: // VDS_E_VOLUME_SIMPLE_SPANNED
|
|
return "The operation is only supported on simple or spanned volumes.";
|
|
case 0x8004258C: // VDS_E_PARTITION_MSR
|
|
case 0x8004258D: // VDS_E_PARTITION_LDM
|
|
return "The operation is not supported on this type of partitions.";
|
|
case 0x0004258E: // VDS_S_WINPE_BOOTENTRY
|
|
return "The boot entries cannot be updated automatically on WinPE.";
|
|
case 0x8004258F: // VDS_E_ALIGN_NOT_A_POWER_OF_TWO
|
|
return "The alignment is not a power of two.";
|
|
case 0x80042590: // VDS_E_ALIGN_IS_ZERO
|
|
return "The alignment is zero.";
|
|
case 0x80042593: // VDS_E_FS_NOT_DETERMINED
|
|
return "The default file system could not be determined.";
|
|
case 0x80042595: // VDS_E_DISK_NOT_OFFLINE
|
|
return "This disk is already online.";
|
|
case 0x80042596: // VDS_E_FAILED_TO_ONLINE_DISK
|
|
return "The online operation failed.";
|
|
case 0x80042597: // VDS_E_FAILED_TO_OFFLINE_DISK
|
|
return "The offline operation failed.";
|
|
case 0x80042598: // VDS_E_BAD_REVISION_NUMBER
|
|
return "The operation could not be completed because the specified revision number is not supported.";
|
|
case 0x00042700: // VDS_S_NAME_TRUNCATED
|
|
return "The name was set successfully but had to be truncated.";
|
|
case 0x80042701: // VDS_E_NAME_NOT_UNIQUE
|
|
return "The specified name is not unique.";
|
|
case 0x8004270F: // VDS_E_NO_DISK_PATHNAME
|
|
return "The disk's path could not be retrieved. Some operations on the disk might fail.";
|
|
case 0x80042711: // VDS_E_NO_VOLUME_PATHNAME
|
|
return "The path could not be retrieved for one or more volumes.";
|
|
case 0x80042712: // VDS_E_PROVIDER_CACHE_OUTOFSYNC
|
|
return "The provider's cache is not in sync with the driver cache.";
|
|
case 0x80042713: // VDS_E_NO_IMPORT_TARGET
|
|
return "No import target was set for the subsystem.";
|
|
case 0x00042714: // VDS_S_ALREADY_EXISTS
|
|
return "The object already exists.";
|
|
case 0x00042715: // VDS_S_PROPERTIES_INCOMPLETE
|
|
return "Some, but not all, of the properties were successfully retrieved.";
|
|
case 0x80042803: // VDS_E_UNABLE_TO_FIND_BOOT_DISK
|
|
return "Volume disk extent information could not be retrieved for the boot volume.";
|
|
case 0x80042807: // VDS_E_BOOT_DISK
|
|
return "Disk attributes cannot be changed on the boot disk.";
|
|
case 0x00042808: // VDS_S_DISK_MOUNT_FAILED
|
|
case 0x00042809: // VDS_S_DISK_DISMOUNT_FAILED
|
|
return "One or more of the volumes on the disk could not be mounted/dismounted.";
|
|
case 0x8004280A: // VDS_E_DISK_IS_OFFLINE
|
|
case 0x8004280B: // VDS_E_DISK_IS_READ_ONLY
|
|
return "The operation cannot be performed on a disk that is offline or read-only.";
|
|
case 0x8004280C: // VDS_E_PAGEFILE_DISK
|
|
case 0x8004280D: // VDS_E_HIBERNATION_FILE_DISK
|
|
case 0x8004280E: // VDS_E_CRASHDUMP_DISK
|
|
return "The operation cannot be performed on a disk that contains a pagefile, hibernation or crashdump volume.";
|
|
case 0x8004280F: // VDS_E_UNABLE_TO_FIND_SYSTEM_DISK
|
|
return "A system error occurred while retrieving the system disk information.";
|
|
case 0x80042810: // VDS_E_INCORRECT_SYSTEM_VOLUME_EXTENT_INFO
|
|
return "Multiple disk extents reported for the system volume - system error.";
|
|
case 0x80042811: // VDS_E_SYSTEM_DISK
|
|
return "Disk attributes cannot be changed on the current system disk or BIOS disk 0.";
|
|
case 0x80042823: // VDS_E_SECTOR_SIZE_ERROR
|
|
return "The sector size MUST be non-zero, a power of 2, and less than the maximum sector size.";
|
|
case 0x80042907: // VDS_E_SUBSYSTEM_ID_IS_NULL
|
|
return "The provider returned a NULL subsystem identification string.";
|
|
case 0x8004290C: // VDS_E_REBOOT_REQUIRED
|
|
return "A reboot is required before any further operations are initiated.";
|
|
case 0x8004290D: // VDS_E_VOLUME_GUID_PATHNAME_NOT_ALLOWED
|
|
return "Volume GUID pathnames are not valid input to this method.";
|
|
case 0x8004290E: // VDS_E_BOOT_PAGEFILE_DRIVE_LETTER
|
|
return "Assigning or removing drive letters on the current boot or pagefile volume is not allowed.";
|
|
case 0x8004290F: // VDS_E_DELETE_WITH_CRITICAL
|
|
return "Delete is not allowed on a critical volume.";
|
|
case 0x80042910: // VDS_E_CLEAN_WITH_DATA
|
|
case 0x80042911: // VDS_E_CLEAN_WITH_OEM
|
|
return "The FORCE parameter MUST be set to TRUE in order to clean a disk that contains a data or OEM volume.";
|
|
case 0x80042912: // VDS_E_CLEAN_WITH_CRITICAL
|
|
return "Clean is not allowed on a critical disk.";
|
|
case 0x80042913: // VDS_E_FORMAT_CRITICAL
|
|
return "Format is not allowed on a critical volume.";
|
|
case 0x80042914: // VDS_E_NTFS_FORMAT_NOT_SUPPORTED
|
|
case 0x80042915: // VDS_E_FAT32_FORMAT_NOT_SUPPORTED
|
|
case 0x80042916: // VDS_E_FAT_FORMAT_NOT_SUPPORTED
|
|
return "The requested file system format is not supported on this volume.";
|
|
case 0x80042917: // VDS_E_FORMAT_NOT_SUPPORTED
|
|
return "The volume is not formattable.";
|
|
case 0x80042918: // VDS_E_COMPRESSION_NOT_SUPPORTED
|
|
return "The specified file system does not support compression.";
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Convert a windows error to human readable string
|
|
const char *WindowsErrorString(void)
|
|
{
|
|
static char err_string[256] = { 0 };
|
|
|
|
DWORD size, presize;
|
|
DWORD error_code, format_error;
|
|
|
|
error_code = GetLastError();
|
|
// Check for VDS error codes
|
|
if ((SCODE_FACILITY(error_code) == FACILITY_ITF) && (GetVdsError(error_code) != NULL)) {
|
|
static_sprintf(err_string, "[0x%08lX] %s", error_code, GetVdsError(error_code));
|
|
return err_string;
|
|
}
|
|
|
|
static_sprintf(err_string, "[0x%08lX] ", error_code);
|
|
presize = (DWORD)strlen(err_string);
|
|
|
|
size = FormatMessageU(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, HRESULT_CODE(error_code),
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &err_string[presize],
|
|
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);
|
|
} else {
|
|
// Microsoft may suffix CRLF to error messages, which we need to remove...
|
|
assert(presize > 2);
|
|
size += presize - 2;
|
|
// Cannot underflow if the above assert passed since our first char is neither of the following
|
|
while ((err_string[size] == 0x0D) || (err_string[size] == 0x0A) || (err_string[size] == 0x20))
|
|
err_string[size--] = 0;
|
|
}
|
|
|
|
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)) ? LEFT_TO_RIGHT_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<MAX_SIZE_SUFFIXES-1; suffix++) {
|
|
if (hr_size < divider)
|
|
break;
|
|
hr_size /= divider;
|
|
}
|
|
if (suffix == 0) {
|
|
static_sprintf(str_size, "%s%d%s %s", dir, (int)hr_size, dir, _msg_table[MSG_020-MSG_000]);
|
|
} else if (fake_units) {
|
|
if (hr_size < 8) {
|
|
static_sprintf(str_size, (fabs((hr_size*10.0)-(floor(hr_size + 0.5)*10.0)) < 0.5)?"%0.0f%s":"%0.1f%s",
|
|
hr_size, _msg_table[MSG_020+suffix-MSG_000]);
|
|
} else {
|
|
t = (double)upo2((uint16_t)hr_size);
|
|
i_size = (uint16_t)((fabs(1.0f-(hr_size / t)) < 0.05f)?t:hr_size);
|
|
static_sprintf(str_size, "%s%d%s %s", dir, i_size, dir, _msg_table[MSG_020+suffix-MSG_000]);
|
|
}
|
|
} else {
|
|
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]);
|
|
}
|
|
return str_size;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Convert custom error code to messages
|
|
const char* _StrError(DWORD error_code)
|
|
{
|
|
if ( (!IS_ERROR(error_code)) || (SCODE_CODE(error_code) == ERROR_SUCCESS)) {
|
|
return lmprintf(MSG_050);
|
|
}
|
|
if (SCODE_FACILITY(error_code) != FACILITY_STORAGE) {
|
|
SetLastError(error_code);
|
|
return WindowsErrorString();
|
|
}
|
|
switch (SCODE_CODE(error_code)) {
|
|
case ERROR_GEN_FAILURE:
|
|
return lmprintf(MSG_051);
|
|
case ERROR_INCOMPATIBLE_FS:
|
|
return lmprintf(MSG_052);
|
|
case ERROR_ACCESS_DENIED:
|
|
return lmprintf(MSG_053);
|
|
case ERROR_WRITE_PROTECT:
|
|
return lmprintf(MSG_054);
|
|
case ERROR_DEVICE_IN_USE:
|
|
return lmprintf(MSG_055);
|
|
case ERROR_CANT_QUICK_FORMAT:
|
|
return lmprintf(MSG_056);
|
|
case ERROR_LABEL_TOO_LONG:
|
|
return lmprintf(MSG_057);
|
|
case ERROR_INVALID_HANDLE:
|
|
return lmprintf(MSG_058);
|
|
case ERROR_INVALID_CLUSTER_SIZE:
|
|
return lmprintf(MSG_059);
|
|
case ERROR_INVALID_VOLUME_SIZE:
|
|
return lmprintf(MSG_060);
|
|
case ERROR_NO_MEDIA_IN_DRIVE:
|
|
return lmprintf(MSG_061);
|
|
case ERROR_NOT_SUPPORTED:
|
|
return lmprintf(MSG_062);
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
return lmprintf(MSG_063);
|
|
case ERROR_READ_FAULT:
|
|
return lmprintf(MSG_064);
|
|
case ERROR_WRITE_FAULT:
|
|
return lmprintf(MSG_065);
|
|
case ERROR_INSTALL_FAILURE:
|
|
return lmprintf(MSG_066);
|
|
case ERROR_OPEN_FAILED:
|
|
return lmprintf(MSG_067);
|
|
case ERROR_PARTITION_FAILURE:
|
|
return lmprintf(MSG_068);
|
|
case ERROR_CANNOT_COPY:
|
|
return lmprintf(MSG_069);
|
|
case ERROR_CANCELLED:
|
|
return lmprintf(MSG_070);
|
|
case ERROR_CANT_START_THREAD:
|
|
return lmprintf(MSG_071);
|
|
case ERROR_BADBLOCKS_FAILURE:
|
|
return lmprintf(MSG_072);
|
|
case ERROR_ISO_SCAN:
|
|
return lmprintf(MSG_073);
|
|
case ERROR_ISO_EXTRACT:
|
|
return lmprintf(MSG_074);
|
|
case ERROR_CANT_REMOUNT_VOLUME:
|
|
return lmprintf(MSG_075);
|
|
case ERROR_CANT_PATCH:
|
|
return lmprintf(MSG_076);
|
|
case ERROR_CANT_ASSIGN_LETTER:
|
|
return lmprintf(MSG_077);
|
|
case ERROR_CANT_MOUNT_VOLUME:
|
|
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();
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
// A WriteFile() equivalent, with up to nNumRetries write attempts on error.
|
|
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)
|
|
uprintf("Warning: Could not read file pointer %s", WindowsErrorString());
|
|
|
|
if (nNumRetries == 0)
|
|
nNumRetries = 1;
|
|
for (nTry = 1; nTry <= nNumRetries; nTry++) {
|
|
// Need to rewind our file position on retry - if we can't even do that, just give up
|
|
if ((nTry > 1) && (!SetFilePointerEx(hFile, liFilePointer, NULL, FILE_BEGIN))) {
|
|
uprintf("Could not set file pointer - Aborting");
|
|
break;
|
|
}
|
|
if (WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL)) {
|
|
LastWriteError = 0;
|
|
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", *lpNumberOfBytesWritten, nNumberOfBytesToWrite);
|
|
} else {
|
|
uprintf("Write error %s", WindowsErrorString());
|
|
LastWriteError = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|GetLastError();
|
|
}
|
|
// If we can't reposition for the next run, just abort
|
|
if (!readFilePointer)
|
|
break;
|
|
if (nTry < nNumRetries) {
|
|
uprintf("Retrying in %d seconds...", WRITE_TIMEOUT / 1000);
|
|
// Don't sit idly but use the downtime to check for conflicting processes...
|
|
Sleep(CheckDriveAccess(WRITE_TIMEOUT, FALSE));
|
|
}
|
|
}
|
|
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)
|
|
{
|
|
uint64_t CurTime, EndTime = GetTickCount64() + dwMilliseconds;
|
|
DWORD res;
|
|
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) {
|
|
CurTime = GetTickCount64();
|
|
// Account for the case where we may reach the timeout condition while
|
|
// processing timestamps
|
|
if (CurTime < EndTime)
|
|
dwMilliseconds = (DWORD) (EndTime - CurTime);
|
|
else
|
|
res = WAIT_TIMEOUT;
|
|
}
|
|
} while (res == (WAIT_OBJECT_0 + 1));
|
|
|
|
return res;
|
|
}
|