/* QueryVolumeInfo Retrieves the free disk space and file size limit on the truecrypt volume host Parameters: hwndDlg : HWND [in] handle to parent window lpszVolume : char * [in] Pointer to a string that contains the volume path pHostSizeFree : uint64 * [out] returns the free space available on the host (always zero for devices) pSizeLimitFS : uint64 * [out] returns the file size limit of the host file system Return value: int with TrueCrypt error code (ERR_SUCCESS on success) */ int QueryVolumeInfo (HWND hwndDlg, const char *lpszVolume, uint64 * pHostSizeFree, uint64 * pSizeLimitFS ) { int nStatus = ERR_OS_ERROR; char szDiskFile[TC_MAX_PATH], root[MAX_PATH]; BOOL bDevice; enum EV_FileSystem fs; *pSizeLimitFS = (uint64)-1; CreateFullVolumePath (szDiskFile, sizeof(szDiskFile), lpszVolume, &bDevice); if (bDevice) { *pHostSizeFree=0; return ERR_SUCCESS; } if (!GetVolumePathName (szDiskFile, root, sizeof (root))) { nStatus = ERR_OS_ERROR; goto error; } if( ! GetDiskFreeSpaceEx (root,(PULARGE_INTEGER)pHostSizeFree,NULL,NULL) ) { nStatus = ERR_OS_ERROR; goto error; } if ( ! GetFileSystemType(root,&fs) ) { nStatus = ERR_OS_ERROR; goto error; } /* file size limits FAT16 / FAT32 : 4 GB minus 1 byte (2^32 bytes minus 1 byte) NTFS : Architecturally : 16 exabytes minus 1 KB (26^4 bytes minus 1 KB) Implementation (Windows Server 2008): 16 terabytes minus 64 KB (2^44 bytes minus 64 KB) */ switch (fs) { case EV_FS_TYPE_NTFS: *pSizeLimitFS = 16 * BYTES_PER_TB - 64 * BYTES_PER_KB; break; case EV_FS_TYPE_FAT: *pSizeLimitFS = 4 * BYTES_PER_GB - 1; break; default: *pSizeLimitFS = (uint64)-1; } nStatus = ERR_SUCCESS; error: return nStatus; }
int ExtendFileSystem (HWND hwndDlg , wchar_t *lpszVolume, Password *pVolumePassword, int VolumePkcs5, int VolumePim, uint64 newDataAreaSize) { wchar_t szVolumeGUID[128]; int driveNo = -1; wchar_t rootPath[] = L"A:\\"; enum EV_FileSystem fs; DWORD dwError; int nStatus = ERR_SUCCESS; DWORD BytesPerSector; // mount and resize file system DebugAddProgressDlgStatus (hwndDlg, L"Mounting volume ...\r\n"); nStatus=MountVolTemp(hwndDlg, lpszVolume, &driveNo, pVolumePassword, VolumePkcs5, VolumePim); if (nStatus!=ERR_SUCCESS) { driveNo = -1; goto error; } rootPath[0] += driveNo; if ( !GetFileSystemType(rootPath,&fs) ) { dwError = GetLastError(); if (dwError == ERROR_UNRECOGNIZED_VOLUME) { // raw volume with unrecognized file system -> return with no error nStatus = ERR_SUCCESS; goto error; } nStatus = ERR_OS_ERROR; goto error; } if (fs != EV_FS_TYPE_RAW && fs != EV_FS_TYPE_NTFS ) { // FsctlExtendVolume only supports NTFS and RAW -> return with no error nStatus = ERR_SUCCESS; goto error; } // Get volume GUID if (!GetVolumeNameForVolumeMountPoint(rootPath,szVolumeGUID,ARRAYSIZE(szVolumeGUID))) { nStatus = ERR_OS_ERROR; goto error; } else { // strip trailing backslash from volume GUID (otherwise it means root dir) size_t len = wcslen(szVolumeGUID); if (len>0) --len; if (szVolumeGUID[len]==L'\\') szVolumeGUID[len]=0; } // Get Sector Size if ( !GetNtfsNumberOfSectors(rootPath, NULL, &BytesPerSector) ) { nStatus = ERR_OS_ERROR; goto error; } DebugAddProgressDlgStatus (hwndDlg, L"Extending file system ...\r\n"); // extend volume nStatus = FsctlExtendVolume(szVolumeGUID, newDataAreaSize/BytesPerSector ); error: dwError = GetLastError(); if (driveNo>=0) { DebugAddProgressDlgStatus (hwndDlg, L"Unmounting volume ...\r\n"); UnmountVolume (hwndDlg, driveNo, TRUE); } SetLastError (dwError); return nStatus; }
/* 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, char *lpszVolume) { int nStatus = ERR_OS_ERROR; wchar_t szTmp[4096]; Password VolumePassword; int VolumePkcs5 = 0; uint64 hostSize, volSize, hostSizeFree, maxSizeFS; BOOL bIsDevice, bIsLegacy; DWORD dwError; int driveNo; enum EV_FileSystem volFSType; char rootPath[] = "A:\\"; switch (IsSystemDevicePath (lpszVolume, hwndDlg, TRUE)) { case 1: case 2: MessageBoxW (hwndDlg, L"A VeraCrypt system volume can't be expanded.", lpszTitle, MB_OK|MB_ICONEXCLAMATION); goto ret; } EnableElevatedCursorChange (hwndDlg); WaitCursor(); if (IsMountedVolume (lpszVolume)) { Warning ("DISMOUNT_FIRST", hwndDlg); goto ret; } if (Randinit() != ERR_SUCCESS) { nStatus = ERR_PARAMETER_INCORRECT; 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, L"An outer volume containing a hidden volume can't be expanded, because this destroys the hidden volume.", 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; BOOL truecryptMode = FALSE; if (!VeraCryptExpander::ExtcvAskVolumePassword (hwndDlg, &VolumePassword, &VolumePkcs5, &truecryptMode, "ENTER_NORMAL_VOL_PASSWORD", FALSE)) { goto ret; } EnableElevatedCursorChange (hwndDlg); WaitCursor(); if (KeyFilesEnable && FirstKeyFile) KeyFilesApply (hwndDlg, &VolumePassword, FirstKeyFile); WaitCursor (); OpenVolumeThreadParam threadParam; threadParam.context = &expandVol; threadParam.volumePath = lpszVolume; threadParam.password = &VolumePassword; threadParam.pkcs5_prf = VolumePkcs5; threadParam.truecryptMode = FALSE; 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); } WaitCursor(); // auto mount the volume to check the file system type nStatus=MountVolTemp(hwndDlg, lpszVolume, &driveNo, &VolumePassword, VolumePkcs5); 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, L"Not enough free space to expand the volume", 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, L"Warning: The container file is larger than the VeraCrypt volume area. The data after the VeraCrypt volume area will be overwritten.\n\nDo you want to continue?", 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,L"Warning: The VeraCrypt volume contains a FAT file system!\n\nOnly the VeraCrypt volume itself will be expanded, but not the file system.\n\nDo you want to continue?", lpszTitle, YES_NO|MB_ICONQUESTION|MB_DEFBUTTON2) == IDNO) goto ret; break; default: if (MessageBoxW (hwndDlg,L"Warning: The VeraCrypt volume contains an unknown or no file system!\n\nOnly the VeraCrypt volume itself will be expanded, the file system remains unchanged.\n\nDo you want to continue?", lpszTitle, YES_NO|MB_ICONQUESTION|MB_DEFBUTTON2) == IDNO) goto ret; } EXPAND_VOL_THREAD_PARAMS VolExpandParam; VolExpandParam.bInitFreeSpace = (bIsLegacy && bIsDevice) ? FALSE:TRUE; VolExpandParam.szVolumeName = lpszVolume; VolExpandParam.FileSystem = volFSType; VolExpandParam.pVolumePassword = &VolumePassword; VolExpandParam.VolumePkcs5 = VolumePkcs5; VolExpandParam.bIsDevice = bIsDevice; VolExpandParam.bIsLegacy = bIsLegacy; VolExpandParam.oldSize = bIsDevice ? volSize : hostSize; VolExpandParam.newSize = hostSize; VolExpandParam.hostSizeFree = hostSizeFree; 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) { swprintf(szTmp,L"New volume size too small, must be at least %I64u kB larger than the current size.",TC_MINVAL_FS_EXPAND/BYTES_PER_KB); MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_OK | MB_ICONEXCLAMATION ); continue; } if ( newVolumeSize - hostSize > hostSizeFree ) { swprintf(szTmp,L"New volume size too large, not enough space on host drive."); MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_OK | MB_ICONEXCLAMATION ); continue; } if ( newVolumeSize>maxSizeFS ) { swprintf(szTmp,L"Maximum file size of %I64u MB on host drive exceeded.",maxSizeFS/BYTES_PER_MB); MessageBoxW (hwndDlg, L"!\n",lpszTitle, MB_OK | MB_ICONEXCLAMATION ); continue; } } if ( newVolumeSize > TC_MAX_VOLUME_SIZE ) { // note: current limit TC_MAX_VOLUME_SIZE is 1 PetaByte swprintf(szTmp,L"Maximum VeraCrypt volume size of %I64u TB exceeded!\n",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); burn (&VolumePassword, sizeof (VolumePassword)); RestoreDefaultKeyFilesParam(); RandStop (FALSE); NormalCursor(); return; }