Utils: Add env to disable special win32 code

Change-Id: I450152a4d049461b98416fa61a9a1e7082625ecc
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
Marcus Tillmanns
2024-09-12 14:00:07 +02:00
parent 3c384b61b3
commit 0e9038ff62

View File

@@ -129,86 +129,90 @@ bool SaveFile::commit()
FilePath finalFileName = m_finalFilePath.resolveSymlinks(); FilePath finalFileName = m_finalFilePath.resolveSymlinks();
if constexpr (HostOsInfo::isWindowsHost() && !m_finalFilePath.needsDevice()) { if constexpr (HostOsInfo::isWindowsHost()) {
// Release the file lock static const bool disableWinSpecialCode = !qEnvironmentVariableIsEmpty(
m_tempFile.reset(); "QTC_DISABLE_SPECIAL_WIN_SAVEFILE");
bool result = ReplaceFile( if (!m_finalFilePath.needsDevice() && !disableWinSpecialCode) {
finalFileName.nativePath().toStdWString().data(), // Release the file lock
fileName().toStdWString().data(), m_tempFile.reset();
nullptr, bool result = ReplaceFile(
REPLACEFILE_IGNORE_MERGE_ERRORS, finalFileName.nativePath().toStdWString().data(),
nullptr, fileName().toStdWString().data(),
nullptr); nullptr,
if (!result) { REPLACEFILE_IGNORE_MERGE_ERRORS,
DWORD replaceErrorCode = GetLastError(); nullptr,
QString errorStr; nullptr);
if (!finalFileName.exists()) { if (!result) {
// Replace failed because finalFileName does not exist, try rename. DWORD replaceErrorCode = GetLastError();
if (!(result = rename(finalFileName.toFSPathString()))) QString errorStr;
errorStr = errorString(); if (!finalFileName.exists()) {
} else { // Replace failed because finalFileName does not exist, try rename.
if (replaceErrorCode == ERROR_UNABLE_TO_REMOVE_REPLACED) { if (!(result = rename(finalFileName.toFSPathString())))
// If we do not get the rights to remove the original final file we still might try errorStr = errorString();
// to replace the file contents } else {
result = MoveFileEx( if (replaceErrorCode == ERROR_UNABLE_TO_REMOVE_REPLACED) {
fileName().toStdWString().data(), // If we do not get the rights to remove the original final file we still might try
finalFileName.nativePath().toStdWString().data(), // to replace the file contents
MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH); result = MoveFileEx(
if (!result) fileName().toStdWString().data(),
replaceErrorCode = GetLastError(); finalFileName.nativePath().toStdWString().data(),
MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH);
if (!result)
replaceErrorCode = GetLastError();
}
if (!result) {
wchar_t messageBuffer[256];
FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
replaceErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
messageBuffer,
sizeof(messageBuffer),
nullptr);
errorStr = QString::fromWCharArray(messageBuffer);
}
} }
if (!result) { if (!result) {
wchar_t messageBuffer[256]; remove();
FormatMessageW( setErrorString(errorStr);
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
replaceErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
messageBuffer,
sizeof(messageBuffer),
nullptr);
errorStr = QString::fromWCharArray(messageBuffer);
} }
} }
if (!result) {
remove(); return result;
setErrorString(errorStr);
}
} }
return result;
} else {
const QString backupName = finalFileName.toFSPathString() + '~';
// Back up current file.
// If it's opened by another application, the lock follows the move.
if (finalFileName.exists()) {
// Kill old backup. Might be useful if creator crashed before removing backup.
QFile::remove(backupName);
QFile finalFile(finalFileName.toFSPathString());
if (!finalFile.rename(backupName)) {
m_tempFile->filePath().removeFile();
setErrorString(finalFile.errorString());
return false;
}
}
expected_str<void> renameResult = m_tempFile->filePath().renameFile(finalFileName);
if (!renameResult) {
// The case when someone else was able to create finalFileName after we've renamed it.
// Higher level call may try to save this file again but here we do nothing and
// return false while keeping the error string from last rename call.
m_tempFile->filePath().removeFile();
setErrorString(renameResult.error());
QFile::rename(
backupName, finalFileName.toFSPathString()); // rollback to backup if possible ...
return false; // ... or keep the backup copy at least
}
QFile::remove(backupName);
return true;
} }
const QString backupName = finalFileName.toFSPathString() + '~';
// Back up current file.
// If it's opened by another application, the lock follows the move.
if (finalFileName.exists()) {
// Kill old backup. Might be useful if creator crashed before removing backup.
QFile::remove(backupName);
QFile finalFile(finalFileName.toFSPathString());
if (!finalFile.rename(backupName)) {
m_tempFile->filePath().removeFile();
setErrorString(finalFile.errorString());
return false;
}
}
expected_str<void> renameResult = m_tempFile->filePath().renameFile(finalFileName);
if (!renameResult) {
// The case when someone else was able to create finalFileName after we've renamed it.
// Higher level call may try to save this file again but here we do nothing and
// return false while keeping the error string from last rename call.
m_tempFile->filePath().removeFile();
setErrorString(renameResult.error());
QFile::rename(backupName, finalFileName.toFSPathString()); // rollback to backup if possible ...
return false; // ... or keep the backup copy at least
}
QFile::remove(backupName);
return true;
} }
void SaveFile::initializeUmask() void SaveFile::initializeUmask()