1 // This file is part of Desktop App Toolkit,
2 // a set of libraries for developing nice desktop applications.
3 //
4 // For license and copyright information please follow this link:
5 // https://github.com/desktop-app/legal/blob/master/LEGAL
6 //
7 #include "storage/cache/storage_cache_cleaner.h"
8
9 #include <crl/crl.h>
10 #include <QtCore/QDir>
11 #include <QtCore/QFile>
12 #include <unordered_map>
13 #include <set>
14
15 namespace Storage {
16 namespace Cache {
17 namespace details {
18
19 class CleanerObject {
20 public:
21 CleanerObject(
22 crl::weak_on_queue<CleanerObject> weak,
23 const QString &base,
24 base::binary_guard &&guard,
25 FnMut<void(Error)> done);
26
27 private:
28 void start();
29 void scheduleNext();
30 void cleanNext();
31 void done();
32
33 crl::weak_on_queue<CleanerObject> _weak;
34 QString _base, _errorPath;
35 std::vector<QString> _queue;
36 base::binary_guard _guard;
37 FnMut<void(Error)> _done;
38
39 };
40
CleanerObject(crl::weak_on_queue<CleanerObject> weak,const QString & base,base::binary_guard && guard,FnMut<void (Error)> done)41 CleanerObject::CleanerObject(
42 crl::weak_on_queue<CleanerObject> weak,
43 const QString &base,
44 base::binary_guard &&guard,
45 FnMut<void(Error)> done)
46 : _weak(std::move(weak))
47 , _base(base)
48 , _guard(std::move(guard))
49 , _done(std::move(done)) {
50 start();
51 }
52
start()53 void CleanerObject::start() {
54 const auto entries = QDir(_base).entryList(
55 QDir::Dirs | QDir::NoDotAndDotDot);
56 for (const auto &entry : entries) {
57 _queue.push_back(entry);
58 }
59 if (const auto version = ReadVersionValue(_base)) {
60 _queue.erase(
61 ranges::remove(_queue, QString::number(*version)),
62 end(_queue));
63 scheduleNext();
64 } else {
65 _errorPath = VersionFilePath(_base);
66 done();
67 }
68 }
69
scheduleNext()70 void CleanerObject::scheduleNext() {
71 if (_queue.empty()) {
72 done();
73 return;
74 }
75 _weak.with([](CleanerObject &that) {
76 if (that._guard) {
77 that.cleanNext();
78 }
79 });
80 }
81
cleanNext()82 void CleanerObject::cleanNext() {
83 const auto path = _base + _queue.back();
84 _queue.pop_back();
85 if (!QDir(path).removeRecursively()) {
86 _errorPath = path;
87 }
88 scheduleNext();
89 }
90
done()91 void CleanerObject::done() {
92 if (_done) {
93 _done(_errorPath.isEmpty()
94 ? Error::NoError()
95 : Error{ Error::Type::IO, _errorPath });
96 }
97 }
98
Cleaner(const QString & base,base::binary_guard && guard,FnMut<void (Error)> done)99 Cleaner::Cleaner(
100 const QString &base,
101 base::binary_guard &&guard,
102 FnMut<void(Error)> done)
103 : _wrapped(base, std::move(guard), std::move(done)) {
104 }
105
106 Cleaner::~Cleaner() = default;
107
108 } // namespace details
109 } // namespace Cache
110 } // namespace Storage
111