KIO

directorysizejob.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2000, 2006 David Faure <faure@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "directorysizejob.h"
9#include "global.h"
10#include "listjob.h"
11#include <QDebug>
12#include <QTimer>
13#include <kio/jobuidelegatefactory.h>
14
15#include "job_p.h"
16
17#include <set>
18
19namespace KIO
20{
21class DirectorySizeJobPrivate : public KIO::JobPrivate
22{
23public:
24 DirectorySizeJobPrivate()
25 : m_totalSize(0L)
26 , m_totalFiles(0L)
27 , m_totalSubdirs(0L)
28 , m_currentItem(0)
29 {
30 }
31 explicit DirectorySizeJobPrivate(const KFileItemList &lstItems)
32 : m_totalSize(0L)
33 , m_totalFiles(0L)
34 , m_totalSubdirs(0L)
35 , m_lstItems(lstItems)
36 , m_currentItem(0)
37 {
38 }
39 KIO::filesize_t m_totalSize;
40 KIO::filesize_t m_totalFiles;
41 KIO::filesize_t m_totalSubdirs;
42 KFileItemList m_lstItems;
43 int m_currentItem;
44 QHash<long, std::set<long>> m_visitedInodes; // device -> set of inodes
45
46 void startNextJob(const QUrl &url);
47 void slotEntries(KIO::Job *, const KIO::UDSEntryList &);
48 void processNextItem();
49
50 Q_DECLARE_PUBLIC(DirectorySizeJob)
51
52 static inline DirectorySizeJob *newJob(const QUrl &directory)
53 {
54 DirectorySizeJobPrivate *d = new DirectorySizeJobPrivate;
57 d->startNextJob(directory);
58 return job;
59 }
60
61 static inline DirectorySizeJob *newJob(const KFileItemList &lstItems)
62 {
63 DirectorySizeJobPrivate *d = new DirectorySizeJobPrivate(lstItems);
66 QTimer::singleShot(0, job, [d]() {
67 d->processNextItem();
68 });
69 return job;
70 }
71};
72
73} // namespace KIO
74
75using namespace KIO;
76
77DirectorySizeJob::DirectorySizeJob(DirectorySizeJobPrivate &dd)
78 : KIO::Job(dd)
79{
80}
81
82DirectorySizeJob::~DirectorySizeJob()
83{
84}
85
87{
88 return d_func()->m_totalSize;
89}
90
92{
93 return d_func()->m_totalFiles;
94}
95
97{
98 return d_func()->m_totalSubdirs;
99}
100
101void DirectorySizeJobPrivate::processNextItem()
102{
103 Q_Q(DirectorySizeJob);
104 while (m_currentItem < m_lstItems.count()) {
105 const KFileItem item = m_lstItems[m_currentItem++];
106 // qDebug() << item;
107 if (!item.isLink()) {
108 if (item.isDir()) {
109 // qDebug() << "dir -> listing";
110 const auto localPath = item.localPath();
111 if (!localPath.isNull()) {
112 startNextJob(QUrl::fromLocalFile(localPath));
113 } else {
114 startNextJob(item.targetUrl());
115 }
116 return; // we'll come back later, when this one's finished
117 } else {
118 m_totalSize += item.size();
119 m_totalFiles++;
120 // qDebug() << "file -> " << m_totalSize;
121 }
122 } else {
123 m_totalFiles++;
124 }
125 }
126 // qDebug() << "finished";
127 q->emitResult();
128}
129
130void DirectorySizeJobPrivate::startNextJob(const QUrl &url)
131{
132 Q_Q(DirectorySizeJob);
133 // qDebug() << url;
135 listJob->addMetaData(QStringLiteral("details"), QString::number(KIO::StatBasic | KIO::StatResolveSymlink | KIO::StatInode));
136 q->connect(listJob, &KIO::ListJob::entries, q, [this](KIO::Job *job, const KIO::UDSEntryList &list) {
137 slotEntries(job, list);
138 });
139 q->addSubjob(listJob);
140}
141
142void DirectorySizeJobPrivate::slotEntries(KIO::Job *, const KIO::UDSEntryList &list)
143{
146 for (; it != end; ++it) {
147 const KIO::UDSEntry &entry = *it;
148
149 const long device = entry.numberValue(KIO::UDSEntry::UDS_DEVICE_ID, 0);
150 if (device && !entry.isLink()) {
151 // Hard-link detection (#67939)
152 const long inode = entry.numberValue(KIO::UDSEntry::UDS_INODE, 0);
153 std::set<long> &visitedInodes = m_visitedInodes[device]; // find or insert
154 const auto [it, isNewInode] = visitedInodes.insert(inode);
155 if (!isNewInode) {
156 continue;
157 }
158 }
161 if (name == QLatin1Char('.')) {
162 m_totalSize += size;
163 // qDebug() << "'.': added" << size << "->" << m_totalSize;
164 } else if (name != QLatin1String("..")) {
165 if (!entry.isLink()) {
166 m_totalSize += size;
167 }
168 if (!entry.isDir()) {
169 m_totalFiles++;
170 } else {
171 m_totalSubdirs++;
172 }
173 // qDebug() << name << ":" << size << "->" << m_totalSize;
174 }
175 }
176}
177
178void DirectorySizeJob::slotResult(KJob *job)
179{
181 // qDebug() << d->m_totalSize;
182 removeSubjob(job);
183 if (d->m_currentItem < d->m_lstItems.count()) {
184 d->processNextItem();
185 } else {
186 if (job->error()) {
187 setError(job->error());
188 setErrorText(job->errorText());
189 }
190 emitResult();
191 }
192}
193
194// static
196{
197 return DirectorySizeJobPrivate::newJob(directory); // useless - but consistent with other jobs
198}
199
200// static
202{
203 return DirectorySizeJobPrivate::newJob(lstItems);
204}
205
206#include "moc_directorysizejob.cpp"
List of KFileItems, which adds a few helper methods to QList<KFileItem>.
Definition kfileitem.h:632
A KFileItem is a generic class to handle a file, local or remote.
Definition kfileitem.h:36
KIO::filesize_t size() const
Returns the size of the file, if known.
Computes a directory size (similar to "du", but doesn't give the same results since we simply sum up ...
KIO::filesize_t totalSize() const
KIO::filesize_t totalFiles() const
KIO::filesize_t totalSubdirs() const
The base class for all jobs.
bool removeSubjob(KJob *job) override
Mark a sub job as being done.
Definition job.cpp:80
void addMetaData(const QString &key, const QString &value)
Add key/value pair to the meta data that is sent to the worker.
Definition job.cpp:221
A ListJob is allows you to get the get the content of a directory.
void entries(KIO::Job *job, const KIO::UDSEntryList &list)
This signal emits the entry found by the job while listing.
Universal Directory Service.
QString stringValue(uint field) const
Definition udsentry.cpp:365
long long numberValue(uint field, long long defaultValue=0) const
Definition udsentry.cpp:370
bool isLink() const
Definition udsentry.cpp:380
@ UDS_SIZE
Size of the file.
Definition udsentry.h:203
@ UDS_DEVICE_ID
Device number for this file, used to detect hardlinks.
Definition udsentry.h:298
@ UDS_NAME
Filename - as displayed in directory listings etc.
Definition udsentry.h:224
@ UDS_INODE
Inode number for this file, used to detect hardlinks.
Definition udsentry.h:301
bool isDir() const
Definition udsentry.cpp:375
void setErrorText(const QString &errorText)
void emitResult()
int error() const
void setError(int errorCode)
QString errorText() const
void setUiDelegate(KJobUiDelegate *delegate)
A namespace for KIO globals.
KIOCORE_EXPORT DirectorySizeJob * directorySize(const QUrl &directory)
Computes a directory size (by doing a recursive listing).
KIOCORE_EXPORT KJobUiDelegate * createDefaultJobUiDelegate()
Convenience method: use default factory, if there's one, to create a delegate and return it.
KIOCORE_EXPORT ListJob * listRecursive(const QUrl &url, JobFlags flags=DefaultFlags, ListJob::ListFlags listFlags=ListJob::ListFlag::IncludeHidden)
The same as the previous method, but recurses subdirectories.
Definition listjob.cpp:244
@ HideProgressInfo
Hide progress information dialog, i.e. don't show a GUI.
Definition job_base.h:251
qulonglong filesize_t
64-bit file size
Definition global.h:35
@ StatBasic
Filename, access, type, size, linkdest.
Definition global.h:255
@ StatResolveSymlink
Resolve symlinks.
Definition global.h:261
@ StatInode
dev, inode
Definition global.h:265
KIOCORE_EXPORT QStringList list(const QString &fileClass)
Returns a list of directories associated with this file-class.
QString name(StandardAction id)
const QList< QKeySequence > & end()
iterator insert(const Key &key, const T &value)
iterator begin()
qsizetype count() const const
iterator end()
QString number(double n, char format, int precision)
QUrl fromLocalFile(const QString &localFile)
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 16:58:45 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.