diff options
author | Mounir IDRASSI <mounir.idrassi@idrix.fr> | 2023-06-04 16:25:55 +0200 |
---|---|---|
committer | Mounir IDRASSI <mounir.idrassi@idrix.fr> | 2023-06-04 16:25:55 +0200 |
commit | 22466535f1b9cbe1bd98363cfa98f7f796bc408a (patch) | |
tree | 7ee1c59af8e16b57953a86f8837fe465e418f60a | |
parent | 3c68349a39877c5420c727cd53143ab442963759 (diff) | |
download | VeraCrypt-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.c | 72 | ||||
-rw-r--r-- | src/Format/InPlace.h | 1 |
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); |