VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Mount
diff options
context:
space:
mode:
authorMounir IDRASSI <mounir.idrassi@idrix.fr>2015-05-17 10:14:58 (GMT)
committerMounir IDRASSI <mounir.idrassi@idrix.fr>2015-05-17 10:16:16 (GMT)
commitf72125ea71f98d0147bb742b48d1097844949c9e (patch)
tree836b63959937bb846553f7f851be9e5e405c1ea0 /src/Mount
parent4695920b41e969bed138bfe2fe0d877b2abb36f6 (diff)
downloadVeraCrypt-f72125ea71f98d0147bb742b48d1097844949c9e.zip
VeraCrypt-f72125ea71f98d0147bb742b48d1097844949c9e.tar.gz
Windows: First implementation of non-system volumes decryption.
Diffstat (limited to 'src/Mount')
-rw-r--r--src/Mount/Mount.c376
-rw-r--r--src/Mount/Mount.h2
-rw-r--r--src/Mount/Mount.rc1
-rw-r--r--src/Mount/Resource.h3
4 files changed, 365 insertions, 17 deletions
diff --git a/src/Mount/Mount.c b/src/Mount/Mount.c
index 716f792..1288f8d 100644
--- a/src/Mount/Mount.c
+++ b/src/Mount/Mount.c
@@ -454,6 +454,184 @@ BOOL ActiveSysEncDeviceSelected (void)
return FALSE;
}
+// When a function does not require the affected volume to be dismounted, there may be cases where we have two valid
+// paths selected in the main window and we cannot be sure which of them the user really intends to apply the function to.
+// This function asks the user to explicitly select either the volume path specified in the input field below the main
+// drive list (whether mounted or not), or the path to the volume selected in the main drive list. If, however, both
+// of the GUI elements contain the same volume (or one of them does not contain any path), this function does not
+// ask the user and returns the volume path directly (no selection ambiguity).
+// If driveNoPtr is not NULL, and the volume is mounted, its drive letter is returned in *driveNoPtr (if no valid drive
+// letter is resolved, -1 is stored instead).
+static string ResolveAmbiguousSelection (HWND hwndDlg, int *driveNoPtr)
+{
+ LPARAM selectedDrive = GetSelectedLong (GetDlgItem (MainDlg, IDC_DRIVELIST));
+
+ char volPathInputField [TC_MAX_PATH];
+ wchar_t volPathInputFieldW [TC_MAX_PATH];
+
+ wchar_t volPathDriveListW [TC_MAX_PATH];
+ string volPathDriveListStr;
+ wstring volPathDriveListWStr;
+
+ string retPath;
+
+ VOLUME_PROPERTIES_STRUCT prop;
+ DWORD dwResult;
+
+ BOOL useInputField = TRUE;
+
+ memset (&prop, 0, sizeof(prop));
+
+ BOOL ambig = (LOWORD (selectedDrive) != TC_MLIST_ITEM_FREE && LOWORD (selectedDrive) != 0xffff && HIWORD (selectedDrive) != 0xffff
+ && VolumeSelected (MainDlg));
+
+ if (VolumeSelected (MainDlg))
+ {
+ // volPathInputField will contain the volume path (if any) from the input field below the drive list
+ GetWindowText (GetDlgItem (MainDlg, IDC_VOLUME), volPathInputField, sizeof (volPathInputField));
+
+ if (!ambig)
+ retPath = (string) volPathInputField;
+ }
+
+ if (LOWORD (selectedDrive) != TC_MLIST_ITEM_FREE && LOWORD (selectedDrive) != 0xffff && HIWORD (selectedDrive) != 0xffff)
+ {
+ // A volume is selected in the main drive list.
+
+ switch (LOWORD (selectedDrive))
+ {
+ case TC_MLIST_ITEM_NONSYS_VOL:
+ prop.driveNo = HIWORD (selectedDrive) - 'A';
+
+ if (!DeviceIoControl (hDriver, TC_IOCTL_GET_VOLUME_PROPERTIES, &prop, sizeof (prop), &prop, sizeof (prop), &dwResult, NULL) || dwResult == 0)
+ {
+ // The driver did not return any path for this drive letter (the volume may have been dismounted).
+
+ // Return whatever is in the input field below the drive list (even if empty)
+ return ((string) volPathInputField);
+ }
+
+ // volPathDriveListWStr will contain the volume path selected in the main drive list
+ volPathDriveListWStr = (wstring) prop.wszVolume;
+ volPathDriveListStr = WideToSingleString (volPathDriveListWStr);
+ break;
+
+ case TC_MLIST_ITEM_SYS_PARTITION:
+
+ GetSysDevicePaths (MainDlg);
+
+ if (bCachedSysDevicePathsValid)
+ {
+ volPathDriveListStr = (string) SysPartitionDevicePath;
+ volPathDriveListWStr = SingleStringToWide (volPathDriveListStr);
+ }
+
+ break;
+
+ case TC_MLIST_ITEM_SYS_DRIVE:
+
+ GetSysDevicePaths (MainDlg);
+
+ if (bCachedSysDevicePathsValid)
+ {
+ volPathDriveListStr = (string) SysDriveDevicePath;
+ volPathDriveListWStr = SingleStringToWide (volPathDriveListStr);
+ }
+
+ break;
+ }
+
+ if (!ambig)
+ {
+ useInputField = FALSE;
+ retPath = volPathDriveListStr;
+ }
+ }
+
+ if (ambig)
+ {
+ /* We have two paths. Compare them and if they don't match, ask the user to select one of them. Otherwise, return the path without asking. */
+
+ if (memcmp (volPathDriveListStr.c_str (), "\\??\\", 4) == 0)
+ {
+ // The volume path starts with "\\??\\" which is used for file-hosted containers. We're going to strip this prefix.
+
+ volPathDriveListStr = (string) (volPathDriveListStr.c_str () + 4);
+ volPathDriveListWStr = SingleStringToWide (volPathDriveListStr);
+ }
+
+ StringCbCopyW (volPathDriveListW, sizeof(volPathDriveListW), SingleStringToWide (volPathDriveListStr).c_str ());
+
+ ToSBCS (volPathDriveListW, sizeof(volPathDriveListW));
+ StringCbCopyA ((char *) volPathInputFieldW, sizeof(volPathInputFieldW), volPathInputField);
+ ToUNICODE ((char *) volPathInputFieldW, sizeof(volPathInputFieldW));
+
+ if (strcmp (((memcmp ((char *) volPathDriveListW, "\\??\\", 4) == 0) ? (char *) volPathDriveListW + 4 : (char *) volPathDriveListW), volPathInputField) != 0)
+ {
+ // The path selected in the input field is different from the path to the volume selected
+ // in the drive lettter list. We have to resolve possible ambiguity.
+
+ wchar_t *tmp[] = {L"", L"", L"", L"", L"", 0};
+ const int maxVolPathLen = 80;
+
+ if (volPathDriveListWStr.length () > maxVolPathLen)
+ {
+ // Ellipsis (path too long)
+ volPathDriveListWStr = wstring (L"...") + volPathDriveListWStr.substr (volPathDriveListWStr.length () - maxVolPathLen, maxVolPathLen);
+ }
+
+ wstring volPathInputFieldWStr (volPathInputFieldW);
+
+ if (volPathInputFieldWStr.length () > maxVolPathLen)
+ {
+ // Ellipsis (path too long)
+ volPathInputFieldWStr = wstring (L"...") + volPathInputFieldWStr.substr (volPathInputFieldWStr.length () - maxVolPathLen, maxVolPathLen);
+ }
+
+ tmp[1] = GetString ("AMBIGUOUS_VOL_SELECTION");
+ tmp[2] = (wchar_t *) volPathDriveListWStr.c_str();
+ tmp[3] = (wchar_t *) volPathInputFieldWStr.c_str();
+ tmp[4] = GetString ("IDCANCEL");
+
+ switch (AskMultiChoice ((void **) tmp, FALSE, hwndDlg))
+ {
+ case 1:
+ retPath = volPathDriveListStr;
+ break;
+
+ case 2:
+ retPath = (string) volPathInputField;
+ break;
+
+ default:
+ if (driveNoPtr != NULL)
+ *driveNoPtr = -1;
+
+ return string ("");
+ }
+ }
+ else
+ {
+ // Both selected paths are the same
+ retPath = (string) volPathInputField;
+ }
+ }
+
+ if (driveNoPtr != NULL)
+ *driveNoPtr = GetMountedVolumeDriveNo ((char *) retPath.c_str ());
+
+
+ if (memcmp (retPath.c_str (), "\\??\\", 4) == 0)
+ {
+ // The selected volume path starts with "\\??\\" which is used for file-hosted containers. We're going to strip this prefix.
+
+ retPath = (string) (retPath.c_str () + 4);
+ }
+
+ return retPath;
+}
+
+
void LoadSettings (HWND hwndDlg)
{
EnableHwEncryption ((ReadDriverConfigurationFlags() & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION) ? FALSE : TRUE);
@@ -730,7 +908,7 @@ static BOOL SysEncDeviceActive (BOOL bSilent)
return (BootEncStatus.DriveMounted);
}
-// Returns TRUE if the entire system drive (as opposed to the system partition only) is (or is to be) encrypted
+// Returns TRUE if the entire system drive (as opposed to the system partition only) of the currently running OS is (or is to be) encrypted
BOOL WholeSysDriveEncryption (BOOL bSilent)
{
try
@@ -956,18 +1134,16 @@ BOOL CheckSysEncMountWithoutPBA (HWND hwndDlg, const char *devicePath, BOOL quie
// Returns TRUE if the host drive of the specified partition contains a portion of the TrueCrypt Boot Loader
// and if the drive is not within key scope of active system encryption (e.g. the system drive of the running OS).
// If bPrebootPasswordDlgMode is TRUE, this function returns FALSE (because the check would be redundant).
-BOOL TCBootLoaderOnInactiveSysEncDrive (void)
+BOOL TCBootLoaderOnInactiveSysEncDrive (char *szDevicePath)
{
try
{
int driveNo;
- char szDevicePath [TC_MAX_PATH+1];
char parentDrivePath [TC_MAX_PATH+1];
if (bPrebootPasswordDlgMode)
return FALSE;
- GetWindowText (GetDlgItem (MainDlg, IDC_VOLUME), szDevicePath, sizeof (szDevicePath));
if (sscanf (szDevicePath, "\\Device\\Harddisk%d\\Partition", &driveNo) != 1)
return FALSE;
@@ -1037,7 +1213,7 @@ BOOL SelectItem (HWND hTree, char nLetter)
static void LaunchVolCreationWizard (HWND hwndDlg, const char *arg)
{
- char t[TC_MAX_PATH] = {'"',0};
+ char t[TC_MAX_PATH + 1024] = {'"',0};
char *tmp;
GetModuleFileName (NULL, t+1, sizeof(t)-1);
@@ -3671,7 +3847,9 @@ LPARAM GetSelectedLong (HWND hTree)
item.mask = LVIF_PARAM;
item.iItem = hItem;
- if (ListView_GetItem (hTree, &item) == FALSE)
+ if ( (ListView_GetItemCount (hTree) < 1)
+ || (ListView_GetItem (hTree, &item) == FALSE)
+ )
return MAKELONG (0xffff, 0xffff);
else
return item.lParam;
@@ -4490,7 +4668,7 @@ static void EncryptSystemDevice (HWND hwndDlg)
if (!MutexExistsOnSystem (TC_MUTEX_NAME_SYSENC)) // If no instance of the wizard is currently taking care of system encryption
{
- LaunchVolCreationWizard (MainDlg, "/sysenc");
+ LaunchVolCreationWizard (hwndDlg, "/sysenc");
}
else
Warning ("SYSTEM_ENCRYPTION_IN_PROGRESS_ELSEWHERE", hwndDlg);
@@ -4504,7 +4682,7 @@ static void EncryptSystemDevice (HWND hwndDlg)
if (!MutexExistsOnSystem (TC_MUTEX_NAME_SYSENC)) // If no instance of the wizard is currently taking care of system encryption
{
- LaunchVolCreationWizard (MainDlg, "/sysenc");
+ LaunchVolCreationWizard (hwndDlg, "/sysenc");
}
else
Warning ("SYSTEM_ENCRYPTION_IN_PROGRESS_ELSEWHERE", hwndDlg);
@@ -4584,7 +4762,7 @@ static void DecryptSystemDevice (HWND hwndDlg)
}
CloseSysEncMutex ();
- LaunchVolCreationWizard (MainDlg, "/dsysenc");
+ LaunchVolCreationWizard (hwndDlg, "/dsysenc");
}
else
Warning ("SYSTEM_ENCRYPTION_IN_PROGRESS_ELSEWHERE", hwndDlg);
@@ -4599,7 +4777,118 @@ static void CreateHiddenOS (HWND hwndDlg)
// such information, but will exit (displaying only an error meessage).
Info("HIDDEN_OS_PREINFO", hwndDlg);
- LaunchVolCreationWizard (MainDlg, "/isysenc");
+ LaunchVolCreationWizard (hwndDlg, "/isysenc");
+}
+
+static void DecryptNonSysDevice (HWND hwndDlg, BOOL bResolveAmbiguousSelection, BOOL bUseDriveListSel)
+{
+ string scPath;
+
+ if (bResolveAmbiguousSelection)
+ {
+ scPath = ResolveAmbiguousSelection (hwndDlg, NULL);
+
+ if (scPath.empty ())
+ {
+ // The user selected Cancel
+ return;
+ }
+ }
+ else if (bUseDriveListSel)
+ {
+ // Decrypt mounted volume selected in the main drive list
+
+ LPARAM lLetter = GetSelectedLong (GetDlgItem (MainDlg, IDC_DRIVELIST));
+
+ if (LOWORD (lLetter) != 0xffff)
+ {
+ VOLUME_PROPERTIES_STRUCT prop;
+ DWORD bytesReturned;
+
+ memset (&prop, 0, sizeof (prop));
+ prop.driveNo = (char) HIWORD (lLetter) - 'A';
+
+ if (!DeviceIoControl (hDriver, TC_IOCTL_GET_VOLUME_PROPERTIES, &prop, sizeof (prop), &prop, sizeof (prop), &bytesReturned, NULL))
+ {
+ handleWin32Error (MainDlg);
+ return;
+ }
+
+ scPath = WideToSingleString ((wchar_t *) prop.wszVolume);
+ }
+ else
+ return;
+ }
+ else
+ {
+ // Decrypt volume specified in the input field below the main drive list
+
+ char volPath [TC_MAX_PATH];
+
+ GetWindowText (GetDlgItem (MainDlg, IDC_VOLUME), volPath, sizeof (volPath));
+
+ scPath = volPath;
+ }
+
+ if (scPath.empty ())
+ {
+ Warning ("NO_VOLUME_SELECTED", hwndDlg);
+ return;
+ }
+
+ WaitCursor();
+
+ switch (IsSystemDevicePath ((char *) scPath.c_str (), MainDlg, TRUE))
+ {
+ case 1:
+ case 2:
+ // The user wants to decrypt the system partition/drive. Divert to the appropriate function.
+
+ NormalCursor ();
+
+ DecryptSystemDevice (hwndDlg);
+ return;
+ }
+
+ WaitCursor();
+
+ // Make sure the user is not attempting to decrypt a partition on an entirely encrypted system drive.
+ if (IsNonSysPartitionOnSysDrive (scPath.c_str ()) == 1)
+ {
+ if (WholeSysDriveEncryption (TRUE))
+ {
+ // The system drive is entirely encrypted and the encrypted OS is running
+
+ NormalCursor ();
+
+ Warning ("CANT_DECRYPT_PARTITION_ON_ENTIRELY_ENCRYPTED_SYS_DRIVE", hwndDlg);
+ return;
+ }
+ }
+ else if (TCBootLoaderOnInactiveSysEncDrive ((char *) scPath.c_str ()))
+ {
+ // The system drive MAY be entirely encrypted (external access without PBA) and the potentially encrypted OS is not running
+
+ NormalCursor ();
+
+ Warning ("CANT_DECRYPT_PARTITION_ON_ENTIRELY_ENCRYPTED_SYS_DRIVE_UNSURE", hwndDlg);
+
+ // We allow the user to continue as we don't know if the drive is really an encrypted system drive.
+ // If it is, the user has been warned and he will not be able to start decrypting, because the
+ // format wizard will not enable (nor will it allow the user to enable) the mount option for
+ // external without-PBA access (the user will receive the 'Incorrect password' error message).
+ }
+
+ NormalCursor ();
+
+
+ if (AskNoYesString ((wstring (GetString ("CONFIRM_DECRYPT_NON_SYS_DEVICE")) + L"\n\n" + SingleStringToWide (scPath)).c_str(), hwndDlg) == IDNO)
+ return;
+
+ if (AskWarnNoYes ("CONFIRM_DECRYPT_NON_SYS_DEVICE_CAUTION", hwndDlg) == IDNO)
+ return;
+
+ LaunchVolCreationWizard (hwndDlg, (string ("/inplacedec \"") + scPath + "\"").c_str ());
}
// Blindly attempts (without any checks) to instruct the wizard to resume whatever system encryption process
@@ -4802,12 +5091,12 @@ static void ShowSystemEncryptionStatus (HWND hwndDlg)
}
-static void ResumeInterruptedNonSysInplaceEncProcess (void)
+static void ResumeInterruptedNonSysInplaceEncProcess (BOOL bDecrypt)
{
// IMPORTANT: This function must not check any config files! Otherwise, if a config file was lost or corrupt,
// the user would not be able resume encryption and the data on the volume would be inaccessible.
- LaunchVolCreationWizard (MainDlg, "/zinplace");
+ LaunchVolCreationWizard (MainDlg, bDecrypt? "/resumeinplacedec" : "/zinplace");
}
BOOL SelectContainer (HWND hwndDlg)
@@ -5435,8 +5724,9 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa
if (bInPlaceEncNonSysPending && !NonSysInplaceEncInProgressElsewhere())
{
- if (AskNonSysInPlaceEncryptionResume(hwndDlg) == IDYES)
- ResumeInterruptedNonSysInplaceEncProcess ();
+ BOOL bDecrypt = FALSE;
+ if (AskNonSysInPlaceEncryptionResume(hwndDlg, &bDecrypt) == IDYES)
+ ResumeInterruptedNonSysInplaceEncProcess (bDecrypt);
}
}
@@ -6101,6 +6391,8 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa
AppendMenuW (popup, MF_STRING, IDPM_ADD_TO_FAVORITES, GetString ("IDPM_ADD_TO_FAVORITES"));
AppendMenuW (popup, MF_STRING, IDPM_ADD_TO_SYSTEM_FAVORITES, GetString ("IDPM_ADD_TO_SYSTEM_FAVORITES"));
AppendMenu (popup, MF_SEPARATOR, 0, "");
+ AppendMenuW (popup, MF_STRING, IDM_DECRYPT_NONSYS_VOL, GetString ("IDM_DECRYPT_NONSYS_VOL"));
+ AppendMenu (popup, MF_SEPARATOR, 0, "");
AppendMenuW (popup, MF_STRING, IDM_VOLUME_PROPERTIES, GetString ("IDPM_PROPERTIES"));
break;
@@ -6152,6 +6444,11 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa
Dismount (hwndDlg, -2);
break;
+ case IDM_DECRYPT_NONSYS_VOL:
+ if (CheckMountList (hwndDlg, FALSE))
+ DecryptNonSysDevice (hwndDlg, FALSE, TRUE);
+ break;
+
case IDPM_OPEN_VOLUME:
{
int state = GetItemLong(GetDlgItem (hwndDlg, IDC_DRIVELIST), ((LPNMITEMACTIVATE)lParam)->iItem );
@@ -6351,6 +6648,8 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa
AppendMenuW (popup, MF_STRING, IDM_ADD_REMOVE_VOL_KEYFILES, GetString ("IDM_ADD_REMOVE_VOL_KEYFILES"));
AppendMenuW (popup, MF_STRING, IDM_REMOVE_ALL_KEYFILES_FROM_VOL, GetString ("IDM_REMOVE_ALL_KEYFILES_FROM_VOL"));
AppendMenu (popup, MF_SEPARATOR, 0, "");
+ AppendMenuW (popup, MF_STRING, IDM_DECRYPT_NONSYS_VOL, GetString ("IDM_DECRYPT_NONSYS_VOL"));
+ AppendMenu (popup, MF_SEPARATOR, 0, NULL);
AppendMenuW (popup, MF_STRING, IDM_BACKUP_VOL_HEADER, GetString ("IDM_BACKUP_VOL_HEADER"));
AppendMenuW (popup, MF_STRING, IDM_RESTORE_VOL_HEADER, GetString ("IDM_RESTORE_VOL_HEADER"));
}
@@ -6369,6 +6668,17 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa
switch (menuItem)
{
+ case IDM_DECRYPT_NONSYS_VOL:
+ if (!VolumeSelected(hwndDlg))
+ {
+ Warning ("NO_VOLUME_SELECTED", hwndDlg);
+ }
+ else
+ {
+ DecryptNonSysDevice (hwndDlg, TRUE, FALSE);
+ }
+ break;
+
case IDM_CHANGE_PASSWORD:
if (!VolumeSelected(hwndDlg))
{
@@ -6469,6 +6779,22 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa
return 1;
}
+ if (lw == IDM_DECRYPT_NONSYS_VOL)
+ {
+ LPARAM selectedDrive = GetSelectedLong (GetDlgItem (hwndDlg, IDC_DRIVELIST));
+
+ if (LOWORD (selectedDrive) == TC_MLIST_ITEM_FREE && !VolumeSelected (MainDlg))
+ {
+ Warning ("NO_VOLUME_SELECTED", hwndDlg);
+ }
+ else
+ {
+ DecryptNonSysDevice (hwndDlg, TRUE, FALSE);
+ }
+
+ return 1;
+ }
+
if (lw == IDM_CHANGE_PASSWORD)
{
if (!VolumeSelected(hwndDlg))
@@ -6963,7 +7289,27 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa
if (lw == IDM_RESUME_INTERRUPTED_PROC)
{
- ResumeInterruptedNonSysInplaceEncProcess ();
+ // Ask the user to select encryption, decryption, or cancel
+ BOOL bDecrypt = FALSE;
+ char *tmpStr[] = {0,
+ "CHOOSE_ENCRYPT_OR_DECRYPT",
+ "ENCRYPT",
+ "DECRYPT",
+ "IDCANCEL",
+ 0};
+
+ switch (AskMultiChoice ((void **) tmpStr, FALSE, hwndDlg))
+ {
+ case 1:
+ bDecrypt = FALSE;
+ break;
+ case 2:
+ bDecrypt = TRUE;
+ break;
+ default:
+ return 1;
+ }
+ ResumeInterruptedNonSysInplaceEncProcess (bDecrypt);
return 1;
}
diff --git a/src/Mount/Mount.h b/src/Mount/Mount.h
index 6c3cf01..be5585b 100644
--- a/src/Mount/Mount.h
+++ b/src/Mount/Mount.h
@@ -98,7 +98,7 @@ void ChangeMainWindowVisibility ();
void LaunchVolCreationWizard (HWND hwndDlg);
BOOL WholeSysDriveEncryption (BOOL bSilent);
BOOL CheckSysEncMountWithoutPBA (HWND hwndDlg, const char *devicePath, BOOL quiet);
-BOOL TCBootLoaderOnInactiveSysEncDrive (void);
+BOOL TCBootLoaderOnInactiveSysEncDrive (char *szDevicePath);
void CreateRescueDisk (HWND hwndDlg);
int BackupVolumeHeader (HWND hwndDlg, BOOL bRequireConfirmation, const char *lpszVolume);
int RestoreVolumeHeader (HWND hwndDlg, const char *lpszVolume);
diff --git a/src/Mount/Mount.rc b/src/Mount/Mount.rc
index 145132d..e52e509 100644
--- a/src/Mount/Mount.rc
+++ b/src/Mount/Mount.rc
@@ -538,6 +538,7 @@ BEGIN
MENUITEM "Select Device...", IDM_SELECT_DEVICE
MENUITEM SEPARATOR
MENUITEM "Create New Volume...", IDM_CREATE_VOLUME
+ MENUITEM "Permanently Decrypt...", IDM_DECRYPT_NONSYS_VOL
MENUITEM "Resume Interrupted Process", IDM_RESUME_INTERRUPTED_PROC
MENUITEM SEPARATOR
MENUITEM "Mount Volume", IDM_MOUNT_VOLUME
diff --git a/src/Mount/Resource.h b/src/Mount/Resource.h
index 568d6c7..fe57e0d 100644
--- a/src/Mount/Resource.h
+++ b/src/Mount/Resource.h
@@ -229,6 +229,7 @@
#define IDM_DONATE 40064
#define IDM_VOLUME_EXPANDER 40065
#define IDM_DEFAULT_MOUNT_PARAMETERS 40066
+#define IDM_DECRYPT_NONSYS_VOL 40067
// Next default values for new objects
//
@@ -236,7 +237,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 119
-#define _APS_NEXT_COMMAND_VALUE 40067
+#define _APS_NEXT_COMMAND_VALUE 40068
#define _APS_NEXT_CONTROL_VALUE 1142
#define _APS_NEXT_SYMED_VALUE 101
#endif