1
0
mirror of https://github.com/veracrypt/VeraCrypt.git synced 2025-11-11 11:08:02 -06:00
Files
VeraCrypt/src/ExpandVolume/DlgExpandVolume.cpp

845 lines
24 KiB
C++

/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of TrueCrypt 7.1a, which is
Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
governed by the TrueCrypt License 3.0, also from the source code of
Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
and which is governed by the 'License Agreement for Encryption for the Masses'
and also from the source code of extcv, which is Copyright (c) 2009-2010 Kih-Oskh
or Copyright (c) 2012-2013 Josef Schneider <josef@netpage.dk>
Modifications and additions to the original source code (contained in this file)
and all other portions of this file are Copyright (c) 2013-2017 IDRIX
and are governed by the Apache License 2.0 the full text of which is
contained in the file License.txt included in VeraCrypt binary and source
code distribution packages. */
#include "Tcdefs.h"
#include <time.h>
#include <math.h>
#include <dbt.h>
#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
#include <windowsx.h>
#include <stdio.h>
#include "Apidrvr.h"
#include "Volumes.h"
#include "Crypto.h"
#include "Dlgcode.h"
#include "Language.h"
#include "Pkcs5.h"
#include "Random.h"
// #include "../Mount/Mount.h"
#include "../Common/Dictionary.h"
#include "../Common/Common.h"
#include "../Common/Resource.h"
#include "../Common/SecurityToken.h"
#include "../Common/Progress.h"
#include "ExpandVolume.h"
#include "Resource.h"
// TO DO: display sector sizes different than 512 bytes
#define SECTOR_SIZE_MSG 512
#define TIMER_ID_RANDVIEW 0xff
#define TIMER_INTERVAL_RANDVIEW 50
BOOL bSeManageVolumeNameSet = FALSE;
// see definition of enum EV_FileSystem
const wchar_t * szFileSystemStr[4] = {L"RAW",L"FAT",L"NTFS",L"EXFAT"};
// prototypes for internal functions
BOOL CALLBACK ExpandVolSizeDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK ExpandVolProgressDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
namespace VeraCryptExpander
{
/* defined in WinMain.c, referenced by ExpandVolumeWizard() */
int ExtcvAskVolumePassword (HWND hwndDlg, const wchar_t* fileName, Password *password, int *pkcs5, int *pim, char *titleStringId, BOOL enableMountOptions);
}
int GetSpaceString(wchar_t *dest, size_t cbDest, uint64 size, BOOL bDevice)
{
const wchar_t * szFmtBytes = L"%.0lf %s";
const wchar_t * szFmtOther = L"%.2lf %s";
const wchar_t * SuffixStr[] = {GetString("BYTE"), GetString("KB"), GetString("MB"), GetString("GB"), GetString("TB")};
const uint64 Muliplier[] = {1, BYTES_PER_KB, BYTES_PER_MB, BYTES_PER_GB, BYTES_PER_TB};
const int nMaxSuffix = sizeof(Muliplier)/sizeof(uint64) - 1;
int i;
for (i=1; i<=nMaxSuffix && size>Muliplier[i]; i++) ;
--i;
if (bDevice) {
wchar_t szTemp[512];
if (StringCbPrintfW(szTemp, sizeof(szTemp),i?szFmtOther:szFmtBytes, size/(double)Muliplier[i], SuffixStr[i]) < 0 )
return -1;
return StringCbPrintfW(dest, cbDest, L"%I64u sectors (%s)", size/SECTOR_SIZE_MSG , szTemp);
}
return StringCbPrintfW(dest, cbDest,i?szFmtOther:szFmtBytes, size/(double)Muliplier[i], SuffixStr[i]);
}
void SetCurrentVolSize(HWND hwndDlg, uint64 size)
{
const uint64 Muliplier[] = {BYTES_PER_KB, BYTES_PER_MB, BYTES_PER_GB, BYTES_PER_TB};
const int IdRadioBtn[] = {IDC_KB, IDC_MB, IDC_GB, IDC_TB};
const int nMaxSuffix = sizeof(Muliplier)/sizeof(uint64) - 1;
int i;
wchar_t szTemp[256];
for (i=1; i<=nMaxSuffix && size>Muliplier[i]; i++) ;
--i;
SendDlgItemMessage (hwndDlg, IdRadioBtn[i], BM_SETCHECK, BST_CHECKED, 0);
StringCbPrintfW(szTemp,sizeof(szTemp),L"%I64u",size/Muliplier[i]);
SetWindowText (GetDlgItem (hwndDlg, IDC_SIZEBOX), szTemp);
}
uint64 GetSizeBoxMultiplier(HWND hwndDlg)
{
const uint64 Muliplier[] = {BYTES_PER_KB, BYTES_PER_MB, BYTES_PER_GB, BYTES_PER_TB};
const int IdRadioBtn[] = {IDC_KB, IDC_MB, IDC_GB, IDC_TB};
const int nMaxSuffix = sizeof(Muliplier)/sizeof(uint64) - 1;
int i;
for (i=nMaxSuffix; i>0 && !IsButtonChecked (GetDlgItem (hwndDlg, IdRadioBtn[i])); --i) ;
return Muliplier[i];
}
void HandleQuickExpanddCheckBox (HWND hwndDlg)
{
if (IsButtonChecked (GetDlgItem (hwndDlg, IDC_INIT_NEWSPACE)))
{
EnableWindow (GetDlgItem (hwndDlg, IDC_QUICKEXPAND), FALSE);
SendDlgItemMessage (hwndDlg, IDC_QUICKEXPAND, BM_SETCHECK, BST_UNCHECKED, 0);
}
else
{
EnableWindow (GetDlgItem (hwndDlg, IDC_QUICKEXPAND), TRUE);
}
}
BOOL CALLBACK ExpandVolSizeDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
static EXPAND_VOL_THREAD_PARAMS *pVolExpandParam;
WORD lw = LOWORD (wParam);
switch (msg)
{
case WM_INITDIALOG:
{
wchar_t szTemp[4096];
pVolExpandParam = (EXPAND_VOL_THREAD_PARAMS*)lParam;
LocalizeDialog (hwndDlg, NULL);
EnableWindow (GetDlgItem (hwndDlg, IDC_SIZEBOX), !pVolExpandParam->bIsDevice);
EnableWindow (GetDlgItem (hwndDlg, IDC_KB), !pVolExpandParam->bIsDevice);
EnableWindow (GetDlgItem (hwndDlg, IDC_MB), !pVolExpandParam->bIsDevice);
EnableWindow (GetDlgItem (hwndDlg, IDC_GB), !pVolExpandParam->bIsDevice);
EnableWindow (GetDlgItem (hwndDlg, IDC_TB), !pVolExpandParam->bIsDevice);
EnableWindow (GetDlgItem (hwndDlg, IDC_INIT_NEWSPACE),
!(pVolExpandParam->bIsLegacy && pVolExpandParam->bIsDevice));
SendDlgItemMessage (hwndDlg, IDC_INIT_NEWSPACE, BM_SETCHECK,
pVolExpandParam->bInitFreeSpace ? BST_CHECKED : BST_UNCHECKED, 0);
if (!pVolExpandParam->bIsDevice)
SetCurrentVolSize(hwndDlg,pVolExpandParam->oldSize);
SendMessage (GetDlgItem (hwndDlg, IDC_BOX_HELP), WM_SETFONT, (WPARAM) hBoldFont, (LPARAM) TRUE);
GetSpaceString(szTemp,sizeof(szTemp),pVolExpandParam->oldSize,pVolExpandParam->bIsDevice);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_OLDSIZE), szTemp);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_NAME), pVolExpandParam->szVolumeName);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_FILE_SYSTEM), szFileSystemStr[pVolExpandParam->FileSystem]);
if (pVolExpandParam->bIsDevice)
{
GetSpaceString(szTemp,sizeof(szTemp),pVolExpandParam->newSize,TRUE);
}
else
{
wchar_t szHostFreeStr[256];
SetWindowText (GetDlgItem (hwndDlg, IDT_NEW_SIZE), L"");
GetSpaceString(szHostFreeStr,sizeof(szHostFreeStr),pVolExpandParam->hostSizeFree,FALSE);
StringCbPrintfW (szTemp,sizeof(szTemp),GetString("EXPANDER_FREE_SPACE"), szHostFreeStr);
if (!pVolExpandParam->bDisableQuickExpand)
{
ShowWindow (GetDlgItem (hwndDlg, IDC_QUICKEXPAND), SW_SHOW);
HandleQuickExpanddCheckBox (hwndDlg);
}
}
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_NEWSIZE), szTemp);
// set help text
if (pVolExpandParam->bIsDevice)
{
StringCbPrintfW (szTemp,sizeof(szTemp),GetString("EXPANDER_HELP_DEVICE"));
if (pVolExpandParam->bIsLegacy)
StringCbCatW(szTemp,sizeof(szTemp),L" Note: filling the new space with random data is not supported for legacy volumes.");
}
else
{
StringCbPrintfW (szTemp, sizeof(szTemp),GetString("EXPANDER_HELP_FILE"),TC_MINVAL_FS_EXPAND/1024);
}
SetWindowText (GetDlgItem (hwndDlg, IDC_BOX_HELP), szTemp);
}
return 0;
case WM_COMMAND:
if (lw == IDCANCEL)
{
EndDialog (hwndDlg, lw);
return 1;
}
if (lw == IDC_CONTINUE)
{
wchar_t szTemp[4096];
pVolExpandParam->bInitFreeSpace = IsButtonChecked (GetDlgItem (hwndDlg, IDC_INIT_NEWSPACE));
pVolExpandParam->bQuickExpand = IsButtonChecked (GetDlgItem (hwndDlg, IDC_QUICKEXPAND));
if (!pVolExpandParam->bIsDevice) // for devices new size is set by calling function
{
GetWindowText (GetDlgItem (hwndDlg, IDC_SIZEBOX), szTemp, ARRAYSIZE (szTemp));
pVolExpandParam->newSize = _wtoi64(szTemp) * GetSizeBoxMultiplier(hwndDlg);
}
EndDialog (hwndDlg, lw);
return 1;
}
if (lw == IDC_INIT_NEWSPACE && !pVolExpandParam->bDisableQuickExpand)
{
HandleQuickExpanddCheckBox (hwndDlg);
return 1;
}
if (lw == IDC_QUICKEXPAND && IsButtonChecked (GetDlgItem (hwndDlg, IDC_QUICKEXPAND)))
{
// If quick expand selected, then we warn about security issue
if (MessageBoxW (hwndDlg, GetString ("QUICK_EXPAND_WARNING"),
lpszTitle, YES_NO|MB_ICONWARNING|MB_DEFBUTTON2) == IDNO)
{
SendDlgItemMessage (hwndDlg, IDC_QUICKEXPAND, BM_SETCHECK, BST_UNCHECKED, 0);
return 1;
}
}
return 0;
}
return 0;
}
extern "C" void AddProgressDlgStatus(HWND hwndDlg, const wchar_t* szText)
{
HWND hwndCtrl;
hwndCtrl = GetDlgItem (hwndDlg,IDC_BOX_STATUS);
SendMessage(hwndCtrl,EM_REPLACESEL,FALSE,(LPARAM)szText);
SendMessage(hwndCtrl,EM_SCROLLCARET,0,0);
}
extern "C" void SetProgressDlgStatus(HWND hwndDlg, const wchar_t* szText)
{
HWND hwndCtrl;
hwndCtrl = GetDlgItem (hwndDlg,IDC_BOX_STATUS);
SendMessage(hwndCtrl,EM_SETSEL,0,-1);
SendMessage(hwndCtrl,EM_REPLACESEL,FALSE,(LPARAM)szText);
SendMessage(hwndCtrl,EM_SCROLLCARET,0,0);
}
BOOL CALLBACK ExpandVolProgressDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
static EXPAND_VOL_THREAD_PARAMS *pProgressDlgParam;
static BOOL bVolTransformStarted = FALSE;
static BOOL showRandPool = TRUE;
static unsigned char randPool[16];
static unsigned char maskRandPool [16];
static BOOL bUseMask = FALSE;
static DWORD mouseEntropyGathered = 0xFFFFFFFF;
static DWORD mouseEventsInitialCount = 0;
/* max value of entropy needed to fill all random pool = 8 * RNG_POOL_SIZE = 2560 bits */
static const DWORD maxEntropyLevel = RNG_POOL_SIZE * 8;
static HWND hEntropyBar = NULL;
WORD lw = LOWORD (wParam);
switch (msg)
{
case WM_INITDIALOG:
{
wchar_t szOldHostSize[512], szNewHostSize[512];
HCRYPTPROV hRngProv;
pProgressDlgParam = (EXPAND_VOL_THREAD_PARAMS*)lParam;
bVolTransformStarted = FALSE;
showRandPool = FALSE;
hCurPage = hwndDlg;
nPbar = IDC_PROGRESS_BAR;
VirtualLock (randPool, sizeof(randPool));
VirtualLock (&mouseEntropyGathered, sizeof(mouseEntropyGathered));
VirtualLock (maskRandPool, sizeof(maskRandPool));
LocalizeDialog (hwndDlg, NULL);
mouseEntropyGathered = 0xFFFFFFFF;
mouseEventsInitialCount = 0;
bUseMask = FALSE;
if (CryptAcquireContext (&hRngProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
{
if (CryptGenRandom (hRngProv, sizeof (maskRandPool), maskRandPool))
bUseMask = TRUE;
CryptReleaseContext (hRngProv, 0);
}
GetSpaceString(szOldHostSize,sizeof(szOldHostSize),pProgressDlgParam->oldSize,pProgressDlgParam->bIsDevice);
GetSpaceString(szNewHostSize,sizeof(szNewHostSize),pProgressDlgParam->newSize,pProgressDlgParam->bIsDevice);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_OLDSIZE), szOldHostSize);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_NEWSIZE), szNewHostSize);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_NAME), pProgressDlgParam->szVolumeName);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_FILE_SYSTEM), szFileSystemStr[pProgressDlgParam->FileSystem]);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_INITSPACE), pProgressDlgParam->bInitFreeSpace?GetString("UISTR_YES"):GetString("UISTR_NO"));
SendMessage (GetDlgItem (hwndDlg, IDC_BOX_STATUS), WM_SETFONT, (WPARAM) hBoldFont, (LPARAM) TRUE);
SendMessage (GetDlgItem (hwndDlg, IDC_RANDOM_BYTES), WM_SETFONT, (WPARAM) hFixedDigitFont, (LPARAM) TRUE);
// set status text
if ( !pProgressDlgParam->bInitFreeSpace && pProgressDlgParam->bIsLegacy )
{
showRandPool = FALSE;
EnableWindow (GetDlgItem (hwndDlg, IDC_DISPLAY_POOL_CONTENTS), FALSE);
EnableWindow (GetDlgItem (hwndDlg, IDC_RANDOM_BYTES), FALSE);
SetDlgItemText(hwndDlg, IDC_BOX_STATUS, GetString("EXPANDER_STATUS_TEXT_LEGACY"));
}
else
{
SetDlgItemText(hwndDlg, IDC_BOX_STATUS, GetString("EXPANDER_STATUS_TEXT"));
}
SendMessage (GetDlgItem (hwndDlg, IDC_DISPLAY_POOL_CONTENTS), BM_SETCHECK, BST_UNCHECKED, 0);
hEntropyBar = GetDlgItem (hwndDlg, IDC_ENTROPY_BAR);
SendMessage (hEntropyBar, PBM_SETRANGE32, 0, maxEntropyLevel);
SendMessage (hEntropyBar, PBM_SETSTEP, 1, 0);
SetTimer (hwndDlg, TIMER_ID_RANDVIEW, TIMER_INTERVAL_RANDVIEW, NULL);
}
return 0;
case TC_APPMSG_VOL_TRANSFORM_THREAD_ENDED:
{
int nStatus = (int)lParam;
NormalCursor ();
if (nStatus != 0)
{
if ( nStatus != ERR_USER_ABORT )
AddProgressDlgStatus (hwndDlg, GetString("EXPANDER_FINISH_ERROR"));
else
AddProgressDlgStatus (hwndDlg, GetString("EXPANDER_FINISH_ABORT"));
}
else
{
AddProgressDlgStatus (hwndDlg, GetString("EXPANDER_FINISH_OK"));
}
SetWindowText (GetDlgItem (hwndDlg, IDC_CONTINUE), GetString("EXIT"));
EnableWindow (GetDlgItem (hwndDlg, IDC_CONTINUE), TRUE);
EnableWindow (GetDlgItem (hwndDlg, IDCANCEL), FALSE);
}
return 1;
case WM_TIMER:
switch (wParam)
{
case TIMER_ID_RANDVIEW:
{
wchar_t szRndPool[64] = {0};
DWORD mouseEventsCounter;
RandpeekBytes (hwndDlg, randPool, sizeof (randPool),&mouseEventsCounter);
ProcessEntropyEstimate (hEntropyBar, &mouseEventsInitialCount, mouseEventsCounter, maxEntropyLevel, &mouseEntropyGathered);
if (showRandPool)
StringCbPrintfW (szRndPool, sizeof(szRndPool), L"%08X%08X%08X%08X",
*((DWORD*) (randPool + 12)), *((DWORD*) (randPool + 8)), *((DWORD*) (randPool + 4)), *((DWORD*) (randPool)));
else if (bUseMask)
{
for (int i = 0; i < 16; i++)
{
wchar_t tmp2[3];
unsigned char tmpByte = randPool[i] ^ maskRandPool[i];
tmp2[0] = (wchar_t) (((tmpByte >> 4) % 6) + L'*');
tmp2[1] = (wchar_t) (((tmpByte & 0x0F) % 6) + L'*');
tmp2[2] = 0;
StringCbCatW (szRndPool, sizeof(szRndPool), tmp2);
}
}
else
{
wmemset (szRndPool, L'*', 32);
}
SetWindowText (GetDlgItem (hwndDlg, IDC_RANDOM_BYTES), szRndPool);
burn (randPool, sizeof(randPool));
burn (szRndPool, sizeof(szRndPool));
}
return 1;
}
return 0;
case WM_COMMAND:
if (lw == IDC_DISPLAY_POOL_CONTENTS)
{
showRandPool = IsButtonChecked (GetDlgItem (hwndDlg, IDC_DISPLAY_POOL_CONTENTS));
return 1;
}
if (lw == IDCANCEL)
{
if (bVolTransformStarted)
{
if (MessageBoxW (hwndDlg, GetString("EXPANDER_CANCEL_WARNING"), lpszTitle, YES_NO|MB_ICONQUESTION|MB_DEFBUTTON2) == IDNO)
return 1;
// tell the volume transform thread to terminate
bVolTransformThreadCancel = TRUE;
}
NormalCursor ();
EndDialog (hwndDlg, lw);
return 1;
}
if (lw == IDC_CONTINUE)
{
if (bVolTransformStarted)
{
// TransformThreadFunction finished -> OK button is now exit
NormalCursor ();
EndDialog (hwndDlg, lw);
}
else
{
showRandPool = FALSE;
KillTimer (hwndDlg, TIMER_ID_RANDVIEW);
EnableWindow (GetDlgItem (hwndDlg, IDC_DISPLAY_POOL_CONTENTS), FALSE);
EnableWindow (GetDlgItem (hwndDlg, IDC_CONTINUE), FALSE);
SetProgressDlgStatus (hwndDlg, GetString("EXPANDER_STARTING_STATUS"));
bVolTransformStarted = TRUE;
pProgressDlgParam->hwndDlg = hwndDlg;
if ( _beginthread (volTransformThreadFunction, 0, pProgressDlgParam) == -1L )
{
handleError (hwndDlg, ERR_OS_ERROR, SRC_POS);
EndDialog (hwndDlg, lw);
}
WaitCursor();
}
return 1;
}
return 0;
case WM_NCDESTROY:
burn (randPool, sizeof (randPool));
burn (&mouseEventsInitialCount, sizeof(mouseEventsInitialCount));
burn (&mouseEntropyGathered, sizeof(mouseEntropyGathered));
burn (maskRandPool, sizeof(maskRandPool));
return 0;
}
return 0;
}
typedef struct
{
OpenVolumeContext *context;
const wchar_t *volumePath;
Password *password;
int pkcs5_prf;
int pim;
BOOL write;
BOOL preserveTimestamps;
BOOL useBackupHeader;
int* nStatus;
} OpenVolumeThreadParam;
void CALLBACK OpenVolumeWaitThreadProc(void* pArg, HWND hwndDlg)
{
OpenVolumeThreadParam* pThreadParam = (OpenVolumeThreadParam*) pArg;
*(pThreadParam)->nStatus = OpenVolume(pThreadParam->context, pThreadParam->volumePath, pThreadParam->password, pThreadParam->pkcs5_prf,
pThreadParam->pim, pThreadParam->write, pThreadParam->preserveTimestamps, pThreadParam->useBackupHeader);
}
/*
ExpandVolumeWizard
Expands a trucrypt volume (wizard for user interface)
Parameters:
hwndDlg : HWND
[in] handle to parent window (if any)
szVolume : char *
[in] Pointer to a string with the volume name (e.g. '\Device\Harddisk0\Partition1' or 'C:\topsecret.tc')
Return value:
none
*/
void ExpandVolumeWizard (HWND hwndDlg, wchar_t *lpszVolume)
{
int nStatus = ERR_OS_ERROR;
wchar_t szTmp[4096];
Password VolumePassword;
int VolumePkcs5 = 0, VolumePim = -1;
uint64 hostSize, volSize, hostSizeFree, maxSizeFS;
BOOL bIsDevice, bIsLegacy;
DWORD dwError;
int driveNo;
enum EV_FileSystem volFSType;
wchar_t rootPath[] = L"A:\\";
switch (IsSystemDevicePath (lpszVolume, hwndDlg, TRUE))
{
case 1:
case 2:
MessageBoxW (hwndDlg, GetString("EXPANDER_SYSTEM_VOLUME_ERROR"), lpszTitle, MB_OK|MB_ICONEXCLAMATION);
goto ret;
}
EnableElevatedCursorChange (hwndDlg);
WaitCursor();
if (IsMountedVolume (lpszVolume))
{
Warning ("DISMOUNT_FIRST", hwndDlg);
goto ret;
}
if (Randinit() != ERR_SUCCESS) {
if (CryptoAPILastError == ERROR_SUCCESS)
nStatus = ERR_RAND_INIT_FAILED;
else
nStatus = ERR_CAPI_INIT_FAILED;
goto error;
}
NormalCursor();
// Ask the user if there is a hidden volume
char *volTypeChoices[] = {0, "DOES_VOLUME_CONTAIN_HIDDEN", "VOLUME_CONTAINS_HIDDEN", "VOLUME_DOES_NOT_CONTAIN_HIDDEN", "IDCANCEL", 0};
switch (AskMultiChoice ((void **) volTypeChoices, FALSE, hwndDlg))
{
case 1:
MessageBoxW (hwndDlg, GetString("EXPANDER_HIDDEN_VOLUME_ERROR"), lpszTitle, MB_OK|MB_ICONEXCLAMATION);
goto ret;
case 2:
break;
default:
nStatus = ERR_SUCCESS;
goto ret;
}
WaitCursor();
nStatus = QueryVolumeInfo(hwndDlg,lpszVolume,&hostSizeFree,&maxSizeFS);
if (nStatus!=ERR_SUCCESS)
{
nStatus = ERR_OS_ERROR;
goto error;
}
NormalCursor();
while (TRUE)
{
OpenVolumeContext expandVol;
if (!VeraCryptExpander::ExtcvAskVolumePassword (hwndDlg, lpszVolume, &VolumePassword, &VolumePkcs5, &VolumePim, "ENTER_NORMAL_VOL_PASSWORD", FALSE))
{
goto ret;
}
EnableElevatedCursorChange (hwndDlg);
WaitCursor();
if (KeyFilesEnable && FirstKeyFile)
KeyFilesApply (hwndDlg, &VolumePassword, FirstKeyFile, lpszVolume);
OpenVolumeThreadParam threadParam;
threadParam.context = &expandVol;
threadParam.volumePath = lpszVolume;
threadParam.password = &VolumePassword;
threadParam.pkcs5_prf = VolumePkcs5;
threadParam.pim = VolumePim;
threadParam.write = FALSE;
threadParam.preserveTimestamps = bPreserveTimestamp;
threadParam.useBackupHeader = FALSE;
threadParam.nStatus = &nStatus;
ShowWaitDialog (hwndDlg, TRUE, OpenVolumeWaitThreadProc, &threadParam);
NormalCursor ();
dwError = GetLastError();
if (nStatus == ERR_SUCCESS)
{
bIsDevice = expandVol.IsDevice;
bIsLegacy = expandVol.CryptoInfo->LegacyVolume;
hostSize = expandVol.HostSize;
VolumePkcs5 = expandVol.CryptoInfo->pkcs5;
if ( bIsLegacy )
{
if ( bIsDevice )
volSize = 0; // updated later
else
volSize = hostSize;
}
else
{
volSize = GetVolumeSizeByDataAreaSize (expandVol.CryptoInfo->VolumeSize.Value, bIsLegacy);
}
CloseVolume (&expandVol);
break;
}
else if (nStatus != ERR_PASSWORD_WRONG)
{
SetLastError (dwError);
goto error;
}
NormalCursor();
handleError (hwndDlg, nStatus, SRC_POS);
}
WaitCursor();
// auto mount the volume to check the file system type
nStatus=MountVolTemp(hwndDlg, lpszVolume, &driveNo, &VolumePassword, VolumePkcs5, VolumePim);
if (nStatus != ERR_SUCCESS)
goto error;
rootPath[0] += driveNo;
if ( !GetFileSystemType(rootPath,&volFSType) )
volFSType = EV_FS_TYPE_RAW;
if ( bIsLegacy && bIsDevice && volFSType == EV_FS_TYPE_NTFS )
{
uint64 NumberOfSectors;
DWORD BytesPerSector;
if ( !GetNtfsNumberOfSectors(rootPath, &NumberOfSectors, &BytesPerSector) )
nStatus = ERR_OS_ERROR;
// NTFS reported size does not include boot sector copy at volume end
volSize = ( NumberOfSectors + 1 ) * BytesPerSector;
}
UnmountVolume (hwndDlg, driveNo, TRUE);
NormalCursor();
if (nStatus != ERR_SUCCESS)
goto error;
if ( bIsDevice && bIsLegacy && volFSType != EV_FS_TYPE_NTFS )
{
MessageBoxW (hwndDlg,
L"Expanding a device hosted legacy volume with no NTFS file system\n"
L"is unsupported.\n"
L"Note that expanding the VeraCrypt volume itself is not neccessary\n"
L"for legacy volumes.\n",
lpszTitle, MB_OK|MB_ICONEXCLAMATION);
goto ret;
}
// check if there is enough free space on host device/drive to expand the volume
if ( (bIsDevice && hostSize < volSize + TC_MINVAL_FS_EXPAND) || (!bIsDevice && hostSizeFree < TC_MINVAL_FS_EXPAND) )
{
MessageBoxW (hwndDlg, GetString("EXPANDER_NO_FREE_SPACE"), lpszTitle, MB_OK|MB_ICONEXCLAMATION);
goto ret;
}
if (!bIsDevice && hostSize != volSize ) {
// there is some junk data at the end of the volume
if (MessageBoxW (hwndDlg, GetString("EXPANDER_WARNING_FILE_CONTAINER_JUNK"), lpszTitle, YES_NO|MB_ICONQUESTION|MB_DEFBUTTON2) == IDNO)
goto ret;
}
switch (volFSType)
{
case EV_FS_TYPE_NTFS:
break;
case EV_FS_TYPE_FAT:
if (MessageBoxW (hwndDlg, GetString("EXPANDER_WARNING_FAT"),
lpszTitle, YES_NO|MB_ICONQUESTION|MB_DEFBUTTON2) == IDNO)
goto ret;
break;
case EV_FS_TYPE_EXFAT:
if (MessageBoxW (hwndDlg, GetString("EXPANDER_WARNING_EXFAT"),
lpszTitle, YES_NO|MB_ICONQUESTION|MB_DEFBUTTON2) == IDNO)
goto ret;
break;
default:
if (MessageBoxW (hwndDlg, GetString("EXPANDER_WARNING_UNKNOWN_FS"),
lpszTitle, YES_NO|MB_ICONQUESTION|MB_DEFBUTTON2) == IDNO)
goto ret;
}
EXPAND_VOL_THREAD_PARAMS VolExpandParam;
VolExpandParam.bInitFreeSpace = (bIsLegacy && bIsDevice) ? FALSE:TRUE;
VolExpandParam.bQuickExpand = FALSE;
VolExpandParam.bDisableQuickExpand = bIsDevice;
VolExpandParam.szVolumeName = lpszVolume;
VolExpandParam.FileSystem = volFSType;
VolExpandParam.pVolumePassword = &VolumePassword;
VolExpandParam.VolumePkcs5 = VolumePkcs5;
VolExpandParam.VolumePim = VolumePim;
VolExpandParam.bIsDevice = bIsDevice;
VolExpandParam.bIsLegacy = bIsLegacy;
VolExpandParam.oldSize = bIsDevice ? volSize : hostSize;
VolExpandParam.newSize = hostSize;
VolExpandParam.hostSizeFree = hostSizeFree;
// disable Quick Expand if the file is sparse or compressed
if (!bIsDevice)
{
DWORD dwFileAttrib = GetFileAttributesW (lpszVolume);
if (INVALID_FILE_ATTRIBUTES != dwFileAttrib)
{
if (dwFileAttrib & (FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_SPARSE_FILE))
VolExpandParam.bDisableQuickExpand = TRUE;
}
}
while (1)
{
uint64 newVolumeSize;
if (IDCANCEL == DialogBoxParamW (hInst,
MAKEINTRESOURCEW (IDD_SIZE_DIALOG), hwndDlg,
(DLGPROC) ExpandVolSizeDlgProc, (LPARAM) &VolExpandParam))
{
goto ret;
}
newVolumeSize = VolExpandParam.newSize;
if ( !bIsDevice )
{
if ( (newVolumeSize < hostSize + TC_MINVAL_FS_EXPAND) && ((hostSize == volSize) || (newVolumeSize != hostSize) || ((hostSize - volSize) < TC_MINVAL_FS_EXPAND)))
{
StringCbPrintfW(szTmp,sizeof(szTmp),GetString("EXPANDER_ERROR_VOLUME_SIZE_TOO_SMALL"),TC_MINVAL_FS_EXPAND/BYTES_PER_KB);
MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_OK | MB_ICONEXCLAMATION );
continue;
}
if ( newVolumeSize - hostSize > hostSizeFree )
{
StringCbPrintfW(szTmp,sizeof(szTmp), GetString("EXPANDER_ERROR_VOLUME_SIZE_TOO_LARGE"));
MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_OK | MB_ICONEXCLAMATION );
continue;
}
if ( newVolumeSize>maxSizeFS )
{
StringCbPrintfW(szTmp,sizeof(szTmp), GetString("EXPANDER_ERROR_MAX_FILE_SIZE_EXCEEDED"),maxSizeFS/BYTES_PER_MB);
MessageBoxW (hwndDlg, L"!\n",lpszTitle, MB_OK | MB_ICONEXCLAMATION );
continue;
}
if (VolExpandParam.bQuickExpand && !bSeManageVolumeNameSet)
{
if (!SetPrivilege (SE_MANAGE_VOLUME_NAME, TRUE))
{
MessageBoxW (hwndDlg, GetString("EXPANDER_ERROR_QUICKEXPAND_PRIVILEGES"),lpszTitle, MB_OK | MB_ICONEXCLAMATION );
VolExpandParam.bQuickExpand = FALSE;
continue;
}
bSeManageVolumeNameSet = TRUE;
}
}
if ( newVolumeSize > TC_MAX_VOLUME_SIZE )
{
// note: current limit TC_MAX_VOLUME_SIZE is 1 PetaByte
StringCbPrintfW(szTmp,sizeof(szTmp), GetString("EXPANDER_ERROR_MAX_VC_VOLUME_SIZE_EXCEEDED"),TC_MAX_VOLUME_SIZE/BYTES_PER_TB);
MessageBoxW (hwndDlg, szTmp,lpszTitle, MB_OK | MB_ICONEXCLAMATION );
if (bIsDevice)
break; // TODO: ask to limit volume size to TC_MAX_VOLUME_SIZE
continue;
}
break;
}
VolExpandParam.oldSize = volSize;
// start progress dialog
DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_EXPAND_PROGRESS_DLG), hwndDlg,
(DLGPROC) ExpandVolProgressDlgProc, (LPARAM) &VolExpandParam );
ret:
nStatus = ERR_SUCCESS;
error:
if (nStatus != 0)
handleError (hwndDlg, nStatus, SRC_POS);
burn (&VolumePassword, sizeof (VolumePassword));
RestoreDefaultKeyFilesParam();
RandStop (FALSE);
NormalCursor();
return;
}