6#include <qcoreapplication.h>
8#include <qdirlisting.h>
9#include <private/qabstractfileiconprovider_p.h>
10#include <private/qfileinfo_p.h>
13# include <sys/types.h>
15#if defined(Q_OS_VXWORKS)
16# include "qplatformdefs.h"
21using namespace Qt::StringLiterals;
23#ifdef QT_BUILD_INTERNAL
24Q_CONSTINIT
static QBasicAtomicInt fetchedRoot = Q_BASIC_ATOMIC_INITIALIZER(
false);
25Q_AUTOTEST_EXPORT
void qt_test_resetFetchedRoot()
27 fetchedRoot.storeRelaxed(
false);
30Q_AUTOTEST_EXPORT
bool qt_test_isFetchedRoot()
32 return fetchedRoot.loadRelaxed();
38 QString driveName = drive.absoluteFilePath();
40 if (driveName.startsWith(u'/'))
41 return drive.fileName();
42 if (driveName.endsWith(u'/'))
49
50
51QFileInfoGatherer::QFileInfoGatherer(QObject *parent)
53 , m_iconProvider(&defaultProvider)
59
60
61QFileInfoGatherer::~QFileInfoGatherer()
67bool QFileInfoGatherer::event(QEvent *event)
69 if (event->type() == QEvent::DeferredDelete && isRunning()) {
81 if (QCoreApplication::closingDown())
84 connect(
this, &QThread::finished,
this, [
this]{
delete this; });
89 return QThread::event(event);
92void QFileInfoGatherer::requestAbort()
94 requestInterruption();
95 QMutexLocker locker(&mutex);
99void QFileInfoGatherer::setResolveSymlinks(
bool enable)
103 m_resolveSymlinks = enable;
107void QFileInfoGatherer::driveAdded()
109 fetchExtendedInformation(QString(), QStringList());
112void QFileInfoGatherer::driveRemoved()
115 const QFileInfoList driveInfoList = QDir::drives();
116 for (
const QFileInfo &fi : driveInfoList)
117 drives.append(translateDriveName(fi));
118 emit newListOfFiles(QString(), drives);
121bool QFileInfoGatherer::resolveSymlinks()
const
124 return m_resolveSymlinks;
130void QFileInfoGatherer::setIconProvider(QAbstractFileIconProvider *provider)
132 m_iconProvider = provider;
135QAbstractFileIconProvider *QFileInfoGatherer::iconProvider()
const
137 return m_iconProvider;
141
142
143
144
145void QFileInfoGatherer::fetchExtendedInformation(
const QString &path,
const QStringList &files)
147 QMutexLocker locker(&mutex);
150 while ((loc =
this->path.lastIndexOf(path, loc - 1)) != -1) {
151 if (
this->files.at(loc) == files)
158 this->path.push(path);
159 this->files.push(files);
162 getFileInfos(path, files);
165#if QT_CONFIG(filesystemwatcher)
168 && !path.startsWith(
"//"_L1) ) {
169 if (!watchedDirectories().contains(path))
170 watchPaths(QStringList(path));
176
177
178
179
180void QFileInfoGatherer::updateFile(
const QString &filePath)
182 QString dir = filePath.mid(0, filePath.lastIndexOf(u'/'));
183 QString fileName = filePath.mid(dir.size() + 1);
184 fetchExtendedInformation(dir, QStringList(fileName));
187QStringList QFileInfoGatherer::watchedFiles()
const
189#if QT_CONFIG(filesystemwatcher)
191 return m_watcher->files();
196QStringList QFileInfoGatherer::watchedDirectories()
const
198#if QT_CONFIG(filesystemwatcher)
200 return m_watcher->directories();
205void QFileInfoGatherer::createWatcher()
207#if QT_CONFIG(filesystemwatcher)
208 m_watcher =
new QFileSystemWatcher(
this);
209 connect(m_watcher, &QFileSystemWatcher::directoryChanged,
this, &QFileInfoGatherer::list);
210 connect(m_watcher, &QFileSystemWatcher::fileChanged,
this, &QFileInfoGatherer::updateFile);
211# if defined(Q_OS_WIN)
212 const QVariant listener = m_watcher->property(
"_q_driveListener");
213 if (listener.canConvert<QObject *>()) {
214 if (QObject *driveListener = listener.value<QObject *>()) {
215 connect(driveListener, SIGNAL(driveAdded()),
this, SLOT(driveAdded()));
216 connect(driveListener, SIGNAL(driveRemoved()),
this, SLOT(driveRemoved()));
223void QFileInfoGatherer::watchPaths(
const QStringList &paths)
225#if QT_CONFIG(filesystemwatcher)
227 if (m_watcher ==
nullptr)
229 m_watcher->addPaths(paths);
236void QFileInfoGatherer::unwatchPaths(
const QStringList &paths)
238#if QT_CONFIG(filesystemwatcher)
239 if (m_watcher && !paths.isEmpty())
240 m_watcher->removePaths(paths);
246bool QFileInfoGatherer::isWatching()
const
249#if QT_CONFIG(filesystemwatcher)
250 QMutexLocker locker(&mutex);
257
258
259
260
261
262
263
264
265void QFileInfoGatherer::setWatching(
bool v)
267#if QT_CONFIG(filesystemwatcher)
268 QMutexLocker locker(&mutex);
269 if (v != m_watching) {
272 delete std::exchange(m_watcher,
nullptr);
280
281
282
283
284void QFileInfoGatherer::clear()
286#if QT_CONFIG(filesystemwatcher)
287 QMutexLocker locker(&mutex);
288 unwatchPaths(watchedFiles());
289 unwatchPaths(watchedDirectories());
294
295
296
297
298void QFileInfoGatherer::removePath(
const QString &path)
300#if QT_CONFIG(filesystemwatcher)
301 QMutexLocker locker(&mutex);
302 unwatchPaths(QStringList(path));
309
310
311
312
313void QFileInfoGatherer::list(
const QString &directoryPath)
315 fetchExtendedInformation(directoryPath, QStringList());
319
320
321void QFileInfoGatherer::run()
326 setTerminationEnabled(
false);
327 QMutexLocker locker(&mutex);
328 while (!isInterruptionRequested() && path.isEmpty())
329 condition.wait(&mutex);
330 if (isInterruptionRequested())
332 const QString thisPath = std::as_const(path).front();
334 const QStringList thisList = std::as_const(files).front();
341 setTerminationEnabled(
true);
342 getFileInfos(thisPath, thisList);
346QExtendedInformation QFileInfoGatherer::getInfo(
const QFileInfo &fileInfo)
const
348 QExtendedInformation info(fileInfo);
349 if (m_iconProvider) {
350 info.icon = m_iconProvider->icon(fileInfo);
351 info.displayType = m_iconProvider->type(fileInfo);
353 info.displayType = QAbstractFileIconProviderPrivate::getFileType(fileInfo);
355#if QT_CONFIG(filesystemwatcher)
357 static const bool watchFiles = qEnvironmentVariableIsSet(
"QT_FILESYSTEMMODEL_WATCH_FILES");
359 if (!fileInfo.exists() && !fileInfo.isSymLink()) {
360 const_cast<QFileInfoGatherer *>(
this)->
361 unwatchPaths(QStringList(fileInfo.absoluteFilePath()));
363 const QString path = fileInfo.absoluteFilePath();
364 if (!path.isEmpty() && fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable()
365 && !watchedFiles().contains(path)) {
366 const_cast<QFileInfoGatherer *>(
this)->watchPaths(QStringList(path));
373 if (m_resolveSymlinks && info.isSymLink(
true)) {
374 QFileInfo resolvedInfo(QFileInfo(fileInfo.symLinkTarget()).canonicalFilePath());
375 if (resolvedInfo.exists()) {
376 emit nameResolved(fileInfo.filePath(), resolvedInfo.fileName());
384
385
386
387void QFileInfoGatherer::getFileInfos(
const QString &path,
const QStringList &files)
390 if (path.isEmpty()) {
391#ifdef QT_BUILD_INTERNAL
392 fetchedRoot.storeRelaxed(
true);
394 QList<std::pair<QString, QFileInfo>> updatedFiles;
395 auto addToUpdatedFiles = [&updatedFiles](QFileInfo &&fileInfo) {
397 updatedFiles.emplace_back(std::pair{translateDriveName(fileInfo), fileInfo});
400 if (files.isEmpty()) {
403 QFileInfoList infoList = QDir::drives();
404 updatedFiles.reserve(infoList.size());
405 for (
auto rit = infoList.rbegin(), rend = infoList.rend(); rit != rend; ++rit)
406 addToUpdatedFiles(std::move(*rit));
408 updatedFiles.reserve(files.size());
409 for (
auto rit = files.crbegin(), rend = files.crend(); rit != rend; ++rit)
410 addToUpdatedFiles(QFileInfo(*rit));
412 emit updates(path, updatedFiles);
419 bool firstTime =
true;
420 QList<std::pair<QString, QFileInfo>> updatedFiles;
421 QStringList filesToCheck = files;
423 QStringList allFiles;
424 if (files.isEmpty()) {
425 using F = QDirListing::IteratorFlag;
426 constexpr auto flags = F::ResolveSymlinks | F::IncludeHidden | F::IncludeDotAndDotDot
427 | F::IncludeBrokenSymlinks;
428 for (
const auto &dirEntry : QDirListing(path, flags)) {
429 if (isInterruptionRequested())
431 fileInfo = dirEntry.fileInfo();
433 allFiles.append(fileInfo.fileName());
434 fetch(fileInfo, base, firstTime, updatedFiles, path);
437 if (!allFiles.isEmpty())
438 emit newListOfFiles(path, allFiles);
440 QStringList::const_iterator filesIt = filesToCheck.constBegin();
441 while (!isInterruptionRequested() && filesIt != filesToCheck.constEnd()) {
442 fileInfo.setFile(path + QDir::separator() + *filesIt);
445 fetch(fileInfo, base, firstTime, updatedFiles, path);
447 if (!updatedFiles.isEmpty())
448 emit updates(path, updatedFiles);
449 emit directoryLoaded(path);
452void QFileInfoGatherer::fetch(
const QFileInfo &fileInfo, QElapsedTimer &base,
bool &firstTime,
453 QList<std::pair<QString, QFileInfo>> &updatedFiles,
const QString &path)
455 updatedFiles.emplace_back(std::pair(fileInfo.fileName(), fileInfo));
456 QElapsedTimer current;
458 if ((firstTime && updatedFiles.size() > 100) || base.msecsTo(current) > 1000) {
459 emit updates(path, updatedFiles);
460 updatedFiles.clear();
468#include "moc_qfileinfogatherer_p.cpp"
static QString translateDriveName(const QFileInfo &drive)