Skip to content

Latest commit

 

History

History
231 lines (195 loc) · 7.6 KB

diskusage.cpp

File metadata and controls

231 lines (195 loc) · 7.6 KB
 
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
/*
* Copyright (C) 2015 Jolla Ltd.
* Contact: Thomas Perl <thomas.perl@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* "Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Nemo Mobile nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
*/
#include "diskusage.h"
#include "diskusage_p.h"
#include <QThread>
#include <QDebug>
#include <QJSEngine>
Jul 21, 2016
Jul 21, 2016
39
#include <QDir>
Mar 6, 2015
Mar 6, 2015
41
42
43
44
45
46
47
48
49
50
51
DiskUsageWorker::DiskUsageWorker(QObject *parent)
: QObject(parent)
, m_quit(false)
{
}
DiskUsageWorker::~DiskUsageWorker()
{
}
Mar 17, 2015
Mar 17, 2015
52
void DiskUsageWorker::submit(QStringList paths, QJSValue *callback)
Mar 6, 2015
Mar 6, 2015
53
{
Mar 17, 2015
Mar 17, 2015
54
emit finished(calculate(paths), callback);
Mar 6, 2015
Mar 6, 2015
55
56
}
Mar 17, 2015
Mar 17, 2015
57
QVariantMap DiskUsageWorker::calculate(QStringList paths)
58
59
{
QVariantMap usage;
Jul 21, 2016
Jul 21, 2016
60
// expanded Path places the object in the tree so parents can have it subtracted from its total
Mar 12, 2015
Mar 12, 2015
61
QMap<QString, QString> expandedPaths; // input path -> expanded path
Mar 17, 2015
Mar 17, 2015
62
QMap<QString, QString> originalPaths; // expanded path -> input path
Jul 21, 2016
Jul 21, 2016
64
65
66
67
// Older adaptations (e.g. Jolla 1) don't have /home/.android/. Android home is in the root.
QString androidHome = QString("/home/.android");
bool androidHomeExists = QDir(androidHome).exists();
68
foreach (const QString &path, paths) {
Jul 21, 2016
Jul 21, 2016
69
QString expandedPath;
Mar 6, 2015
Mar 6, 2015
70
71
72
73
74
75
76
// Pseudo-path for querying RPM database for file sizes
// ----------------------------------------------------
// Example path with package name: ":rpm:python3-base"
// Example path with glob: ":rpm:harbour-*" (will sum up all matching package sizes)
if (path.startsWith(":rpm:")) {
QString glob = path.mid(5);
usage[path] = calculateRpmSize(glob);
Jul 21, 2016
Jul 21, 2016
77
expandedPath = "/usr/" + path;
Mar 6, 2015
Mar 6, 2015
78
79
80
81
} else if (path.startsWith(":apkd:")) {
// Pseudo-path for querying Android apps' data usage
QString rest = path.mid(6);
usage[path] = calculateApkdSize(rest);
Jul 21, 2016
Jul 21, 2016
82
expandedPath = (androidHomeExists ? androidHome : "") + "/data/data";
Mar 6, 2015
Mar 6, 2015
83
} else {
Jul 21, 2016
Jul 21, 2016
84
85
86
87
quint64 size = calculateSize(path, &expandedPath, androidHomeExists);
if (expandedPath.startsWith(androidHome) && !androidHomeExists) {
expandedPath = expandedPath.mid(androidHome.length());
}
Mar 12, 2015
Mar 12, 2015
88
usage[path] = size;
Mar 6, 2015
Mar 6, 2015
89
}
Jul 21, 2016
Jul 21, 2016
91
92
expandedPaths[path] = expandedPath;
originalPaths[expandedPath] = path;
93
94
95
96
97
if (m_quit) {
break;
}
}
Mar 17, 2015
Mar 17, 2015
98
99
100
// Sort keys in reverse order (so child directories come before their
// parents, and the calculation is done correctly, no child directory
// subtracted once too often), for example:
Oct 17, 2019
Oct 17, 2019
101
102
// 1. a0 = size(/home/<user>/foo/)
// 2. b0 = size(/home/<user>/)
Mar 17, 2015
Mar 17, 2015
103
104
105
106
107
108
109
110
111
112
113
114
115
// 3. c0 = size(/)
//
// This will calculate the following changes in the nested for loop below:
// 1. b1 = b0 - a0
// 2. c1 = c0 - a0
// 3. c2 = c1 - b1
//
// Combined and simplified, this will give us the output values:
// 1. a' = a0
// 2. b' = b1 = b0 - a0
// 3. c' = c2 = c1 - b1 = (c0 - a0) - (b0 - a0) = c0 - a0 - b0 + a0 = c0 - b0
//
// Or with paths:
Oct 17, 2019
Oct 17, 2019
116
117
118
// 1. output(/home/<user>/foo/) = size(/home/<user>/foo/)
// 2. output(/home/<user>/) = size(/home/<user>/) - size(/home/<user>/foo/)
// 3. output(/) = size(/) - size(/home/<user>/)
Mar 17, 2015
Mar 17, 2015
119
120
121
122
123
124
125
126
127
QStringList keys;
foreach (const QString &key, usage.uniqueKeys()) {
keys << expandedPaths.value(key, key);
}
qStableSort(keys.begin(), keys.end(), qGreater<QString>());
for (int i=0; i<keys.length(); i++) {
for (int j=i+1; j<keys.length(); j++) {
QString subpath = keys[i];
QString path = keys[j];
128
Mar 12, 2015
Mar 12, 2015
129
if ((subpath.length() > path.length() && subpath.indexOf(path) == 0) || (path == "/")) {
Mar 17, 2015
Mar 17, 2015
130
131
132
qlonglong subbytes = usage[originalPaths.value(subpath, subpath)].toLongLong();
qlonglong bytes = usage[originalPaths.value(path, path)].toLongLong();
133
bytes -= subbytes;
Mar 17, 2015
Mar 17, 2015
134
usage[originalPaths.value(path, path)] = bytes;
135
136
137
138
}
}
}
Mar 17, 2015
Mar 17, 2015
139
return usage;
140
141
142
143
144
145
146
147
148
149
150
151
152
153
}
class DiskUsagePrivate
{
Q_DISABLE_COPY(DiskUsagePrivate)
Q_DECLARE_PUBLIC(DiskUsage)
DiskUsage * const q_ptr;
public:
DiskUsagePrivate(DiskUsage *usage);
~DiskUsagePrivate();
private:
Mar 10, 2015
Mar 10, 2015
154
QThread *m_thread;
155
156
157
158
159
DiskUsageWorker *m_worker;
};
DiskUsagePrivate::DiskUsagePrivate(DiskUsage *usage)
: q_ptr(usage)
Mar 10, 2015
Mar 10, 2015
160
, m_thread(new QThread())
161
162
, m_worker(new DiskUsageWorker())
{
Mar 10, 2015
Mar 10, 2015
163
m_worker->moveToThread(m_thread);
164
165
166
167
168
169
170
QObject::connect(usage, SIGNAL(submit(QStringList, QJSValue *)),
m_worker, SLOT(submit(QStringList, QJSValue *)));
QObject::connect(m_worker, SIGNAL(finished(QVariantMap, QJSValue *)),
usage, SLOT(finished(QVariantMap, QJSValue *)));
Mar 10, 2015
Mar 10, 2015
171
172
173
174
175
176
177
QObject::connect(m_thread, SIGNAL(finished()),
m_worker, SLOT(deleteLater()));
QObject::connect(m_thread, SIGNAL(finished()),
m_thread, SLOT(deleteLater()));
m_thread->start();
178
179
180
181
182
183
184
}
DiskUsagePrivate::~DiskUsagePrivate()
{
// Make sure the worker quits as soon as possible
m_worker->scheduleQuit();
Mar 10, 2015
Mar 10, 2015
185
186
// Tell thread to shut down as early as possible
m_thread->quit();
187
188
189
190
191
192
193
194
}
DiskUsage::DiskUsage(QObject *parent)
: QObject(parent)
, d_ptr(new DiskUsagePrivate(this))
, m_working(false)
{
Sep 2, 2019
Sep 2, 2019
195
qWarning() << Q_FUNC_INFO << "DiskUsage is deprecated in org.nemomobile.systemsettings package 0.5.22 (Sept 2019), use DiskUsage from Nemo.FileManager instead.";
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
}
DiskUsage::~DiskUsage()
{
}
void DiskUsage::calculate(const QStringList &paths, QJSValue callback)
{
QJSValue *cb = 0;
if (!callback.isNull() && !callback.isUndefined() && callback.isCallable()) {
cb = new QJSValue(callback);
}
setWorking(true);
emit submit(paths, cb);
}
void DiskUsage::finished(QVariantMap usage, QJSValue *callback)
{
if (callback) {
callback->call(QJSValueList() << callback->engine()->toScriptValue(usage));
delete callback;
}
Oct 6, 2016
Oct 6, 2016
221
222
223
224
// the result has been set, so emit resultChanged() even if result was not valid
m_result = usage;
emit resultChanged();
225
226
setWorking(false);
}
Oct 6, 2016
Oct 6, 2016
227
228
229
230
231
QVariantMap DiskUsage::result() const
{
return m_result;
}