[core] improve mounting/unmounting of volumes

* Factorize drive letter removal into a RemoveDriveLetters() call.
* Improve MountVolume() and RemountVolume() calls.
* Also bump Rufus version to 3.13
This commit is contained in:
Pete Batard 2020-10-26 11:48:33 +00:00
parent 3758f84b17
commit b2b621cec7
No known key found for this signature in database
GPG key ID: 38E0CF5E69EDD671
8 changed files with 99 additions and 61 deletions

20
configure vendored
View file

@ -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.69 for rufus 3.12. # Generated by GNU Autoconf 2.69 for rufus 3.13.
# #
# Report bugs to <https://github.com/pbatard/rufus/issues>. # Report bugs to <https://github.com/pbatard/rufus/issues>.
# #
@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='rufus' PACKAGE_NAME='rufus'
PACKAGE_TARNAME='rufus' PACKAGE_TARNAME='rufus'
PACKAGE_VERSION='3.12' PACKAGE_VERSION='3.13'
PACKAGE_STRING='rufus 3.12' PACKAGE_STRING='rufus 3.13'
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'
@ -1228,7 +1228,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 3.12 to adapt to many kinds of systems. \`configure' configures rufus 3.13 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1294,7 +1294,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 3.12:";; short | recursive ) echo "Configuration of rufus 3.13:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1385,7 +1385,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 3.12 rufus configure 3.13
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@ -1440,7 +1440,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 3.12, which was It was created by rufus $as_me 3.13, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@ -2303,7 +2303,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='rufus' PACKAGE='rufus'
VERSION='3.12' VERSION='3.13'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@ -4484,7 +4484,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 3.12, which was This file was extended by rufus $as_me 3.13, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -4538,7 +4538,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
rufus config.status 3.12 rufus config.status 3.13
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View file

@ -1,4 +1,4 @@
AC_INIT([rufus], [3.12], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie]) AC_INIT([rufus], [3.13], [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])

View file

@ -8,7 +8,7 @@
for an interesting struggle, when you also happen to have a comma in one of the fields... --> for an interesting struggle, when you also happen to have a comma in one of the fields... -->
<Identity <Identity
Name="Rufus" Name="Rufus"
Version="3.12.1710.0" Version="3.13.1710.0"
ProcessorArchitecture="@ARCH@" ProcessorArchitecture="@ARCH@"
Publisher='CN=Akeo Consulting, O=Akeo Consulting, STREET=24 Grey Rock, L=Milford, S=Co. Donegal, PostalCode=F92 D667, C=IE' /> Publisher='CN=Akeo Consulting, O=Akeo Consulting, STREET=24 Grey Rock, L=Milford, S=Co. Donegal, PostalCode=F92 D667, C=IE' />
<Properties> <Properties>

View file

@ -1,6 +1,6 @@
@echo off @echo off
setlocal EnableExtensions DisableDelayedExpansion setlocal EnableExtensions DisableDelayedExpansion
set VERSION=3.12 set VERSION=3.13
del /q *.appx >NUL 2>&1 del /q *.appx >NUL 2>&1
del /q *.appxbundle >NUL 2>&1 del /q *.appxbundle >NUL 2>&1

View file

@ -1099,6 +1099,47 @@ UINT GetDriveTypeFromIndex(DWORD DriveIndex)
return drive_type; return drive_type;
} }
// Removes all drive letters associated with the specific drive, and return
// either the first or last letter that was removed, according to bReturnLast.
char RemoveDriveLetters(DWORD DriveIndex, BOOL bReturnLast, BOOL bSilent)
{
int i, len;
char drive_letters[27] = { 0 }, drive_name[4] = "#:\\";
if (!GetDriveLetters(DriveIndex, drive_letters)) {
suprintf("Failed to get a drive letter");
return 0;
}
if (drive_letters[0] == 0) {
suprintf("No drive letter was assigned...");
return GetUnusedDriveLetter();
}
len = (int)strlen(drive_letters);
if (len == 0)
return 0;
// Unmount all mounted volumes that belong to this drive
for (i = 0; i < len; i++) {
// Check that the current image isn't located on a drive we are trying to dismount
if ((boot_type == BT_IMAGE) && (drive_letters[i] == (PathGetDriveNumberU(image_path) + 'A'))) {
if ((PathGetDriveNumberU(image_path) + 'A') == drive_letters[i]) {
suprintf("ABORTED: Cannot use an image that is located on the target drive!");
return 0;
}
}
drive_name[0] = drive_letters[i];
// DefineDosDevice() cannot have a trailing backslash...
drive_name[2] = 0;
DefineDosDeviceA(DDD_REMOVE_DEFINITION, drive_name, NULL);
// ... but DeleteVolumeMountPoint() requires one. Go figure...
drive_name[2] = '\\';
if (!DeleteVolumeMountPointA(drive_name))
suprintf("Failed to delete mountpoint %s: %s", drive_name, WindowsErrorString());
}
return drive_letters[bReturnLast ? (len - 1) : 0];
}
/* /*
* Return the next unused drive letter from the system or NUL on error. * Return the next unused drive letter from the system or NUL on error.
*/ */
@ -1719,15 +1760,33 @@ BOOL UnmountVolume(HANDLE hDrive)
*/ */
BOOL MountVolume(char* drive_name, char *volume_name) BOOL MountVolume(char* drive_name, char *volume_name)
{ {
char mounted_guid[52]; char mounted_guid[52], dos_name[] = "?:";
#if defined(WINDOWS_IS_NOT_BUGGY) #if defined(WINDOWS_IS_NOT_BUGGY)
char mounted_letter[27] = { 0 }; char mounted_letter[27] = { 0 };
DWORD size; DWORD size;
#endif #endif
if ((drive_name == NULL) || (volume_name == NULL) || (drive_name[0] == '?') || if ((drive_name == NULL) || (volume_name == NULL) || (drive_name[0] == '?')) {
(strncmp(volume_name, groot_name, groot_len) == 0)) SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
}
// If we are working with a "\\?\GLOBALROOT" device, SetVolumeMountPoint()
// is useless, so try with DefineDosDevice() instead.
if (_strnicmp(volume_name, groot_name, groot_len) == 0) {
dos_name[0] = drive_name[0];
// Microsoft will also have to explain why "In no case is a trailing backslash allowed" [1] in
// DefineDosDevice(), instead of just checking if the driver parameter is "X:\" and remove the
// backslash from a copy of the parameter in the bloody API call. *THIS* really tells a lot
// about the level of thought and foresight that actually goes into the Windows APIs...
// [1] https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-definedosdevicew
if (!DefineDosDeviceA(DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM, dos_name, &volume_name[14])) {
uprintf("Could not mount %s as %C:", volume_name, drive_name[0]);
return FALSE;
}
uprintf("%s was successfully mounted as %C:", volume_name, drive_name[0]);
return TRUE;
}
// Great: Windows has a *MAJOR BUG* whereas, in some circumstances, GetVolumePathNamesForVolumeName() // Great: Windows has a *MAJOR BUG* whereas, in some circumstances, GetVolumePathNamesForVolumeName()
// can return the *WRONG* drive letter. And yes, we validated that this is *NOT* an issue like stack // can return the *WRONG* drive letter. And yes, we validated that this is *NOT* an issue like stack
@ -1837,19 +1896,13 @@ BOOL RemountVolume(char* drive_name)
// UDF requires a sync/flush, and it's also a good idea for other FS's // UDF requires a sync/flush, and it's also a good idea for other FS's
FlushDrive(drive_name[0]); FlushDrive(drive_name[0]);
if (GetVolumeNameForVolumeMountPointA(drive_name, volume_name, sizeof(volume_name))) { if (GetVolumeNameForVolumeMountPointA(drive_name, volume_name, sizeof(volume_name))) {
if (DeleteVolumeMountPointA(drive_name)) { if (MountVolume(drive_name, volume_name)) {
Sleep(200); uprintf("Successfully remounted %s as %C:", volume_name, drive_name[0]);
if (MountVolume(drive_name, volume_name)) {
uprintf("Successfully remounted %s as %C:", volume_name, drive_name[0]);
} else {
uprintf("Failed to remount %s as %C:", volume_name, drive_name[0]);
// This will leave the drive inaccessible and must be flagged as an error
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_REMOUNT_VOLUME);
return FALSE;
}
} else { } else {
uprintf("Could not remount %s as %C: %s", volume_name, drive_name[0], WindowsErrorString()); uprintf("Could not remount %s as %C: %s", volume_name, drive_name[0], WindowsErrorString());
// Try to continue regardless // This will leave the drive inaccessible and must be flagged as an error
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_REMOUNT_VOLUME);
return FALSE;
} }
} }
return TRUE; return TRUE;

View file

@ -384,6 +384,7 @@ BOOL GetDriveLetters(DWORD DriveIndex, char* drive_letters);
UINT GetDriveTypeFromIndex(DWORD DriveIndex); UINT GetDriveTypeFromIndex(DWORD DriveIndex);
char GetUnusedDriveLetter(void); char GetUnusedDriveLetter(void);
BOOL IsDriveLetterInUse(const char drive_letter); BOOL IsDriveLetterInUse(const char drive_letter);
char RemoveDriveLetters(DWORD DriveIndex, BOOL bUseLast, BOOL bSilent);
BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label); BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label);
uint64_t GetDriveSize(DWORD DriveIndex); uint64_t GetDriveSize(DWORD DriveIndex);
BOOL IsMediaPresent(DWORD DriveIndex); BOOL IsMediaPresent(DWORD DriveIndex);

View file

@ -1660,7 +1660,7 @@ out:
*/ */
DWORD WINAPI FormatThread(void* param) DWORD WINAPI FormatThread(void* param)
{ {
int i, r; int r;
BOOL ret, use_large_fat32, windows_to_go, actual_lock_drive = lock_drive; BOOL ret, use_large_fat32, windows_to_go, actual_lock_drive = lock_drive;
DWORD cr, DriveIndex = (DWORD)(uintptr_t)param, ClusterSize, Flags; DWORD cr, DriveIndex = (DWORD)(uintptr_t)param, ClusterSize, Flags;
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE; HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
@ -1714,32 +1714,13 @@ DWORD WINAPI FormatThread(void* param)
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_ASSIGN_LETTER); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_ASSIGN_LETTER);
goto out; goto out;
} }
if (drive_letters[0] == 0) {
uprintf("No drive letter was assigned..."); // Unassign all drives letters
drive_name[0] = GetUnusedDriveLetter(); drive_name[0] = RemoveDriveLetters(DriveIndex, TRUE, FALSE);
if (drive_name[0] == 0) { if (drive_name[0] == 0) {
uprintf("Could not find a suitable drive letter"); uprintf("Unable to find a drive letter to use");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_ASSIGN_LETTER); FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_ASSIGN_LETTER);
goto out; goto out;
}
} else {
// Unmount all mounted volumes that belong to this drive
// Do it in reverse so that we always end on the first volume letter
for (i = (int)safe_strlen(drive_letters); i > 0; i--) {
drive_name[0] = drive_letters[i-1];
if (boot_type == BT_IMAGE) {
// If we are using an image, check that it isn't located on the drive we are trying to format
if ((PathGetDriveNumberU(image_path) + 'A') == drive_letters[i-1]) {
uprintf("ABORTED: Cannot use an image that is located on the target drive!");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED;
goto out;
}
}
if (!DeleteVolumeMountPointA(drive_name)) {
uprintf("Failed to delete mountpoint %s: %s", drive_name, WindowsErrorString());
// Try to continue. We will bail out if this causes an issue.
}
}
} }
uprintf("Will use '%C:' as volume mountpoint", drive_name[0]); uprintf("Will use '%C:' as volume mountpoint", drive_name[0]);
@ -2012,6 +1993,9 @@ DWORD WINAPI FormatThread(void* param)
} }
uprintf("Found volume %s", volume_name); uprintf("Found volume %s", volume_name);
// Windows is really finicky with regards to reassigning drive letters even after
// we forcibly removed them, so add yet another explicit call to RemoveDriveLetters()
RemoveDriveLetters(DriveIndex, FALSE, TRUE);
if (!MountVolume(drive_name, volume_name)) { if (!MountVolume(drive_name, volume_name)) {
uprintf("Could not remount %s as %C: %s\n", volume_name, drive_name[0], WindowsErrorString()); uprintf("Could not remount %s as %C: %s\n", volume_name, drive_name[0], WindowsErrorString());
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_MOUNT_VOLUME); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_MOUNT_VOLUME);
@ -2080,7 +2064,7 @@ DWORD WINAPI FormatThread(void* param)
} }
CHECK_FOR_USER_CANCEL; CHECK_FOR_USER_CANCEL;
// We issue a complete remount of the filesystem at on account of: // We issue a complete remount of the filesystem on account of:
// - Ensuring the file explorer properly detects that the volume was updated // - Ensuring the file explorer properly detects that the volume was updated
// - Ensuring that an NTFS system will be reparsed so that it becomes bootable // - Ensuring that an NTFS system will be reparsed so that it becomes bootable
if (!RemountVolume(drive_name)) if (!RemountVolume(drive_name))

View file

@ -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 3.12.1713" CAPTION "Rufus 3.13.1714"
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
@ -395,8 +395,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,12,1713,0 FILEVERSION 3,13,1714,0
PRODUCTVERSION 3,12,1713,0 PRODUCTVERSION 3,13,1714,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -414,13 +414,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", "3.12.1713" VALUE "FileVersion", "3.13.1714"
VALUE "InternalName", "Rufus" VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2020 Pete Batard (GPL v3)" VALUE "LegalCopyright", "© 2011-2020 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-3.12.exe" VALUE "OriginalFilename", "rufus-3.13.exe"
VALUE "ProductName", "Rufus" VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "3.12.1713" VALUE "ProductVersion", "3.13.1714"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"