diff --git a/CMakeLists.txt b/CMakeLists.txt index f8ff36e..2c09554 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ use_cpp_utilities(VISIBILITY PUBLIC) include(3rdParty) use_zlib() use_crypto() +use_standard_filesystem() # include modules to apply configuration include(BasicConfig) diff --git a/io/passwordfile.cpp b/io/passwordfile.cpp index 2486872..bb2b042 100644 --- a/io/passwordfile.cpp +++ b/io/passwordfile.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -400,7 +401,9 @@ void PasswordFile::save(PasswordFileSaveFlags options) } // use already opened and writable file; otherwise re-open the file + auto fileSize = std::size_t(); if (m_file.good() && m_file.is_open() && !(m_openOptions & PasswordFileOpenFlags::ReadOnly)) { + fileSize = size(); m_file.seekp(0); } else { m_file.clear(); @@ -418,8 +421,16 @@ void PasswordFile::save(PasswordFileSaveFlags options) } } + // write entries write(options); m_file.flush(); + + // truncate file if it became smaller + const auto newSize = static_cast(m_file.tellp()); + if (fileSize && newSize < fileSize) { + m_file.close(); + std::filesystem::resize_file(m_path, newSize); + } } /*! diff --git a/tests/passwordfiletests.cpp b/tests/passwordfiletests.cpp index fc11a23..abf4b76 100644 --- a/tests/passwordfiletests.cpp +++ b/tests/passwordfiletests.cpp @@ -208,7 +208,7 @@ void PasswordFileTests::testExtendedWriting() CPPUNIT_ASSERT_EQUAL(""s, file.extendedHeader()); CPPUNIT_ASSERT_EQUAL(""s, file.encryptedExtendedHeader()); file.rootEntry()->setLabel("testfile2 - modified"); - new AccountEntry("newAccount", file.rootEntry()); + auto *const newAccount = new AccountEntry("newAccount", file.rootEntry()); file.setPassword("654321"); file.extendedHeader() = "foo"; file.encryptedExtendedHeader() = "bar"; @@ -220,4 +220,18 @@ void PasswordFileTests::testExtendedWriting() // check backup files testReading("extended writing", testfile1 + ".backup", "123456", testfile2 + ".backup", string(), false, false); + + // remove newAccount again to check what happens if the file size decreases + const auto fileSize = file.size(); + delete newAccount; + file.save(PasswordFileSaveFlags::Encryption | PasswordFileSaveFlags::PasswordHashing); + file.close(); + file.clearEntries(); + file.open(); + CPPUNIT_ASSERT_LESS(fileSize, file.size()); + file.load(); + + auto path = std::list{"newAccount"}; + CPPUNIT_ASSERT(file.rootEntry()); + CPPUNIT_ASSERT(!file.rootEntry()->entryByPath(path)); }