From 60612635ef844525ab683249963d86409e8f5490 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Feb 2020 18:54:16 +0400 Subject: [PATCH] Use QSaveFile to write sensitive settings / data. --- Telegram/SourceFiles/storage/localstorage.cpp | 99 ++++++++++--------- 1 file changed, 55 insertions(+), 44 deletions(-) diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 0ac58bec4..8d83f7bf1 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -41,6 +41,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "facades.h" #include +#include #include #include @@ -118,10 +119,18 @@ inline constexpr auto is_flag_type(FileOption) { return true; }; bool keyAlreadyUsed(QString &name, FileOptions options = FileOption::User | FileOption::Safe) { name += '0'; - if (QFileInfo(name).exists()) return true; + if (QFileInfo(name).exists()) { + return true; + } if (options & (FileOption::Safe)) { name[name.size() - 1] = '1'; - return QFileInfo(name).exists(); + if (QFileInfo(name).exists()) { + return true; + } + name[name.size() - 1] = 's'; + if (QFileInfo(name).exists()) { + return true; + } } return false; } @@ -160,6 +169,8 @@ void clearKey(const FileKey &key, FileOptions options = FileOption::User | FileO if (options & FileOption::Safe) { name[name.size() - 1] = '1'; QFile::remove(name); + name[name.size() - 1] = 's'; + QFile::remove(name); } } @@ -240,10 +251,12 @@ struct EncryptedDescriptor { }; struct FileWriteDescriptor { - FileWriteDescriptor(const FileKey &key, FileOptions options = FileOption::User | FileOption::Safe) { + FileWriteDescriptor(const FileKey &key, FileOptions options = FileOption::User | FileOption::Safe) + : file((options & FileOption::Safe) ? (QFileDevice&)saveFile : plainFile) { init(toFilePart(key), options); } - FileWriteDescriptor(const QString &name, FileOptions options = FileOption::User | FileOption::Safe) { + FileWriteDescriptor(const QString &name, FileOptions options = FileOption::User | FileOption::Safe) + : file((options & FileOption::Safe) ? (QFileDevice&)saveFile : plainFile) { init(name, options); } void init(const QString &name, FileOptions options) { @@ -253,29 +266,13 @@ struct FileWriteDescriptor { if (!_working()) return; } - // detect order of read attempts and file version - QString toWrite[2]; - toWrite[0] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '0'; + const auto base = ((options & FileOption::User) ? _userBasePath : _basePath) + name; if (options & FileOption::Safe) { - toWrite[1] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '1'; - QFileInfo toWrite0(toWrite[0]); - QFileInfo toWrite1(toWrite[1]); - if (toWrite0.exists()) { - if (toWrite1.exists()) { - QDateTime mod0 = toWrite0.lastModified(), mod1 = toWrite1.lastModified(); - if (mod0 > mod1) { - qSwap(toWrite[0], toWrite[1]); - } - } else { - qSwap(toWrite[0], toWrite[1]); - } - toDelete = toWrite[1]; - } else if (toWrite1.exists()) { - toDelete = toWrite[1]; - } + toDelete = base; + saveFile.setFileName(base + 's'); + } else { + plainFile.setFileName(base + '0'); } - - file.setFileName(toWrite[0]); if (file.open(QIODevice::WriteOnly)) { file.write(tdfMagic, tdfMagicLen); qint32 version = AppVersion; @@ -330,17 +327,21 @@ struct FileWriteDescriptor { md5.feed(&version, sizeof(version)); md5.feed(tdfMagic, tdfMagicLen); file.write((const char*)md5.result(), 0x10); - file.flush(); -#ifndef Q_OS_WIN - fsync(file.handle()); -#endif // Q_OS_WIN - file.close(); + + if (saveFile.isOpen()) { + saveFile.commit(); + } else { + plainFile.close(); + } if (!toDelete.isEmpty()) { - QFile::remove(toDelete); + QFile::remove(toDelete + '0'); + QFile::remove(toDelete + '1'); } } - QFile file; + QFile plainFile; + QSaveFile saveFile; + QFileDevice &file; QDataStream stream; QString toDelete; @@ -360,25 +361,35 @@ bool readFile(FileReadDescriptor &result, const QString &name, FileOptions optio if (!_working()) return false; } + const auto base = ((options & FileOption::User) ? _userBasePath : _basePath) + name; + // detect order of read attempts QString toTry[2]; - toTry[0] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '0'; if (options & FileOption::Safe) { - QFileInfo toTry0(toTry[0]); - if (toTry0.exists()) { - toTry[1] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '1'; - QFileInfo toTry1(toTry[1]); - if (toTry1.exists()) { - QDateTime mod0 = toTry0.lastModified(), mod1 = toTry1.lastModified(); - if (mod0 < mod1) { - qSwap(toTry[0], toTry[1]); + const auto modern = base + 's'; + if (QFileInfo(modern).exists()) { + toTry[0] = modern; + } else { + // Legacy way. + toTry[0] = base + '0'; + QFileInfo toTry0(toTry[0]); + if (toTry0.exists()) { + toTry[1] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '1'; + QFileInfo toTry1(toTry[1]); + if (toTry1.exists()) { + QDateTime mod0 = toTry0.lastModified(), mod1 = toTry1.lastModified(); + if (mod0 < mod1) { + qSwap(toTry[0], toTry[1]); + } + } else { + toTry[1] = QString(); } } else { - toTry[1] = QString(); + toTry[0][toTry[0].size() - 1] = '1'; } - } else { - toTry[0][toTry[0].size() - 1] = '1'; } + } else { + toTry[0] = base + '0'; } for (int32 i = 0; i < 2; ++i) { QString fname(toTry[i]);