Windows: better workaround for cases where ERROR_INVALID_PARAMETER is returned during system encryption which is due to 4096-bytes alignment of disk.

This commit is contained in:
Mounir IDRASSI 2017-07-20 00:52:03 +02:00
parent fe26ed8a5d
commit 3021745f67
No known key found for this signature in database
GPG Key ID: DD0C382D5FCFB8FC
2 changed files with 108 additions and 35 deletions

View File

@ -474,12 +474,12 @@ namespace VeraCrypt
#endif // SETUP
File::File (wstring path, bool readOnly, bool create, bool useNormalAttributes) : Elevated (false), FileOpen (false), ReadOnly (readOnly), LastError(0)
File::File (wstring path, bool readOnly, bool create) : Elevated (false), FileOpen (false), ReadOnly (readOnly), LastError(0)
{
Handle = CreateFile (path.c_str(),
readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, create ? CREATE_ALWAYS : OPEN_EXISTING,
useNormalAttributes? FILE_ATTRIBUTE_NORMAL : (FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_WRITE_THROUGH), NULL);
FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_WRITE_THROUGH, NULL);
if (Handle != INVALID_HANDLE_VALUE)
{
@ -530,7 +530,45 @@ namespace VeraCrypt
return bytesRead;
}
throw_sys_if (!ReadFile (Handle, buffer, size, &bytesRead, NULL));
if (!ReadFile (Handle, buffer, size, &bytesRead, NULL))
{
DWORD dwLastError = GetLastError();
if ((dwLastError == ERROR_INVALID_PARAMETER) && IsDevice && (size % 4096))
{
DWORD remainingSize = (size % 4096);
DWORD alignedSize = size - remainingSize;
LARGE_INTEGER offset;
if (alignedSize)
{
if (ReadFile (Handle, buffer, alignedSize, &bytesRead, NULL))
{
if (bytesRead < alignedSize)
return bytesRead;
buffer += alignedSize;
size -= alignedSize;
}
else
throw SystemException (SRC_POS);
}
if (ReadFile (Handle, ReadBuffer, 4096, &bytesRead, NULL))
{
DWORD effectiveSize = min (bytesRead, remainingSize);
memcpy (buffer, ReadBuffer, effectiveSize);
offset.QuadPart = - ((LONGLONG) bytesRead) + (LONGLONG) effectiveSize;
SetFilePointerEx (Handle, offset, NULL, FILE_CURRENT);
return alignedSize + effectiveSize;
}
else
throw SystemException (SRC_POS);
}
else
throw SystemException (SRC_POS);
}
return bytesRead;
}
@ -600,7 +638,63 @@ namespace VeraCrypt
}
else
{
throw_sys_if (!WriteFile (Handle, buffer, size, &bytesWritten, NULL) || bytesWritten != size);
if (!WriteFile (Handle, buffer, size, &bytesWritten, NULL))
{
DWORD dwLastError = GetLastError ();
if ((ERROR_INVALID_PARAMETER == dwLastError) && IsDevice && !ReadOnly && (size % 4096))
{
bool bSuccess = false;
DWORD remainingSize = (size % 4096);
DWORD alignedSize = size - remainingSize;
DWORD bytesRead = 0;
bytesWritten = 0;
if (alignedSize)
{
if (WriteFile (Handle, buffer, alignedSize, &bytesWritten, NULL))
{
throw_sys_if (bytesWritten != alignedSize);
buffer += alignedSize;
size -= alignedSize;
}
else
{
bytesWritten = 0;
dwLastError = GetLastError ();
}
}
if (!alignedSize || (alignedSize && bytesWritten))
{
LARGE_INTEGER offset;
throw_sys_if (!ReadFile (Handle, ReadBuffer, 4096, &bytesRead, NULL) || (bytesRead != 4096));
offset.QuadPart = -4096;
throw_sys_if (!SetFilePointerEx (Handle, offset, NULL, FILE_CURRENT));
memcpy (ReadBuffer, buffer, remainingSize);
if (WriteFile (Handle, ReadBuffer, 4096, &bytesWritten, NULL))
{
throw_sys_if (bytesWritten != 4096);
bSuccess = true;
}
else
{
dwLastError = GetLastError ();
}
}
if (!bSuccess)
{
SetLastError (dwLastError);
throw SystemException (SRC_POS);
}
}
else
throw SystemException (SRC_POS);
}
else
throw_sys_if (bytesWritten != size);
}
}
catch (SystemException &e)
@ -2134,21 +2228,10 @@ namespace VeraCrypt
memcpy (fileContent.data(), "\xEF\xBB\xBF", 3);
memcpy (&fileContent[dwOffset], pbData, dwDataLen);
try
{
File f(pathESP + szFilePath, false, true);
f.Write(fileContent.data(), dwSize);
f.Close();
}
catch (SystemException &e)
{
if (e.ErrorCode != ERROR_INVALID_PARAMETER)
throw;
// try again with normal attributes
File f(pathESP + szFilePath, false, true, true);
f.Write(fileContent.data(), dwSize);
f.Close();
}
File f(pathESP + szFilePath, false, true);
f.Write(fileContent.data(), dwSize);
f.Close();
}
EfiBoot::EfiBoot() {
@ -2436,22 +2519,11 @@ namespace VeraCrypt
void EfiBoot::SaveFile(const wchar_t* name, byte* data, DWORD size) {
wstring path = EfiBootPartPath;
path += name;
try
{
File f(path, false, true);
f.Write(data, size);
f.Close();
}
catch (SystemException &e)
{
if (e.ErrorCode != ERROR_INVALID_PARAMETER)
throw;
// try again with normal attributes
File f(path, false, true, true);
f.Write(data, size);
f.Close();
}
File f(path, false, true);
f.Write(data, size);
f.Close();
}
void EfiBoot::GetFileSize(const wchar_t* name, unsigned __int64& size) {

View File

@ -37,7 +37,7 @@ namespace VeraCrypt
{
public:
File () : Elevated (false), FileOpen (false), ReadOnly (false), FilePointerPosition(0), Handle(INVALID_HANDLE_VALUE), IsDevice(false), LastError(0) { }
File (wstring path,bool readOnly = false, bool create = false, bool useNormalAttributes = false);
File (wstring path,bool readOnly = false, bool create = false);
virtual ~File () { Close(); }
void CheckOpened (const char* srcPos) { if (!FileOpen) { SetLastError (LastError); throw SystemException (srcPos);} }
@ -58,6 +58,7 @@ namespace VeraCrypt
bool IsDevice;
wstring Path;
DWORD LastError;
BYTE ReadBuffer[4096];
};