1 /**
2  * @file mega/sync.h
3  * @brief Class for synchronizing local and remote trees
4  *
5  * (c) 2013-2014 by Mega Limited, Auckland, New Zealand
6  *
7  * This file is part of the MEGA SDK - Client Access Engine.
8  *
9  * Applications using the MEGA API must present a valid application key
10  * and comply with the the rules set forth in the Terms of Service.
11  *
12  * The MEGA SDK is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  *
16  * @copyright Simplified (2-clause) BSD License.
17  *
18  * You should have received a copy of the license along with this
19  * program.
20  */
21 
22 #ifndef MEGA_SYNC_H
23 #define MEGA_SYNC_H 1
24 
25 #ifdef ENABLE_SYNC
26 #include "megaclient.h"
27 
28 namespace mega {
29 
30 // Searching from the back, this function compares path1 and path2 character by character and
31 // returns the number of consecutive character matches (excluding separators) but only including whole node names.
32 // It's assumed that the paths are normalized (e.g. not contain ..) and separated with the given `localseparator`.
33 // `accumulated` is a buffer that is used to avoid constant reallocations.
34 int computeReversePathMatchScore(string& accumulated, const LocalPath& path1, const LocalPath& path2, const FileSystemAccess&);
35 
36 // Recursively iterates through the filesystem tree starting at the sync root and assigns
37 // fs IDs to those local nodes that match the fingerprint retrieved from disk.
38 bool assignFilesystemIds(Sync& sync, MegaApp& app, FileSystemAccess& fsaccess, handlelocalnode_map& fsidnodes,
39                          LocalPath& localdebris);
40 
41 // A collection of sync configs backed by a database table
42 class MEGA_API SyncConfigBag
43 {
44 public:
45     SyncConfigBag(DbAccess& dbaccess, FileSystemAccess& fsaccess, PrnGen& rng, const std::string& id);
46 
47     MEGA_DISABLE_COPY_MOVE(SyncConfigBag)
48 
49     // Adds a new sync config or updates if exists already
50     void insert(const SyncConfig& syncConfig);
51 
52     // Removes a sync config at the given local path
53     void remove(const std::string& localPath);
54 
55     // Returns the sync config at the given local path
56     const SyncConfig* get(const std::string& localPath) const;
57 
58     // Removes all sync configs
59     void clear();
60 
61     // Returns all current sync configs
62     std::vector<SyncConfig> all() const;
63 
64 private:
65     std::unique_ptr<DbTable> mTable; // table for caching the sync configs
66     std::map<std::string, SyncConfig> mSyncConfigs; // map of local paths to sync configs
67 };
68 
69 class MEGA_API Sync
70 {
71 public:
72 
73     // returns the sync config
74     const SyncConfig& getConfig() const;
75 
76     // sets whether this sync is resumable (default is true)
77     void setResumable(bool isResumable);
78 
79     void* appData = nullptr;
80 
81     MegaClient* client = nullptr;
82 
83     // sync-wide directory notification provider
84     std::unique_ptr<DirNotify> dirnotify;
85 
86     // root of local filesystem tree, holding the sync's root folder.  Never null except briefly in the destructor (to ensure efficient db usage)
87     unique_ptr<LocalNode> localroot;
88 
89     FileSystemType mFilesystemType = FS_UNKNOWN;
90 
91     // Path used to normalize sync locaroot name when using prefix /System/Volumes/Data needed by fsevents, due to notification paths
92     // are served with such prefix from macOS catalina +
93 #ifdef __APPLE__
94     string mFsEventsPath;
95 #endif
96     // current state
97     syncstate_t state = SYNC_INITIALSCAN;
98 
99     // are we conducting a full tree scan? (during initialization and if event notification failed)
100     bool fullscan = true;
101 
102     // syncing to an inbound share?
103     bool inshare = false;
104 
105     // deletion queue
106     set<uint32_t> deleteq;
107 
108     // insertion/update queue
109     localnode_set insertq;
110 
111     // adds an entry to the delete queue - removes it from insertq
112     void statecachedel(LocalNode*);
113 
114     // adds an entry to the insert queue - removes it from deleteq
115     void statecacheadd(LocalNode*);
116 
117     // recursively add children
118     void addstatecachechildren(uint32_t, idlocalnode_map*, LocalPath&, LocalNode*, int);
119 
120     // Caches all synchronized LocalNode
121     void cachenodes();
122 
123     // change state, signal to application
124     void changestate(syncstate_t);
125 
126     // skip duplicates and self-caused
127     bool checkValidNotification(int q, Notification& notification);
128 
129     // process and remove one directory notification queue item from *notify
130     dstime procscanq(int);
131 
132     // recursively look for vanished child nodes and delete them
133     void deletemissing(LocalNode*);
134 
135     // scan specific path
136     LocalNode* checkpath(LocalNode*, LocalPath*, string* const, dstime*, bool wejustcreatedthisfolder, DirAccess* iteratingDir);
137 
138     m_off_t localbytes = 0;
139     unsigned localnodes[2]{};
140 
141     // look up LocalNode relative to localroot
142     LocalNode* localnodebypath(LocalNode*, const LocalPath&, LocalNode** = NULL, string* = NULL);
143 
144     // Assigns fs IDs to those local nodes that match the fingerprint retrieved from disk.
145     // The fs IDs of unmatched nodes are invalidated.
146     bool assignfsids();
147 
148     // scan items in specified path and add as children of the specified
149     // LocalNode
150     bool scan(LocalPath*, FileAccess*);
151 
152     // own position in session sync list
153     sync_list::iterator sync_it{};
154 
155     // rescan sequence number (incremented when a full rescan or a new
156     // notification batch starts)
157     int scanseqno = 0;
158 
159     // notified nodes originating from this sync bear this tag
160     int tag = 0;
161 
162     // debris path component relative to the base path
163     string debris;
164     LocalPath localdebris;
165 
166     // permanent lock on the debris/tmp folder
167     std::unique_ptr<FileAccess> tmpfa;
168 
169     // state cache table
170     DbTable* statecachetable = nullptr;
171 
172     // move file or folder to localdebris
173     bool movetolocaldebris(LocalPath& localpath);
174 
175     // original filesystem fingerprint
176     fsfp_t fsfp = 0;
177 
178     // does the filesystem have stable IDs? (FAT does not)
179     bool fsstableids = false;
180 
181     // Error that causes a cancellation
182     error errorcode = API_OK;
183 
184     // true if the sync hasn't loaded cached LocalNodes yet
185     bool initializing = true;
186 
187     // true if the local synced folder is a network folder
188     bool isnetwork = false;
189 
190     // values related to possible files being updated
191     m_off_t updatedfilesize = ~0;
192     m_time_t updatedfilets = 0;
193     m_time_t updatedfileinitialts = 0;
194 
195     Sync(MegaClient*, SyncConfig, const char*, string*, Node*, bool, int, void*);
196     ~Sync();
197 
198     static const int SCANNING_DELAY_DS;
199     static const int EXTRA_SCANNING_DELAY_DS;
200     static const int FILE_UPDATE_DELAY_DS;
201     static const int FILE_UPDATE_MAX_DELAY_SECS;
202     static const dstime RECENT_VERSION_INTERVAL_SECS;
203 
204 protected :
205     bool readstatecache();
206 
207 private:
208     std::string mLocalPath;
209 };
210 } // namespace
211 
212 #endif
213 #endif
214