1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
// **************************************************************************
// * 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) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
#ifndef VERSIONING_HEADER_8760247652438056
#define VERSIONING_HEADER_8760247652438056
#include <vector>
#include <functional>
#include <zen/time.h>
#include <zen/zstring.h>
#include <zen/int64.h>
#include <zen/file_error.h>
#include "../structures.h"
namespace zen
{
struct CallbackMoveDir;
struct CallbackMoveFile;
//e.g. move C:\Source\subdir\Sample.txt -> D:\Revisions\subdir\Sample.txt 2012-05-15 131513.txt
//scheme: <revisions directory>\<relpath>\<filename>.<ext> YYYY-MM-DD HHMMSS.<ext>
/*
- ignores missing source files/dirs
- creates missing intermediate directories
- does not create empty directories
- handles symlinks
- replaces already existing target files/dirs (supports retry)
=> (unlikely) risk of data loss for naming convention "versioning":
race-condition if two FFS instances start at the very same second OR multiple folder pairs process the same filename!!
*/
class FileVersioner
{
public:
FileVersioner(const Zstring& versioningDirectory, //throw FileError
VersioningStyle versioningStyle,
const TimeComp& timeStamp) : //max versions per file; < 0 := no limit
versioningStyle_(versioningStyle),
versioningDirectory_(versioningDirectory),
timeStamp_(formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"), timeStamp)) //e.g. "2012-05-15 131513"
{
if (timeStamp_.size() != 17) //formatTime() returns empty string on error; unexpected length: e.g. problem in year 10000!
throw FileError(_("Unable to create timestamp for versioning:") + L" \"" + timeStamp_ + L"\"");
}
bool revisionFile(const Zstring& fullName, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError; return "false" if file is not existing
void revisionDir (const Zstring& fullName, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
//void limitVersions(std::function<void()> updateUI); //throw FileError; call when done revisioning!
private:
bool revisionFileImpl(const Zstring& fullName, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
void revisionDirImpl (const Zstring& fullName, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
const VersioningStyle versioningStyle_;
const Zstring versioningDirectory_;
const Zstring timeStamp_;
//std::vector<Zstring> fileRelNames; //store list of revisioned file and symlink relative names for limitVersions()
};
struct CallbackMoveFile //see CallbackCopyFile for limitations when throwing exceptions!
{
virtual ~CallbackMoveFile() {}
virtual void updateStatus(Int64 bytesDelta) = 0; //called frequently if move has to revert to copy + delete:
};
struct CallbackMoveDir //see CallbackCopyFile for limitations when throwing exceptions!
{
virtual ~CallbackMoveDir() {}
virtual void onBeforeFileMove(const Zstring& fileFrom, const Zstring& fileTo) = 0; //one call for each *existing* object!
virtual void onBeforeDirMove (const Zstring& dirFrom, const Zstring& dirTo ) = 0; //
virtual void updateStatus(Int64 bytesDelta) = 0; //called frequently if move has to revert to copy + delete:
};
namespace impl //declare for unit tests:
{
bool isMatchingVersion(const Zstring& shortname, const Zstring& shortnameVersion);
}
}
#endif //VERSIONING_HEADER_8760247652438056
|