summaryrefslogtreecommitdiff
path: root/FreeFileSync/Source/base/db_file.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'FreeFileSync/Source/base/db_file.cpp')
-rw-r--r--FreeFileSync/Source/base/db_file.cpp150
1 files changed, 77 insertions, 73 deletions
diff --git a/FreeFileSync/Source/base/db_file.cpp b/FreeFileSync/Source/base/db_file.cpp
index ed32e884..27f47565 100644
--- a/FreeFileSync/Source/base/db_file.cpp
+++ b/FreeFileSync/Source/base/db_file.cpp
@@ -11,6 +11,7 @@
#include <zen/build_info.h>
#include <zen/zlib_wrap.h>
#include "../afs/concrete.h"
+#include "../afs/native.h"
#include "status_handler_impl.h"
@@ -23,7 +24,7 @@ namespace
//-------------------------------------------------------------------------------------------------------------------------------
const char DB_FILE_DESCR[] = "FreeFileSync";
const int DB_FILE_VERSION = 11; //2020-02-07
-const int DB_STREAM_VERSION = 3; //2017-02-01
+const int DB_STREAM_VERSION = 4; //2021-02-14
//-------------------------------------------------------------------------------------------------------------------------------
DEFINE_NEW_FILE_ERROR(FileErrorDatabaseNotExisting)
@@ -44,7 +45,7 @@ using DbStreams = std::unordered_map<UniqueId, SessionData>; //list of streams b
| ensure 32/64 bit portability: use fixed size data types only e.g. uint32_t |
------------------------------------------------------------------------------*/
-template <SelectedSide side> inline
+template <SelectSide side> inline
AbstractPath getDatabaseFilePath(const BaseFolderPair& baseFolder)
{
static_assert(std::endian::native == std::endian::little);
@@ -57,13 +58,13 @@ AbstractPath getDatabaseFilePath(const BaseFolderPair& baseFolder)
- 32 vs 64-bit: already handled
=> give db files different names: */
- const Zstring dbName = Zstr(".sync"); //files beginning with dots are hidden e.g. in Nautilus
+ const Zstring dbName = Zstr(".sync"); //files beginning with dots are usually hidden
return AFS::appendRelPath(baseFolder.getAbstractPath<side>(), dbName + SYNC_DB_FILE_ENDING);
}
//#######################################################################################################################################
-void saveStreams(const DbStreams& streamList, const AbstractPath& dbPath, const IOCallback& notifyUnbufferedIO /*throw X*/) //throw FileError, X
+void saveStreams(const DbStreams& streamList, const AbstractPath& dbPath, const IoCallback& notifyUnbufferedIO /*throw X*/) //throw FileError, X
{
MemoryStreamOut<std::string> memStreamOut;
@@ -98,7 +99,7 @@ void saveStreams(const DbStreams& streamList, const AbstractPath& dbPath, const
}
-DbStreams loadStreams(const AbstractPath& dbPath, const IOCallback& notifyUnbufferedIO /*throw X*/) //throw FileError, FileErrorDatabaseNotExisting, X
+DbStreams loadStreams(const AbstractPath& dbPath, const IoCallback& notifyUnbufferedIO /*throw X*/) //throw FileError, FileErrorDatabaseNotExisting, X
{
std::string byteStream;
try
@@ -133,7 +134,7 @@ DbStreams loadStreams(const AbstractPath& dbPath, const IOCallback& notifyUnbuff
if (version == 9 || //TODO: remove migration code at some time! v9 used until 2017-02-01
version == 10) //TODO: remove migration code at some time! v10 used until 2020-02-07
;
- else if (version == DB_FILE_VERSION)//catch data corruption ASAP + don't rely on std::bad_alloc for consistency checking
+ else if (version == DB_FILE_VERSION) //catch data corruption ASAP + don't rely on std::bad_alloc for consistency checking
// => only "partially" useful for container/stream metadata since the streams data is zlib-compressed
{
assert(byteStream.size() >= sizeof(uint32_t)); //obviously in this context!
@@ -273,8 +274,8 @@ private:
writeItemName(itemName);
writeNumber(streamOutSmallNum_, static_cast<int32_t>(inSyncData.cmpVar));
- writeLinkDescr(inSyncData.left);
- writeLinkDescr(inSyncData.right);
+ writeNumber<int64_t>(streamOutBigNum_, inSyncData.left .modTime);
+ writeNumber<int64_t>(streamOutBigNum_, inSyncData.right.modTime);
}
writeNumber<uint32_t>(streamOutSmallNum_, static_cast<uint32_t>(container.folders.size()));
@@ -291,13 +292,11 @@ private:
void writeFileDescr(const InSyncDescrFile& descr)
{
- writeNumber<int64_t>(streamOutBigNum_, descr.modTime);
- writeContainer<std::string>(streamOutBigNum_, descr.fileId);
+ writeNumber<int64_t >(streamOutBigNum_, descr.modTime);
+ writeNumber<AFS::FingerPrint>(streamOutBigNum_, descr.filePrint);
static_assert(sizeof(descr.modTime) <= sizeof(int64_t)); //ensure cross-platform compatibility!
}
- void writeLinkDescr(const InSyncDescrLink& descr) { writeNumber<int64_t>(streamOutBigNum_, descr.modTime); }
-
/* maximize zlib compression by grouping similar data (=> 20% size reduction!)
-> further ~5% reduction possible by having one container per data type
@@ -364,7 +363,8 @@ public:
parser.recurse(output.ref()); //throw SysError
return output;
}
- else if (streamVersion == DB_STREAM_VERSION)
+ else if (streamVersion == 3 || //TODO: remove migration code at some time! 2021-02-14
+ streamVersion == DB_STREAM_VERSION)
{
MemoryStreamIn<std::string>& streamInPart1 = leadStreamLeft ? streamInL : streamInR;
MemoryStreamIn<std::string>& streamInPart2 = leadStreamLeft ? streamInR : streamInL;
@@ -387,9 +387,9 @@ public:
decompress(bufSmallNum), //throw SysError
decompress(bufBigNum)); //
if (leadStreamLeft)
- parser.recurse<LEFT_SIDE>(output.ref()); //throw SysError
+ parser.recurse<SelectSide::left>(output.ref()); //throw SysError
else
- parser.recurse<RIGHT_SIDE>(output.ref()); //throw SysError
+ parser.recurse<SelectSide::right>(output.ref()); //throw SysError
return output;
}
else
@@ -406,23 +406,20 @@ private:
streamVersion_(streamVersion),
streamInText_(bufText),
streamInSmallNum_(bufSmallNumbers),
- streamInBigNum_(bufBigNumbers)
- {
- (void)streamVersion_; //clang: -Wunused-private-field
- }
+ streamInBigNum_(bufBigNumbers) {}
- template <SelectedSide leadSide>
+ template <SelectSide leadSide>
void recurse(InSyncFolder& container) //throw SysError
{
- size_t fileCount = readNumber<uint32_t>(streamInSmallNum_);
+ size_t fileCount = readNumber<uint32_t>(streamInSmallNum_); //throw SysErrorUnexpectedEos
while (fileCount-- != 0)
{
- const Zstring itemName = readItemName();
- const auto cmpVar = static_cast<CompareVariant>(readNumber<int32_t>(streamInSmallNum_));
- const uint64_t fileSize = readNumber<uint64_t>(streamInSmallNum_);
+ const Zstring itemName = readItemName(); //
+ const auto cmpVar = static_cast<CompareVariant>(readNumber<int32_t>(streamInSmallNum_)); //
+ const uint64_t fileSize = readNumber<uint64_t>(streamInSmallNum_); //
- const InSyncDescrFile dataL = readFileDescr();
- const InSyncDescrFile dataT = readFileDescr();
+ const InSyncDescrFile dataL = readFileDescr(); //throw SysErrorUnexpectedEos
+ const InSyncDescrFile dataT = readFileDescr(); //
container.addFile(itemName,
SelectParam<leadSide>::ref(dataL, dataT),
@@ -432,22 +429,22 @@ private:
size_t linkCount = readNumber<uint32_t>(streamInSmallNum_);
while (linkCount-- != 0)
{
- const Zstring itemName = readItemName();
- const auto cmpVar = static_cast<CompareVariant>(readNumber<int32_t>(streamInSmallNum_));
+ const Zstring itemName = readItemName(); //
+ const auto cmpVar = static_cast<CompareVariant>(readNumber<int32_t>(streamInSmallNum_)); //
- const InSyncDescrLink dataL = readLinkDescr();
- const InSyncDescrLink dataT = readLinkDescr();
+ const InSyncDescrLink dataL(readNumber<int64_t>(streamInBigNum_)); //throw SysErrorUnexpectedEos
+ const InSyncDescrLink dataT(readNumber<int64_t>(streamInBigNum_)); //
container.addSymlink(itemName,
SelectParam<leadSide>::ref(dataL, dataT),
SelectParam<leadSide>::ref(dataT, dataL), cmpVar);
}
- size_t dirCount = readNumber<uint32_t>(streamInSmallNum_);
+ size_t dirCount = readNumber<uint32_t>(streamInSmallNum_); //
while (dirCount-- != 0)
{
- const Zstring itemName = readItemName();
- const auto status = static_cast<InSyncFolder::InSyncStatus>(readNumber<int32_t>(streamInSmallNum_));
+ const Zstring itemName = readItemName(); //
+ const auto status = static_cast<InSyncFolder::InSyncStatus>(readNumber<int32_t>(streamInSmallNum_)); //
InSyncFolder& dbFolder = container.addFolder(itemName, status);
recurse<leadSide>(dbFolder);
@@ -458,17 +455,24 @@ private:
InSyncDescrFile readFileDescr() //throw SysErrorUnexpectedEos
{
- //attention: order of function argument evaluation is undefined! So do it one after the other...
- const auto modTime = readNumber<int64_t>(streamInBigNum_); //throw SysErrorUnexpectedEos
- const auto fileId = readContainer<std::string>(streamInBigNum_); //
+ const auto modTime = readNumber<int64_t>(streamInBigNum_); //throw SysErrorUnexpectedEos
- return InSyncDescrFile(modTime, fileId);
- }
+ AFS::FingerPrint filePrint = 0;
+ if (streamVersion_ == 3) //TODO: remove migration code at some time! 2021-02-14
+ {
+ const auto& devFileId = readContainer<std::string>(streamInBigNum_); //throw SysErrorUnexpectedEos
+ ino_t fileIndex = 0;
+ if (devFileId.size() == sizeof(dev_t) + sizeof(fileIndex))
+ {
+ std::memcpy(&fileIndex, &devFileId[devFileId.size() - sizeof(fileIndex)], sizeof(fileIndex));
+ filePrint = fileIndex;
+ }
+ else assert(devFileId.empty());
+ }
+ else
+ filePrint = readNumber<AFS::FingerPrint>(streamInBigNum_); //throw SysErrorUnexpectedEos
- InSyncDescrLink readLinkDescr() //throw SysErrorUnexpectedEos
- {
- const auto modTime = readNumber<int64_t>(streamInBigNum_); //throw SysErrorUnexpectedEos
- return InSyncDescrLink(modTime);
+ return InSyncDescrFile(modTime, filePrint);
}
//TODO: remove migration code at some time! 2017-02-01
@@ -491,10 +495,10 @@ private:
const auto cmpVar = static_cast<CompareVariant>(readNumber<int32_t>(inputBoth_));
const uint64_t fileSize = readNumber<uint64_t>(inputBoth_);
const auto modTimeL = readNumber<int64_t>(inputLeft_);
- const auto fileIdL = readContainer<std::string>(inputLeft_);
+ /*const auto fileIdL =*/ readContainer<std::string>(inputLeft_);
const auto modTimeR = readNumber<int64_t>(inputRight_);
- const auto fileIdR = readContainer<std::string>(inputRight_);
- container.addFile(itemName, InSyncDescrFile(modTimeL, fileIdL), InSyncDescrFile(modTimeR, fileIdR), cmpVar, fileSize);
+ /*const auto fileIdR =*/ readContainer<std::string>(inputRight_);
+ container.addFile(itemName, InSyncDescrFile(modTimeL, AFS::FingerPrint()), InSyncDescrFile(modTimeR, AFS::FingerPrint()), cmpVar, fileSize);
}
size_t linkCount = readNumber<uint32_t>(inputBoth_);
@@ -568,23 +572,23 @@ private:
{
//Caveat: If FILE_EQUAL, we *implicitly* assume equal left and right short names matching case: InSyncFolder's mapping tables use short name as a key!
//This makes us silently dependent from code in algorithm.h!!!
- assert(getUnicodeNormalForm(file.getItemName<LEFT_SIDE>()) == getUnicodeNormalForm(file.getItemName<RIGHT_SIDE>()));
- assert(file.getFileSize<LEFT_SIDE>() == file.getFileSize<RIGHT_SIDE>());
+ assert(getUnicodeNormalForm(file.getItemName<SelectSide::left>()) == getUnicodeNormalForm(file.getItemName<SelectSide::right>()));
+ assert(file.getFileSize<SelectSide::left>() == file.getFileSize<SelectSide::right>());
//create or update new "in-sync" state
dbFiles.insert_or_assign(file.getItemNameAny(),
- InSyncFile(InSyncDescrFile(file.getLastWriteTime< LEFT_SIDE>(),
- file.getFileId < LEFT_SIDE>()),
- InSyncDescrFile(file.getLastWriteTime<RIGHT_SIDE>(),
- file.getFileId <RIGHT_SIDE>()),
+ InSyncFile(InSyncDescrFile(file.getLastWriteTime< SelectSide::left>(),
+ file.getFilePrint < SelectSide::left>()),
+ InSyncDescrFile(file.getLastWriteTime<SelectSide::right>(),
+ file.getFilePrint <SelectSide::right>()),
activeCmpVar_,
- file.getFileSize<LEFT_SIDE>()));
+ file.getFileSize<SelectSide::left>()));
toPreserve.insert(file.getItemNameAny());
}
else //not in sync: preserve last synchronous state
{
- toPreserve.insert(file.getItemName< LEFT_SIDE>()); //left/right may differ in case!
- toPreserve.insert(file.getItemName<RIGHT_SIDE>()); //
+ toPreserve.insert(file.getItemName< SelectSide::left>()); //left/right may differ in case!
+ toPreserve.insert(file.getItemName<SelectSide::right>()); //
}
}
@@ -609,19 +613,19 @@ private:
{
if (symlink.getLinkCategory() == SYMLINK_EQUAL) //data in sync: write current state
{
- assert(getUnicodeNormalForm(symlink.getItemName<LEFT_SIDE>()) == getUnicodeNormalForm(symlink.getItemName<RIGHT_SIDE>()));
+ assert(getUnicodeNormalForm(symlink.getItemName<SelectSide::left>()) == getUnicodeNormalForm(symlink.getItemName<SelectSide::right>()));
//create or update new "in-sync" state
dbSymlinks.insert_or_assign(symlink.getItemNameAny(),
- InSyncSymlink(InSyncDescrLink(symlink.getLastWriteTime< LEFT_SIDE>()),
- InSyncDescrLink(symlink.getLastWriteTime<RIGHT_SIDE>()),
+ InSyncSymlink(InSyncDescrLink(symlink.getLastWriteTime< SelectSide::left>()),
+ InSyncDescrLink(symlink.getLastWriteTime<SelectSide::right>()),
activeCmpVar_));
toPreserve.insert(symlink.getItemNameAny());
}
else //not in sync: preserve last synchronous state
{
- toPreserve.insert(symlink.getItemName< LEFT_SIDE>()); //left/right may differ in case!
- toPreserve.insert(symlink.getItemName<RIGHT_SIDE>()); //
+ toPreserve.insert(symlink.getItemName< SelectSide::left>()); //left/right may differ in case!
+ toPreserve.insert(symlink.getItemName<SelectSide::right>()); //
}
}
@@ -645,7 +649,7 @@ private:
{
if (folder.getDirCategory() == DIR_EQUAL)
{
- assert(getUnicodeNormalForm(folder.getItemName<LEFT_SIDE>()) == getUnicodeNormalForm(folder.getItemName<RIGHT_SIDE>()));
+ assert(getUnicodeNormalForm(folder.getItemName<SelectSide::left>()) == getUnicodeNormalForm(folder.getItemName<SelectSide::right>()));
//update directory entry only (shallow), but do *not touch* existing child elements!!!
InSyncFolder& dbFolder = dbFolders.emplace(folder.getItemNameAny(), InSyncFolder(InSyncFolder::DIR_STATUS_IN_SYNC)).first->second; //get or create
@@ -655,8 +659,8 @@ private:
}
else //not in sync: preserve last synchronous state
{
- toPreserve.emplace(folder.getItemName< LEFT_SIDE>(), &folder); //names differing in case? => treat like any other folder rename
- toPreserve.emplace(folder.getItemName<RIGHT_SIDE>(), &folder); //=> no *new* database entries even if child items are in sync
+ toPreserve.emplace(folder.getItemName< SelectSide::left>(), &folder); //names differing in case? => treat like any other folder rename
+ toPreserve.emplace(folder.getItemName<SelectSide::right>(), &folder); //=> no *new* database entries even if child items are in sync
}
}
@@ -749,7 +753,7 @@ std::pair<DbStreams::const_iterator,
}
}
- return { itCommonL, itCommonR };
+ return {itCommonL, itCommonR};
}
}
@@ -762,11 +766,11 @@ std::unordered_map<const BaseFolderPair*, SharedRef<const InSyncFolder>> fff::lo
for (const BaseFolderPair* baseFolder : baseFolders)
//avoid race condition with directory existence check: reading sync.ffs_db may succeed although first dir check had failed => conflicts!
- if (baseFolder->isAvailable< LEFT_SIDE>() &&
- baseFolder->isAvailable<RIGHT_SIDE>())
+ if (baseFolder->isAvailable< SelectSide::left>() &&
+ baseFolder->isAvailable<SelectSide::right>())
{
- dbFilePaths.insert(getDatabaseFilePath< LEFT_SIDE>(*baseFolder));
- dbFilePaths.insert(getDatabaseFilePath<RIGHT_SIDE>(*baseFolder));
+ dbFilePaths.insert(getDatabaseFilePath< SelectSide::left>(*baseFolder));
+ dbFilePaths.insert(getDatabaseFilePath<SelectSide::right>(*baseFolder));
}
//else: ignore; there's no value in reporting it other than to confuse users
@@ -801,11 +805,11 @@ std::unordered_map<const BaseFolderPair*, SharedRef<const InSyncFolder>> fff::lo
std::unordered_map<const BaseFolderPair*, SharedRef<const InSyncFolder>> output;
for (const BaseFolderPair* baseFolder : baseFolders)
- if (baseFolder->isAvailable< LEFT_SIDE>() &&
- baseFolder->isAvailable<RIGHT_SIDE>())
+ if (baseFolder->isAvailable< SelectSide::left>() &&
+ baseFolder->isAvailable<SelectSide::right>())
{
- const AbstractPath dbPathL = getDatabaseFilePath< LEFT_SIDE>(*baseFolder);
- const AbstractPath dbPathR = getDatabaseFilePath<RIGHT_SIDE>(*baseFolder);
+ const AbstractPath dbPathL = getDatabaseFilePath< SelectSide::left>(*baseFolder);
+ const AbstractPath dbPathR = getDatabaseFilePath<SelectSide::right>(*baseFolder);
auto itL = dbStreamsByPath.find(dbPathL);
auto itR = dbStreamsByPath.find(dbPathR);
@@ -842,8 +846,8 @@ std::unordered_map<const BaseFolderPair*, SharedRef<const InSyncFolder>> fff::lo
void fff::saveLastSynchronousState(const BaseFolderPair& baseFolder, bool transactionalCopy,
PhaseCallback& callback /*throw X*/) //throw X
{
- const AbstractPath dbPathL = getDatabaseFilePath< LEFT_SIDE>(baseFolder);
- const AbstractPath dbPathR = getDatabaseFilePath<RIGHT_SIDE>(baseFolder);
+ const AbstractPath dbPathL = getDatabaseFilePath< SelectSide::left>(baseFolder);
+ const AbstractPath dbPathR = getDatabaseFilePath<SelectSide::right>(baseFolder);
//------------ (try to) load DB files in parallel -------------------------
DbStreams streamsL; //list of session ID + DirInfo-stream
bgstack15