From 0d44be7a686244e07f4f146d5a5ff0ec65204f40 Mon Sep 17 00:00:00 2001 From: sniperbeamer Date: Mon, 18 Jan 2010 21:48:50 +0000 Subject: [PATCH] Make file saving transactional git-svn-id: https://svn.code.sf.net/p/keepassx/code/trunk@361 b624d157-de02-0410-bad0-e51aec6abb33 --- src/Kdb3Database.cpp | 85 ++++++++++++++++++++++++++++++-------------- src/Kdb3Database.h | 2 ++ 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/src/Kdb3Database.cpp b/src/Kdb3Database.cpp index e614268..86913bc 100644 --- a/src/Kdb3Database.cpp +++ b/src/Kdb3Database.cpp @@ -518,12 +518,6 @@ bool Kdb3Database::load(QString identifier, bool readOnly){ return false; bool Kdb3Database::loadReal(QString filename, bool readOnly, bool differentEncoding) { - unsigned long total_size,crypto_size; - quint32 Signature1,Signature2,Version,NumGroups,NumEntries,Flags; - quint8 FinalRandomSeed[16]; - quint8 ContentsHash[32]; - quint8 EncryptionIV[16]; - File = new QFile(filename); if (readOnly) { if(!File->open(QIODevice::ReadOnly)){ @@ -547,6 +541,14 @@ bool Kdb3Database::loadReal(QString filename, bool readOnly, bool differentEncod } } + openedReadOnly = readOnly; + + unsigned long total_size,crypto_size; + quint32 Signature1,Signature2,Version,NumGroups,NumEntries,Flags; + quint8 FinalRandomSeed[16]; + quint8 ContentsHash[32]; + quint8 EncryptionIV[16]; + total_size=File->size(); char* buffer = new char[total_size]; File->read(buffer,total_size); @@ -1352,6 +1354,18 @@ bool Kdb3Database::save(){ return false; } + if (!File->isOpen()) { + if(!File->open(QIODevice::ReadWrite)){ + error=tr("Could not open file."); + return false; + } + } + + if(!(File->openMode() & QIODevice::WriteOnly)){ + error = tr("The database has been opened read-only."); + return false; + } + //Delete old backup entries if (config->backup() && config->backupDelete() && config->backupDeleteAfter()>0 && backupGroup()){ QDateTime time = QDateTime::currentDateTime().addDays(-config->backupDeleteAfter()); @@ -1367,11 +1381,6 @@ bool Kdb3Database::save(){ quint8 ContentsHash[32]; quint8 EncryptionIV[16]; - if(!(File->openMode() & QIODevice::WriteOnly)){ - error = tr("The database has been opened read-only."); - return false; - } - unsigned int FileSize; QList MetaStreams; @@ -1488,31 +1497,53 @@ bool Kdb3Database::save(){ int size = EncryptedPartSize+DB_HEADER_SIZE; - if (!File->resize(size)){ - // only recreate file if the new database is smaller - if (File->size() > size) { - qDebug("Unable to resize, trying to recreate file"); - if (!File->remove() || !File->open(QIODevice::ReadWrite)) { - delete [] buffer; - error=decodeFileError(File->error()); - return false; - } - } - } - File->seek(0); - if (File->write(buffer,size)!=size){ - delete [] buffer; + if (!saveFileTransactional(buffer, size)) { error=decodeFileError(File->error()); + delete [] buffer; return false; } - if (!syncFile(File)) - qWarning("Unable to flush file to disk"); delete [] buffer; //if(SearchGroupID!=-1)Groups.push_back(SearchGroup); return true; } +bool Kdb3Database::saveFileTransactional(char* buffer, int size) { + QString orgFilename = File->fileName(); + QFile* tmpFile = new QFile(orgFilename + ".tmp"); + if (!tmpFile->open(QIODevice::WriteOnly|QIODevice::Truncate)) { + tmpFile->remove(); + delete tmpFile; + return false; + } + if (tmpFile->write(buffer,size) != size) { + tmpFile->remove(); + delete tmpFile; + return false; + } + if (!syncFile(tmpFile)) + qWarning("Unable to flush file to disk"); + tmpFile->close(); + if (!File->remove()) { + delete tmpFile; + return false; + } + delete File; + File = NULL; + if (!tmpFile->rename(orgFilename)) { + delete tmpFile; + File = new QFile(orgFilename); + return false; + } + File = tmpFile; + if (!tmpFile->open(QIODevice::ReadWrite)) { + delete tmpFile; + return false; + } + + return true; +} + void Kdb3Database::createCustomIconsMetaStream(StdEntry* e){ /* Rev 3 */ e->BinaryDesc="bin-stream"; diff --git a/src/Kdb3Database.h b/src/Kdb3Database.h index ca96db9..4e05087 100644 --- a/src/Kdb3Database.h +++ b/src/Kdb3Database.h @@ -138,6 +138,7 @@ public: virtual ~Kdb3Database(){}; virtual bool load(QString identifier, bool readOnly); virtual bool save(); + virtual bool saveFileTransactional(char* buffer, int size); virtual bool close(); virtual void create(); virtual int numEntries(); @@ -236,6 +237,7 @@ private: StdGroup RootGroup; QListCustomIcons; QFile* File; + bool openedReadOnly; QString error; bool KeyError; bool PotentialEncodingIssueLatin1;