From 5035e7b5fb9a0c08dd10658ef0581c9a3d2c000a Mon Sep 17 00:00:00 2001 From: Mathew Sutcliffe Date: Fri, 4 Nov 2016 01:24:19 +0000 Subject: [PATCH] refs #782 CAtomicFile on Windows: flush buffer before attempting to rename, and use ReplaceFile to rename if target already exists. --- src/blackmisc/atomicfile.cpp | 12 ++++++++++-- src/blackmisc/atomicfile.h | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/blackmisc/atomicfile.cpp b/src/blackmisc/atomicfile.cpp index b28bda36f..d94018919 100644 --- a/src/blackmisc/atomicfile.cpp +++ b/src/blackmisc/atomicfile.cpp @@ -21,6 +21,7 @@ #include #elif defined(Q_OS_WIN32) #include +#include #endif //! \var qt_ntfs_permission_lookup @@ -73,6 +74,10 @@ namespace BlackMisc { if (! isOpen()) { return; } +#if defined(Q_OS_WIN32) + FlushFileBuffers(reinterpret_cast(_get_osfhandle(handle()))); +#endif + QFile::close(); if (error() == NoError) { replaceOriginal(); } @@ -135,13 +140,16 @@ namespace BlackMisc const auto prefix = "\\\\?\\"; // support long paths: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath return (prefix + QDir::toNativeSeparators(QDir::cleanPath(QFileInfo(s).absoluteFilePath()))).toStdWString(); }; - auto result = MoveFileEx(encode(fileName()).c_str(), encode(m_originalFilename).c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH); + auto replace = exists(m_originalFilename); + auto result = replace + ? ReplaceFile(encode(m_originalFilename).c_str(), encode(fileName()).c_str(), nullptr, REPLACEFILE_IGNORE_MERGE_ERRORS, nullptr, nullptr) + : MoveFileEx(encode(fileName()).c_str(), encode(m_originalFilename).c_str(), MOVEFILE_WRITE_THROUGH); if (! result) { m_renameError = true; wchar_t *s = nullptr; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 0, reinterpret_cast(&s), 0, nullptr); - setErrorString(QString::fromWCharArray(s).simplified()); + setErrorString((replace ? "ReplaceFile: " : "MoveFileEx: ") + QString::fromWCharArray(s).simplified()); LocalFree(reinterpret_cast(s)); } } diff --git a/src/blackmisc/atomicfile.h b/src/blackmisc/atomicfile.h index 126cbd86e..d7b467d6c 100644 --- a/src/blackmisc/atomicfile.h +++ b/src/blackmisc/atomicfile.h @@ -27,6 +27,8 @@ namespace BlackMisc * when it is closed, so that it overwrites the target file as a single, atomic transaction. * * If the application crashes while data is still being written, the original file is unchanged. + * + * \fixme Consider using QSaveFile. */ class BLACKMISC_EXPORT CAtomicFile : public QFile {