1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5/*!
6 \since 4.3
7 \class QDirIterator
8 \inmodule QtCore
9 \ingroup io
10 \brief The QDirIterator class provides an iterator for directory entrylists.
11
12 You can use QDirIterator to navigate entries of a directory one at a time.
13 It is similar to QDir::entryList() and QDir::entryInfoList(), but because
14 it lists entries one at a time instead of all at once, it scales better
15 and is more suitable for large directories. It also supports listing
16 directory contents recursively, and following symbolic links. Unlike
17 QDir::entryList(), QDirIterator does not support sorting.
18
19 The QDirIterator constructor takes a QDir or a directory as
20 argument. After construction, the iterator is located before the first
21 directory entry. Here's how to iterate over all the entries sequentially:
22
23 \snippet code/src_corelib_io_qdiriterator.cpp 0
24
25 Here's how to find and read all files filtered by name, recursively:
26
27 \snippet code/src_corelib_io_qdiriterator.cpp 1
28
29 The next() and nextFileInfo() functions advance the iterator and return
30 the path or the QFileInfo of the next directory entry. You can also call
31 filePath() or fileInfo() to get the current file path or QFileInfo without
32 first advancing the iterator. The fileName() function returns only the
33 name of the file, similar to how QDir::entryList() works.
34
35 Unlike Qt's container iterators, QDirIterator is uni-directional (i.e.,
36 you cannot iterate directories in reverse order) and does not allow random
37 access.
38
39 \note This class is deprecated and may be removed in a Qt release. Use
40 QDirListing instead, see \l {Porting QDirIterator to QDirListing}.
41
42 \sa QDir, QDir::entryList()
43*/
44
45/*! \enum QDirIterator::IteratorFlag
46
47 This enum describes flags that you can combine to configure the behavior
48 of QDirIterator.
49
50 \value NoIteratorFlags The default value, representing no flags. The
51 iterator will return entries for the assigned path.
52
53 \value Subdirectories List entries inside all subdirectories as well.
54
55 \value FollowSymlinks When combined with Subdirectories, this flag
56 enables iterating through all subdirectories of the assigned path,
57 following all symbolic links. Symbolic link loops (e.g., "link" => "." or
58 "link" => "..") are automatically detected and ignored.
59*/
60
61#include "qdiriterator.h"
62#include "qdir_p.h"
63#include "qabstractfileengine_p.h"
64#include "qdirlisting.h"
65#include "qdirentryinfo_p.h"
66
67#include <QtCore/qset.h>
68#include <QtCore/qstack.h>
69#include <QtCore/qvariant.h>
70#if QT_CONFIG(regularexpression)
71#include <QtCore/qregularexpression.h>
72#endif
73
74#include <QtCore/private/qfilesystemiterator_p.h>
75#include <QtCore/private/qfilesystementry_p.h>
76#include <QtCore/private/qfilesystemmetadata_p.h>
77#include <QtCore/private/qfilesystemengine_p.h>
78#include <QtCore/private/qfileinfo_p.h>
79#include <QtCore/private/qduplicatetracker_p.h>
80
81#include <memory>
82#include <stack>
83#include <vector>
84
85QT_BEGIN_NAMESPACE
86
87using namespace Qt::StringLiterals;
88
89class QDirIteratorPrivate
90{
91public:
92 QDirIteratorPrivate(const QString &path, const QStringList &nameFilters = {},
93 QDir::Filters filters = QDir::NoFilter,
94 QDirIterator::IteratorFlags flags = QDirIterator::NoIteratorFlags)
95 : lister(path, nameFilters, filters.toInt(), flags.toInt())
96 { init(); }
97
98 void init()
99 {
100 it = lister.begin();
101 if (it != lister.end())
102 nextFileInfo = it->fileInfo();
103 }
104
105 void advance()
106 {
107 // Match the behavior of advance() from before porting to QDirListing,
108 // that is, even if hasNext() returns false, calling next() returns an
109 // empty string without crashing. QTBUG-130142
110 if (it == lister.end()) {
111 currentFileInfo = {};
112 return;
113 }
114 currentFileInfo = nextFileInfo;
115 if (++it != lister.end()) {
116 nextFileInfo = it->fileInfo();
117 }
118 }
119
120 QDirListing lister;
121 QDirListing::const_iterator it = {};
122 QFileInfo currentFileInfo;
123 QFileInfo nextFileInfo;
124};
125
126/*!
127 Constructs a QDirIterator that can iterate over \a dir's entrylist, using
128 \a dir's name filters and regular filters. You can pass options via \a
129 flags to decide how the directory should be iterated.
130
131 By default, \a flags is NoIteratorFlags, which provides the same behavior
132 as in QDir::entryList().
133
134 The sorting in \a dir is ignored.
135
136 \note To list symlinks that point to non existing files, QDir::System must be
137 passed to the flags.
138
139 \sa hasNext(), next(), IteratorFlags
140*/
141QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
142 : d(new QDirIteratorPrivate(dir.path(), dir.nameFilters(), dir.filter(), flags))
143{
144}
145
146/*!
147 Constructs a QDirIterator that can iterate over \a path, with no name
148 filtering and \a filters for entry filtering. You can pass options via \a
149 flags to decide how the directory should be iterated.
150
151 By default, \a filters is QDir::NoFilter, and \a flags is NoIteratorFlags,
152 which provides the same behavior as in QDir::entryList().
153
154 \note To list symlinks that point to non existing files, QDir::System must be
155 passed to the flags.
156
157 \sa hasNext(), next(), IteratorFlags
158*/
159QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags)
160 : d(new QDirIteratorPrivate(path, {}, filters, flags))
161{
162}
163
164/*!
165 Constructs a QDirIterator that can iterate over \a path. You can pass
166 options via \a flags to decide how the directory should be iterated.
167
168 By default, \a flags is NoIteratorFlags, which provides the same behavior
169 as in QDir::entryList().
170
171 \note To list symlinks that point to non existing files, QDir::System must be
172 passed to the flags.
173
174 \sa hasNext(), next(), IteratorFlags
175*/
176QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
177 : d(new QDirIteratorPrivate(path, {}, QDir::NoFilter, flags))
178{
179}
180
181/*!
182 Constructs a QDirIterator that can iterate over \a path, using \a
183 nameFilters and \a filters. You can pass options via \a flags to decide
184 how the directory should be iterated.
185
186 By default, \a flags is NoIteratorFlags, which provides the same behavior
187 as QDir::entryList().
188
189 For example, the following iterator could be used to iterate over audio
190 files:
191
192 \snippet code/src_corelib_io_qdiriterator.cpp 2
193
194 \note To list symlinks that point to non existing files, QDir::System must be
195 passed to the flags.
196
197 \sa hasNext(), next(), IteratorFlags, QDir::setNameFilters()
198*/
199QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters,
200 QDir::Filters filters, IteratorFlags flags)
201 : d(new QDirIteratorPrivate(path, nameFilters, filters, flags))
202{
203}
204
205/*!
206 Destroys the QDirIterator.
207*/
208QDirIterator::~QDirIterator()
209{
210}
211
212/*!
213 Advances the iterator to the next entry, and returns the file path of this
214 new entry. If hasNext() returns \c false, this function does nothing, and
215 returns an empty QString. Ideally you should always call hasNext() before
216 calling this method.
217
218 You can call fileName() or filePath() to get the current entry's file name
219 or path, or fileInfo() to get a QFileInfo for the current entry.
220
221 Call nextFileInfo() instead of next() if you're interested in the QFileInfo.
222
223 \sa hasNext(), nextFileInfo(), fileName(), filePath(), fileInfo()
224*/
225QString QDirIterator::next()
226{
227 d->advance();
228 return d->currentFileInfo.filePath();
229}
230
231/*!
232 \since 6.3
233
234 Advances the iterator to the next entry, and returns the file info of this
235 new entry. If hasNext() returns \c false, this function does nothing, and
236 returns an empty QFileInfo. Ideally you should always call hasNext() before
237 calling this method.
238
239 You can call fileName() or filePath() to get the current entry's file name
240 or path, or fileInfo() to get a QFileInfo for the current entry.
241
242 Call next() instead of nextFileInfo() when all you need is the filePath().
243
244 \sa hasNext(), fileName(), filePath(), fileInfo()
245*/
246QFileInfo QDirIterator::nextFileInfo()
247{
248 d->advance();
249 return d->currentFileInfo;
250}
251
252/*!
253 Returns \c true if there is at least one more entry in the directory;
254 otherwise, false is returned.
255
256 \sa next(), nextFileInfo(), fileName(), filePath(), fileInfo()
257*/
258bool QDirIterator::hasNext() const
259{
260 return d->it != d->lister.end();
261}
262
263/*!
264 Returns the file name for the current directory entry, without the path
265 prepended.
266
267 This function is convenient when iterating a single directory. When using
268 the QDirIterator::Subdirectories flag, you can use filePath() to get the
269 full path.
270
271 \sa filePath(), fileInfo()
272*/
273QString QDirIterator::fileName() const
274{
275 return d->currentFileInfo.fileName();
276}
277
278/*!
279 Returns the full file path for the current directory entry.
280
281 \sa fileInfo(), fileName()
282*/
283QString QDirIterator::filePath() const
284{
285 return d->currentFileInfo.filePath();
286}
287
288/*!
289 Returns a QFileInfo for the current directory entry.
290
291 \sa filePath(), fileName()
292*/
293QFileInfo QDirIterator::fileInfo() const
294{
295 return d->currentFileInfo;
296}
297
298/*!
299 Returns the base directory of the iterator.
300*/
301QString QDirIterator::path() const
302{
303 return d->lister.iteratorPath();
304}
305
306QT_END_NAMESPACE
307

source code of qtbase/src/corelib/io/qdiriterator.cpp