VeraCrypt
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMounir IDRASSI <mounir.idrassi@idrix.fr>2023-06-04 16:25:55 +0200
committerMounir IDRASSI <mounir.idrassi@idrix.fr>2023-06-04 16:25:55 +0200
commit22466535f1b9cbe1bd98363cfa98f7f796bc408a (patch)
tree7ee1c59af8e16b57953a86f8837fe465e418f60a
parent3c68349a39877c5420c727cd53143ab442963759 (diff)
downloadVeraCrypt-22466535f1b9cbe1bd98363cfa98f7f796bc408a.tar.gz
VeraCrypt-22466535f1b9cbe1bd98363cfa98f7f796bc408a.zip
Windows: Possible workaround for logarithmic slowdown for Encrypt-In-Place on large volumes (relates to #1063)
We replace absolute file pointer moving by relative moving with respect to current position. This was implemented as a workaround to address the performance issues related to in-place encryption. When using SetFilePointerEx() with FILE_BEGIN as the reference point, reaching the end of large drives during in-place encryption can cause significant slowdowns. By moving the file pointer relatively, these performance issues are mitigated.
-rw-r--r--src/Format/InPlace.c72
-rw-r--r--src/Format/InPlace.h1
2 files changed, 52 insertions, 21 deletions
diff --git a/src/Format/InPlace.c b/src/Format/InPlace.c
index f6166dab..4549cc53 100644
--- a/src/Format/InPlace.c
+++ b/src/Format/InPlace.c
@@ -592,9 +592,9 @@ int EncryptPartitionInPlaceBegin (volatile FORMAT_VOL_PARAMETERS *volParams, vol
goto closing_seq;
offset.QuadPart = TC_VOLUME_DATA_OFFSET + dataAreaSize;
- if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
+ if (!MoveFilePointer (dev, offset))
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
@@ -638,9 +638,9 @@ int EncryptPartitionInPlaceBegin (volatile FORMAT_VOL_PARAMETERS *volParams, vol
crypto_close (dummyInfo);
offset.QuadPart += TC_HIDDEN_VOLUME_HEADER_OFFSET;
- if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
+ if (!MoveFilePointer (dev, offset))
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
@@ -915,9 +915,9 @@ int EncryptPartitionInPlaceResume (HANDLE dev,
inplace_enc_read:
offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize - TC_VOLUME_DATA_OFFSET;
- if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
+ if (MoveFilePointer (dev, offset) == 0)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
@@ -1006,16 +1006,16 @@ inplace_enc_read:
EncryptDataUnits (wipeBuffer, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo);
memcpy (wipeRandCharsUpdate, wipeBuffer, sizeof (wipeRandCharsUpdate));
}
- if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
+ if (MoveFilePointer (dev, offset) == 0
|| WriteFile (dev, wipeBuffer, workChunkSize, &n, NULL) == 0)
{
// Write error
dwError = GetLastError();
// Undo failed write operation
- if (workChunkSize > TC_VOLUME_DATA_OFFSET && SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
+ if (workChunkSize > TC_VOLUME_DATA_OFFSET && MoveFilePointer (dev, offset))
{
DecryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo);
WriteFile (dev, buf + TC_VOLUME_DATA_OFFSET, workChunkSize - TC_VOLUME_DATA_OFFSET, &n, NULL);
}
@@ -1033,9 +1033,9 @@ inplace_enc_read:
// Write the ciphertext
offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize;
- if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
+ if (MoveFilePointer (dev, offset) == 0)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
@@ -1045,9 +1045,9 @@ inplace_enc_read:
// Write error
dwError = GetLastError();
// Undo failed write operation
- if (workChunkSize > TC_VOLUME_DATA_OFFSET && SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
+ if (workChunkSize > TC_VOLUME_DATA_OFFSET && MoveFilePointer (dev, offset))
{
DecryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo);
WriteFile (dev, buf + TC_VOLUME_DATA_OFFSET, workChunkSize - TC_VOLUME_DATA_OFFSET, &n, NULL);
}
@@ -1147,9 +1147,9 @@ inplace_enc_read:
offset.QuadPart = TC_VOLUME_HEADER_OFFSET;
- if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
+ if (MoveFilePointer (dev, offset) == 0
|| !WriteEffectiveVolumeHeader (TRUE, dev, (byte *) header))
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
@@ -1206,9 +1206,9 @@ inplace_enc_read:
crypto_close (dummyInfo);
offset.QuadPart += TC_HIDDEN_VOLUME_HEADER_OFFSET;
- if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
+ if (MoveFilePointer (dev, offset) == 0
|| !WriteEffectiveVolumeHeader (TRUE, dev, (byte *) header))
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
@@ -1543,9 +1543,9 @@ int DecryptPartitionInPlace (volatile FORMAT_VOL_PARAMETERS *volParams, volatile
// Read the ciphertext into RAM
offset.QuadPart = workChunkStartByteOffset;
- if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
+ if (MoveFilePointer (dev, offset) == 0)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
@@ -1577,9 +1577,9 @@ int DecryptPartitionInPlace (volatile FORMAT_VOL_PARAMETERS *volParams, volatile
tmpSectorOffset.QuadPart = offset.QuadPart;
for (tmpSectorCount = workChunkSize / sectorSize; tmpSectorCount > 0; --tmpSectorCount)
{
- if (SetFilePointerEx (dev, tmpSectorOffset, NULL, FILE_BEGIN) == 0)
+ if (MoveFilePointer (dev, tmpSectorOffset) == 0)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
@@ -1639,9 +1639,9 @@ int DecryptPartitionInPlace (volatile FORMAT_VOL_PARAMETERS *volParams, volatile
// Write the plaintext
offset.QuadPart = workChunkStartByteOffset - TC_VOLUME_DATA_OFFSET;
- if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
+ if (MoveFilePointer (dev, offset) == 0)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
@@ -1723,9 +1723,9 @@ int DecryptPartitionInPlace (volatile FORMAT_VOL_PARAMETERS *volParams, volatile
for (offset.QuadPart = masterCryptoInfo->VolumeSize.Value;
offset.QuadPart <= deviceSize - sectorSize;
offset.QuadPart += sectorSize)
{
- if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
+ if (MoveFilePointer (dev, offset) == 0)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
@@ -1863,9 +1863,9 @@ int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_IN
fieldPos = (byte *) header + TC_HEADER_OFFSET_ENCRYPTED_AREA_START;
offset.QuadPart = deviceSize - TC_VOLUME_HEADER_GROUP_SIZE;
- if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
+ if (MoveFilePointer (dev, offset) == 0
|| !ReadEffectiveVolumeHeader (TRUE, dev, header, &n) || n < TC_VOLUME_HEADER_EFFECTIVE_SIZE)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
@@ -1912,9 +1912,9 @@ int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_IN
EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, pCryptoInfo);
- if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
+ if (MoveFilePointer (dev, offset) == 0
|| !WriteEffectiveVolumeHeader (TRUE, dev, header))
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
@@ -2091,9 +2091,9 @@ static int ConcealNTFS (HANDLE dev)
DWORD dwError;
offset.QuadPart = 0;
- if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
+ if (MoveFilePointer (dev, offset) == 0)
return ERR_OS_ERROR;
if (ReadFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed, NULL) == 0)
return ERR_OS_ERROR;
@@ -2102,9 +2102,9 @@ static int ConcealNTFS (HANDLE dev)
buf[i] ^= TC_NTFS_CONCEAL_CONSTANT;
offset.QuadPart = 0;
- if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
+ if (MoveFilePointer (dev, offset) == 0)
return ERR_OS_ERROR;
if (WriteFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed, NULL) == 0)
{
@@ -2121,9 +2121,9 @@ static int ConcealNTFS (HANDLE dev)
do
{
Sleep (1);
}
- while (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
+ while (MoveFilePointer (dev, offset) == 0
|| WriteFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed2, NULL) == 0);
SetLastError (dwError);
@@ -2197,8 +2197,37 @@ BOOL SaveNonSysInPlaceEncSettings (int delta, WipeAlgorithmId newWipeAlgorithm,
return SaveBufferToFile (str, GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC), (DWORD) strlen(str), FALSE, FALSE);
}
+// This function moves the file pointer to the given offset. It first retrieves the current
+// file position using SetFilePointerEx() with FILE_CURRENT as the reference point, and then
+// calculates the difference between the current position and the desired position. Subsequently,
+// it moves the file pointer by the difference calculated using SetFilePointerEx() again.
+//
+// This approach of moving the file pointer relatively (instead of absolutely) was implemented
+// as a workaround to address the performance issues related to in-place encryption. When using
+// SetFilePointerEx() with FILE_BEGIN as the reference point, reaching the end of large drives
+// during in-place encryption can cause significant slowdowns. By moving the file pointer
+// relatively, these performance issues are mitigated.
+BOOL MoveFilePointer (HANDLE dev, LARGE_INTEGER offset)
+{
+ LARGE_INTEGER currOffset;
+ LARGE_INTEGER diffOffset;
+
+ currOffset.QuadPart = 0;
+ if (SetFilePointerEx (dev, currOffset, &currOffset, FILE_CURRENT) == 0)
+ return FALSE;
+
+ diffOffset.QuadPart = offset.QuadPart - currOffset.QuadPart;
+ if (diffOffset.QuadPart == 0)
+ return TRUE;
+
+ // Moves the file pointer by the difference between current and desired positions
+ if (SetFilePointerEx (dev, diffOffset, NULL, FILE_CURRENT) == 0)
+ return FALSE;
+
+ return TRUE;
+}
// Repairs damaged sectors (i.e. those with read errors) by zeroing them.
// Note that this operating fails if there are any write errors.
int ZeroUnreadableSectors (HANDLE dev, LARGE_INTEGER startOffset, int64 size, int sectorSize, uint64 *zeroedSectorCount)
@@ -2216,9 +2245,9 @@ int ZeroUnreadableSectors (HANDLE dev, LARGE_INTEGER startOffset, int64 size, in
if (!sectorBuffer)
return ERR_OUTOFMEMORY;
- if (SetFilePointerEx (dev, startOffset, NULL, FILE_BEGIN) == 0)
+ if (!MoveFilePointer(dev, workOffset))
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
@@ -2229,9 +2258,10 @@ int ZeroUnreadableSectors (HANDLE dev, LARGE_INTEGER startOffset, int64 size, in
if (ReadFile (dev, sectorBuffer, sectorSize, &n, NULL) == 0)
{
memset (sectorBuffer, 0, sectorSize);
- if (SetFilePointerEx (dev, workOffset, NULL, FILE_BEGIN) == 0)
+ // If ReadFile failed, move back to start of the unreadable sector
+ if (MoveFilePointer (dev, workOffset) == 0)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
@@ -2280,9 +2310,9 @@ static int OpenBackupHeader (HANDLE dev, const wchar_t *devicePath, Password *pa
offset.QuadPart = deviceSize - TC_VOLUME_HEADER_GROUP_SIZE;
- if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
+ if (MoveFilePointer (dev, offset) == 0
|| !ReadEffectiveVolumeHeader (TRUE, dev, (byte *) header, &n) || n < TC_VOLUME_HEADER_EFFECTIVE_SIZE)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
diff --git a/src/Format/InPlace.h b/src/Format/InPlace.h
index 717a8ed3..f2d97bed 100644
--- a/src/Format/InPlace.h
+++ b/src/Format/InPlace.h
@@ -42,8 +42,9 @@ static HANDLE OpenPartitionVolume (HWND hwndDlg, const wchar_t *devName, BOOL bE
static int DismountFileSystem (HWND hwndDlg, HANDLE dev, int driveLetter, BOOL bForcedAllowed, BOOL bForcedRequiresConfirmation, BOOL bSilent);
static int ConcealNTFS (HANDLE dev);
BOOL SaveNonSysInPlaceEncSettings (int delta, WipeAlgorithmId wipeAlgorithm, BOOL bDecrypting);
static void ExportProgressStats (__int64 bytesDone, __int64 totalSize);
+BOOL MoveFilePointer (HANDLE dev, LARGE_INTEGER offset);
int ZeroUnreadableSectors (HANDLE dev, LARGE_INTEGER startOffset, int64 size, int sectorSize, uint64 *zeroedSectorCount);
static int OpenBackupHeader (HANDLE dev, const wchar_t *devicePath, Password *password, int pkcs5, int pim, PCRYPTO_INFO *retCryptoInfo, CRYPTO_INFO *headerCryptoInfo, __int64 deviceSize);
BOOL MoveClustersBeforeThreshold (HANDLE volumeHandle, PWSTR volumeDevicePath, int64 clusterThreshold);