VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Common/Format.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Common/Format.c')
-rw-r--r--src/Common/Format.c291
1 files changed, 204 insertions, 87 deletions
diff --git a/src/Common/Format.c b/src/Common/Format.c
index f691c78d..4d8dfed9 100644
--- a/src/Common/Format.c
+++ b/src/Common/Format.c
@@ -218,7 +218,7 @@ begin_format:
bFailedRequiredDASD = TRUE;
}
}
- else if (IsOSAtLeast (WIN_VISTA) && driveLetter == -1)
+ else if (driveLetter == -1)
{
// Windows Vista doesn't allow overwriting sectors belonging to an unformatted partition
// to which no drive letter has been assigned under the system. This problem can be worked
@@ -344,6 +344,32 @@ begin_format:
else
{
/* File-hosted volume */
+ BOOL speedupFileCreation = FALSE;
+ BOOL delayedSpeedupFileCreation = FALSE;
+ // speedup for file creation only makes sens when using quick format for non hidden volumes
+ if (!volParams->hiddenVol && !bInstantRetryOtherFilesys && volParams->quickFormat && volParams->fastCreateFile)
+ {
+ // we set required privileges to speedup file creation before we create the file so that the file handle inherits the privileges
+ if (!SetPrivilege(SE_MANAGE_VOLUME_NAME, TRUE))
+ {
+ DWORD dwLastError = GetLastError();
+ if (!IsAdmin () && IsUacSupported ())
+ {
+ speedupFileCreation = TRUE;
+ delayedSpeedupFileCreation = TRUE;
+ }
+ else if (Silent || (MessageBoxW(hwndDlg, GetString ("ADMIN_PRIVILEGES_WARN_MANAGE_VOLUME"), lpszTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) == IDNO))
+ {
+ SetLastError(dwLastError);
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+ }
+ else
+ {
+ speedupFileCreation = TRUE;
+ }
+ }
dev = CreateFile (volParams->volumePath, GENERIC_READ | GENERIC_WRITE,
(volParams->hiddenVol || bInstantRetryOtherFilesys) ? (FILE_SHARE_READ | FILE_SHARE_WRITE) : 0,
@@ -373,13 +399,8 @@ begin_format:
if (!volParams->hiddenVol && !bInstantRetryOtherFilesys)
{
LARGE_INTEGER volumeSize;
- BOOL speedupFileCreation = FALSE;
volumeSize.QuadPart = dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE;
- // speedup for file creation only makes sens when using quick format
- if (volParams->quickFormat && volParams->fastCreateFile)
- speedupFileCreation = TRUE;
-
if (volParams->sparseFileSwitch && volParams->quickFormat)
{
// Create as sparse file container
@@ -391,12 +412,15 @@ begin_format:
}
}
- // Preallocate the file
- if (!SetFilePointerEx (dev, volumeSize, NULL, FILE_BEGIN)
- || !SetEndOfFile (dev))
+ if (!delayedSpeedupFileCreation)
{
- nStatus = ERR_OS_ERROR;
- goto error;
+ // Preallocate the file
+ if (!SetFilePointerEx (dev, volumeSize, NULL, FILE_BEGIN)
+ || !SetEndOfFile (dev))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
}
if (speedupFileCreation)
@@ -405,8 +429,46 @@ begin_format:
// this has security issues since it will put existing disk content into file container
// We use this mechanism only when switch /fastCreateFile specific and when quick format
// also specified and which is documented to have security issues.
- // we don't check returned status because failure is not issue for us
- SetFileValidData (dev, volumeSize.QuadPart);
+ if (delayedSpeedupFileCreation)
+ {
+ // in case of delayed speedup we need to set the file size to a minimal value before performing the real preallocation through UAC
+ LARGE_INTEGER minimalSize;
+ DWORD dwOpStatus;
+ // 16K
+ minimalSize.QuadPart = 16 * 1024;
+ if (!SetFilePointerEx (dev, minimalSize, NULL, FILE_BEGIN)
+ || !SetEndOfFile (dev))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+
+ FlushFileBuffers (dev);
+ CloseHandle (dev);
+ dev = INVALID_HANDLE_VALUE;
+
+ dwOpStatus = UacFastFileCreation (volParams->hwndDlg, volParams->volumePath, volumeSize.QuadPart);
+ if (dwOpStatus != 0)
+ {
+ SetLastError(dwOpStatus);
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+
+ // open again the file now that it was created
+ dev = CreateFile (volParams->volumePath, GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING, 0, NULL);
+ if (dev == INVALID_HANDLE_VALUE)
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+ }
+ else if (!SetFileValidData (dev, volumeSize.QuadPart))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
}
if (SetFilePointer (dev, 0, NULL, FILE_BEGIN) != 0)
@@ -521,7 +583,7 @@ begin_format:
goto error;
}
- nStatus = FormatNoFs (hwndDlg, startSector, num_sectors, dev, cryptoInfo, volParams->quickFormat);
+ nStatus = FormatNoFs (hwndDlg, startSector, num_sectors, dev, cryptoInfo, volParams->quickFormat, volParams->bDevice);
if (volParams->bDevice)
StopFormatWriteThread();
@@ -554,7 +616,7 @@ begin_format:
goto error;
}
- nStatus = FormatFat (hwndDlg, startSector, &ft, (void *) dev, cryptoInfo, volParams->quickFormat);
+ nStatus = FormatFat (hwndDlg, startSector, &ft, (void *) dev, cryptoInfo, volParams->quickFormat, volParams->bDevice);
if (volParams->bDevice)
StopFormatWriteThread();
@@ -768,7 +830,7 @@ error:
mountOptions.PartitionInInactiveSysEncScope = FALSE;
mountOptions.UseBackupHeader = FALSE;
- if (MountVolume (volParams->hwndDlg, driveNo, volParams->volumePath, volParams->password, volParams->pkcs5, volParams->pim, FALSE, FALSE, FALSE, TRUE, &mountOptions, Silent, TRUE) < 1)
+ if (MountVolume (volParams->hwndDlg, driveNo, volParams->volumePath, volParams->password, volParams->pkcs5, volParams->pim, FALSE, FALSE, TRUE, &mountOptions, Silent, TRUE) < 1)
{
if (!Silent)
{
@@ -780,16 +842,24 @@ error:
}
retCode = ExternalFormatFs (driveNo, volParams->clusterSize, fsType);
- if (retCode != TRUE)
+ if (retCode != 0)
{
+
/* fallback to using FormatEx function from fmifs.dll */
if (!Silent && !IsAdmin () && IsUacSupported ())
retCode = UacFormatFs (volParams->hwndDlg, driveNo, volParams->clusterSize, fsType);
else
- retCode = FormatFs (driveNo, volParams->clusterSize, fsType);
+ retCode = FormatFs (driveNo, volParams->clusterSize, fsType, FALSE); /* no need to fallback to format.com since we have already tried it without elevation */
+
+ if (retCode != 0)
+ {
+ wchar_t auxLine[2048];
+ StringCbPrintfW (auxLine, sizeof(auxLine), GetString ("FORMATEX_API_FAILED"), FormatExGetMessage(retCode));
+ ErrorDirect(auxLine, volParams->hwndDlg);
+ }
}
- if (retCode != TRUE)
+ if (retCode != 0)
{
if (!UnmountVolumeAfterFormatExCall (volParams->hwndDlg, driveNo) && !Silent)
MessageBoxW (volParams->hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND);
@@ -830,11 +900,13 @@ fv_end:
}
-int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, __int64 num_sectors, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat)
+int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, unsigned __int64 num_sectors, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat, BOOL bDevice)
{
int write_buf_cnt = 0;
char sector[TC_MAX_VOLUME_SECTOR_SIZE], *write_buf;
unsigned __int64 nSecNo = startSector;
+ unsigned __int64 nSkipSectors = 128 * (unsigned __int64) BYTES_PER_MB / FormatSectorSize;
+ DWORD bytesWritten;
int retVal = 0;
DWORD err;
CRYPTOPP_ALIGN_DATA(16) char temporaryKey[MASTER_KEYDATA_SIZE];
@@ -910,18 +982,56 @@ int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, __int64 num_sectors,
while (num_sectors--)
{
- if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
+ if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, startSector,
cryptoInfo) == FALSE)
goto fail;
}
+ if (UpdateProgressBar ((nSecNo - startSector) * FormatSectorSize))
+ return FALSE;
+
if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo))
goto fail;
}
+ else if (!bDevice)
+ {
+ // Quick format: write a zeroed sector every 128 MiB, leaving other sectors untouched
+ // This helps users visualize the progress of actual file creation while forcing Windows
+ // to allocate the disk space of each 128 MiB chunk immediately, otherwise, Windows
+ // would delay the allocation until we write the backup header at the end of the volume which
+ // would make the user think that the format process has stalled after progress bar reaches 100%.
+ while (num_sectors >= nSkipSectors)
+ {
+ // seek to next sector to be written
+ nSecNo += (nSkipSectors - 1);
+ startOffset.QuadPart = nSecNo * FormatSectorSize;
+ if (!MoveFilePointer ((HANDLE) dev, startOffset))
+ {
+ goto fail;
+ }
+
+ // sector array has been zeroed above
+ if (!WriteFile ((HANDLE) dev, sector, FormatSectorSize, &bytesWritten, NULL)
+ || bytesWritten != FormatSectorSize)
+ {
+ goto fail;
+ }
+
+ nSecNo++;
+ num_sectors -= nSkipSectors;
+
+ if (UpdateProgressBar ((nSecNo - startSector)* FormatSectorSize))
+ goto fail;
+ }
+
+ nSecNo += num_sectors;
+ }
else
- nSecNo = num_sectors;
+ {
+ nSecNo += num_sectors;
+ }
- UpdateProgressBar (nSecNo * FormatSectorSize);
+ UpdateProgressBar ((nSecNo - startSector) * FormatSectorSize);
// Restore the original secondary key (XTS mode) in case NTFS format fails and the user wants to try FAT immediately
memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2));
@@ -973,6 +1083,46 @@ fail:
volatile BOOLEAN FormatExError;
+volatile int FormatExErrorCommand;
+
+LPCWSTR FormatExGetMessage (int command)
+{
+ static WCHAR h_szMsg[32];
+ switch (command)
+ {
+ case FMIFS_DONE:
+ return L"FORMAT_FINISHED";
+ case FMIFS_STRUCTURE_PROGRESS:
+ return L"FORMAT_STRUCTURE_PROGRESS";
+ case FMIFS_MEDIA_WRITE_PROTECTED:
+ return L"FORMAT_MEDIA_WRITE_PROTECTED";
+ case FMIFS_INCOMPATIBLE_FILE_SYSTEM:
+ return L"FORMAT_INCOMPATIBLE_FILE_SYSTEM";
+ case FMIFS_ACCESS_DENIED:
+ return L"FORMAT_ACCESS_DENIED";
+ case FMIFS_VOLUME_IN_USE:
+ return L"FORMAT_VOLUME_IN_USE";
+ case FMIFS_CLUSTER_SIZE_TOO_SMALL:
+ return L"FORMAT_CLUSTER_SIZE_TOO_SMALL";
+ case FMIFS_CLUSTER_SIZE_TOO_BIG:
+ return L"FORMAT_CLUSTER_SIZE_TOO_BIG";
+ case FMIFS_VOLUME_TOO_SMALL:
+ return L"FORMAT_VOLUME_TOO_SMALL";
+ case FMIFS_VOLUME_TOO_BIG:
+ return L"FORMAT_VOLUME_TOO_BIG";
+ case FMIFS_NO_MEDIA_IN_DRIVE:
+ return L"FORMAT_NO_MEDIA_IN_DRIVE";
+ case FMIFS_DEVICE_NOT_READY:
+ return L"FORMAT_DEVICE_NOT_READY";
+ case FMIFS_BAD_LABEL:
+ return L"FORMAT_BAD_LABEL";
+ case FMIFS_CANT_QUICK_FORMAT:
+ return L"FORMAT_CANT_QUICK_FORMAT";
+ default:
+ StringCbPrintfW (h_szMsg, sizeof(h_szMsg), L"0x%.8X", command);
+ return h_szMsg;
+ }
+}
BOOLEAN __stdcall FormatExCallback (int command, DWORD subCommand, PVOID parameter)
{
@@ -1029,10 +1179,14 @@ BOOLEAN __stdcall FormatExCallback (int command, DWORD subCommand, PVOID paramet
FormatExError = TRUE;
break;
}
+ if (FormatExError)
+ {
+ FormatExErrorCommand = command;
+ }
return (FormatExError? FALSE : TRUE);
}
-BOOL FormatFs (int driveNo, int clusterSize, int fsType)
+int FormatFs (int driveNo, int clusterSize, int fsType, BOOL bFallBackExternal)
{
wchar_t dllPath[MAX_PATH] = {0};
WCHAR dir[8] = { (WCHAR) driveNo + L'A', 0 };
@@ -1078,41 +1232,45 @@ BOOL FormatFs (int driveNo, int clusterSize, int fsType)
StringCchCatW (dir, ARRAYSIZE(dir), L":\\");
FormatExError = TRUE;
+ FormatExErrorCommand = 0;
// Windows sometimes fails to format a volume (hosted on a removable medium) as NTFS.
// It often helps to retry several times.
for (i = 0; i < 50 && FormatExError; i++)
{
FormatExError = FALSE;
- FormatEx (dir, FMIFS_HARDDISK, szFsFormat, szLabel, TRUE, clusterSize * FormatSectorSize, FormatExCallback);
+ FormatExErrorCommand = 0;
+ FormatEx (dir, FMIFS_REMOVAL, szFsFormat, szLabel, TRUE, clusterSize * FormatSectorSize, FormatExCallback);
}
// The device may be referenced for some time after FormatEx() returns
Sleep (4000);
FreeLibrary (hModule);
- return FormatExError? FALSE : TRUE;
+
+ if (FormatExError && bFallBackExternal)
+ {
+ return ExternalFormatFs (driveNo, clusterSize, fsType);
+ }
+
+ return FormatExError? FormatExErrorCommand : 0;
}
-BOOL FormatNtfs (int driveNo, int clusterSize)
+int FormatNtfs (int driveNo, int clusterSize, BOOL bFallBackExternal)
{
- return FormatFs (driveNo, clusterSize, FILESYS_NTFS);
+ return FormatFs (driveNo, clusterSize, FILESYS_NTFS, bFallBackExternal);
}
/* call Windows format.com program to perform formatting */
-BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType)
+int ExternalFormatFs (int driveNo, int clusterSize, int fsType)
{
wchar_t exePath[MAX_PATH] = {0};
- HANDLE hChildStd_IN_Rd = NULL;
- HANDLE hChildStd_IN_Wr = NULL;
- HANDLE hChildStd_OUT_Rd = NULL;
- HANDLE hChildStd_OUT_Wr = NULL;
WCHAR szFsFormat[16];
TCHAR szCmdline[2 * MAX_PATH];
STARTUPINFO siStartInfo;
PROCESS_INFORMATION piProcInfo;
BOOL bSuccess = FALSE;
- SECURITY_ATTRIBUTES saAttr;
+ int iRet = 0;
switch (fsType)
{
@@ -1129,35 +1287,6 @@ BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType)
return FALSE;
}
- /* Set the bInheritHandle flag so pipe handles are inherited. */
- saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
- saAttr.bInheritHandle = TRUE;
- saAttr.lpSecurityDescriptor = NULL;
-
- /* Create a pipe for the child process's STDOUT. */
- if ( !CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &saAttr, 0) )
- return FALSE;
-
- /* Ensure the read handle to the pipe for STDOUT is not inherited. */
- /* Create a pipe for the child process's STDIN. */
- if ( !SetHandleInformation(hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)
- || !CreatePipe(&hChildStd_IN_Rd, &hChildStd_IN_Wr, &saAttr, 0))
- {
- CloseHandle (hChildStd_OUT_Rd);
- CloseHandle (hChildStd_OUT_Wr);
- return FALSE;
- }
-
- /* Ensure the write handle to the pipe for STDIN is not inherited. */
- if ( !SetHandleInformation(hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
- {
- CloseHandle (hChildStd_OUT_Rd);
- CloseHandle (hChildStd_OUT_Wr);
- CloseHandle (hChildStd_IN_Rd);
- CloseHandle (hChildStd_IN_Wr);
- return FALSE;
- }
-
if (GetSystemDirectory (exePath, MAX_PATH))
{
StringCchCatW(exePath, ARRAYSIZE(exePath), L"\\format.com");
@@ -1165,7 +1294,7 @@ BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType)
else
StringCchCopyW(exePath, ARRAYSIZE(exePath), L"C:\\Windows\\System32\\format.com");
- StringCbPrintf (szCmdline, sizeof(szCmdline), L"%s %c: /FS:%s /Q /X /V:\"\"", exePath, (WCHAR) driveNo + L'A', szFsFormat);
+ StringCbPrintf (szCmdline, sizeof(szCmdline), L"%s %c: /FS:%s /Q /X /V:\"\" /Y", exePath, (WCHAR) driveNo + L'A', szFsFormat);
if (clusterSize)
{
@@ -1188,15 +1317,11 @@ BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType)
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
/* Set up members of the STARTUPINFO structure.
- This structure specifies the STDIN and STDOUT handles for redirection.
*/
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
- siStartInfo.hStdError = hChildStd_OUT_Wr;
- siStartInfo.hStdOutput = hChildStd_OUT_Wr;
- siStartInfo.hStdInput = hChildStd_IN_Rd;
siStartInfo.wShowWindow = SW_HIDE;
- siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ siStartInfo.dwFlags |= STARTF_USESHOWWINDOW;
/* Create the child process. */
bSuccess = CreateProcess(NULL,
@@ -1212,11 +1337,7 @@ BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType)
if (bSuccess)
{
- /* Unblock the format process by simulating hit on ENTER key */
- DWORD dwExitCode, dwWritten;
- LPCSTR newLine = "\n";
-
- WriteFile(hChildStd_IN_Wr, (LPCVOID) newLine, 1, &dwWritten, NULL);
+ DWORD dwExitCode;
/* wait for the format process to finish */
WaitForSingleObject (piProcInfo.hProcess, INFINITE);
@@ -1224,29 +1345,25 @@ BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType)
/* check if it was successfull */
if (GetExitCodeProcess (piProcInfo.hProcess, &dwExitCode))
{
- if (dwExitCode == 0)
- bSuccess = TRUE;
- else
- bSuccess = FALSE;
+ iRet = (int) dwExitCode; /* dwExitCode will be 0 in case of success */
}
else
- bSuccess = FALSE;
+ iRet = (int) GetLastError();
CloseHandle (piProcInfo.hThread);
CloseHandle (piProcInfo.hProcess);
}
+ else
+ {
+ iRet = (int) GetLastError();
+ }
- CloseHandle(hChildStd_OUT_Wr);
- CloseHandle(hChildStd_OUT_Rd);
- CloseHandle(hChildStd_IN_Rd);
- CloseHandle(hChildStd_IN_Wr);
-
- return bSuccess;
+ return iRet;
}
BOOL WriteSector (void *dev, char *sector,
char *write_buf, int *write_buf_cnt,
- __int64 *nSecNo, PCRYPTO_INFO cryptoInfo)
+ unsigned __int64 *nSecNo, unsigned __int64 startSector, PCRYPTO_INFO cryptoInfo)
{
static __int32 updateTime = 0;
@@ -1260,7 +1377,7 @@ BOOL WriteSector (void *dev, char *sector,
if (GetTickCount () - updateTime > 25)
{
- if (UpdateProgressBar (*nSecNo * FormatSectorSize))
+ if (UpdateProgressBar ((*nSecNo - startSector) * FormatSectorSize))
return FALSE;
updateTime = GetTickCount ();