1
1
Fork 0
mirror of https://github.com/pbatard/rufus.git synced 2024-08-14 23:57:05 +00:00

[core] work around Windows' moronic behaviour for mounted VHDs

* If you attempt to read past the end of a mounted VHD, not only will Windows happily
  return data that doesn't exist (instead of returning End of Disk), but it will also
  corrupt the existing data!
* So, to appease the capricious Windows gods, we now make sure that we never attempt
  to read (or write) past the boundaries of the source or target when writing images.
* This should address the last issue from #2468.
* Also set version to rufus-next and make some small improvement in winio.h.
This commit is contained in:
Pete Batard 2024-06-03 12:58:37 +01:00
parent ae3c65e7f8
commit bdff2dc45c
No known key found for this signature in database
GPG key ID: 38E0CF5E69EDD671
5 changed files with 39 additions and 33 deletions

20
configure vendored
View file

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.71 for rufus 4.5.
# Generated by GNU Autoconf 2.71 for rufus 4.6.
#
# Report bugs to <https://github.com/pbatard/rufus/issues>.
#
@ -611,8 +611,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='rufus'
PACKAGE_TARNAME='rufus'
PACKAGE_VERSION='4.5'
PACKAGE_STRING='rufus 4.5'
PACKAGE_VERSION='4.6'
PACKAGE_STRING='rufus 4.6'
PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues'
PACKAGE_URL='https://rufus.ie'
@ -1269,7 +1269,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 4.5 to adapt to many kinds of systems.
\`configure' configures rufus 4.6 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1336,7 +1336,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of rufus 4.5:";;
short | recursive ) echo "Configuration of rufus 4.6:";;
esac
cat <<\_ACEOF
@ -1428,7 +1428,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
rufus configure 4.5
rufus configure 4.6
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@ -1504,7 +1504,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 4.5, which was
It was created by rufus $as_me 4.6, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@ -2767,7 +2767,7 @@ fi
# Define the identity of the package.
PACKAGE='rufus'
VERSION='4.5'
VERSION='4.6'
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@ -5309,7 +5309,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 4.5, which was
This file was extended by rufus $as_me 4.6, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -5365,7 +5365,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
rufus config.status 4.5
rufus config.status 4.6
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"

View file

@ -1,4 +1,4 @@
AC_INIT([rufus], [4.5], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie])
AC_INIT([rufus], [4.6], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie])
AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies])
AC_CONFIG_SRCDIR([src/rufus.c])
AC_CONFIG_MACRO_DIR([m4])

View file

@ -1150,8 +1150,8 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
BOOL s, ret = FALSE;
LARGE_INTEGER li;
HANDLE hSourceImage = INVALID_HANDLE_VALUE;
DWORD i, read_size[NUM_BUFFERS], write_size, comp_size, buf_size;
uint64_t wb, target_size = bZeroDrive ? SelectedDrive.DiskSize : img_report.image_size;
DWORD i, read_size[NUM_BUFFERS] = { 0 }, write_size, comp_size, buf_size;
uint64_t wb, target_size = bZeroDrive ? SelectedDrive.DiskSize : MIN((uint64_t)SelectedDrive.DiskSize, img_report.image_size);
uint64_t cur_value, last_value = 0;
int64_t bled_ret;
uint8_t* buffer = NULL;
@ -1341,7 +1341,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
assert((uintptr_t)buffer % SelectedDrive.SectorSize == 0);
// Start the initial read
ReadFileAsync(hSourceImage, &buffer[read_bufnum * buf_size], buf_size);
ReadFileAsync(hSourceImage, &buffer[read_bufnum * buf_size], (DWORD)MIN(buf_size, target_size));
read_size[proc_bufnum] = 1; // To avoid early loop exit
for (wb = 0; read_size[proc_bufnum] != 0; wb += read_size[proc_bufnum]) {
@ -1362,21 +1362,25 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
goto out;
}
// 2. Update the read size
// 2a) Don't overflow our projected size (mostly for VHDs)
if (wb + read_size[read_bufnum] > target_size)
read_size[read_bufnum] = (DWORD)(target_size - wb);
// 2b) WriteFile fails unless the size is a multiple of sector size
if (read_size[read_bufnum] % SelectedDrive.SectorSize != 0)
read_size[read_bufnum] = ((read_size[read_bufnum] + SelectedDrive.SectorSize - 1) /
SelectedDrive.SectorSize) * SelectedDrive.SectorSize;
// 2. WriteFile fails unless the size is a multiple of sector size
if (read_size[read_bufnum] % SelectedDrive.SectorSize != 0) {
assert(HI_ALIGN_X_TO_Y(read_size[read_bufnum], SelectedDrive.SectorSize) <= buf_size);
read_size[read_bufnum] = HI_ALIGN_X_TO_Y(read_size[read_bufnum], SelectedDrive.SectorSize);
}
// 3. Switch to the next reading buffer
proc_bufnum = read_bufnum;
read_bufnum = (read_bufnum + 1) % NUM_BUFFERS;
// 3. Launch the next asynchronous read operation
ReadFileAsync(hSourceImage, &buffer[read_bufnum * buf_size], buf_size);
// It is VERY IMPORTANT here that we don't attempt to read past the source
// or target sizes, as mounted VHDs will SCREW YOU if you attempt to do so
// and will even start returning ERRONEOUS DATA for sectors before the end
// of the disk... So we make sure to adjust the size not to ever overflow.
// Also we need to make sure we add read_size[proc_bufnum] to wb since we
// have already read the data and are about to write it.
ReadFileAsync(hSourceImage, &buffer[read_bufnum * buf_size], (DWORD)MIN(buf_size, target_size - (wb + read_size[proc_bufnum])));
// 4. Synchronously write the current data buffer
for (i = 1; i <= WRITE_RETRIES; i++) {

View file

@ -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 4.5.2181"
CAPTION "Rufus 4.6.2182"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@ -397,8 +397,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,5,2181,0
PRODUCTVERSION 4,5,2181,0
FILEVERSION 4,6,2182,0
PRODUCTVERSION 4,6,2182,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -416,13 +416,13 @@ BEGIN
VALUE "Comments", "https://rufus.ie"
VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "4.5.2181"
VALUE "FileVersion", "4.6.2182"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "<22> 2011-2024 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
VALUE "OriginalFilename", "rufus-4.5.exe"
VALUE "OriginalFilename", "rufus-4.6.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "4.5.2181"
VALUE "ProductVersion", "4.6.2182"
END
END
BLOCK "VarFileInfo"

View file

@ -102,11 +102,13 @@ static __inline BOOL ReadFileAsync(HANDLE h, LPVOID lpBuffer, DWORD nNumberOfByt
ASYNC_FD* fd = (ASYNC_FD*)h;
fd->Overlapped.bOffsetUpdated = FALSE;
if (!ReadFile(fd->hFile, lpBuffer, nNumberOfBytesToRead, NULL,
(OVERLAPPED*)&fd->Overlapped))
// TODO: Is it possible to get ERROR_HANDLE_EOF here?
(OVERLAPPED*)&fd->Overlapped)) {
// Is it possible to get ERROR_HANDLE_EOF here?
assert(GetLastError() != ERROR_HANDLE_EOF);
fd->iStatus = (GetLastError() == ERROR_IO_PENDING) ? -1 : 0;
else
} else {
fd->iStatus = 1;
}
return (fd->iStatus != 0);
}
@ -165,11 +167,11 @@ static __inline BOOL GetSizeAsync(HANDLE h, LPDWORD lpNumberOfBytes)
SetLastError(ERROR_NO_MORE_ITEMS);
return FALSE;
}
fd->Overlapped.bOffsetUpdated = TRUE;
if (!GetOverlappedResultEx(fd->hFile, (OVERLAPPED*)&fd->Overlapped,
lpNumberOfBytes, WRITE_TIMEOUT, (fd->iStatus < 0)))
// When reading from VHD/VHDX we get SECTOR_NOT_FOUND rather than EOF for the end of the drive
return (GetLastError() == ERROR_HANDLE_EOF || GetLastError() == ERROR_SECTOR_NOT_FOUND);
fd->Overlapped.Offset += *lpNumberOfBytes;
fd->Overlapped.bOffsetUpdated = TRUE;
return TRUE;
}