Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qfilesystemiterator_unix.cpp
Go to the documentation of this file.
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#include "qplatformdefs.h"
7
8#ifndef QT_NO_FILESYSTEMITERATOR
9
10#include <qvarlengtharray.h>
11
12#include <private/qstringconverter_p.h>
13
14#include <memory>
15
16#include <stdlib.h>
17#include <errno.h>
18
20
21/*
22 Native filesystem iterator, which uses ::opendir()/readdir()/dirent from the system
23 libraries to iterate over the directory represented by \a entry.
24*/
25QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry)
26 : dirPath(entry.filePath())
27{
28 dir.reset(QT_OPENDIR(entry.nativeFilePath().constData()));
29 if (!dir) {
30 lastError = errno;
31 } else {
32 if (!dirPath.endsWith(u'/'))
33 dirPath.append(u'/');
34 }
35}
36
37QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDirListing::IteratorFlags)
38 : QFileSystemIterator(entry)
39{}
40
41QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters)
42 : QFileSystemIterator(entry)
43{
44}
45
46QFileSystemIterator::~QFileSystemIterator() = default;
47
48QFileSystemNativeId QFileSystemIterator::nativeId() const
49{
50 if (!dir)
51 return {};
52#if QT_CONFIG(dirfd)
53 // We can use dirfd() to fstat() the open directory - no race condition.
54 return QFileSystemEngine::nativeId(dirfd(dir.get()));
55#else
56 // We must stat() the name - possible race condition, but already present
57 // in QDirListing because we use full file names.
58 return QFileSystemEngine::nativeId(
59 QFileSystemEntry(dirPath, QFileSystemEntry::FromInternalPath()));
60#endif
61}
62
63std::optional<QDirEntryInfo> QFileSystemIterator::advance()
64{
65 auto asFileEntry = [this](QStringView name) {
66#ifdef Q_OS_DARWIN
67 // must match QFile::decodeName
68 QString normalized = name.toString().normalized(QString::NormalizationForm_C);
69 name = normalized;
70#endif
71 return QFileSystemEntry(dirPath + name, QFileSystemEntry::FromInternalPath());
72 };
73 if (!dir)
74 return std::nullopt;
75
76 for (;;) {
77 // From readdir man page:
78 // If the end of the directory stream is reached, NULL is returned and errno is
79 // not changed. If an error occurs, NULL is returned and errno is set to indicate
80 // the error. To distinguish end of stream from an error, set errno to zero before
81 // calling readdir() and then check the value of errno if NULL is returned.
82 errno = 0;
83 dirEntry = QT_READDIR(dir.get());
84
85 if (dirEntry) {
86 // POSIX allows readdir() to return a file name in struct dirent that
87 // extends past the end of the d_name array (it's a char[1] array on QNX, for
88 // example). Therefore, we *must* call strlen() on it to get the actual length
89 // of the file name. See:
90 // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html#tag_13_07_05
91 QByteArrayView name(dirEntry->d_name, strlen(dirEntry->d_name));
92 // name.size() is sufficient here, see QUtf8::convertToUnicode() for details
93 QVarLengthArray<char16_t> buffer(name.size());
94 QStringDecoder toUtf16(QStringDecoder::Utf8);
95 auto *end = toUtf16.appendToBuffer(buffer.data(), name);
96 buffer.resize(end - buffer.constData());
97 if (!toUtf16.hasError()) {
98 QFileSystemMetaData metaData;
99 metaData.fillFromDirEnt(*dirEntry);
100 return QDirEntryInfo{asFileEntry(buffer), std::move(metaData)};
101 } else {
102 errno = EILSEQ; // Invalid or incomplete multibyte or wide character
103 }
104 } else {
105 break;
106 }
107 }
108
109 lastError = errno;
110 return std::nullopt;
111}
112
113QT_END_NAMESPACE
114
115#endif // QT_NO_FILESYSTEMITERATOR
Combined button and popup list for selecting options.