📄 inplace.c
字号:
if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545)
{
nStatus = ERR_PARAMETER_INCORRECT;
goto closing_seq;
}
mputInt64 (fieldPos, (masterCryptoInfo->EncryptedAreaStart.Value));
mputInt64 (fieldPos, (masterCryptoInfo->EncryptedAreaLength.Value));
headerCrc32 = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
fieldPos = (byte *) header + TC_HEADER_OFFSET_HEADER_CRC;
mputLong (fieldPos, headerCrc32);
EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
|| WriteFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
closing_seq:
dwError = GetLastError();
burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
TCfree (header);
if (nStatus != ERR_SUCCESS)
SetLastError (dwError);
return nStatus;
}
static HANDLE OpenPartitionVolume (const char *devName,
BOOL bExclusiveRequired,
BOOL bSharedRequired,
BOOL bSharedRequiresConfirmation,
BOOL bShowAlternativeSteps,
BOOL bSilent)
{
HANDLE dev = INVALID_HANDLE_VALUE;
int retryCount = 0;
if (bExclusiveRequired)
bSharedRequired = FALSE;
if (bExclusiveRequired || !bSharedRequired)
{
// Exclusive access
// Note that when exclusive access is denied, it is worth retrying (usually succeeds after a few tries).
while (dev == INVALID_HANDLE_VALUE && retryCount++ < EXCL_ACCESS_MAX_AUTO_RETRIES)
{
dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL);
if (retryCount > 1)
Sleep (EXCL_ACCESS_AUTO_RETRY_DELAY);
}
}
if (dev == INVALID_HANDLE_VALUE)
{
if (bExclusiveRequired)
{
if (!bSilent)
{
handleWin32Error (MainDlg);
if (bShowAlternativeSteps)
ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE);
else
Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL");
}
return INVALID_HANDLE_VALUE;
}
// Shared mode
dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL);
if (dev != INVALID_HANDLE_VALUE)
{
if (bSharedRequiresConfirmation
&& !bSilent
&& AskWarnNoYes ("DEVICE_IN_USE_INPLACE_ENC") == IDNO)
{
CloseHandle (dev);
return INVALID_HANDLE_VALUE;
}
}
else
{
if (!bSilent)
{
handleWin32Error (MainDlg);
if (bShowAlternativeSteps)
ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE);
else
Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL");
}
return INVALID_HANDLE_VALUE;
}
}
return dev;
}
static int DismountFileSystem (HANDLE dev,
int driveLetter,
BOOL bForcedAllowed,
BOOL bForcedRequiresConfirmation,
BOOL bSilent)
{
int attempt;
BOOL bResult;
DWORD dwResult;
CloseVolumeExplorerWindows (MainDlg, driveLetter);
attempt = UNMOUNT_MAX_AUTO_RETRIES * 10;
while (!(bResult = DeviceIoControl (dev, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL))
&& attempt > 0)
{
Sleep (UNMOUNT_AUTO_RETRY_DELAY);
attempt--;
}
if (!bResult)
{
if (!bForcedAllowed)
{
if (!bSilent)
ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_LOCK_OR_DISMOUNT_FILESYS", TRUE);
return ERR_DONT_REPORT;
}
if (bForcedRequiresConfirmation
&& !bSilent
&& AskWarnYesNo ("VOL_LOCK_FAILED_OFFER_FORCED_DISMOUNT") == IDNO)
{
return ERR_DONT_REPORT;
}
}
// Dismount the volume
attempt = UNMOUNT_MAX_AUTO_RETRIES * 10;
while (!(bResult = DeviceIoControl (dev, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL))
&& attempt > 0)
{
Sleep (UNMOUNT_AUTO_RETRY_DELAY);
attempt--;
}
if (!bResult)
{
if (!bSilent)
ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_LOCK_OR_DISMOUNT_FILESYS", TRUE);
return ERR_DONT_REPORT;
}
return ERR_SUCCESS;
}
// Easy-to-undo modification applied to conceal the NTFS filesystem (to prevent Windows and apps from
// interfering with it until the volume has been fully encrypted). Note that this function will precisely
// undo any modifications it made to the filesystem automatically if an error occurs when writing (including
// physical drive defects).
static int ConcealNTFS (HANDLE dev)
{
char buf [TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE];
DWORD nbrBytesProcessed, nbrBytesProcessed2;
int i;
LARGE_INTEGER offset;
DWORD dwError;
offset.QuadPart = 0;
if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
return ERR_OS_ERROR;
if (ReadFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed, NULL) == 0)
return ERR_OS_ERROR;
for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE; i++)
buf[i] ^= TC_NTFS_CONCEAL_CONSTANT;
offset.QuadPart = 0;
if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
return ERR_OS_ERROR;
if (WriteFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed, NULL) == 0)
{
// One or more of the sectors is/are probably damaged and cause write errors.
// We must undo the modifications we made.
dwError = GetLastError();
for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE; i++)
buf[i] ^= TC_NTFS_CONCEAL_CONSTANT;
offset.QuadPart = 0;
do
{
Sleep (1);
}
while (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
|| WriteFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed2, NULL) == 0);
SetLastError (dwError);
return ERR_OS_ERROR;
}
return ERR_SUCCESS;
}
void ShowInPlaceEncErrMsgWAltSteps (char *iniStrId, BOOL bErr)
{
wchar_t msg[30000];
wcscpy (msg, GetString (iniStrId));
wcscat (msg, L"\n\n\n");
wcscat (msg, GetString ("INPLACE_ENC_ALTERNATIVE_STEPS"));
if (bErr)
ErrorDirect (msg);
else
WarningDirect (msg);
}
static void ExportProgressStats (__int64 bytesDone, __int64 totalSectors)
{
NonSysInplaceEncBytesDone = bytesDone;
NonSysInplaceEncTotalSectors = totalSectors;
}
void SetNonSysInplaceEncUIStatus (int nonSysInplaceEncStatus)
{
NonSysInplaceEncStatus = nonSysInplaceEncStatus;
}
BOOL SaveNonSysInPlaceEncSettings (int delta, WipeAlgorithmId newWipeAlgorithm)
{
int count;
char str[32];
WipeAlgorithmId savedWipeAlgorithm = TC_WIPE_NONE;
if (delta == 0)
return TRUE;
count = LoadNonSysInPlaceEncSettings (&savedWipeAlgorithm) + delta;
if (count < 1)
{
if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC)))
remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC));
if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE)))
remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE));
if (!IsNonInstallMode () && SystemEncryptionStatus == SYSENC_STATUS_NONE)
ManageStartupSeqWiz (TRUE, "");
return TRUE;
}
else
{
if (newWipeAlgorithm != TC_WIPE_NONE)
{
sprintf (str, "%d", (int) newWipeAlgorithm);
SaveBufferToFile (str, GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE), strlen(str), FALSE);
}
else if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE)))
{
remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE));
}
sprintf (str, "%d", count);
return SaveBufferToFile (str, GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC), strlen(str), FALSE);
}
}
// 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)
{
int nStatus;
DWORD n;
int64 sectorCount;
LARGE_INTEGER workOffset;
byte *sectorBuffer = NULL;
DWORD dwError;
workOffset.QuadPart = startOffset.QuadPart;
sectorBuffer = (byte *) TCalloc (sectorSize);
if (!sectorBuffer)
return ERR_OUTOFMEMORY;
if (SetFilePointerEx (dev, startOffset, NULL, FILE_BEGIN) == 0)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount)
{
if (ReadFile (dev, sectorBuffer, sectorSize, &n, NULL) == 0)
{
memset (sectorBuffer, 0, sectorSize);
if (SetFilePointerEx (dev, workOffset, NULL, FILE_BEGIN) == 0)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
if (WriteFile (dev, sectorBuffer, sectorSize, &n, NULL) == 0)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
++(*zeroedSectorCount);
}
workOffset.QuadPart += n;
}
nStatus = ERR_SUCCESS;
closing_seq:
dwError = GetLastError();
if (sectorBuffer != NULL)
TCfree (sectorBuffer);
if (nStatus != ERR_SUCCESS)
SetLastError (dwError);
return nStatus;
}
static int OpenBackupHeader (HANDLE dev, const char *devicePath, Password *password, PCRYPTO_INFO *retMasterCryptoInfo, CRYPTO_INFO *headerCryptoInfo, __int64 deviceSize)
{
LARGE_INTEGER offset;
DWORD n;
int nStatus = ERR_SUCCESS;
char *header;
DWORD dwError;
header = (char *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE);
if (!header)
return ERR_OUTOFMEMORY;
VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
offset.QuadPart = deviceSize - TC_VOLUME_HEADER_GROUP_SIZE;
if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
|| ReadFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0)
{
nStatus = ERR_OS_ERROR;
goto closing_seq;
}
nStatus = ReadVolumeHeader (FALSE, header, password, retMasterCryptoInfo, headerCryptoInfo);
if (nStatus != ERR_SUCCESS)
goto closing_seq;
closing_seq:
dwError = GetLastError();
burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
TCfree (header);
dwError = GetLastError();
if (nStatus != ERR_SUCCESS)
SetLastError (dwError);
return nStatus;
}
static BOOL GetFreeClusterBeforeThreshold (HANDLE volumeHandle, int64 *freeCluster, int64 clusterThreshold)
{
const int bitmapSize = 65536;
byte bitmapBuffer[bitmapSize + sizeof (VOLUME_BITMAP_BUFFER)];
VOLUME_BITMAP_BUFFER *bitmap = (VOLUME_BITMAP_BUFFER *) bitmapBuffer;
STARTING_LCN_INPUT_BUFFER startLcn;
startLcn.StartingLcn.QuadPart = 0;
DWORD bytesReturned;
while (DeviceIoControl (volumeHandle, FSCTL_GET_VOLUME_BITMAP, &startLcn, sizeof (startLcn), &bitmapBuffer, sizeof (bitmapBuffer), &bytesReturned, NULL)
|| GetLastError() == ERROR_MORE_DATA)
{
for (int64 bitmapIndex = 0; bitmapIndex < min (bitmapSize, (bitmap->BitmapSize.QuadPart / 8)); ++bitmapIndex)
{
if (bitmap->StartingLcn.QuadPart + bitmapIndex * 8 >= clusterThreshold)
goto err;
if (bitmap->Buffer[bitmapIndex] != 0xff)
{
for (int bit = 0; bit < 8; ++bit)
{
if ((bitmap->Buffer[bitmapIndex] & (1 << bit)) == 0)
{
*freeCluster = bitmap->StartingLcn.QuadPart + bitmapIndex * 8 + bit;
if (*freeCluster >= clusterThreshold)
goto err;
return TRUE;
}
}
}
}
startLcn.StartingLcn.QuadPart += min (bitmapSize * 8, bitmap->BitmapSize.QuadPart);
}
err:
SetLastError (ERROR_DISK_FULL);
return FALSE;
}
static BOOL MoveClustersBeforeThresholdInDir (HANDLE volumeHandle, const wstring &directory, int64 clusterThreshold)
{
WIN32_FIND_DATAW findData;
HANDLE findHandle = FindFirstFileW (((directory.size() <= 3 ? L"" : L"\\\\?\\") + directory + L"\\*").c_str(), &findData);
if (findHandle == INVALID_HANDLE_VALUE)
return TRUE; // Error ignored
finally_do_arg (HANDLE, findHandle, { FindClose (finally_arg); });
// Find all files and directories
do
{
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
wstring subDir = findData.cFileName;
if (subDir == L"." || subDir == L"..")
continue;
if (!MoveClustersBeforeThresholdInDir (volumeHandle, directory + L"\\" + subDir, clusterThreshold))
return FALSE;
}
DWORD access = FILE_READ_ATTRIBUTES;
if (findData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)
access = FILE_READ_DATA;
HANDLE fsObject = CreateFileW ((directory + L"\\" + findData.cFileName).c_str(), access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (fsObject == INVALID_HANDLE_VALUE)
continue;
finally_do_arg (HANDLE, fsObject, { CloseHandle (finally_arg); });
STARTING_VCN_INPUT_BUFFER startVcn;
startVcn.StartingVcn.QuadPart = 0;
RETRIEVAL_POINTERS_BUFFER retPointers;
DWORD bytesReturned;
// Find clusters allocated beyond the threshold
while (DeviceIoControl (fsObject, FSCTL_GET_RETRIEVAL_POINTERS, &startVcn, sizeof (startVcn), &retPointers, sizeof (retPointers), &bytesReturned, NULL)
|| GetLastError() == ERROR_MORE_DATA)
{
if (retPointers.ExtentCount == 0)
break;
if (retPointers.Extents[0].Lcn.QuadPart != -1)
{
int64 extentStartCluster = retPointers.Extents[0].Lcn.QuadPart;
int64 extentLen = retPointers.Extents[0].NextVcn.QuadPart - retPointers.StartingVcn.QuadPart;
int64 extentEndCluster = extentStartCluster + extentLen - 1;
if (extentEndCluster >= clusterThreshold)
{
// Move clusters before the threshold
for (int64 movedCluster = max (extentStartCluster, clusterThreshold); movedCluster <= extentEndCluster; ++movedCluster)
{
for (int retry = 0; ; ++retry)
{
MOVE_FILE_DATA moveData;
if (GetFreeClusterBeforeThreshold (volumeHandle, &moveData.StartingLcn.QuadPart, clusterThreshold))
{
moveData.FileHandle = fsObject;
moveData.StartingVcn.QuadPart = movedCluster - extentStartCluster + retPointers.StartingVcn.QuadPart;
moveData.ClusterCount = 1;
if (DeviceIoControl (volumeHandle, FSCTL_MOVE_FILE, &moveData, sizeof (moveData), NULL, 0, &bytesReturned, NULL))
break;
}
if (retry > 200)
return FALSE;
// There are possible race conditions as we work on a live filesystem
Sleep (100);
}
}
}
}
startVcn.StartingVcn = retPointers.Extents[0].NextVcn;
}
} while (FindNextFileW (findHandle, &findData));
return TRUE;
}
BOOL MoveClustersBeforeThreshold (HANDLE volumeHandle, PWSTR volumeDevicePath, int64 clusterThreshold)
{
int drive = GetDiskDeviceDriveLetter (volumeDevicePath);
if (drive == -1)
{
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
wstring volumeRoot = L"X:";
volumeRoot[0] = L'A' + drive;
return MoveClustersBeforeThresholdInDir (volumeHandle, volumeRoot, clusterThreshold);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -