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
4#include "qplatformdefs.h"
5#include "qfilesystemiterator_p.h"
6
7#ifndef QT_NO_FILESYSTEMITERATOR
8
9#include <qvarlengtharray.h>
10
11#include <memory>
12
13#include <stdlib.h>
14#include <errno.h>
15
16QT_BEGIN_NAMESPACE
17
18/*
19 Native filesystem iterator, which uses ::opendir()/readdir()/dirent from the system
20 libraries to iterate over the directory represented by \a entry.
21*/
22QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry)
23 : dirPath(entry.filePath()),
24 toUtf16(QStringDecoder::Utf8)
25{
26 dir.reset(QT_OPENDIR(name: entry.nativeFilePath().constData()));
27 if (!dir) {
28 lastError = errno;
29 } else {
30 if (!dirPath.endsWith(c: u'/'))
31 dirPath.append(c: u'/');
32 }
33}
34
35QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDirListing::IteratorFlags)
36 : QFileSystemIterator(entry)
37{}
38
39QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters)
40 : QFileSystemIterator(entry)
41{
42}
43
44QFileSystemIterator::~QFileSystemIterator() = default;
45
46bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData)
47{
48 auto asFileEntry = [this](QStringView name) {
49#ifdef Q_OS_DARWIN
50 // must match QFile::decodeName
51 QString normalized = name.toString().normalized(QString::NormalizationForm_C);
52 name = normalized;
53#endif
54 return QFileSystemEntry(dirPath + name, QFileSystemEntry::FromInternalPath());
55 };
56 if (!dir)
57 return false;
58
59 for (;;) {
60 // From readdir man page:
61 // If the end of the directory stream is reached, NULL is returned and errno is
62 // not changed. If an error occurs, NULL is returned and errno is set to indicate
63 // the error. To distinguish end of stream from an error, set errno to zero before
64 // calling readdir() and then check the value of errno if NULL is returned.
65 errno = 0;
66 dirEntry = QT_READDIR(dirp: dir.get());
67
68 if (dirEntry) {
69 // POSIX allows readdir() to return a file name in struct dirent that
70 // extends past the end of the d_name array (it's a char[1] array on QNX, for
71 // example). Therefore, we *must* call strlen() on it to get the actual length
72 // of the file name. See:
73 // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html#tag_13_07_05
74 QByteArrayView name(dirEntry->d_name, strlen(s: dirEntry->d_name));
75 // name.size() is sufficient here, see QUtf8::convertToUnicode() for details
76 QVarLengthArray<char16_t> buffer(name.size());
77 auto *end = toUtf16.appendToBuffer(out: buffer.data(), ba: name);
78 buffer.resize(sz: end - buffer.constData());
79 if (!toUtf16.hasError()) {
80 fileEntry = asFileEntry(buffer);
81 metaData.fillFromDirEnt(statBuffer: *dirEntry);
82 return true;
83 } else {
84 errno = EILSEQ; // Invalid or incomplete multibyte or wide character
85 }
86 } else {
87 break;
88 }
89 }
90
91 lastError = errno;
92 return false;
93}
94
95QT_END_NAMESPACE
96
97#endif // QT_NO_FILESYSTEMITERATOR
98

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