summaryrefslogtreecommitdiff
path: root/library/dbFile.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:08:06 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:08:06 +0200
commitfbe76102e941b9f1edaf236788e42678f05fdf9a (patch)
treef5f538316019fa89be8dc478103490c3a826f3ac /library/dbFile.cpp
parent3.8 (diff)
downloadFreeFileSync-fbe76102e941b9f1edaf236788e42678f05fdf9a.tar.gz
FreeFileSync-fbe76102e941b9f1edaf236788e42678f05fdf9a.tar.bz2
FreeFileSync-fbe76102e941b9f1edaf236788e42678f05fdf9a.zip
3.9
Diffstat (limited to 'library/dbFile.cpp')
-rw-r--r--library/dbFile.cpp462
1 files changed, 0 insertions, 462 deletions
diff --git a/library/dbFile.cpp b/library/dbFile.cpp
deleted file mode 100644
index 1919dd6d..00000000
--- a/library/dbFile.cpp
+++ /dev/null
@@ -1,462 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-//
-#include "dbFile.h"
-#include <wx/wfstream.h>
-#include <wx/zstream.h>
-#include "../shared/globalFunctions.h"
-#include "../shared/fileError.h"
-#include <wx/intl.h>
-#include "../shared/stringConv.h"
-#include "../shared/fileHandling.h"
-#include <wx/mstream.h>
-#include "../shared/serialize.h"
-#include "../shared/fileIO.h"
-#include "../shared/loki/ScopeGuard.h"
-
-#ifdef FFS_WIN
-#include <wx/msw/wrapwin.h> //includes "windows.h"
-#include "../shared/longPathPrefix.h"
-#endif
-
-using namespace FreeFileSync;
-
-
-namespace
-{
-//-------------------------------------------------------------------------------------------------------------------------------
-const char FILE_FORMAT_DESCR[] = "FreeFileSync";
-const int FILE_FORMAT_VER = 4;
-//-------------------------------------------------------------------------------------------------------------------------------
-
-
-//yet another layer of indirection: Since 32/64 bit builds are binary incompatible, we want them to write into "distinct parts" of the db-file
-//just like we were actually accessing different files
-class FileInputStreamDB : public FileInputStream
-{
-public:
- FileInputStreamDB(const Zstring& filename) : //throw FileError()
- FileInputStream(filename)
- {
- //read FreeFileSync file identifier
- char formatDescr[sizeof(FILE_FORMAT_DESCR)];
- Read(formatDescr, sizeof(formatDescr)); //throw (FileError)
- formatDescr[sizeof(formatDescr) - 1] = 0;
-
- if (std::string(formatDescr) != FILE_FORMAT_DESCR)
- throw FileError(wxString(_("Incompatible synchronization database format:")) + wxT(" \n") + wxT("\"") + zToWx(filename) + wxT("\""));
- }
-
-private:
-};
-
-
-class FileOutputStreamDB : public FileOutputStream
-{
-public:
- FileOutputStreamDB(const Zstring& filename) : //throw FileError()
- FileOutputStream(filename)
- {
- //write FreeFileSync file identifier
- Write(FILE_FORMAT_DESCR, sizeof(FILE_FORMAT_DESCR)); //throw (FileError)
- }
-
-private:
-};
-}
-//#######################################################################################################################################
-
-
-
-
-class ReadDirInfo : public Utility::ReadInputStream
-{
-public:
- ReadDirInfo(wxInputStream& stream, const wxString& errorObjName, DirInformation& dirInfo) : ReadInputStream(stream, errorObjName)
- {
- //read filter settings
- dirInfo.filter = BaseFilter::loadFilter(getStream());
- check();
-
- //start recursion
- execute(dirInfo.baseDirContainer);
- }
-
-private:
- void execute(DirContainer& dirCont) const
- {
- size_t fileCount = readNumberC<size_t>();
- while (fileCount-- != 0)
- readSubFile(dirCont);
-
- size_t symlinkCount = readNumberC<size_t>();
- while (symlinkCount-- != 0)
- readSubLink(dirCont);
-
- size_t dirCount = readNumberC<size_t>();
- while (dirCount-- != 0)
- readSubDirectory(dirCont);
- }
-
- void readSubFile(DirContainer& dirCont) const
- {
- //attention: order of function argument evaluation is undefined! So do it one after the other...
- const Zstring shortName = readStringC(); //file name
-
- const long modHigh = readNumberC<long>();
- const unsigned long modLow = readNumberC<unsigned long>();
-
- const unsigned long sizeHigh = readNumberC<unsigned long>();
- const unsigned long sizeLow = readNumberC<unsigned long>();
-
- //const Utility::FileID fileIdentifier(stream_);
- //check();
-
- dirCont.addSubFile(shortName,
- FileDescriptor(wxLongLong(modHigh, modLow),
- wxULongLong(sizeHigh, sizeLow)));
- }
-
-
- void readSubLink(DirContainer& dirCont) const
- {
- //attention: order of function argument evaluation is undefined! So do it one after the other...
- const Zstring shortName = readStringC(); //file name
- const long modHigh = readNumberC<long>();
- const unsigned long modLow = readNumberC<unsigned long>();
- const Zstring targetPath = readStringC(); //file name
- const LinkDescriptor::LinkType linkType = static_cast<LinkDescriptor::LinkType>(readNumberC<int>());
-
- dirCont.addSubLink(shortName,
- LinkDescriptor(wxLongLong(modHigh, modLow), targetPath, linkType));
- }
-
-
- void readSubDirectory(DirContainer& dirCont) const
- {
- const Zstring shortName = readStringC(); //directory name
- DirContainer& subDir = dirCont.addSubDir(shortName);
- execute(subDir); //recurse
- }
-};
-
-
-typedef boost::shared_ptr<std::vector<char> > MemoryStreamPtr; //byte stream representing DirInformation
-typedef std::map<Utility::UniqueId, MemoryStreamPtr> DirectoryTOC; //list of streams ordered by a UUID pointing to their partner database
-typedef std::pair<Utility::UniqueId, DirectoryTOC> DbStreamData; //header data: UUID representing this database, item data: list of dir-streams
-/* Example
-left side right side
---------- ----------
-DB-ID 123 <-\ /-> DB-ID 567
- \/
-Partner-ID 111 /\ Partner-ID 222
-Partner-ID 567 _/ \_ Partner-ID 123
- ... ...
-*/
-
-class ReadFileStream : public Utility::ReadInputStream
-{
-public:
- ReadFileStream(wxInputStream& stream, const wxString& filename, DbStreamData& output) : ReadInputStream(stream, filename)
- {
- if (readNumberC<int>() != FILE_FORMAT_VER) //read file format version
- throw FileError(wxString(_("Incompatible synchronization database format:")) + wxT(" \n") + wxT("\"") + filename + wxT("\""));
-
- //read DB id
- output.first = Utility::UniqueId(getStream());
- check();
-
- DirectoryTOC& dbList = output.second;
- dbList.clear();
-
- size_t dbCount = readNumberC<size_t>(); //number of databases: one for each sync-pair
- while (dbCount-- != 0)
- {
- const Utility::UniqueId partnerID(getStream()); //DB id of partner databases
- check();
-
- CharArray buffer = readArrayC(); //read db-entry stream (containing DirInformation)
-
- dbList.insert(std::make_pair(partnerID, buffer));
- }
- }
-};
-
-
-DbStreamData loadFile(const Zstring& filename) //throw (FileError)
-{
- if (!FreeFileSync::fileExists(filename))
- throw FileError(wxString(_("Initial synchronization:")) + wxT(" \n\n") +
- _("One of the FreeFileSync database files is not yet existing:") + wxT(" \n") +
- wxT("\"") + zToWx(filename) + wxT("\""));
-
- //read format description (uncompressed)
- FileInputStreamDB uncompressed(filename); //throw (FileError)
-
- wxZlibInputStream input(uncompressed, wxZLIB_ZLIB);
-
- DbStreamData output;
- ReadFileStream(input, zToWx(filename), output);
- return output;
-}
-
-
-std::pair<DirInfoPtr, DirInfoPtr> FreeFileSync::loadFromDisk(const BaseDirMapping& baseMapping) //throw (FileError)
-{
- const Zstring fileNameLeft = baseMapping.getDBFilename<LEFT_SIDE>();
- const Zstring fileNameRight = baseMapping.getDBFilename<RIGHT_SIDE>();
-
- try
- {
- //read file data: db ID + mapping of partner-ID/DirInfo-stream
- const DbStreamData dbEntriesLeft = ::loadFile(fileNameLeft);
- const DbStreamData dbEntriesRight = ::loadFile(fileNameRight);
-
- //find associated DirInfo-streams
- DirectoryTOC::const_iterator dbLeft = dbEntriesLeft.second.find(dbEntriesRight.first); //find left db-entry that corresponds to right database
- if (dbLeft == dbEntriesLeft.second.end())
- throw FileError(wxString(_("Initial synchronization:")) + wxT(" \n\n") +
- _("One of the FreeFileSync database entries within the following file is not yet existing:") + wxT(" \n") +
- wxT("\"") + zToWx(fileNameLeft) + wxT("\""));
-
- DirectoryTOC::const_iterator dbRight = dbEntriesRight.second.find(dbEntriesLeft.first); //find left db-entry that corresponds to right database
- if (dbRight == dbEntriesRight.second.end())
- throw FileError(wxString(_("Initial synchronization:")) + wxT(" \n\n") +
- _("One of the FreeFileSync database entries within the following file is not yet existing:") + wxT(" \n") +
- wxT("\"") + zToWx(fileNameRight) + wxT("\""));
-
- //read streams into DirInfo
- boost::shared_ptr<DirInformation> dirInfoLeft(new DirInformation);
- wxMemoryInputStream buffer(&(*dbLeft->second)[0], dbLeft->second->size()); //convert char-array to inputstream: no copying, ownership not transferred
- ReadDirInfo(buffer, zToWx(fileNameLeft), *dirInfoLeft); //read file/dir information
-
- boost::shared_ptr<DirInformation> dirInfoRight(new DirInformation);
- wxMemoryInputStream buffer2(&(*dbRight->second)[0], dbRight->second->size()); //convert char-array to inputstream: no copying, ownership not transferred
- ReadDirInfo(buffer2, zToWx(fileNameRight), *dirInfoRight); //read file/dir information
-
- return std::make_pair(dirInfoLeft, dirInfoRight);
- }
- catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file
- {
- throw FileError(wxString(_("Error reading from synchronization database:")) + wxT(" (bad_alloc)"));
- }
-}
-
-
-//-------------------------------------------------------------------------------------------------------------------------
-
-template <SelectedSide side>
-struct IsNonEmpty
-{
- bool operator()(const FileSystemObject& fsObj) const
- {
- return !fsObj.isEmpty<side>();
- }
-};
-
-
-template <SelectedSide side>
-class SaveDirInfo : public Utility::WriteOutputStream
-{
-public:
- SaveDirInfo(const BaseDirMapping& baseMapping, const wxString& errorObjName, wxOutputStream& stream) : WriteOutputStream(errorObjName, stream)
- {
- //save filter settings
- baseMapping.getFilter()->saveFilter(getStream());
- check();
-
- //start recursion
- execute(baseMapping);
- }
-
-private:
- friend class Utility::Proxy<SaveDirInfo<side> >; //friend declaration of std::for_each is NOT sufficient as implementation is compiler dependent!
-
- void execute(const HierarchyObject& hierObj)
- {
- Utility::Proxy<SaveDirInfo<side> > prx(*this); //grant std::for_each access to private parts of this class
-
- writeNumberC<size_t>(std::count_if(hierObj.useSubFiles().begin(), hierObj.useSubFiles().end(), IsNonEmpty<side>())); //number of (existing) files
- std::for_each(hierObj.useSubFiles().begin(), hierObj.useSubFiles().end(), prx);
-
- writeNumberC<size_t>(std::count_if(hierObj.useSubLinks().begin(), hierObj.useSubLinks().end(), IsNonEmpty<side>())); //number of (existing) files
- std::for_each(hierObj.useSubLinks().begin(), hierObj.useSubLinks().end(), prx);
-
- writeNumberC<size_t>(std::count_if(hierObj.useSubDirs().begin(), hierObj.useSubDirs().end(), IsNonEmpty<side>())); //number of (existing) directories
- std::for_each(hierObj.useSubDirs().begin(), hierObj.useSubDirs().end(), prx);
- }
-
- void operator()(const FileMapping& fileMap)
- {
- if (!fileMap.isEmpty<side>())
- {
- writeStringC(fileMap.getObjShortName()); //file name
- writeNumberC<long>( fileMap.getLastWriteTime<side>().GetHi()); //last modification time
- writeNumberC<unsigned long>(fileMap.getLastWriteTime<side>().GetLo()); //
- writeNumberC<unsigned long>(fileMap.getFileSize<side>().GetHi()); //filesize
- writeNumberC<unsigned long>(fileMap.getFileSize<side>().GetLo()); //
-
- //fileMap.getFileID<side>().toStream(stream_); //unique file identifier
- //check();
- }
- }
-
- void operator()(const SymLinkMapping& linkObj)
- {
- if (!linkObj.isEmpty<side>())
- {
- writeStringC(linkObj.getObjShortName());
- writeNumberC<long>( linkObj.getLastWriteTime<side>().GetHi()); //last modification time
- writeNumberC<unsigned long>(linkObj.getLastWriteTime<side>().GetLo()); //
- writeStringC(linkObj.getTargetPath<side>());
- writeNumberC<int>(linkObj.getLinkType<side>());
- }
- }
-
- void operator()(const DirMapping& dirMap)
- {
- if (!dirMap.isEmpty<side>())
- {
- writeStringC(dirMap.getObjShortName()); //directory name
- execute(dirMap); //recurse
- }
- }
-};
-
-
-class WriteFileStream : public Utility::WriteOutputStream
-{
-public:
- WriteFileStream(const DbStreamData& input, const wxString& filename, wxOutputStream& stream) : WriteOutputStream(filename, stream)
- {
- //save file format version
- writeNumberC<int>(FILE_FORMAT_VER);
-
- //write DB id
- input.first.toStream(getStream());
- check();
-
- const DirectoryTOC& dbList = input.second;
-
- writeNumberC<size_t>(dbList.size()); //number of database records: one for each sync-pair
-
- for (DirectoryTOC::const_iterator i = dbList.begin(); i != dbList.end(); ++i)
- {
- i->first.toStream(getStream()); //DB id of partner database
- check();
-
- writeArrayC(*(i->second)); //write DirInformation stream
- }
- }
-};
-
-
-//save/load DirContainer
-void saveFile(const DbStreamData& dbStream, const Zstring& filename) //throw (FileError)
-{
- {
- //write format description (uncompressed)
- FileOutputStreamDB uncompressed(filename); //throw (FileError)
-
- wxZlibOutputStream output(uncompressed, 4, wxZLIB_ZLIB);
- /* 4 - best compromise between speed and compression: (scanning 200.000 objects)
- 0 (uncompressed) 8,95 MB - 422 ms
- 2 2,07 MB - 470 ms
- 4 1,87 MB - 500 ms
- 6 1,77 MB - 613 ms
- 9 (maximal compression) 1,74 MB - 3330 ms */
-
- WriteFileStream(dbStream, zToWx(filename), output);
- }
- //(try to) hide database file
-#ifdef FFS_WIN
- ::SetFileAttributes(FreeFileSync::applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN);
-#endif
-}
-
-
-void FreeFileSync::saveToDisk(const BaseDirMapping& baseMapping) //throw (FileError)
-{
- //transactional behaviour! write to tmp files first
- const Zstring fileNameLeftTmp = baseMapping.getDBFilename<LEFT_SIDE>() + DefaultStr(".tmp");
- const Zstring fileNameRightTmp = baseMapping.getDBFilename<RIGHT_SIDE>() + DefaultStr(".tmp");;
-
- //delete old tmp file, if necessary -> throws if deletion fails!
- removeFile(fileNameLeftTmp);
- removeFile(fileNameRightTmp);
-
- //load old database files...
-
- //read file data: db ID + mapping of partner-ID/DirInfo-stream: may throw!
- DbStreamData dbEntriesLeft;
- if (FreeFileSync::fileExists(baseMapping.getDBFilename<LEFT_SIDE>()))
- try
- {
- dbEntriesLeft = ::loadFile(baseMapping.getDBFilename<LEFT_SIDE>());
- }
- catch(FileError&) {} //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
- //else -> dbEntriesLeft has empty mapping, but already a DB-ID!
-
- //read file data: db ID + mapping of partner-ID/DirInfo-stream: may throw!
- DbStreamData dbEntriesRight;
- if (FreeFileSync::fileExists(baseMapping.getDBFilename<RIGHT_SIDE>()))
- try
- {
- dbEntriesRight = ::loadFile(baseMapping.getDBFilename<RIGHT_SIDE>());
- }
- catch(FileError&) {} //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
-
- //create new database entries
- MemoryStreamPtr dbEntryLeft(new std::vector<char>);
- {
- wxMemoryOutputStream buffer;
- SaveDirInfo<LEFT_SIDE>(baseMapping, zToWx(baseMapping.getDBFilename<LEFT_SIDE>()), buffer);
- dbEntryLeft->resize(buffer.GetSize()); //convert output stream to char-array
- buffer.CopyTo(&(*dbEntryLeft)[0], buffer.GetSize()); //
- }
-
- MemoryStreamPtr dbEntryRight(new std::vector<char>);
- {
- wxMemoryOutputStream buffer;
- SaveDirInfo<RIGHT_SIDE>(baseMapping, zToWx(baseMapping.getDBFilename<RIGHT_SIDE>()), buffer);
- dbEntryRight->resize(buffer.GetSize()); //convert output stream to char-array
- buffer.CopyTo(&(*dbEntryRight)[0], buffer.GetSize()); //
- }
-
- //create/update DirInfo-streams
- dbEntriesLeft.second[dbEntriesRight.first] = dbEntryLeft;
- dbEntriesRight.second[dbEntriesLeft.first] = dbEntryRight;
-
-
- struct TryCleanUp //ensure cleanup if working with temporary failed!
- {
- static void tryDeleteFile(const Zstring& filename) //throw ()
- {
- try
- {
- removeFile(filename);
- }
- catch (...) {}
- }
- };
-
- //write (temp-) files...
- Loki::ScopeGuard guardTempFileLeft = Loki::MakeGuard(&TryCleanUp::tryDeleteFile, fileNameLeftTmp);
- saveFile(dbEntriesLeft, fileNameLeftTmp); //throw (FileError)
-
- Loki::ScopeGuard guardTempFileRight = Loki::MakeGuard(&TryCleanUp::tryDeleteFile, fileNameRightTmp);
- saveFile(dbEntriesRight, fileNameRightTmp); //throw (FileError)
-
- //operation finished: rename temp files -> this should work transactionally:
- //if there were no write access, creation of temp files would have failed
- removeFile(baseMapping.getDBFilename<LEFT_SIDE>());
- removeFile(baseMapping.getDBFilename<RIGHT_SIDE>());
- renameFile(fileNameLeftTmp, baseMapping.getDBFilename<LEFT_SIDE>()); //throw (FileError);
- renameFile(fileNameRightTmp, baseMapping.getDBFilename<RIGHT_SIDE>()); //throw (FileError);
-
- guardTempFileLeft.Dismiss(); //no need to delete temp file anymore
- guardTempFileRight.Dismiss(); //
-}
bgstack15