| 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 |  | 
| 16 | QT_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 | */ | 
| 22 | QFileSystemIterator::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 |  | 
| 35 | QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDirListing::IteratorFlags) | 
| 36 |     : QFileSystemIterator(entry) | 
| 37 | {} | 
| 38 |  | 
| 39 | QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters) | 
| 40 |     : QFileSystemIterator(entry) | 
| 41 | { | 
| 42 | } | 
| 43 |  | 
| 44 | QFileSystemIterator::~QFileSystemIterator() = default; | 
| 45 |  | 
| 46 | bool 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 |  | 
| 95 | QT_END_NAMESPACE | 
| 96 |  | 
| 97 | #endif // QT_NO_FILESYSTEMITERATOR | 
| 98 |  |