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
51
52
55
56
57QFileInfoGatherer::QFileInfoGatherer(QObject *parent)
59 , m_iconProvider(&defaultProvider)
65
66
67QFileInfoGatherer::~QFileInfoGatherer()
73bool QFileInfoGatherer::event(QEvent *event)
75 if (event->type() == QEvent::DeferredDelete && isRunning()) {
87 if (QCoreApplication::closingDown())
90 connect(
this, &QThread::finished,
this, [
this]{
delete this; });
95 return QThread::event(event);
98void QFileInfoGatherer::requestAbort()
100 requestInterruption();
101 QMutexLocker locker(&mutex);
105void QFileInfoGatherer::setResolveSymlinks(
bool enable)
109 m_resolveSymlinks = enable;
113void QFileInfoGatherer::driveAdded()
115 fetchExtendedInformation(QString(), QStringList());
118void QFileInfoGatherer::driveRemoved()
121 const QFileInfoList driveInfoList = QDir::drives();
122 for (
const QFileInfo &fi : driveInfoList)
123 drives.append(translateDriveName(fi));
124 emit newListOfFiles(QString(), drives);
127bool QFileInfoGatherer::resolveSymlinks()
const
130 return m_resolveSymlinks;
136void QFileInfoGatherer::setIconProvider(QAbstractFileIconProvider *provider)
138 m_iconProvider = provider;
141QAbstractFileIconProvider *QFileInfoGatherer::iconProvider()
const
143 return m_iconProvider;
147
148
149
150
151void QFileInfoGatherer::fetchExtendedInformation(
const QString &path,
const QStringList &files)
153 QMutexLocker locker(&mutex);
156 while ((loc =
this->path.lastIndexOf(path, loc - 1)) != -1) {
157 if (
this->files.at(loc) == files)
164 this->path.push(path);
165 this->files.push(files);
168 getFileInfos(path, files);
171#if QT_CONFIG(filesystemwatcher)
174 && !path.startsWith(
"//"_L1) ) {
175 if (!watchedDirectories().contains(path))
176 watchPaths(QStringList(path));
182
183
184
185
186void QFileInfoGatherer::updateFile(
const QString &filePath)
188 QString dir = filePath.mid(0, filePath.lastIndexOf(u'/'));
189 QString fileName = filePath.mid(dir.size() + 1);
190 fetchExtendedInformation(dir, QStringList(fileName));
193QStringList QFileInfoGatherer::watchedFiles()
const
195#if QT_CONFIG(filesystemwatcher)
197 return m_watcher->files();
202QStringList QFileInfoGatherer::watchedDirectories()
const
204#if QT_CONFIG(filesystemwatcher)
206 return m_watcher->directories();
211void QFileInfoGatherer::createWatcher()
213#if QT_CONFIG(filesystemwatcher)
214 m_watcher =
new QFileSystemWatcher(
this);
215 connect(m_watcher, &QFileSystemWatcher::directoryChanged,
this, &QFileInfoGatherer::list);
216 connect(m_watcher, &QFileSystemWatcher::fileChanged,
this, &QFileInfoGatherer::updateFile);
217# if defined(Q_OS_WIN)
218 const QVariant listener = m_watcher->property(
"_q_driveListener");
219 if (listener.canConvert<QObject *>()) {
220 if (QObject *driveListener = listener.value<QObject *>()) {
221 connect(driveListener, SIGNAL(driveAdded()),
this, SLOT(driveAdded()));
222 connect(driveListener, SIGNAL(driveRemoved()),
this, SLOT(driveRemoved()));
229void QFileInfoGatherer::watchPaths(
const QStringList &paths)
231#if QT_CONFIG(filesystemwatcher)
233 if (m_watcher ==
nullptr)
235 m_watcher->addPaths(paths);
242void QFileInfoGatherer::unwatchPaths(
const QStringList &paths)
244#if QT_CONFIG(filesystemwatcher)
245 if (m_watcher && !paths.isEmpty())
246 m_watcher->removePaths(paths);
252bool QFileInfoGatherer::isWatching()
const
255#if QT_CONFIG(filesystemwatcher)
256 QMutexLocker locker(&mutex);
263
264
265
266
267
268
269
270
271void QFileInfoGatherer::setWatching(
bool v)
273#if QT_CONFIG(filesystemwatcher)
274 QMutexLocker locker(&mutex);
275 if (v != m_watching) {
278 delete std::exchange(m_watcher,
nullptr);
286
287
288
289
290void QFileInfoGatherer::clear()
292#if QT_CONFIG(filesystemwatcher)
293 QMutexLocker locker(&mutex);
294 unwatchPaths(watchedFiles());
295 unwatchPaths(watchedDirectories());
300
301
302
303
304void QFileInfoGatherer::removePath(
const QString &path)
306#if QT_CONFIG(filesystemwatcher)
307 QMutexLocker locker(&mutex);
308 unwatchPaths(QStringList(path));
315
316
317
318
319void QFileInfoGatherer::list(
const QString &directoryPath)
321 fetchExtendedInformation(directoryPath, QStringList());
325
326
327void QFileInfoGatherer::run()
332 setTerminationEnabled(
false);
333 QMutexLocker locker(&mutex);
334 while (!isInterruptionRequested() && path.isEmpty())
335 condition.wait(&mutex);
336 if (isInterruptionRequested())
338 const QString thisPath = std::as_const(path).front();
340 const QStringList thisList = std::as_const(files).front();
347 setTerminationEnabled(
true);
348 getFileInfos(thisPath, thisList);
352QExtendedInformation QFileInfoGatherer::getInfo(
const QFileInfo &fileInfo)
const
354 QExtendedInformation info(fileInfo);
355 if (m_iconProvider) {
356 info.icon = m_iconProvider->icon(fileInfo);
357 info.displayType = m_iconProvider->type(fileInfo);
359 info.displayType = QAbstractFileIconProviderPrivate::getFileType(fileInfo);
361#if QT_CONFIG(filesystemwatcher)
363 static const bool watchFiles = qEnvironmentVariableIsSet(
"QT_FILESYSTEMMODEL_WATCH_FILES");
365 if (!fileInfo.exists() && !fileInfo.isSymLink()) {
366 const_cast<QFileInfoGatherer *>(
this)->
367 unwatchPaths(QStringList(fileInfo.absoluteFilePath()));
369 const QString path = fileInfo.absoluteFilePath();
370 if (!path.isEmpty() && fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable()
371 && !watchedFiles().contains(path)) {
372 const_cast<QFileInfoGatherer *>(
this)->watchPaths(QStringList(path));
379 if (m_resolveSymlinks && info.isSymLink(
true)) {
380 QFileInfo resolvedInfo(QFileInfo(fileInfo.symLinkTarget()).canonicalFilePath());
381 if (resolvedInfo.exists()) {
382 emit nameResolved(fileInfo.filePath(), resolvedInfo.fileName());
390
391
392
393void QFileInfoGatherer::getFileInfos(
const QString &path,
const QStringList &files)
396 if (path.isEmpty()) {
397#ifdef QT_BUILD_INTERNAL
398 fetchedRoot.storeRelaxed(
true);
400 QList<std::pair<QString, QFileInfo>> updatedFiles;
401 auto addToUpdatedFiles = [&updatedFiles](QFileInfo &&fileInfo) {
403 updatedFiles.emplace_back(std::pair{translateDriveName(fileInfo), fileInfo});
406 if (files.isEmpty()) {
409 QFileInfoList infoList = QDir::drives();
410 updatedFiles.reserve(infoList.size());
411 for (
auto rit = infoList.rbegin(), rend = infoList.rend(); rit != rend; ++rit)
412 addToUpdatedFiles(std::move(*rit));
414 updatedFiles.reserve(files.size());
415 for (
auto rit = files.crbegin(), rend = files.crend(); rit != rend; ++rit)
416 addToUpdatedFiles(QFileInfo(*rit));
418 emit updates(path, updatedFiles);
425 bool firstTime =
true;
426 QList<std::pair<QString, QFileInfo>> updatedFiles;
427 QStringList filesToCheck = files;
429 QStringList allFiles;
430 if (files.isEmpty()) {
431 using F = QDirListing::IteratorFlag;
432 constexpr auto flags = F::ResolveSymlinks | F::IncludeHidden | F::IncludeDotAndDotDot
433 | F::IncludeBrokenSymlinks;
434 for (
const auto &dirEntry : QDirListing(path, flags)) {
435 if (isInterruptionRequested())
437 fileInfo = dirEntry.fileInfo();
439 allFiles.append(fileInfo.fileName());
440 fetch(fileInfo, base, firstTime, updatedFiles, path);
443 if (!allFiles.isEmpty())
444 emit newListOfFiles(path, allFiles);
446 QStringList::const_iterator filesIt = filesToCheck.constBegin();
447 while (!isInterruptionRequested() && filesIt != filesToCheck.constEnd()) {
448 fileInfo.setFile(path + QDir::separator() + *filesIt);
451 fetch(fileInfo, base, firstTime, updatedFiles, path);
453 if (!updatedFiles.isEmpty())
454 emit updates(path, updatedFiles);
455 emit directoryLoaded(path);
458void QFileInfoGatherer::fetch(
const QFileInfo &fileInfo, QElapsedTimer &base,
bool &firstTime,
459 QList<std::pair<QString, QFileInfo>> &updatedFiles,
const QString &path)
461 updatedFiles.emplace_back(std::pair(fileInfo.fileName(), fileInfo));
462 QElapsedTimer current;
464 if ((firstTime && updatedFiles.size() > 100) || base.msecsTo(current) > 1000) {
465 emit updates(path, updatedFiles);
466 updatedFiles.clear();
474#include "moc_qfileinfogatherer_p.cpp"
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString translateDriveName(const QFileInfo &drive)