KIO

listjob.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 2000 Stephan Kulow <[email protected]>
4  SPDX-FileCopyrightText: 2000-2009 David Faure <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "listjob.h"
10 #include "../utils_p.h"
11 #include "job_p.h"
12 #include "slave.h"
13 #include <QTimer>
14 #include <kurlauthorized.h>
15 
16 #include <QDebug>
17 
18 using namespace KIO;
19 
20 class KIO::ListJobPrivate : public KIO::SimpleJobPrivate
21 {
22 public:
23  ListJobPrivate(const QUrl &url, bool _recursive, const QString &prefix, const QString &displayPrefix, bool _includeHidden)
24  : SimpleJobPrivate(url, CMD_LISTDIR, QByteArray())
25  , recursive(_recursive)
26  , includeHidden(_includeHidden)
27  , m_prefix(prefix)
28  , m_displayPrefix(displayPrefix)
29  , m_processedEntries(0)
30  {
31  }
32  bool recursive;
33  bool includeHidden;
34  QString m_prefix;
35  QString m_displayPrefix;
36  unsigned long m_processedEntries;
37  QUrl m_redirectionURL;
38 
39  /**
40  * @internal
41  * Called by the scheduler when a @p slave gets to
42  * work on this job.
43  * @param slave the slave that starts working on this job
44  */
45  void start(Slave *slave) override;
46 
47  void slotListEntries(const KIO::UDSEntryList &list);
48  void slotRedirection(const QUrl &url);
49  void gotEntries(KIO::Job *subjob, const KIO::UDSEntryList &list);
50  void slotSubError(ListJob *job, ListJob *subJob);
51 
52  Q_DECLARE_PUBLIC(ListJob)
53 
54  static inline ListJob *
55  newJob(const QUrl &u, bool _recursive, const QString &prefix, const QString &displayPrefix, bool _includeHidden, JobFlags flags = HideProgressInfo)
56  {
57  ListJob *job = new ListJob(*new ListJobPrivate(u, _recursive, prefix, displayPrefix, _includeHidden));
59  if (!(flags & HideProgressInfo)) {
61  }
62  return job;
63  }
64  static inline ListJob *newJobNoUi(const QUrl &u, bool _recursive, const QString &prefix, const QString &displayPrefix, bool _includeHidden)
65  {
66  return new ListJob(*new ListJobPrivate(u, _recursive, prefix, displayPrefix, _includeHidden));
67  }
68 };
69 
70 ListJob::ListJob(ListJobPrivate &dd)
71  : SimpleJob(dd)
72 {
73  Q_D(ListJob);
74  // We couldn't set the args when calling the parent constructor,
75  // so do it now.
76  QDataStream stream(&d->m_packedArgs, QIODevice::WriteOnly);
77  stream << d->m_url;
78 }
79 
80 ListJob::~ListJob()
81 {
82 }
83 
84 void ListJobPrivate::slotListEntries(const KIO::UDSEntryList &list)
85 {
86  Q_Q(ListJob);
87  // Emit progress info (takes care of emit processedSize and percent)
88  m_processedEntries += list.count();
89  slotProcessedSize(m_processedEntries);
90 
91  if (recursive) {
94 
95  for (; it != end; ++it) {
96  const UDSEntry &entry = *it;
97 
98  QUrl itemURL;
99  const QString udsUrl = entry.stringValue(KIO::UDSEntry::UDS_URL);
100  QString filename;
101  if (!udsUrl.isEmpty()) {
102  itemURL = QUrl(udsUrl);
103  filename = itemURL.fileName();
104  } else { // no URL, use the name
105  itemURL = q->url();
106  filename = entry.stringValue(KIO::UDSEntry::UDS_NAME);
107  Q_ASSERT(!filename.isEmpty()); // we'll recurse forever otherwise :)
108  itemURL.setPath(Utils::concatPaths(itemURL.path(), filename));
109  }
110 
111  if (entry.isDir() && !entry.isLink()) {
112  Q_ASSERT(!filename.isEmpty());
114  if (displayName.isEmpty()) {
115  displayName = filename;
116  }
117  // skip hidden dirs when listing if requested
118  if (filename != QLatin1String("..") && filename != QLatin1String(".") && (includeHidden || filename[0] != QLatin1Char('.'))) {
119  ListJob *job = ListJobPrivate::newJobNoUi(itemURL,
120  true /*recursive*/,
121  m_prefix + filename + QLatin1Char('/'),
122  m_displayPrefix + displayName + QLatin1Char('/'),
123  includeHidden);
124  QObject::connect(job, &ListJob::entries, q, [this](KIO::Job *job, const KIO::UDSEntryList &list) {
125  gotEntries(job, list);
126  });
127  QObject::connect(job, &ListJob::subError, q, [this](KIO::ListJob *job, KIO::ListJob *ljob) {
128  slotSubError(job, ljob);
129  });
130 
131  q->addSubjob(job);
132  }
133  }
134  }
135  }
136 
137  // Not recursive, or top-level of recursive listing : return now (send . and .. as well)
138  // exclusion of hidden files also requires the full sweep, but the case for full-listing
139  // a single dir is probably common enough to justify the shortcut
140  if (m_prefix.isNull() && includeHidden) {
141  Q_EMIT q->entries(q, list);
142  } else {
143  UDSEntryList newlist = list;
144 
145  auto removeFunc = [this](const UDSEntry &entry) {
146  const QString filename = entry.stringValue(KIO::UDSEntry::UDS_NAME);
147  // Avoid returning entries like subdir/. and subdir/.., but include . and .. for
148  // the toplevel dir, and skip hidden files/dirs if that was requested
149  const bool shouldEmit = (m_prefix.isNull() || (filename != QLatin1String("..") && filename != QLatin1String(".")))
150  && (includeHidden || (filename[0] != QLatin1Char('.')));
151  return !shouldEmit;
152  };
153  newlist.erase(std::remove_if(newlist.begin(), newlist.end(), removeFunc), newlist.end());
154 
155  for (UDSEntry &newone : newlist) {
156  // Modify the name in the UDSEntry
157  const QString filename = newone.stringValue(KIO::UDSEntry::UDS_NAME);
159  if (displayName.isEmpty()) {
160  displayName = filename;
161  }
162 
163  // ## Didn't find a way to use the iterator instead of re-doing a key lookup
164  newone.replace(KIO::UDSEntry::UDS_NAME, m_prefix + filename);
165  newone.replace(KIO::UDSEntry::UDS_DISPLAY_NAME, m_displayPrefix + displayName);
166  }
167 
168  Q_EMIT q->entries(q, newlist);
169  }
170 }
171 
172 void ListJobPrivate::gotEntries(KIO::Job *, const KIO::UDSEntryList &list)
173 {
174  // Forward entries received by subjob - faking we received them ourselves
175  Q_Q(ListJob);
176  Q_EMIT q->entries(q, list);
177 }
178 
179 void ListJobPrivate::slotSubError(KIO::ListJob * /*job*/, KIO::ListJob *subJob)
180 {
181  Q_Q(ListJob);
182  Q_EMIT q->subError(q, subJob); // Let the signal of subError go up
183 }
184 
185 void ListJob::slotResult(KJob *job)
186 {
187  Q_D(ListJob);
188  if (job->error()) {
189  // If we can't list a subdir, the result is still ok
190  // This is why we override KCompositeJob::slotResult - to not set
191  // an error on parent job.
192  // Let's emit a signal about this though
193  Q_EMIT subError(this, static_cast<KIO::ListJob *>(job));
194  }
195  removeSubjob(job);
196  if (!hasSubjobs() && !d->m_slave) { // if the main directory listing is still running, it will emit result in SimpleJob::slotFinished()
197  emitResult();
198  }
199 }
200 
201 void ListJobPrivate::slotRedirection(const QUrl &url)
202 {
203  Q_Q(ListJob);
204  if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("redirect"), m_url, url)) {
205  qCWarning(KIO_CORE) << "Redirection from" << m_url << "to" << url << "REJECTED!";
206  return;
207  }
208  m_redirectionURL = url; // We'll remember that when the job finishes
209  Q_EMIT q->redirection(q, m_redirectionURL);
210 }
211 
212 void ListJob::slotFinished()
213 {
214  Q_D(ListJob);
215 
216  if (!d->m_redirectionURL.isEmpty() && d->m_redirectionURL.isValid() && !error()) {
217  // qDebug() << "Redirection to " << d->m_redirectionURL;
218  if (queryMetaData(QStringLiteral("permanent-redirect")) == QLatin1String("true")) {
219  Q_EMIT permanentRedirection(this, d->m_url, d->m_redirectionURL);
220  }
221 
222  if (d->m_redirectionHandlingEnabled) {
223  d->m_packedArgs.truncate(0);
224  QDataStream stream(&d->m_packedArgs, QIODevice::WriteOnly);
225  stream << d->m_redirectionURL;
226 
227  d->restartAfterRedirection(&d->m_redirectionURL);
228  return;
229  }
230  }
231 
232  // Return slave to the scheduler
234 }
235 
236 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 101)
237 void ListJob::slotMetaData(const KIO::MetaData &_metaData)
238 {
239  SimpleJob::slotMetaData(_metaData);
240 }
241 #endif
242 
243 ListJob *KIO::listDir(const QUrl &url, JobFlags flags, bool includeHidden)
244 {
245  return ListJobPrivate::newJob(url, false, QString(), QString(), includeHidden, flags);
246 }
247 
248 ListJob *KIO::listRecursive(const QUrl &url, JobFlags flags, bool includeHidden)
249 {
250  return ListJobPrivate::newJob(url, true, QString(), QString(), includeHidden, flags);
251 }
252 
253 void ListJob::setUnrestricted(bool unrestricted)
254 {
255  Q_D(ListJob);
256  if (unrestricted) {
257  d->m_extraFlags |= JobPrivate::EF_ListJobUnrestricted;
258  } else {
259  d->m_extraFlags &= ~JobPrivate::EF_ListJobUnrestricted;
260  }
261 }
262 
263 void ListJobPrivate::start(Slave *slave)
264 {
265  Q_Q(ListJob);
266  if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("list"), m_url, m_url) && !(m_extraFlags & EF_ListJobUnrestricted)) {
267  q->setError(ERR_ACCESS_DENIED);
268  q->setErrorText(m_url.toDisplayString());
269  QTimer::singleShot(0, q, &ListJob::slotFinished);
270  return;
271  }
272  QObject::connect(slave, &Slave::listEntries, q, [this](const KIO::UDSEntryList &list) {
273  slotListEntries(list);
274  });
275 
276  QObject::connect(slave, &Slave::totalSize, q, [this](KIO::filesize_t size) {
277  slotTotalSize(size);
278  });
279 
280  QObject::connect(slave, &Slave::redirection, q, [this](const QUrl &url) {
281  slotRedirection(url);
282  });
283 
285 }
286 
288 {
289  return d_func()->m_redirectionURL;
290 }
291 
292 #include "moc_listjob.cpp"
bool isNull() const const
virtual void registerJob(KJob *job)
Q_EMITQ_EMIT
qulonglong filesize_t
64-bit file size
Definition: global.h:39
int count(const T &value) const const
bool isDir() const
Definition: udsentry.cpp:386
QString url(QUrl::FormattingOptions options) const const
Q_SCRIPTABLE Q_NOREPLY void start()
void entries(KIO::Job *job, const KIO::UDSEntryList &list)
This signal emits the entry found by the job while listing.
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
Returns a list of directories associated with this file-class.
Definition: krecentdirs.cpp:39
void permanentRedirection(KIO::Job *job, const QUrl &fromUrl, const QUrl &toUrl)
Signals a permanent redirection.
bool authorizeUrlAction(const QString &action, const QUrl &baseURL, const QUrl &destURL)
Returns whether a certain URL related action is authorized.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString queryMetaData(const QString &key)
Query meta data received from the worker.
Definition: job.cpp:217
@ UDS_NAME
Filename - as displayed in directory listings etc.
Definition: udsentry.h:249
KIOCORE_EXPORT KJobTrackerInterface * getJobTracker()
Returns the job tracker to be used by all KIO jobs (in which HideProgressInfo is not set)
Definition: jobtracker.cpp:14
QString stringValue(uint field) const
Definition: udsentry.cpp:376
const QUrl & redirectionUrl() const
Returns the ListJob's redirection URL.
Definition: listjob.cpp:287
KIOCORE_EXPORT ListJob * listRecursive(const QUrl &url, JobFlags flags=DefaultFlags, bool includeHidden=true)
The same as the previous method, but recurses subdirectories.
Definition: listjob.cpp:248
virtual void slotFinished()
Called when the worker marks the job as finished.
Definition: simplejob.cpp:200
@ UDS_URL
An alternative URL (If different from the caption).
Definition: udsentry.h:276
virtual void slotMetaData(const KIO::MetaData &_metaData)
MetaData from the worker is received.
Definition: simplejob.cpp:302
bool isEmpty() const const
QString fileName(QUrl::ComponentFormattingOptions options) const const
KIOCORE_EXPORT KJobUiDelegate * createDefaultJobUiDelegate()
Convenience method: use default factory, if there's one, to create a delegate and return it.
void setUnrestricted(bool unrestricted)
Do not apply any KIOSK restrictions to this job.
Definition: listjob.cpp:253
QString & replace(int position, int n, QChar after)
AKONADI_CALENDAR_EXPORT QString displayName(Akonadi::ETMCalendar *calendar, const Akonadi::Collection &collection)
bool isLink() const
Definition: udsentry.cpp:391
QString path(QUrl::ComponentFormattingOptions options) const const
QList::iterator erase(QList::iterator pos)
void setPath(const QString &path, QUrl::ParsingMode mode)
void setUiDelegate(KJobUiDelegate *delegate)
A namespace for KIO globals.
QList::iterator begin()
@ HideProgressInfo
Hide progress information dialog, i.e. don't show a GUI.
Definition: job_base.h:275
void emitResult()
@ UDS_DISPLAY_NAME
If set, contains the label to display instead of the 'real name' in UDS_NAME.
Definition: udsentry.h:297
int error() const
KIOCORE_EXPORT ListJob * listDir(const QUrl &url, JobFlags flags=DefaultFlags, bool includeHidden=true)
List the contents of url, which is assumed to be a directory.
Definition: listjob.cpp:243
bool hasSubjobs() const
QList::iterator end()
bool removeSubjob(KJob *job) override
Mark a sub job as being done.
Definition: job.cpp:87
void subError(KIO::ListJob *job, KIO::ListJob *subJob)
This signal is emitted when a sub-directory could not be listed.
const QList< QKeySequence > & end()
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Mar 23 2023 03:59:42 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.