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:
parent
ae3c65e7f8
commit
bdff2dc45c
5 changed files with 39 additions and 33 deletions
20
configure
vendored
20
configure
vendored
|
@ -1,6 +1,6 @@
|
||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# 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>.
|
# Report bugs to <https://github.com/pbatard/rufus/issues>.
|
||||||
#
|
#
|
||||||
|
@ -611,8 +611,8 @@ MAKEFLAGS=
|
||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='rufus'
|
PACKAGE_NAME='rufus'
|
||||||
PACKAGE_TARNAME='rufus'
|
PACKAGE_TARNAME='rufus'
|
||||||
PACKAGE_VERSION='4.5'
|
PACKAGE_VERSION='4.6'
|
||||||
PACKAGE_STRING='rufus 4.5'
|
PACKAGE_STRING='rufus 4.6'
|
||||||
PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues'
|
PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues'
|
||||||
PACKAGE_URL='https://rufus.ie'
|
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.
|
# 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.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
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]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
|
@ -1336,7 +1336,7 @@ fi
|
||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of rufus 4.5:";;
|
short | recursive ) echo "Configuration of rufus 4.6:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
|
@ -1428,7 +1428,7 @@ fi
|
||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
rufus configure 4.5
|
rufus configure 4.6
|
||||||
generated by GNU Autoconf 2.71
|
generated by GNU Autoconf 2.71
|
||||||
|
|
||||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||||
|
@ -1504,7 +1504,7 @@ cat >config.log <<_ACEOF
|
||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
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
|
generated by GNU Autoconf 2.71. Invocation command line was
|
||||||
|
|
||||||
$ $0$ac_configure_args_raw
|
$ $0$ac_configure_args_raw
|
||||||
|
@ -2767,7 +2767,7 @@ fi
|
||||||
|
|
||||||
# Define the identity of the package.
|
# Define the identity of the package.
|
||||||
PACKAGE='rufus'
|
PACKAGE='rufus'
|
||||||
VERSION='4.5'
|
VERSION='4.6'
|
||||||
|
|
||||||
|
|
||||||
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
|
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
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
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
|
generated by GNU Autoconf 2.71. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
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
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config='$ac_cs_config_escaped'
|
ac_cs_config='$ac_cs_config_escaped'
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
rufus config.status 4.5
|
rufus config.status 4.6
|
||||||
configured by $0, generated by GNU Autoconf 2.71,
|
configured by $0, generated by GNU Autoconf 2.71,
|
||||||
with options \\"\$ac_cs_config\\"
|
with options \\"\$ac_cs_config\\"
|
||||||
|
|
||||||
|
|
|
@ -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])
|
AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies])
|
||||||
AC_CONFIG_SRCDIR([src/rufus.c])
|
AC_CONFIG_SRCDIR([src/rufus.c])
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
|
|
28
src/format.c
28
src/format.c
|
@ -1150,8 +1150,8 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
|
||||||
BOOL s, ret = FALSE;
|
BOOL s, ret = FALSE;
|
||||||
LARGE_INTEGER li;
|
LARGE_INTEGER li;
|
||||||
HANDLE hSourceImage = INVALID_HANDLE_VALUE;
|
HANDLE hSourceImage = INVALID_HANDLE_VALUE;
|
||||||
DWORD i, read_size[NUM_BUFFERS], write_size, comp_size, buf_size;
|
DWORD i, read_size[NUM_BUFFERS] = { 0 }, write_size, comp_size, buf_size;
|
||||||
uint64_t wb, target_size = bZeroDrive ? SelectedDrive.DiskSize : img_report.image_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;
|
uint64_t cur_value, last_value = 0;
|
||||||
int64_t bled_ret;
|
int64_t bled_ret;
|
||||||
uint8_t* buffer = NULL;
|
uint8_t* buffer = NULL;
|
||||||
|
@ -1341,7 +1341,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
|
||||||
assert((uintptr_t)buffer % SelectedDrive.SectorSize == 0);
|
assert((uintptr_t)buffer % SelectedDrive.SectorSize == 0);
|
||||||
|
|
||||||
// Start the initial read
|
// 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
|
read_size[proc_bufnum] = 1; // To avoid early loop exit
|
||||||
for (wb = 0; read_size[proc_bufnum] != 0; wb += read_size[proc_bufnum]) {
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Update the read size
|
|
||||||
// 2a) Don't overflow our projected size (mostly for VHDs)
|
// 2. WriteFile fails unless the size is a multiple of sector size
|
||||||
if (wb + read_size[read_bufnum] > target_size)
|
if (read_size[read_bufnum] % SelectedDrive.SectorSize != 0) {
|
||||||
read_size[read_bufnum] = (DWORD)(target_size - wb);
|
assert(HI_ALIGN_X_TO_Y(read_size[read_bufnum], SelectedDrive.SectorSize) <= buf_size);
|
||||||
// 2b) WriteFile fails unless the size is a multiple of sector size
|
read_size[read_bufnum] = HI_ALIGN_X_TO_Y(read_size[read_bufnum], SelectedDrive.SectorSize);
|
||||||
if (read_size[read_bufnum] % SelectedDrive.SectorSize != 0)
|
}
|
||||||
read_size[read_bufnum] = ((read_size[read_bufnum] + SelectedDrive.SectorSize - 1) /
|
|
||||||
SelectedDrive.SectorSize) * SelectedDrive.SectorSize;
|
|
||||||
|
|
||||||
// 3. Switch to the next reading buffer
|
// 3. Switch to the next reading buffer
|
||||||
proc_bufnum = read_bufnum;
|
proc_bufnum = read_bufnum;
|
||||||
read_bufnum = (read_bufnum + 1) % NUM_BUFFERS;
|
read_bufnum = (read_bufnum + 1) % NUM_BUFFERS;
|
||||||
|
|
||||||
// 3. Launch the next asynchronous read operation
|
// 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
|
// 4. Synchronously write the current data buffer
|
||||||
for (i = 1; i <= WRITE_RETRIES; i++) {
|
for (i = 1; i <= WRITE_RETRIES; i++) {
|
||||||
|
|
12
src/rufus.rc
12
src/rufus.rc
|
@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||||
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||||
EXSTYLE WS_EX_ACCEPTFILES
|
EXSTYLE WS_EX_ACCEPTFILES
|
||||||
CAPTION "Rufus 4.5.2181"
|
CAPTION "Rufus 4.6.2182"
|
||||||
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
||||||
BEGIN
|
BEGIN
|
||||||
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
||||||
|
@ -397,8 +397,8 @@ END
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 4,5,2181,0
|
FILEVERSION 4,6,2182,0
|
||||||
PRODUCTVERSION 4,5,2181,0
|
PRODUCTVERSION 4,6,2182,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -416,13 +416,13 @@ BEGIN
|
||||||
VALUE "Comments", "https://rufus.ie"
|
VALUE "Comments", "https://rufus.ie"
|
||||||
VALUE "CompanyName", "Akeo Consulting"
|
VALUE "CompanyName", "Akeo Consulting"
|
||||||
VALUE "FileDescription", "Rufus"
|
VALUE "FileDescription", "Rufus"
|
||||||
VALUE "FileVersion", "4.5.2181"
|
VALUE "FileVersion", "4.6.2182"
|
||||||
VALUE "InternalName", "Rufus"
|
VALUE "InternalName", "Rufus"
|
||||||
VALUE "LegalCopyright", "<22> 2011-2024 Pete Batard (GPL v3)"
|
VALUE "LegalCopyright", "<22> 2011-2024 Pete Batard (GPL v3)"
|
||||||
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
|
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 "ProductName", "Rufus"
|
||||||
VALUE "ProductVersion", "4.5.2181"
|
VALUE "ProductVersion", "4.6.2182"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
10
src/winio.h
10
src/winio.h
|
@ -102,11 +102,13 @@ static __inline BOOL ReadFileAsync(HANDLE h, LPVOID lpBuffer, DWORD nNumberOfByt
|
||||||
ASYNC_FD* fd = (ASYNC_FD*)h;
|
ASYNC_FD* fd = (ASYNC_FD*)h;
|
||||||
fd->Overlapped.bOffsetUpdated = FALSE;
|
fd->Overlapped.bOffsetUpdated = FALSE;
|
||||||
if (!ReadFile(fd->hFile, lpBuffer, nNumberOfBytesToRead, NULL,
|
if (!ReadFile(fd->hFile, lpBuffer, nNumberOfBytesToRead, NULL,
|
||||||
(OVERLAPPED*)&fd->Overlapped))
|
(OVERLAPPED*)&fd->Overlapped)) {
|
||||||
// TODO: Is it possible to get ERROR_HANDLE_EOF here?
|
// Is it possible to get ERROR_HANDLE_EOF here?
|
||||||
|
assert(GetLastError() != ERROR_HANDLE_EOF);
|
||||||
fd->iStatus = (GetLastError() == ERROR_IO_PENDING) ? -1 : 0;
|
fd->iStatus = (GetLastError() == ERROR_IO_PENDING) ? -1 : 0;
|
||||||
else
|
} else {
|
||||||
fd->iStatus = 1;
|
fd->iStatus = 1;
|
||||||
|
}
|
||||||
return (fd->iStatus != 0);
|
return (fd->iStatus != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,11 +167,11 @@ static __inline BOOL GetSizeAsync(HANDLE h, LPDWORD lpNumberOfBytes)
|
||||||
SetLastError(ERROR_NO_MORE_ITEMS);
|
SetLastError(ERROR_NO_MORE_ITEMS);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
fd->Overlapped.bOffsetUpdated = TRUE;
|
||||||
if (!GetOverlappedResultEx(fd->hFile, (OVERLAPPED*)&fd->Overlapped,
|
if (!GetOverlappedResultEx(fd->hFile, (OVERLAPPED*)&fd->Overlapped,
|
||||||
lpNumberOfBytes, WRITE_TIMEOUT, (fd->iStatus < 0)))
|
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
|
// 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);
|
return (GetLastError() == ERROR_HANDLE_EOF || GetLastError() == ERROR_SECTOR_NOT_FOUND);
|
||||||
fd->Overlapped.Offset += *lpNumberOfBytes;
|
fd->Overlapped.Offset += *lpNumberOfBytes;
|
||||||
fd->Overlapped.bOffsetUpdated = TRUE;
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue