11 #include <QStringBuilder>
15 #if defined(Q_OS_POSIX)
18 #elif defined(Q_OS_WIN32)
26 extern Q_CORE_EXPORT
int qt_ntfs_permission_lookup;
28 int qt_ntfs_permission_lookup = 0;
34 bool checkPermissions(CAtomicFile::OpenMode mode,
const QFileInfo &fileInfo)
37 qt_ntfs_permission_lookup++;
38 if ((mode & CAtomicFile::ReadOnly) && !fileInfo.isReadable()) { ok =
false; }
39 if ((mode & CAtomicFile::WriteOnly) && !fileInfo.isWritable()) { ok =
false; }
40 qt_ntfs_permission_lookup--;
46 m_originalFilename = fileName();
47 QFileInfo fileInfo(fileName());
48 if (exists() && !checkPermissions(mode, fileInfo))
50 m_permissionError =
true;
51 setErrorString(
"Wrong permissions");
54 setFileName(QFileInfo(fileInfo.dir(),
".tmp." + fileInfo.fileName() +
"." + randomSuffix()).filePath());
55 if (exists()) { remove(); }
60 if (exists(m_originalFilename) && !copy(m_originalFilename, fileName())) { ok =
false; }
63 if (ok && !QFile::open(mode)) { ok =
false; }
64 if (!ok) { setFileName(m_originalFilename); }
70 if (std::uncaught_exceptions() > 0) { QFile::close(); }
75 if (!isOpen()) {
return; }
77 #if defined(Q_OS_WIN32)
78 FlushFileBuffers(
reinterpret_cast<HANDLE
>(_get_osfhandle(handle())));
83 if (
error() == NoError) { replaceOriginal(); }
84 setFileName(m_originalFilename);
90 return error() == NoError;
95 if (!isOpen()) {
return; }
99 setFileName(m_originalFilename);
104 if (m_renameError) {
return RenameError; }
105 if (m_permissionError) {
return PermissionsError; }
106 return QFile::error();
111 m_renameError =
false;
112 m_permissionError =
false;
116 QString CAtomicFile::randomSuffix()
118 constexpr
auto max = 2176782335;
119 return QStringLiteral(
"%1").arg(
120 std::uniform_int_distribution<std::decay_t<decltype(max)>>(0, max)(private_ns::defaultRandomGenerator()), 6,
124 #if defined(Q_OS_POSIX)
125 void CAtomicFile::replaceOriginal()
127 auto result = ::rename(qPrintable(fileName()), qPrintable(m_originalFilename));
130 m_renameError =
true;
132 auto x = strerror_r(errno, s,
sizeof(s));
133 setErrorString(QString::fromLocal8Bit(s));
134 static_assert(std::is_same_v<decltype(x),
int>,
135 "Non-standard signature of POSIX function strerror_r, check documentation.");
138 #elif defined(Q_OS_WIN32)
139 void CAtomicFile::replaceOriginal()
141 auto encode = [](
const QString &s) {
145 return (prefix + QDir::toNativeSeparators(QDir::cleanPath(QFileInfo(s).absoluteFilePath()))).toStdWString();
147 auto replace = exists(m_originalFilename);
148 auto result = replace ? ReplaceFile(encode(m_originalFilename).c_str(), encode(fileName()).c_str(),
nullptr,
149 REPLACEFILE_IGNORE_MERGE_ERRORS,
nullptr,
nullptr) :
150 MoveFileEx(encode(fileName()).c_str(), encode(m_originalFilename).c_str(),
151 MOVEFILE_WRITE_THROUGH);
154 wchar_t *s =
nullptr;
155 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
nullptr, GetLastError(), 0,
156 reinterpret_cast<LPWSTR
>(&s), 0,
nullptr);
157 const QString windowsError =
158 (replace ? u
"ReplaceFile: " : u
"MoveFileEx: ") % QString::fromWCharArray(s).simplified();
159 LocalFree(
reinterpret_cast<HLOCAL
>(s));
162 if (exists(m_originalFilename))
164 QFile old(m_originalFilename);
168 m_renameError =
true;
169 setErrorString(windowsError % u
" QFile::remove: " % old.errorString());
173 rename(m_originalFilename);
177 void CAtomicFile::replaceOriginal()
179 if (exists(m_originalFilename)) { remove(m_originalFilename); }
180 rename(m_originalFilename);
virtual bool open(OpenMode mode)
bool checkedClose()
Calls close() and returns false if there was an error at any stage.
void abandon()
Closes the file without renaming it.
Free functions in swift::misc.