234{
237 {
239 }
240
242
243 std::size_t countRecentUpdates = 0;
244 std::size_t countArchivedUpdates = 0;
245
246
247 for (auto const& entry : applied)
249 ++countRecentUpdates;
250 else
251 ++countArchivedUpdates;
252
253
255 for (auto& entry : applied)
256 hashToName.insert(std::make_pair(entry.second.hash, entry.first));
257
258 std::size_t importedUpdates = 0;
259
261 {
262 auto filePath = sqlFile.first;
263 auto fileState = sqlFile.second;
264
265 LOG_DEBUG(
"sql.updates",
"Checking update \"{}\"...", filePath.filename().generic_string());
266
267 AppliedFileStorage::const_iterator iter = applied.find(filePath.filename().string());
268 if (iter != applied.end())
269 {
270
271 if (!redundancyChecks)
272 {
273 LOG_DEBUG(
"sql.updates",
">> Update is already applied, skipping redundancy checks.");
274 applied.erase(iter);
275 return;
276 }
277
278
279 if (!archivedRedundancy && (iter->second.state ==
ARCHIVED) && (sqlFile.second ==
ARCHIVED))
280 {
281 LOG_DEBUG(
"sql.updates",
">> Update is archived and marked as archived in database, skipping redundancy checks.");
282 applied.erase(iter);
283 return;
284 }
285 }
286
288
290
291
292 if (iter == applied.end())
293 {
294
295 HashToFileNameStorage::const_iterator const hashIter = hashToName.find(hash);
296 if (hashIter != hashToName.end())
297 {
298
299 LocaleFileStorage::const_iterator localeIter;
300
301
302 for (localeIter = available.begin(); (localeIter != available.end()) &&
303 (localeIter->first.filename().string() != hashIter->second); ++localeIter);
304
305
306 if (localeIter != available.end())
307 {
308 LOG_WARN(
"sql.updates",
">> It seems like the update \"{}\" \'{}\' was renamed, but the old file is still there! " \
309 "Treating it as a new file! (It is probably an unmodified copy of the file \"{}\")",
310 filePath.filename().string(), hash.substr(0, 7),
311 localeIter->first.filename().string());
312 }
313 else
314 {
315 LOG_INFO(
"sql.updates",
">> Renaming update \"{}\" to \"{}\" \'{}\'.",
316 hashIter->second, filePath.filename().string(), hash.substr(0, 7));
317
318 RenameEntry(hashIter->second, filePath.filename().string());
319 applied.erase(hashIter->second);
320 return;
321 }
322 }
323
324 else
325 {
326 LOG_INFO(
"sql.updates",
">> Applying update \"{}\" \'{}\'...",
327 filePath.filename().string(), hash.substr(0, 7));
328 }
329 }
330
331 else if (allowRehash && iter->second.hash.empty())
332 {
334
335 LOG_INFO(
"sql.updates",
">> Re-hashing update \"{}\" \'{}\'...", filePath.filename().string(),
336 hash.substr(0, 7));
337 }
338 else
339 {
340
341 if (iter->second.hash != hash)
342 {
343 LOG_INFO(
"sql.updates",
">> Reapplying update \"{}\" \'{}\' -> \'{}\' (it changed)...", filePath.filename().string(),
344 iter->second.hash.substr(0, 7), hash.substr(0, 7));
345 }
346 else
347 {
348
349 if (iter->second.state != fileState)
350 {
351 LOG_DEBUG(
"sql.updates",
">> Updating the state of \"{}\" to \'{}\'...",
353
354 UpdateState(filePath.filename().string(), fileState);
355 }
356
357 LOG_DEBUG(
"sql.updates",
">> Update is already applied and matches the hash \'{}\'.", hash.substr(0, 7));
358
359 applied.erase(iter);
360 return;
361 }
362 }
363
365 AppliedFileEntry const file = { filePath.filename().string(), hash, fileState, 0 };
366
367 switch (mode)
368 {
370 speed =
Apply(filePath);
371 [[fallthrough]];
374 break;
375 }
376
377 if (iter != applied.end())
378 applied.erase(iter);
379
381 ++importedUpdates;
382 };
383
384
385 for (auto const& availableQuery : available)
386 {
387 if (availableQuery.second !=
CUSTOM && availableQuery.second !=
MODULE)
388 ApplyUpdateFile(availableQuery);
389 }
390
391
392 for (auto const& availableQuery : available)
393 {
394 if (availableQuery.second ==
CUSTOM || availableQuery.second ==
MODULE)
395 ApplyUpdateFile(availableQuery);
396 }
397
398
400 {
401 bool const doCleanup = (cleanDeadReferencesMaxCount < 0) || (applied.size() <= static_cast<size_t>(cleanDeadReferencesMaxCount));
402
404 for (auto const& entry : applied)
405 {
406 if (entry.second.state !=
MODULE)
407 {
409 ">> The file \'{}\' was applied to the database, but is missing in"
410 " your update directory now!",
411 entry.first);
412
413 if (doCleanup)
414 {
415 LOG_INFO(
"sql.updates",
"Deleting orphaned entry \'{}\'...", entry.first);
416 toCleanup.insert(entry);
417 }
418 }
419 }
420
421 if (!toCleanup.empty())
422 {
423 if (doCleanup)
425 else
426 {
428 "Cleanup is disabled! There were {} dirty files applied to your database, "
429 "but they are now missing in your source directory!",
430 toCleanup.size());
431 }
432 }
433 }
434
435 return UpdateResult(importedUpdates, countRecentUpdates, countArchivedUpdates);
436}
#define LOG_INFO(filterType__,...)
Definition: Log.h:164
#define LOG_ERROR(filterType__,...)
Definition: Log.h:156
#define LOG_DEBUG(filterType__,...)
Definition: Log.h:168
std::string ByteArrayToHexStr(Container const &c, bool reverse=false)
Definition: Util.h:381
static Digest GetDigestOf(uint8 const *data, std::size_t len)
Definition: CryptoHash.h:48
Definition: UpdateFetcher.h:30
uint32 Apply(Path const &path) const
Definition: UpdateFetcher.cpp:438
LocaleFileStorage GetFileList() const
Definition: UpdateFetcher.cpp:62
void UpdateState(std::string const &name, State const state) const
Definition: UpdateFetcher.cpp:503
UpdateMode
Definition: UpdateFetcher.h:66
std::string ReadSQLUpdate(Path const &file) const
Definition: UpdateFetcher.cpp:206
void UpdateEntry(AppliedFileEntry const &entry, uint32 const speed=0) const
Definition: UpdateFetcher.cpp:452
void RenameEntry(std::string const &from, std::string const &to) const
Definition: UpdateFetcher.cpp:461
std::unordered_map< std::string, std::string > HashToFileNameStorage
Definition: UpdateFetcher.h:134
AppliedFileStorage ReceiveAppliedFiles() const
Definition: UpdateFetcher.cpp:183
void CleanUp(AppliedFileStorage const &storage) const
Definition: UpdateFetcher.cpp:480