File indexing completed on 2024-04-21 04:57:58
0001 /* This file is part of FSView. 0002 SPDX-FileCopyrightText: 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-only 0005 */ 0006 0007 #include "scan.h" 0008 0009 #include <QDir> 0010 #include <QStringList> 0011 #include <QSet> 0012 #include <qplatformdefs.h> 0013 0014 #include <kauthorized.h> 0015 #include <kurlauthorized.h> 0016 0017 #include "inode.h" 0018 #include "fsviewdebug.h" 0019 0020 // ScanManager 0021 0022 ScanManager::ScanManager() 0023 { 0024 _topDir = nullptr; 0025 _listener = nullptr; 0026 } 0027 0028 ScanManager::ScanManager(const QString &path) 0029 { 0030 _topDir = nullptr; 0031 _listener = nullptr; 0032 setTop(path); 0033 } 0034 0035 ScanManager::~ScanManager() 0036 { 0037 stopScan(); 0038 delete _topDir; 0039 } 0040 0041 void ScanManager::setListener(ScanListener *l) 0042 { 0043 _listener = l; 0044 } 0045 0046 ScanDir *ScanManager::setTop(const QString &path, int data) 0047 { 0048 stopScan(); 0049 if (_topDir) { 0050 delete _topDir; 0051 _topDir = nullptr; 0052 } 0053 if (!path.isEmpty()) { 0054 _topDir = new ScanDir(path, this, nullptr, data); 0055 } 0056 return _topDir; 0057 } 0058 0059 bool ScanManager::scanRunning() 0060 { 0061 if (!_topDir) { 0062 return false; 0063 } 0064 0065 return _topDir->scanRunning(); 0066 } 0067 0068 void ScanManager::startScan(ScanDir *from) 0069 { 0070 if (!_topDir) { 0071 return; 0072 } 0073 if (!from) { 0074 from = _topDir; 0075 } 0076 0077 if (scanRunning()) { 0078 stopScan(); 0079 } 0080 0081 from->clear(); 0082 if (from->parent()) { 0083 from->parent()->setupChildRescan(); 0084 } 0085 0086 _list.append(new ScanItem(from->path(), from)); 0087 } 0088 0089 void ScanManager::stopScan() 0090 { 0091 if (!_topDir) { 0092 return; 0093 } 0094 0095 if (0) qCDebug(FSVIEWLOG) << "ScanManager::stopScan, scanLength " 0096 << _list.count(); 0097 0098 while (!_list.isEmpty()) { 0099 ScanItem *si = _list.takeFirst(); 0100 si->dir->finish(); 0101 delete si; 0102 } 0103 } 0104 0105 int ScanManager::scan(int data) 0106 { 0107 if (_list.isEmpty()) { 0108 return false; 0109 } 0110 ScanItem *si = _list.takeFirst(); 0111 0112 int newCount = si->dir->scan(si, _list, data); 0113 delete si; 0114 0115 return newCount; 0116 } 0117 0118 // ScanFile 0119 0120 ScanFile::ScanFile() 0121 { 0122 _size = 0; 0123 _listener = nullptr; 0124 } 0125 0126 ScanFile::ScanFile(const QString &n, KIO::fileoffset_t s) 0127 { 0128 _name = n; 0129 _size = s; 0130 _listener = nullptr; 0131 } 0132 0133 ScanFile::~ScanFile() 0134 { 0135 if (_listener) { 0136 _listener->destroyed(this); 0137 } 0138 } 0139 0140 // ScanDir 0141 0142 ScanDir::ScanDir() 0143 { 0144 _dirty = true; 0145 _dirsFinished = -1; /* scan not started */ 0146 0147 _parent = nullptr; 0148 _manager = nullptr; 0149 _listener = nullptr; 0150 _data = 0; 0151 } 0152 0153 ScanDir::ScanDir(const QString &n, ScanManager *m, 0154 ScanDir *p, int data) 0155 : _name(n) 0156 { 0157 _dirty = true; 0158 _dirsFinished = -1; /* scan not started */ 0159 0160 _parent = p; 0161 _manager = m; 0162 _listener = nullptr; 0163 _data = data; 0164 } 0165 0166 ScanDir::~ScanDir() 0167 { 0168 if (_listener) { 0169 _listener->destroyed(this); 0170 } 0171 } 0172 0173 void ScanDir::setListener(ScanListener *l) 0174 { 0175 _listener = l; 0176 } 0177 0178 QString ScanDir::path() 0179 { 0180 if (_parent) { 0181 QString p = _parent->path(); 0182 if (!p.endsWith(QLatin1Char('/'))) { 0183 p += QLatin1Char('/'); 0184 } 0185 return p + _name; 0186 } 0187 0188 return _name; 0189 } 0190 0191 void ScanDir::clear() 0192 { 0193 _dirty = true; 0194 _dirsFinished = -1; /* scan not started */ 0195 0196 _files.clear(); 0197 _dirs.clear(); 0198 } 0199 0200 void ScanDir::update() 0201 { 0202 if (!_dirty) { 0203 return; 0204 } 0205 _dirty = false; 0206 0207 _fileCount = 0; 0208 _dirCount = 0; 0209 _size = 0; 0210 0211 if (_dirsFinished == -1) { 0212 return; 0213 } 0214 0215 if (_files.count() > 0) { 0216 _fileCount += _files.count(); 0217 _size = _fileSize; 0218 } 0219 if (_dirs.count() > 0) { 0220 _dirCount += _dirs.count(); 0221 ScanDirVector::iterator it; 0222 for (it = _dirs.begin(); it != _dirs.end(); ++it) { 0223 (*it).update(); 0224 _fileCount += (*it)._fileCount; 0225 _dirCount += (*it)._dirCount; 0226 _size += (*it)._size; 0227 } 0228 } 0229 } 0230 0231 bool ScanDir::isForbiddenDir(QString &d) 0232 { 0233 static QSet<QString> *s = nullptr; 0234 0235 if (!s) { 0236 s = new QSet<QString>; 0237 // directories without real files on Linux 0238 // TODO: should be OS specific 0239 s->insert(QStringLiteral("/proc")); 0240 s->insert(QStringLiteral("/dev")); 0241 s->insert(QStringLiteral("/sys")); 0242 } 0243 return (s->contains(d)); 0244 } 0245 0246 int ScanDir::scan(ScanItem *si, ScanItemList &list, int data) 0247 { 0248 clear(); 0249 _dirsFinished = 0; 0250 _fileSize = 0; 0251 _dirty = true; 0252 0253 if (isForbiddenDir(si->absPath)) { 0254 if (_parent) { 0255 _parent->subScanFinished(); 0256 } 0257 return 0; 0258 } 0259 0260 QUrl u = QUrl::fromLocalFile(si->absPath); 0261 if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("list"), QUrl(), u)) { 0262 if (_parent) { 0263 _parent->subScanFinished(); 0264 } 0265 0266 return 0; 0267 } 0268 0269 QDir d(si->absPath); 0270 const QStringList fileList = d.entryList(QDir::Files | 0271 QDir::Hidden | QDir::NoSymLinks); 0272 0273 if (fileList.count() > 0) { 0274 QT_STATBUF buff; 0275 0276 _files.reserve(fileList.count()); 0277 0278 QStringList::ConstIterator it; 0279 for (it = fileList.constBegin(); it != fileList.constEnd(); ++it) { 0280 QString tmp(si->absPath + QLatin1Char('/') + (*it)); 0281 if (QT_LSTAT(tmp.toStdString().c_str(), &buff) != 0) { 0282 continue; 0283 } 0284 _files.append(ScanFile(*it, buff.st_size)); 0285 _fileSize += buff.st_size; 0286 } 0287 } 0288 0289 const QStringList dirList = d.entryList(QDir::Dirs | 0290 QDir::Hidden | QDir::NoSymLinks | QDir::NoDotAndDotDot); 0291 0292 if (dirList.count() > 0) { 0293 _dirs.reserve(dirList.count()); 0294 0295 QStringList::ConstIterator it; 0296 for (it = dirList.constBegin(); it != dirList.constEnd(); ++it) { 0297 _dirs.append(ScanDir(*it, _manager, this, data)); 0298 QString newpath = si->absPath; 0299 if (!newpath.endsWith(QChar('/'))) { 0300 newpath.append("/"); 0301 } 0302 newpath.append(*it); 0303 list.append(new ScanItem(newpath, &(_dirs.last()))); 0304 } 0305 _dirCount += _dirs.count(); 0306 } 0307 0308 callScanStarted(); 0309 callSizeChanged(); 0310 0311 if (_dirs.count() == 0) { 0312 callScanFinished(); 0313 0314 if (_parent) { 0315 _parent->subScanFinished(); 0316 } 0317 } 0318 0319 return _dirs.count(); 0320 } 0321 0322 void ScanDir::subScanFinished() 0323 { 0324 _dirsFinished++; 0325 callSizeChanged(); 0326 0327 if (0) qCDebug(FSVIEWLOG) << "ScanDir::subScanFinished [" << path() 0328 << "]: " << _dirsFinished << "/" << _dirs.count(); 0329 0330 if (_dirsFinished < _dirs.count()) { 0331 return; 0332 } 0333 0334 /* all subdirs read */ 0335 callScanFinished(); 0336 0337 if (_parent) { 0338 _parent->subScanFinished(); 0339 } 0340 } 0341 0342 void ScanDir::finish() 0343 { 0344 if (scanRunning()) { 0345 _dirsFinished = _dirs.count(); 0346 callScanFinished(); 0347 } 0348 0349 if (_parent) { 0350 _parent->finish(); 0351 } 0352 } 0353 0354 void ScanDir::setupChildRescan() 0355 { 0356 if (_dirs.count() == 0) { 0357 return; 0358 } 0359 0360 _dirsFinished = 0; 0361 ScanDirVector::iterator it; 0362 for (it = _dirs.begin(); it != _dirs.end(); ++it) 0363 if ((*it).scanFinished()) { 0364 _dirsFinished++; 0365 } 0366 0367 if (_parent && 0368 (_dirsFinished < _dirs.count())) { 0369 _parent->setupChildRescan(); 0370 } 0371 0372 callScanStarted(); 0373 } 0374 0375 void ScanDir::callScanStarted() 0376 { 0377 if (0) qCDebug(FSVIEWLOG) << "ScanDir:Started [" << path() 0378 << "]: size " << size() << ", files " << fileCount(); 0379 0380 ScanListener *mListener = _manager ? _manager->listener() : nullptr; 0381 0382 if (_listener) { 0383 _listener->scanStarted(this); 0384 } 0385 if (mListener) { 0386 mListener->scanStarted(this); 0387 } 0388 } 0389 0390 void ScanDir::callSizeChanged() 0391 { 0392 if (0) qCDebug(FSVIEWLOG) << ". [" << path() 0393 << "]: size " << size() << ", files " << fileCount(); 0394 0395 _dirty = true; 0396 0397 if (_parent) { 0398 _parent->callSizeChanged(); 0399 } 0400 0401 ScanListener *mListener = _manager ? _manager->listener() : nullptr; 0402 0403 if (_listener) { 0404 _listener->sizeChanged(this); 0405 } 0406 if (mListener) { 0407 mListener->sizeChanged(this); 0408 } 0409 } 0410 0411 void ScanDir::callScanFinished() 0412 { 0413 if (0) qCDebug(FSVIEWLOG) << "ScanDir:Finished [" << path() 0414 << "]: size " << size() << ", files " << fileCount(); 0415 0416 ScanListener *mListener = _manager ? _manager->listener() : nullptr; 0417 0418 if (_listener) { 0419 _listener->scanFinished(this); 0420 } 0421 if (mListener) { 0422 mListener->scanFinished(this); 0423 } 0424 } 0425