diff --git a/doc/html/en/Command Line Usage for Windows.html b/doc/html/en/Command Line Usage for Windows.html index bbfa3e3a..9c1ea35b 100644 --- a/doc/html/en/Command Line Usage for Windows.html +++ b/doc/html/en/Command Line Usage for Windows.html @@ -111,7 +111,7 @@ If it is followed by n or no: force the displa /cancelmount -Cancels any currently running mount operation and exits without displaying a status message. The process returns exit code 0 when the cancel request is accepted by the driver, or 1 otherwise. +Cancels any currently running mount operation and exits without displaying a status message. The process returns exit code 0 when the cancel request is accepted by the driver, or 1 otherwise. This switch only has an effect while a mount operation is active; if an auto-mount scan is between mount attempts, the scan is not stopped by this command. /secureDesktop diff --git a/src/Common/Cmdline.c b/src/Common/Cmdline.c index 466079fb..a3cf5d07 100644 --- a/src/Common/Cmdline.c +++ b/src/Common/Cmdline.c @@ -67,6 +67,7 @@ BOOL CALLBACK CommandHelpDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM } #if defined(TCMOUNT) && !defined(VCEXPANDER) StringCchCatW (tmp, 8192, L"\nExamples:\n\nMount a volume as X:\tveracrypt.exe /q /v volume.hc /l X\nUnmount a volume X:\tveracrypt.exe /q /u X"); + StringCchCatW (tmp, 8192, L"\n\nNote: /cancelmount requests cancellation of the currently active mount operation only. If auto-mount scanning is between mount attempts, the scan is not stopped by this command."); #endif SetWindowTextW (GetDlgItem (hwndDlg, IDC_COMMANDHELP_TEXT), tmp); diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c index e54ee739..b133e483 100644 --- a/src/Common/Dlgcode.c +++ b/src/Common/Dlgcode.c @@ -8883,8 +8883,6 @@ static UINT g_wmWaitDlg = ::RegisterWindowMessage(L"VeraCryptWaitDlgMessage"); #define WAIT_DLG_CANCEL_RETRY_TIMER_ID 1 #define WAIT_DLG_CANCEL_RETRY_INTERVAL 250 -typedef BOOL (CALLBACK* WaitCancelProc)(void* pArg, HWND hWaitDlg); - typedef struct { HWND hwnd; @@ -9064,7 +9062,7 @@ static LRESULT CALLBACK ShowWaitDialogParentWndProc (HWND hWnd, UINT message, WP } -static void ShowWaitDialogEx(HWND hwnd, BOOL bUseHwndAsParent, WaitThreadProc callback, WaitCancelProc cancelCallback, void* pArg) +void ShowWaitDialogEx(HWND hwnd, BOOL bUseHwndAsParent, WaitThreadProc callback, WaitCancelProc cancelCallback, void* pArg) { BOOL bEffectiveHideWaitingDialog = bCmdHideWaitingDialogValid? bCmdHideWaitingDialog : bHideWaitingDialog; WaitThreadParam threadParam; @@ -9512,7 +9510,10 @@ retry: if (mount.nReturnCode != 0) { if (mount.nReturnCode == ERR_USER_ABORT) + { + SetLastError (ERROR_CANCELLED); return -1; + } if (mount.nReturnCode == ERR_PASSWORD_WRONG) { diff --git a/src/Common/Dlgcode.h b/src/Common/Dlgcode.h index f4308b8b..c8cdb6df 100644 --- a/src/Common/Dlgcode.h +++ b/src/Common/Dlgcode.h @@ -767,7 +767,9 @@ INT_PTR TextEditDialogBox (BOOL readOnly, HWND parent, const WCHAR* Title, std:: // Display a wait dialog while calling the provided callback with the given parameter typedef void (CALLBACK* WaitThreadProc)(void* pArg, HWND hWaitDlg); +typedef BOOL (CALLBACK* WaitCancelProc)(void* pArg, HWND hWaitDlg); void BringToForeground(HWND hWnd); +void ShowWaitDialogEx(HWND hwnd, BOOL bUseHwndAsParent, WaitThreadProc callback, WaitCancelProc cancelCallback, void* pArg); void ShowWaitDialog(HWND hwnd, BOOL bUseHwndAsParent, WaitThreadProc callback, void* pArg); // classes used to implement support for password drag-n-drop from KeePass Password Safe diff --git a/src/Mount/Favorites.cpp b/src/Mount/Favorites.cpp index 6be45ed0..c65d94eb 100644 --- a/src/Mount/Favorites.cpp +++ b/src/Mount/Favorites.cpp @@ -733,6 +733,7 @@ namespace VeraCrypt { FillFavoriteVolumesMenu(); + ::ClearFavoriteVolumeArrivalMountSuppressions (); FavoritesOnArrivalMountRequired.clear(); for (const FavoriteVolume& favorite: FavoriteVolumes) diff --git a/src/Mount/Mount.c b/src/Mount/Mount.c index a2d22457..9607a9f8 100644 --- a/src/Mount/Mount.c +++ b/src/Mount/Mount.c @@ -188,6 +188,273 @@ VOLUME_NOTIFICATIONS_LIST VolumeNotificationsList; static DWORD LastKnownLogicalDrives; static volatile LONG FavoriteMountOnGoing = 0; +static list SuppressedFavoritesOnArrivalMount; + +typedef enum +{ + MountResultFailed = 0, + MountResultSucceeded, + MountResultSkipped, + MountResultCancelled, + MountResultArrivalPasswordPromptDeclined, + /* Preserves legacy favorite-on-arrival behavior: a drive-letter conflict is a + handled skip so the timer does not repeatedly show the same error while the + device remains connected. */ + MountResultDriveLetterUnavailable +} MountResult; + +typedef struct +{ + volatile LONG bAbortRequested; + volatile LONG nCurrentMountDriveNo; +} MountBatchContext; + +typedef struct +{ + BOOL systemFavorites; + BOOL logOnMount; + BOOL hotKeyMount; + MountBatchContext mountBatch; + /* Owned by the thread parameter when non-NULL. */ + FavoriteVolume* favoriteVolumeToMount; +} mountFavoriteVolumeThreadParam; + +static void __cdecl mountFavoriteVolumeThreadFunction (void *pArg); +static BOOL MountFavoriteVolumesWithAbort (HWND hwnd, BOOL systemFavorites, BOOL logOnMount, BOOL hotKeyMount, const FavoriteVolume &favoriteVolumeToMount, MountBatchContext* pMountBatch, MountResult* pBatchResult); + + +static void MountBatchInitialize (MountBatchContext* pMountBatch) +{ + if (pMountBatch) + { + InterlockedExchange (&pMountBatch->bAbortRequested, FALSE); + InterlockedExchange (&pMountBatch->nCurrentMountDriveNo, -1); + } +} + + +static void MountBatchSetCurrentMountDriveNo (MountBatchContext* pMountBatch, int nDosDriveNo) +{ + if (pMountBatch) + InterlockedExchange (&pMountBatch->nCurrentMountDriveNo, nDosDriveNo); +} + + +static void MountBatchClearCurrentMountDriveNo (MountBatchContext* pMountBatch) +{ + MountBatchSetCurrentMountDriveNo (pMountBatch, -1); +} + + +static BOOL MountBatchAbortRequested (MountBatchContext* pMountBatch) +{ + return pMountBatch && InterlockedCompareExchange (&pMountBatch->bAbortRequested, 0, 0) != 0; +} + + +static void MountBatchRequestAbort (MountBatchContext* pMountBatch) +{ + if (pMountBatch) + InterlockedExchange (&pMountBatch->bAbortRequested, TRUE); +} + + +static BOOL MountBatchAbortCurrentMountOperation (MountBatchContext* pMountBatch) +{ + LONG nDosDriveNo; + + if (!pMountBatch) + return FALSE; + + nDosDriveNo = InterlockedCompareExchange (&pMountBatch->nCurrentMountDriveNo, 0, 0); + + /* No mount is registered yet. The abort flag has already been set by the caller, + and MountVolumeWithBatchCancel re-checks that flag after publishing the drive + number, so the worker is guaranteed to honor it before launching the (possibly + long) KDF. Reporting the cancel as handled is therefore safe. */ + if (nDosDriveNo < 0) + return TRUE; + + return AbortMountOperation ((int) nDosDriveNo); +} + + +/* Shared wait-dialog cancel handler for batch mount operations: requests the batch abort + and tries to abort the mount currently in flight. Returns TRUE if the cancel has been + fully handled (so the wait dialog can stop retrying). */ +static BOOL MountBatchCancel (MountBatchContext* pMountBatch) +{ + MountBatchRequestAbort (pMountBatch); + return MountBatchAbortCurrentMountOperation (pMountBatch); +} + + +/* Returns TRUE if a MountVolume()/MountVolumeWithBatchCancel() result indicates the + operation was aborted (either cooperatively through the batch abort flag or through + the driver, e.g. an external /cancelmount). Must be called immediately after the + mount call, before any other Win32 call clobbers the thread's last-error value. */ +static BOOL MountVolumeWasCancelled (int mountResult) +{ + return (mountResult < 0) && (GetLastError () == ERROR_CANCELLED); +} + + +static int MountVolumeWithBatchCancel ( + HWND hwndDlg, + int nDosDriveNo, + wchar_t *szVolFileName, + Password *password, + int pkcs5, + int pim, + BOOL cachePassword, + BOOL cachePim, + BOOL sharedAccess, + const MountOptions* const mountOptionsParam, + BOOL quiet, + BOOL bReportWrongPassword, + MountBatchContext* pMountBatch) +{ + int mounted; + + if (MountBatchAbortRequested (pMountBatch)) + { + SetLastError (ERROR_CANCELLED); + return -1; + } + + MountBatchSetCurrentMountDriveNo (pMountBatch, nDosDriveNo); + + /* Close the cancel race: the cancel callback sets the abort flag before reading the + current drive number, while we publish the drive number before re-reading the flag. + This Dekker-style handshake (both sides use full-barrier Interlocked ops) guarantees + that either the cancel callback sees our drive number and aborts the driver, or we + see the abort flag here and bail out before starting the long mount. */ + if (MountBatchAbortRequested (pMountBatch)) + { + MountBatchClearCurrentMountDriveNo (pMountBatch); + SetLastError (ERROR_CANCELLED); + return -1; + } + + SetLastError (ERROR_SUCCESS); + mounted = MountVolume (hwndDlg, nDosDriveNo, szVolFileName, password, pkcs5, pim, cachePassword, cachePim, sharedAccess, mountOptionsParam, quiet, bReportWrongPassword); + + MountBatchClearCurrentMountDriveNo (pMountBatch); + return mounted; +} + + +static bool FavoriteVolumesMatchForArrivalCancel (const FavoriteVolume& left, const FavoriteVolume& right) +{ + if (left.UseVolumeID && right.UseVolumeID + && !IsRepeatedByteArray (0, left.VolumeID, sizeof (left.VolumeID)) + && !IsRepeatedByteArray (0, right.VolumeID, sizeof (right.VolumeID))) + { + return memcmp (left.VolumeID, right.VolumeID, VOLUME_ID_SIZE) == 0; + } + + if (!left.VolumePathId.empty() && !right.VolumePathId.empty()) + return _wcsicmp (left.VolumePathId.c_str(), right.VolumePathId.c_str()) == 0; + + if (!left.Path.empty() && !right.Path.empty()) + return _wcsicmp (left.Path.c_str(), right.Path.c_str()) == 0; + + return false; +} + + +static bool FavoriteVolumeArrivalMountSuppressed (const list & suppressedFavorites, const FavoriteVolume& favorite) +{ + for (const FavoriteVolume& suppressedFavorite: suppressedFavorites) + { + if (FavoriteVolumesMatchForArrivalCancel (suppressedFavorite, favorite)) + return true; + } + + return false; +} + + +static void SuppressFavoriteVolumeArrivalMount (list & suppressedFavorites, const FavoriteVolume& favorite) +{ + if (!FavoriteVolumeArrivalMountSuppressed (suppressedFavorites, favorite)) + suppressedFavorites.push_back (favorite); +} + + +static void ResumeFavoriteVolumeArrivalMount (list & suppressedFavorites, const FavoriteVolume& favorite) +{ + for (list ::iterator suppressedFavorite = suppressedFavorites.begin(); + suppressedFavorite != suppressedFavorites.end();) + { + if (FavoriteVolumesMatchForArrivalCancel (*suppressedFavorite, favorite)) + suppressedFavorite = suppressedFavorites.erase (suppressedFavorite); + else + ++suppressedFavorite; + } +} + + +void ClearFavoriteVolumeArrivalMountSuppressions () +{ + SuppressedFavoritesOnArrivalMount.clear (); +} + + +/* Determines whether a "mount on arrival" favorite currently refers to a present, + not-yet-mounted volume, normalizing favorite.Path/VolumePathId/DisconnectedDevice + along the way (the favorite is taken by reference). Returns FALSE when the favorite + is already mounted or its device is not present; in that case the caller clears any + arrival-mount suppression and skips it this round. */ +static BOOL FavoriteVolumeArrivalMountCandidate (FavoriteVolume& favorite) +{ + if (favorite.UseVolumeID) + { + if (IsMountedVolumeID (favorite.VolumeID)) + return FALSE; + + std::wstring volDevPath = FindDeviceByVolumeID (favorite.VolumeID, FALSE); + if (volDevPath.length() == 0) + return FALSE; + + favorite.Path = volDevPath; + favorite.DisconnectedDevice = false; + } + else if (!favorite.VolumePathId.empty()) + { + if (IsMountedVolume (favorite.Path.c_str())) + return FALSE; + + wchar_t volDevPath[TC_MAX_PATH]; + if (QueryDosDevice (favorite.VolumePathId.substr (4, favorite.VolumePathId.size() - 5).c_str(), volDevPath, TC_MAX_PATH) == 0) + return FALSE; + + favorite.DisconnectedDevice = false; + } + else if (favorite.Path.find (L"\\\\?\\Volume{") == 0) + { + wstring resolvedPath = VolumeGuidPathToDevicePath (favorite.Path); + if (resolvedPath.empty()) + return FALSE; + + favorite.DisconnectedDevice = false; + favorite.VolumePathId = favorite.Path; + favorite.Path = resolvedPath; + } + + if (IsMountedVolume (favorite.Path.c_str())) + return FALSE; + + if (!IsVolumeDeviceHosted (favorite.Path.c_str())) + { + if (!FileExists (favorite.Path.c_str())) + return FALSE; + } + else if (favorite.VolumePathId.empty()) + return FALSE; + + return TRUE; +} static mountFavoriteVolumeThreadParam* AllocateMountFavoriteVolumeThreadParam (BOOL systemFavorites, BOOL logOnMount, BOOL hotKeyMount, const FavoriteVolume* favoriteVolumeToMount) @@ -199,6 +466,7 @@ static mountFavoriteVolumeThreadParam* AllocateMountFavoriteVolumeThreadParam (B pParam->systemFavorites = systemFavorites; pParam->logOnMount = logOnMount; pParam->hotKeyMount = hotKeyMount; + MountBatchInitialize (&pParam->mountBatch); if (favoriteVolumeToMount) { @@ -5403,9 +5671,10 @@ static int AskVolumePassword (HWND hwndDlg, Password *password, int *pkcs5, int // GUI actions -static BOOL Mount (HWND hwndDlg, int nDosDriveNo, wchar_t *szVolFileName, int pim, int pkcs5) +static MountResult Mount (HWND hwndDlg, int nDosDriveNo, wchar_t *szVolFileName, int pim, int pkcs5, MountBatchContext* pMountBatch) { - BOOL status = FALSE; + BOOL bMountCancelled = FALSE; + MountResult result = MountResultFailed; wchar_t fileName[MAX_PATH]; int mounted = 0, EffectiveVolumePkcs5 = 0; int EffectiveVolumePim = (pim < 0)? CmdVolumePim : pim; @@ -5444,13 +5713,11 @@ static BOOL Mount (HWND hwndDlg, int nDosDriveNo, wchar_t *szVolFileName, int pi if (wcslen(fileName) == 0) { - status = FALSE; goto ret; } if (!TranslateVolumeID (hwndDlg, fileName, ARRAYSIZE (fileName))) { - status = FALSE; goto ret; } @@ -5459,7 +5726,6 @@ static BOOL Mount (HWND hwndDlg, int nDosDriveNo, wchar_t *szVolFileName, int pi if (IsMountedVolume (szVolFileName)) { Warning ("VOL_ALREADY_MOUNTED", hwndDlg); - status = FALSE; goto ret; } @@ -5468,7 +5734,6 @@ static BOOL Mount (HWND hwndDlg, int nDosDriveNo, wchar_t *szVolFileName, int pi if (!MultipleMountOperationInProgress) handleWin32Error (hwndDlg, SRC_POS); - status = FALSE; goto ret; } @@ -5479,26 +5744,32 @@ static BOOL Mount (HWND hwndDlg, int nDosDriveNo, wchar_t *szVolFileName, int pi if (!bUseCmdVolumePassword) { // First try cached passwords and if they fail ask user for a new one - mounted = MountVolume (hwndDlg, nDosDriveNo, szVolFileName, NULL, EffectiveVolumePkcs5, EffectiveVolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, Silent, FALSE); + mounted = MountVolumeWithBatchCancel (hwndDlg, nDosDriveNo, szVolFileName, NULL, EffectiveVolumePkcs5, EffectiveVolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, Silent, FALSE, pMountBatch); + if (MountVolumeWasCancelled (mounted)) + bMountCancelled = TRUE; // If keyfiles are enabled, test empty password first - if (!mounted && KeyFilesEnable && FirstKeyFile && bEffectiveTryEmptyPasswordWhenKeyfileUsed) + if (!bMountCancelled && !mounted && KeyFilesEnable && FirstKeyFile && bEffectiveTryEmptyPasswordWhenKeyfileUsed) { Password emptyPassword = {0}; KeyFilesApply (hwndDlg, &emptyPassword, FirstKeyFile, szVolFileName); - mounted = MountVolume (hwndDlg, nDosDriveNo, szVolFileName, &emptyPassword, EffectiveVolumePkcs5, EffectiveVolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, Silent, FALSE); + mounted = MountVolumeWithBatchCancel (hwndDlg, nDosDriveNo, szVolFileName, &emptyPassword, EffectiveVolumePkcs5, EffectiveVolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, Silent, FALSE, pMountBatch); + if (MountVolumeWasCancelled (mounted)) + bMountCancelled = TRUE; burn (&emptyPassword, sizeof (emptyPassword)); } } // Test password and/or keyfiles used for the previous volume - if (!mounted && bEffectiveCacheDuringMultipleMount && MultipleMountOperationInProgress && VolumePassword.Length != 0) + if (!bMountCancelled && !mounted && bEffectiveCacheDuringMultipleMount && MultipleMountOperationInProgress && VolumePassword.Length != 0) { // if no PIM specified for favorite, we use also the PIM of the previous volume alongside its password. - mounted = MountVolume (hwndDlg, nDosDriveNo, szVolFileName, &VolumePassword, EffectiveVolumePkcs5, (EffectiveVolumePim < 0)? VolumePim : EffectiveVolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, Silent, FALSE); + mounted = MountVolumeWithBatchCancel (hwndDlg, nDosDriveNo, szVolFileName, &VolumePassword, EffectiveVolumePkcs5, (EffectiveVolumePim < 0)? VolumePim : EffectiveVolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, Silent, FALSE, pMountBatch); + if (MountVolumeWasCancelled (mounted)) + bMountCancelled = TRUE; } NormalCursor (); @@ -5513,6 +5784,12 @@ static BOOL Mount (HWND hwndDlg, int nDosDriveNo, wchar_t *szVolFileName, int pi while (mounted == 0) { + if (MountBatchAbortRequested (pMountBatch)) + { + bMountCancelled = TRUE; + goto ret; + } + if (bUseCmdVolumePassword) { VolumePassword = CmdVolumePassword; @@ -5526,7 +5803,11 @@ static BOOL Mount (HWND hwndDlg, int nDosDriveNo, wchar_t *szVolFileName, int pi StringCbCopyW (PasswordDlgVolume, sizeof(PasswordDlgVolume), szVolFileName); if (!AskVolumePassword (hwndDlg, &VolumePassword, &GuiPkcs5, &GuiPim, NULL, TRUE)) + { + if (FavoriteMountOnArrivalInProgress) + result = MountResultArrivalPasswordPromptDeclined; goto ret; + } else { VolumePkcs5 = GuiPkcs5; @@ -5541,7 +5822,9 @@ static BOOL Mount (HWND hwndDlg, int nDosDriveNo, wchar_t *szVolFileName, int pi if (KeyFilesEnable) KeyFilesApply (hwndDlg, &VolumePassword, FirstKeyFile, szVolFileName); - mounted = MountVolume (hwndDlg, nDosDriveNo, szVolFileName, &VolumePassword, VolumePkcs5, VolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, Silent, !Silent); + mounted = MountVolumeWithBatchCancel (hwndDlg, nDosDriveNo, szVolFileName, &VolumePassword, VolumePkcs5, VolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, Silent, !Silent, pMountBatch); + if (MountVolumeWasCancelled (mounted)) + bMountCancelled = TRUE; NormalCursor (); // Check for problematic file extensions (exe, dll, sys) @@ -5564,7 +5847,7 @@ static BOOL Mount (HWND hwndDlg, int nDosDriveNo, wchar_t *szVolFileName, int pi if (mounted > 0) { - status = TRUE; + result = MountResultSucceeded; if (bBeep) MessageBeep (0xFFFFFFFF); @@ -5600,10 +5883,16 @@ ret: if (UsePreferences) bCacheInDriver = bCacheInDriverDefault; - if (status && CloseSecurityTokenSessionsAfterMount && !MultipleMountOperationInProgress) + if (result == MountResultSucceeded && CloseSecurityTokenSessionsAfterMount && !MultipleMountOperationInProgress) SecurityToken::CloseAllSessions(); // TODO Use Token - return status; + if (bMountCancelled) + { + result = MountResultCancelled; + SetLastError (ERROR_CANCELLED); + } + + return result; } @@ -5649,7 +5938,7 @@ void __cdecl mountThreadFunction (void *hwndDlgArg) EnableWindow(hwndDlg, FALSE); finally_do_arg2 (HWND, hwndDlg, BOOL, bIsForeground, { EnableWindow(finally_arg, TRUE); if (finally_arg2) BringToForeground (finally_arg); bPrebootPasswordDlgMode = FALSE;}); - Mount (hwndDlg, -1, 0, -1, -1); + Mount (hwndDlg, -1, 0, -1, -1, NULL); } typedef struct @@ -5871,11 +6160,21 @@ retry: return status; } -static BOOL MountAllDevicesThreadCode (HWND hwndDlg, BOOL bPasswordPrompt) +typedef struct { + BOOL bPasswordPrompt; + BOOL bRet; + MountBatchContext mountBatch; +} MountAllDevicesThreadParam; + +static BOOL MountAllDevicesThreadCode (HWND hwndDlg, MountAllDevicesThreadParam* threadParam) +{ + BOOL bPasswordPrompt = threadParam->bPasswordPrompt; + MountBatchContext* pMountBatch = &threadParam->mountBatch; HWND driveList = GetDlgItem (MainDlg, IDC_DRIVELIST); int selDrive = ListView_GetSelectionMark (driveList); BOOL shared = FALSE, status = FALSE, bHeaderBakRetry = FALSE; + BOOL bCancelled = FALSE; int mountedVolCount = 0; vector devices; int EffectiveVolumePkcs5 = CmdVolumePkcs5; @@ -5901,6 +6200,9 @@ static BOOL MountAllDevicesThreadCode (HWND hwndDlg, BOOL bPasswordPrompt) do { + if (MountBatchAbortRequested (pMountBatch)) + goto post_mount; + if (!bHeaderBakRetry) { if (!CmdVolumePasswordValid && bPasswordPrompt) @@ -5937,13 +6239,22 @@ static BOOL MountAllDevicesThreadCode (HWND hwndDlg, BOOL bPasswordPrompt) if (devices.empty()) devices = GetAvailableHostDevices (true, false, true, true); + if (MountBatchAbortRequested (pMountBatch)) + goto post_mount; + for (const HostDevice& drive: devices) { + if (MountBatchAbortRequested (pMountBatch)) + goto post_mount; + vector partitions = drive.Partitions; partitions.insert (partitions.begin(), drive); for (const HostDevice &device: partitions) { + if (MountBatchAbortRequested (pMountBatch)) + goto post_mount; + wchar_t szPartPath[TC_MAX_PATH]; StringCbCopyW (szPartPath, sizeof (szPartPath), device.Path.c_str()); BOOL mounted = IsMountedVolume (szPartPath); @@ -6006,8 +6317,27 @@ static BOOL MountAllDevicesThreadCode (HWND hwndDlg, BOOL bPasswordPrompt) } // First try user password then cached passwords - if ((mounted = MountVolume (hwndDlg, nDosDriveNo, szPartPath, &VolumePassword, VolumePkcs5, VolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, TRUE, FALSE)) > 0 - || ((VolumePassword.Length > 0) && ((mounted = MountVolume (hwndDlg, nDosDriveNo, szPartPath, NULL, VolumePkcs5, VolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, TRUE, FALSE)) > 0))) + mounted = MountVolumeWithBatchCancel (hwndDlg, nDosDriveNo, szPartPath, &VolumePassword, VolumePkcs5, VolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, TRUE, FALSE, pMountBatch); + if (MountVolumeWasCancelled (mounted)) + { + MountBatchRequestAbort (pMountBatch); + goto post_mount; + } + + if (mounted <= 0 && VolumePassword.Length > 0) + { + if (MountBatchAbortRequested (pMountBatch)) + goto post_mount; + + mounted = MountVolumeWithBatchCancel (hwndDlg, nDosDriveNo, szPartPath, NULL, VolumePkcs5, VolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, TRUE, FALSE, pMountBatch); + if (MountVolumeWasCancelled (mounted)) + { + MountBatchRequestAbort (pMountBatch); + goto post_mount; + } + } + + if (mounted > 0) { // A volume has been successfully mounted @@ -6041,6 +6371,9 @@ static BOOL MountAllDevicesThreadCode (HWND hwndDlg, BOOL bPasswordPrompt) } } + if (MountBatchAbortRequested (pMountBatch)) + goto post_mount; + if (mountedVolCount < 1) { // Failed to mount any volume @@ -6093,7 +6426,10 @@ static BOOL MountAllDevicesThreadCode (HWND hwndDlg, BOOL bPasswordPrompt) } while (bPasswordPrompt && mountedVolCount < 1); - /* One or more volumes successfully mounted */ +post_mount: + /* Finalize any successfully mounted volumes before restoring shared state. */ + + bCancelled = MountBatchAbortRequested (pMountBatch); ResetWrongPwdRetryCount (); @@ -6131,21 +6467,27 @@ ret: NormalCursor(); + if (bCancelled || MountBatchAbortRequested (pMountBatch)) + { + status = FALSE; + SetLastError (ERROR_CANCELLED); + } + return status; } -typedef struct -{ - BOOL bPasswordPrompt; - BOOL bRet; -} MountAllDevicesThreadParam; - void CALLBACK mountAllDevicesThreadProc(void* pArg, HWND hwndDlg) { MountAllDevicesThreadParam* threadParam =(MountAllDevicesThreadParam*) pArg; - BOOL bPasswordPrompt = threadParam->bPasswordPrompt; - threadParam->bRet = MountAllDevicesThreadCode (hwndDlg, bPasswordPrompt); + threadParam->bRet = MountAllDevicesThreadCode (hwndDlg, threadParam); +} + +BOOL CALLBACK mountAllDevicesCancelProc(void* pArg, HWND ) +{ + MountAllDevicesThreadParam* threadParam = (MountAllDevicesThreadParam*) pArg; + + return MountBatchCancel (threadParam ? &threadParam->mountBatch : NULL); } static BOOL MountAllDevices (HWND hwndDlg, BOOL bPasswordPrompt) @@ -6153,11 +6495,18 @@ static BOOL MountAllDevices (HWND hwndDlg, BOOL bPasswordPrompt) MountAllDevicesThreadParam param; param.bPasswordPrompt = bPasswordPrompt; param.bRet = FALSE; + MountBatchInitialize (¶m.mountBatch); if (Silent) mountAllDevicesThreadProc (¶m, hwndDlg); else - ShowWaitDialog (hwndDlg, FALSE, mountAllDevicesThreadProc, ¶m); + ShowWaitDialogEx (hwndDlg, FALSE, mountAllDevicesThreadProc, mountAllDevicesCancelProc, ¶m); + + if (MountBatchAbortRequested (¶m.mountBatch)) + { + param.bRet = FALSE; + SetLastError (ERROR_CANCELLED); + } return param.bRet; } @@ -7536,6 +7885,8 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa // Automount if (bAuto || (Quit && szFileName[0] != 0)) { + BOOL autoMountCancelled = FALSE; + // No drive letter specified on command line if (commandLineDrive == 0) szDriveLetter[0] = (wchar_t) GetFirstAvailableDrive () + L'A'; @@ -7550,11 +7901,17 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa KeyFileCloneAll (FirstCmdKeyFile, &defaultKeyFilesParam.FirstKeyFile); } + SetLastError (ERROR_SUCCESS); if (!MountAllDevices (hwndDlg, !Silent && !CmdVolumePasswordValid && IsPasswordCacheEmpty())) + { + if (GetLastError () == ERROR_CANCELLED) + autoMountCancelled = TRUE; + exitCode = 1; + } } - if (bAutoMountFavorites) + if (!autoMountCancelled && bAutoMountFavorites) { defaultMountOptions = mountOptions; if (FirstCmdKeyFile) @@ -7564,15 +7921,21 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa KeyFileCloneAll (FirstCmdKeyFile, &defaultKeyFilesParam.FirstKeyFile); } + SetLastError (ERROR_SUCCESS); if (!MountFavoriteVolumes (hwndDlg, FALSE, LogOn)) + { + if (GetLastError () == ERROR_CANCELLED) + autoMountCancelled = TRUE; + exitCode = 1; + } } - if (szFileName[0] != 0 && !TranslateVolumeID (hwndDlg, szFileName, ARRAYSIZE (szFileName))) + if (!autoMountCancelled && szFileName[0] != 0 && !TranslateVolumeID (hwndDlg, szFileName, ARRAYSIZE (szFileName))) { exitCode = 1; } - else if (szFileName[0] != 0 && !IsMountedVolume (szFileName)) + else if (!autoMountCancelled && szFileName[0] != 0 && !IsMountedVolume (szFileName)) { BOOL mounted = FALSE; int EffectiveVolumePkcs5 = CmdVolumePkcs5; @@ -7598,6 +7961,7 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa if (FirstCmdKeyFile) KeyFilesApply (hwndDlg, &CmdVolumePassword, FirstCmdKeyFile, szFileName); + SetLastError (ERROR_SUCCESS); mounted = MountVolume (hwndDlg, szDriveLetter[0] - L'A', szFileName, &CmdVolumePassword, EffectiveVolumePkcs5, CmdVolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, Silent, reportBadPasswd); @@ -7607,6 +7971,7 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa else { // Cached password + SetLastError (ERROR_SUCCESS); mounted = MountVolume (hwndDlg, szDriveLetter[0] - L'A', szFileName, NULL, EffectiveVolumePkcs5, CmdVolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, Silent, FALSE); } @@ -7640,6 +8005,7 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa if (KeyFilesEnable && FirstKeyFile) KeyFilesApply (hwndDlg, &VolumePassword, FirstKeyFile, szFileName); + SetLastError (ERROR_SUCCESS); mounted = MountVolume (hwndDlg, szDriveLetter[0] - L'A', szFileName, &VolumePassword, VolumePkcs5, VolumePim, bCacheInDriver, bIncludePimInCache, bForceMount, &mountOptions, FALSE, TRUE); burn (&VolumePassword, sizeof (VolumePassword)); @@ -7676,11 +8042,16 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa } } else + { + if (GetLastError () == ERROR_CANCELLED) + autoMountCancelled = TRUE; + exitCode = 1; + } } - else if (bExplore && GetMountedVolumeDriveNo (szFileName) != -1) + else if (!autoMountCancelled && bExplore && GetMountedVolumeDriveNo (szFileName) != -1) OpenVolumeExplorerWindow (GetMountedVolumeDriveNo (szFileName)); - else if (szFileName[0] != 0 && IsMountedVolume (szFileName)) + else if (!autoMountCancelled && szFileName[0] != 0 && IsMountedVolume (szFileName)) Warning ("VOL_ALREADY_MOUNTED", hwndDlg); if (!Quit) @@ -8061,51 +8432,13 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa for (FavoriteVolume& favorite: FavoritesOnArrivalMountRequired) { - if (favorite.UseVolumeID) + if (!FavoriteVolumeArrivalMountCandidate (favorite)) { - if (IsMountedVolumeID (favorite.VolumeID)) - continue; - - std::wstring volDevPath = FindDeviceByVolumeID (favorite.VolumeID, FALSE); - if (volDevPath.length() > 0) - { - favorite.Path = volDevPath; - favorite.DisconnectedDevice = false; - } - else - continue; - } - else if (!favorite.VolumePathId.empty()) - { - if (IsMountedVolume (favorite.Path.c_str())) - continue; - - wchar_t volDevPath[TC_MAX_PATH]; - if (QueryDosDevice (favorite.VolumePathId.substr (4, favorite.VolumePathId.size() - 5).c_str(), volDevPath, TC_MAX_PATH) == 0) - continue; - - favorite.DisconnectedDevice = false; - } - else if (favorite.Path.find (L"\\\\?\\Volume{") == 0) - { - wstring resolvedPath = VolumeGuidPathToDevicePath (favorite.Path); - if (resolvedPath.empty()) - continue; - - favorite.DisconnectedDevice = false; - favorite.VolumePathId = favorite.Path; - favorite.Path = resolvedPath; - } - - if (IsMountedVolume (favorite.Path.c_str())) + ResumeFavoriteVolumeArrivalMount (SuppressedFavoritesOnArrivalMount, favorite); continue; - - if (!IsVolumeDeviceHosted (favorite.Path.c_str())) - { - if (!FileExists (favorite.Path.c_str())) - continue; } - else if (favorite.VolumePathId.empty()) + + if (FavoriteVolumeArrivalMountSuppressed (SuppressedFavoritesOnArrivalMount, favorite)) continue; bool mountedAndNotDisconnected = false; @@ -8121,14 +8454,26 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa if (!mountedAndNotDisconnected) { BOOL mounted = FALSE; + MountResult mountResult = MountResultFailed; + MountBatchContext mountBatch; + MountBatchInitialize (&mountBatch); { FavoriteMountOnArrivalInProgress = TRUE; finally_do ({ FavoriteMountOnArrivalInProgress = FALSE; }); - mounted = MountFavoriteVolumes (hwndDlg, FALSE, FALSE, FALSE, favorite); + SetLastError (ERROR_SUCCESS); + mounted = MountFavoriteVolumesWithAbort (hwndDlg, FALSE, FALSE, FALSE, favorite, &mountBatch, &mountResult); } if (mounted) + { + ResumeFavoriteVolumeArrivalMount (SuppressedFavoritesOnArrivalMount, favorite); FavoritesMountedOnArrivalStillConnected.push_back (favorite); + } + else if (mountResult == MountResultCancelled || mountResult == MountResultArrivalPasswordPromptDeclined) + { + SuppressFavoriteVolumeArrivalMount (SuppressedFavoritesOnArrivalMount, favorite); + break; + } } } @@ -9323,8 +9668,13 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa { if (0 == _InterlockedCompareExchange(&FavoriteMountOnGoing, 1, 0)) { - if (_beginthread(mountFavoriteVolumeThreadFunction, 0, NULL) == (uintptr_t) -1L) + mountFavoriteVolumeThreadParam* pParam = AllocateMountFavoriteVolumeThreadParam (FALSE, FALSE, FALSE, NULL); + + if (!pParam || _beginthread(mountFavoriteVolumeThreadFunction, 0, pParam) == (uintptr_t) -1L) + { + FreeMountFavoriteVolumeThreadParam (pParam); _InterlockedExchange(&FavoriteMountOnGoing, 0); + } } return 1; } @@ -10877,9 +11227,9 @@ void DismountIdleVolumes () } } -static BOOL MountFavoriteVolumeBase (HWND hwnd, const FavoriteVolume &favorite, BOOL& lastbExplore, BOOL& userForcedReadOnly, BOOL systemFavorites, BOOL logOnMount, BOOL hotKeyMount, const FavoriteVolume &favoriteVolumeToMount) +static MountResult MountFavoriteVolumeBase (HWND hwnd, const FavoriteVolume &favorite, BOOL& lastbExplore, BOOL& userForcedReadOnly, BOOL systemFavorites, BOOL logOnMount, BOOL hotKeyMount, const FavoriteVolume &favoriteVolumeToMount, MountBatchContext* pMountBatch) { - BOOL status = TRUE; + MountResult result = MountResultSkipped; int drive; std::wstring effectiveVolumePath; drive = towupper (favorite.MountPoint[0]) - L'A'; @@ -10892,7 +11242,7 @@ static BOOL MountFavoriteVolumeBase (HWND hwnd, const FavoriteVolume &favorite, { SystemFavoritesServiceLogError (wstring (L"The drive letter ") + (wchar_t) (drive + L'A') + wstring (L" used by favorite \"") + favorite.Path + L"\" is invalid.\nThis system favorite will not be mounted"); } - return FALSE; + return MountResultFailed; } mountOptions.ReadOnly = favorite.ReadOnly || userForcedReadOnly; @@ -10958,7 +11308,7 @@ static BOOL MountFavoriteVolumeBase (HWND hwnd, const FavoriteVolume &favorite, mountOptions.ProtectedHidVolPim = CmdVolumePim; if (Silent || (SecureDesktopDialogBoxParam (hInst, MAKEINTRESOURCEW (IDD_MOUNT_OPTIONS), hwnd, (DLGPROC) MountOptionsDlgProc, (LPARAM) &mountOptions) == IDCANCEL)) { - status = FALSE; + result = MountResultFailed; goto skipMount; } } @@ -10968,7 +11318,7 @@ static BOOL MountFavoriteVolumeBase (HWND hwnd, const FavoriteVolume &favorite, if (ServiceMode) SystemFavoritesServiceLogInfo (wstring (L"Mounting system favorite \"") + effectiveVolumePath + L"\""); - status = Mount (hwnd, drive, (wchar_t *) effectiveVolumePath.c_str(), favorite.Pim, favorite.Pkcs5); + result = Mount (hwnd, drive, (wchar_t *) effectiveVolumePath.c_str(), favorite.Pim, favorite.Pkcs5, pMountBatch); if (ServiceMode) { @@ -10976,7 +11326,7 @@ static BOOL MountFavoriteVolumeBase (HWND hwnd, const FavoriteVolume &favorite, SystemFavoritesServiceStatus.dwCheckPoint++; SystemFavoritesServiceSetStatus (SERVICE_START_PENDING, 120000); - if (status) + if (result == MountResultSucceeded) { SystemFavoritesServiceLogInfo (wstring (L"Favorite \"") + effectiveVolumePath + wstring (L"\" mounted successfully as ") + (wchar_t) (drive + L'A') + L":"); } @@ -10986,7 +11336,7 @@ static BOOL MountFavoriteVolumeBase (HWND hwnd, const FavoriteVolume &favorite, } } - if (status && mountOptions.ReadOnly != prevReadOnly) + if (result == MountResultSucceeded && mountOptions.ReadOnly != prevReadOnly) userForcedReadOnly = mountOptions.ReadOnly; skipMount: @@ -10994,7 +11344,7 @@ skipMount: if (systemFavorites && prevVolumeAtMountPoint[0]) { - if (status) + if (result == MountResultSucceeded) { int freeDrive = GetFirstAvailableDrive(); if (freeDrive != -1) @@ -11020,19 +11370,71 @@ skipMount: } } else if (!systemFavorites && !favoriteVolumeToMount.Path.empty()) + { Error ("DRIVE_LETTER_UNAVAILABLE", MainDlg); + result = MountResultDriveLetterUnavailable; + } else if (ServiceMode && systemFavorites) { SystemFavoritesServiceLogError (wstring (L"The drive letter ") + (wchar_t) (drive + L'A') + wstring (L" used by favorite \"") + effectiveVolumePath + L"\" is already taken.\nThis system favorite will not be mounted"); } - return status; + if (result == MountResultCancelled) + SetLastError (ERROR_CANCELLED); + + return result; } -BOOL MountFavoriteVolumes (HWND hwnd, BOOL systemFavorites, BOOL logOnMount, BOOL hotKeyMount, const FavoriteVolume &favoriteVolumeToMount) +/* Applies a single favorite's mount result to the running batch state. Updates *pbRet + (overall success), *pbMountedAny (whether any volume mounted, for token-session cleanup) + and *pBatchResult (the reason a batch stopped). Returns FALSE if the batch must stop + after this favorite. All out-pointers must be valid. */ +static BOOL HandleFavoriteMountResult (MountResult mountResult, MountBatchContext* pMountBatch, BOOL* pbRet, BOOL* pbMountedAny, MountResult* pBatchResult) { - BOOL bRet = TRUE, status = TRUE; + switch (mountResult) + { + case MountResultSucceeded: + *pbMountedAny = TRUE; + return TRUE; + + case MountResultFailed: + *pbRet = FALSE; + return TRUE; + + case MountResultCancelled: + /* Wait-dialog/driver abort: stop the whole batch. */ + MountBatchRequestAbort (pMountBatch); + *pBatchResult = mountResult; + *pbRet = FALSE; + return FALSE; + + case MountResultArrivalPasswordPromptDeclined: + /* Arrival password-prompt cancel suppresses this favorite without aborting the batch. */ + *pBatchResult = mountResult; + *pbRet = FALSE; + return FALSE; + + case MountResultDriveLetterUnavailable: + /* The favorite's drive letter is taken by another volume. Treat this as a non-fatal + skip (it does not flip overall success to failure): the favorite-on-arrival scan + relies on this so it parks the favorite instead of re-prompting and re-showing the + error on every timer tick. */ + return TRUE; + + case MountResultSkipped: + default: + return TRUE; + } +} + + +static BOOL MountFavoriteVolumesWithAbort (HWND hwnd, BOOL systemFavorites, BOOL logOnMount, BOOL hotKeyMount, const FavoriteVolume &favoriteVolumeToMount, MountBatchContext* pMountBatch, MountResult* pBatchResult) +{ + BOOL bRet = TRUE; + BOOL bMountedAny = FALSE; + MountResult mountResult = MountResultSkipped; + MountResult batchResult = MountResultSucceeded; BOOL lastbExplore; BOOL userForcedReadOnly = FALSE; @@ -11090,7 +11492,8 @@ BOOL MountFavoriteVolumes (HWND hwnd, BOOL systemFavorites, BOOL logOnMount, BOO { if (ServiceMode) SystemFavoritesServiceLogError (wstring (L"An error occured while reading System Favorites XML file")); - return false; + bRet = FALSE; + goto ret; } } else if (!favoriteVolumeToMount.Path.empty()) @@ -11100,6 +11503,13 @@ BOOL MountFavoriteVolumes (HWND hwnd, BOOL systemFavorites, BOOL logOnMount, BOO for (const FavoriteVolume& favorite: favorites) { + if (MountBatchAbortRequested (pMountBatch)) + { + batchResult = MountResultCancelled; + bRet = FALSE; + goto ret; + } + if (ServiceMode && systemFavorites && favorite.DisconnectedDevice) { skippedSystemFavorites.push_back (favorite); @@ -11116,9 +11526,10 @@ BOOL MountFavoriteVolumes (HWND hwnd, BOOL systemFavorites, BOOL logOnMount, BOO continue; } - status = MountFavoriteVolumeBase (hwnd, favorite, lastbExplore, userForcedReadOnly, systemFavorites, logOnMount, hotKeyMount, favoriteVolumeToMount); - if (!status) - bRet = FALSE; + SetLastError (ERROR_SUCCESS); + mountResult = MountFavoriteVolumeBase (hwnd, favorite, lastbExplore, userForcedReadOnly, systemFavorites, logOnMount, hotKeyMount, favoriteVolumeToMount, pMountBatch); + if (!HandleFavoriteMountResult (mountResult, pMountBatch, &bRet, &bMountedAny, &batchResult)) + goto ret; } if (systemFavorites && ServiceMode && !skippedSystemFavorites.empty()) @@ -11129,8 +11540,22 @@ BOOL MountFavoriteVolumes (HWND hwnd, BOOL systemFavorites, BOOL logOnMount, BOO size_t remainingFavorites = skippedSystemFavorites.size(); while ((remainingFavorites > 0) && (retryCounter++ < 4)) { + if (MountBatchAbortRequested (pMountBatch)) + { + batchResult = MountResultCancelled; + bRet = FALSE; + goto ret; + } + Sleep (5000); + if (MountBatchAbortRequested (pMountBatch)) + { + batchResult = MountResultCancelled; + bRet = FALSE; + goto ret; + } + SystemFavoritesServiceLogInfo (wstring (L"Trying to mount skipped system favorites")); // Update the service status to avoid being killed @@ -11140,6 +11565,13 @@ BOOL MountFavoriteVolumes (HWND hwnd, BOOL systemFavorites, BOOL logOnMount, BOO for (vector ::iterator favorite = skippedSystemFavorites.begin(); favorite != skippedSystemFavorites.end(); favorite++) { + if (MountBatchAbortRequested (pMountBatch)) + { + batchResult = MountResultCancelled; + bRet = FALSE; + goto ret; + } + if (favorite->DisconnectedDevice) { // check if the favorite is here and get its path @@ -11164,9 +11596,10 @@ BOOL MountFavoriteVolumes (HWND hwnd, BOOL systemFavorites, BOOL logOnMount, BOO else SystemFavoritesServiceLogInfo (wstring (L"Favorite \"") + favorite->VolumePathId + L"\" is connected. Performing mount."); - status = MountFavoriteVolumeBase (hwnd, *favorite, lastbExplore, userForcedReadOnly, systemFavorites, logOnMount, hotKeyMount, favoriteVolumeToMount); - if (!status) - bRet = FALSE; + SetLastError (ERROR_SUCCESS); + mountResult = MountFavoriteVolumeBase (hwnd, *favorite, lastbExplore, userForcedReadOnly, systemFavorites, logOnMount, hotKeyMount, favoriteVolumeToMount, pMountBatch); + if (!HandleFavoriteMountResult (mountResult, pMountBatch, &bRet, &bMountedAny, &batchResult)) + goto ret; } } } @@ -11182,39 +11615,64 @@ BOOL MountFavoriteVolumes (HWND hwnd, BOOL systemFavorites, BOOL logOnMount, BOO } } +ret: + if (MountBatchAbortRequested (pMountBatch)) + { + batchResult = MountResultCancelled; + bRet = FALSE; + } + MultipleMountOperationInProgress = FALSE; burn (&VolumePassword, sizeof (VolumePassword)); burn (&VolumePkcs5, sizeof (VolumePkcs5)); burn (&VolumePim, sizeof (VolumePim)); - if (bRet && CloseSecurityTokenSessionsAfterMount) + if ((bRet || ((batchResult == MountResultCancelled || batchResult == MountResultArrivalPasswordPromptDeclined) && bMountedAny)) && CloseSecurityTokenSessionsAfterMount) SecurityToken::CloseAllSessions(); // TODO Use Token + if (batchResult == MountResultCancelled) + SetLastError (ERROR_CANCELLED); + + if (pBatchResult) + *pBatchResult = batchResult; + return bRet; } -void CALLBACK mountFavoriteVolumeCallbackFunction (void *pArg, HWND hwnd) +BOOL MountFavoriteVolumes (HWND hwnd, BOOL systemFavorites, BOOL logOnMount, BOOL hotKeyMount, const FavoriteVolume &favoriteVolumeToMount) +{ + MountBatchContext mountBatch; + MountBatchInitialize (&mountBatch); + + return MountFavoriteVolumesWithAbort (hwnd, systemFavorites, logOnMount, hotKeyMount, favoriteVolumeToMount, &mountBatch, NULL); +} + +static void CALLBACK mountFavoriteVolumeCallbackFunction (void *pArg, HWND hwnd) { mountFavoriteVolumeThreadParam* pParam = (mountFavoriteVolumeThreadParam*) pArg; - if (pParam) - { - finally_do_arg (mountFavoriteVolumeThreadParam*, pParam, { FreeMountFavoriteVolumeThreadParam (finally_arg); }); + // pArg is always the thread parameter allocated by the caller before _beginthread. + if (!pParam) + return; - if (pParam->favoriteVolumeToMount) - MountFavoriteVolumes (hwnd, pParam->systemFavorites, pParam->logOnMount, pParam->hotKeyMount, *(pParam->favoriteVolumeToMount)); - else - MountFavoriteVolumes (hwnd, pParam->systemFavorites, pParam->logOnMount, pParam->hotKeyMount); - } - else - MountFavoriteVolumes (hwnd); + const FavoriteVolume& favoriteVolumeToMount = pParam->favoriteVolumeToMount ? *(pParam->favoriteVolumeToMount) : FavoriteVolume(); + MountFavoriteVolumesWithAbort (hwnd, pParam->systemFavorites, pParam->logOnMount, pParam->hotKeyMount, favoriteVolumeToMount, &pParam->mountBatch, NULL); } -void __cdecl mountFavoriteVolumeThreadFunction (void *pArg) +BOOL CALLBACK mountFavoriteVolumeCancelProc(void* pArg, HWND ) +{ + mountFavoriteVolumeThreadParam* threadParam = (mountFavoriteVolumeThreadParam*) pArg; + + return MountBatchCancel (threadParam ? &threadParam->mountBatch : NULL); +} + +static void __cdecl mountFavoriteVolumeThreadFunction (void *pArg) { ScreenCaptureBlocker screenCaptureBlocker; + mountFavoriteVolumeThreadParam* pParam = (mountFavoriteVolumeThreadParam*) pArg; finally_do ({ _InterlockedExchange(&FavoriteMountOnGoing, 0); }); - ShowWaitDialog (MainDlg, FALSE, mountFavoriteVolumeCallbackFunction, pArg); + finally_do_arg (mountFavoriteVolumeThreadParam*, pParam, { FreeMountFavoriteVolumeThreadParam (finally_arg); }); + ShowWaitDialogEx (MainDlg, FALSE, mountFavoriteVolumeCallbackFunction, mountFavoriteVolumeCancelProc, pParam); } static void SaveDefaultKeyFilesParam (HWND hwnd) diff --git a/src/Mount/Mount.h b/src/Mount/Mount.h index 91bdded1..a2fa2056 100644 --- a/src/Mount/Mount.h +++ b/src/Mount/Mount.h @@ -116,18 +116,9 @@ static BOOL CALLBACK DefaultMountParametersDlgProc (HWND hwndDlg, UINT msg, WPAR #ifdef __cplusplus } -typedef struct -{ - BOOL systemFavorites; - BOOL logOnMount; - BOOL hotKeyMount; - /* Owned by the thread parameter when non-NULL. */ - VeraCrypt::FavoriteVolume* favoriteVolumeToMount; -} mountFavoriteVolumeThreadParam; - void SetDriverConfigurationFlag (uint32 flag, BOOL state); BOOL MountFavoriteVolumes (HWND hwnd, BOOL systemFavorites = FALSE, BOOL logOnMount = FALSE, BOOL hotKeyMount = FALSE, const VeraCrypt::FavoriteVolume &favoriteVolumeToMount = VeraCrypt::FavoriteVolume()); -void __cdecl mountFavoriteVolumeThreadFunction (void *pArg); +void ClearFavoriteVolumeArrivalMountSuppressions (); // A class that represents a device based on its device ID class CDevice