Revision control

++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "qfilesystemiterator_p.h"
++ #include "qfilesystemengine_p.h"
++ #include "qoperatingsystemversion.h"
++ #include "qplatformdefs.h"
++
++ #include <QtCore/qt_windows.h>
++ #include <QtCore/private/wcharhelpers_win_p.h>
++
++ QT_BEGIN_NAMESPACE
++
++ using namespace Qt::StringLiterals;
++
++ bool done = true;
++
++ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry)
++ : dirPath(entry.filePath())
++ , nativePath(entry.nativeFilePath())
++ , findFileHandle(INVALID_HANDLE_VALUE)
++ , uncFallback(false)
++ , uncShareIndex(0)
++ , onlyDirs(false)
++ {
++ if (nativePath.endsWith(u".lnk"_s) && !QFileSystemEngine::isDirPath(dirPath, nullptr)) {
++ QFileSystemMetaData metaData;
++ QFileSystemEntry link = QFileSystemEngine::getLinkTarget(entry, metaData);
++ nativePath = link.nativeFilePath();
++ }
++ if (!nativePath.endsWith(u'\\'))
++ nativePath.append(u'\\');
++ nativePath.append(u'*');
++ // In MSVC2015+ case we prepend //?/ for longer file-name support
++ if (!dirPath.endsWith(u'/'))
++ dirPath.append(u'/');
++ }
++
++ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters)
++ : QFileSystemIterator(entry)
++ {
++ if ((filters & (QDir::Dirs|QDir::Drives)) && (!(filters & (QDir::Files))))
++ onlyDirs = true;
++ }
++
++ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry,
++ QDirListing::IteratorFlags flags)
++ : QFileSystemIterator(entry)
++ {
++ onlyDirs = flags.testAnyFlags(QDirListing::IteratorFlag::DirsOnly);
++ }
++
++ QFileSystemIterator::~QFileSystemIterator()
++ {
++ if (findFileHandle != INVALID_HANDLE_VALUE)
++ FindClose(findFileHandle);
++ }
++
++ QFileSystemNativeId QFileSystemIterator::nativeId() const
++ {
++ // nativePath is the resolved directory path with a trailing "\*" search
++ // glob appended (see the constructor). Drop the '*' to recover the
++ // directory itself (the trailing backslash is accepted by CreateFile).
++ QFileSystemEntry entry(nativePath.chopped(1), QFileSystemEntry::FromNativePath());
++ return QFileSystemEngine::nativeId(entry);
++ }
++
++ std::optional<QDirEntryInfo> QFileSystemIterator::advance()
++ {
++ bool haveData = false;
++ WIN32_FIND_DATA findData;
++
++ if (findFileHandle == INVALID_HANDLE_VALUE && !uncFallback) {
++ haveData = true;
++ int infoLevel = 0 ; // FindExInfoStandard;
++ DWORD dwAdditionalFlags = 0;
++ dwAdditionalFlags = 2; // FIND_FIRST_EX_LARGE_FETCH
++ infoLevel = 1 ; // FindExInfoBasic;
++ int searchOps = 0; // FindExSearchNameMatch
++ if (onlyDirs)
++ searchOps = 1 ; // FindExSearchLimitToDirectories
++ findFileHandle = FindFirstFileEx(qt_castToWchar(nativePath),
++ FINDEX_INFO_LEVELS(infoLevel), &findData,
++ FINDEX_SEARCH_OPS(searchOps), 0, dwAdditionalFlags);
++ if (findFileHandle == INVALID_HANDLE_VALUE) {
++ if (nativePath.startsWith("\\\\?\\UNC\\"_L1)) {
++ const auto parts = QStringView{nativePath}.split(u'\\', Qt::SkipEmptyParts);
++ if (parts.count() == 4 && QFileSystemEngine::uncListSharesOnServer(
++ "\\\\"_L1 + parts.at(2), &uncShares)) {
++ if (uncShares.isEmpty())
++ return std::nullopt; // No shares found in the server
++ uncFallback = true;
++ }
++ }
++ }
++ }
++ if (findFileHandle == INVALID_HANDLE_VALUE && !uncFallback)
++ return std::nullopt;
++ // Retrieve the new file information.
++ if (!haveData) {
++ if (uncFallback) {
++ if (++uncShareIndex >= uncShares.count())
++ return std::nullopt;
++ } else {
++ if (!FindNextFile(findFileHandle, &findData))
++ return std::nullopt;
++ }
++ }
++ // Create the new file system entry & meta data.
++ QFileSystemEntry fileEntry;
++ QFileSystemMetaData metaData;
++ if (uncFallback) {
++ fileEntry = QFileSystemEntry(dirPath + uncShares.at(uncShareIndex));
++ metaData.fillFromFileAttribute(FILE_ATTRIBUTE_DIRECTORY);
++ } else {
++ QString fileName = QString::fromWCharArray(findData.cFileName);
++ fileEntry = QFileSystemEntry(dirPath + fileName);
++ if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY || !fileName.endsWith(".lnk"_L1)) {
++ metaData.fillFromFindData(findData, true);
++ }
++ }
++ return QDirEntryInfo{std::move(fileEntry), std::move(metaData)};
++ }
++
++ QT_END_NAMESPACE