18 #include "qgsconfig.h"
23 #include <QRegularExpression>
27 #include <QDirIterator>
31 #include <sys/resource.h>
38 #pragma comment(lib,"Shell32.lib")
44 list << QObject::tr(
"KB" ) << QObject::tr(
"MB" ) << QObject::tr(
"GB" ) << QObject::tr(
"TB" );
46 QStringListIterator i( list );
47 QString unit = QObject::tr(
"B" );
49 double fileSize = bytes;
50 while ( fileSize >= 1024.0 && i.hasNext() )
55 return QStringLiteral(
"%1 %2" ).arg( QString::number( fileSize,
'f', bytes >= 1048576 ? 2 : 0 ), unit );
60 const QRegularExpression rx( QStringLiteral(
"\\*\\.([a-zA-Z0-9]+)" ) );
61 QStringList extensions;
62 QRegularExpressionMatchIterator matches = rx.globalMatch( filter );
64 while ( matches.hasNext() )
66 const QRegularExpressionMatch match = matches.next();
67 if ( match.hasMatch() )
69 QStringList newExtensions = match.capturedTexts();
70 newExtensions.pop_front();
71 extensions.append( newExtensions );
79 const QRegularExpression globPatternsRx( QStringLiteral(
".*\\((.*?)\\)$" ) );
80 const QRegularExpressionMatch matches = globPatternsRx.match( filter );
81 if ( matches.hasMatch() )
82 return matches.captured( 1 );
89 QFileInfo fi( fileName );
90 const QString name = fi.fileName();
91 const QStringList parts = filter.split( QStringLiteral(
";;" ) );
92 for (
const QString &part : parts )
94 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
95 const QStringList globPatterns =
wildcardsFromFilter( part ).split(
' ', QString::SkipEmptyParts );
97 const QStringList globPatterns =
wildcardsFromFilter( part ).split(
' ', Qt::SkipEmptyParts );
99 for (
const QString &glob : globPatterns )
101 const QString re = QRegularExpression::wildcardToRegularExpression( glob );
103 const QRegularExpression globRx( re );
104 if ( globRx.match( name ).hasMatch() )
113 if ( extensions.empty() || f.isEmpty() )
116 QString fileName = f;
118 for (
const QString &extension : std::as_const( extensions ) )
120 const QString extWithDot = extension.startsWith(
'.' ) ? extension :
'.' + extension;
121 if ( fileName.endsWith( extWithDot, Qt::CaseInsensitive ) )
130 const QString extension = extensions.at( 0 );
131 const QString extWithDot = extension.startsWith(
'.' ) ? extension :
'.' + extension;
132 fileName += extWithDot;
146 QRegularExpression rx( QStringLiteral(
"[/\\\\\\?%\\*\\:\\|\"<>]" ) );
148 s.replace( rx, QStringLiteral(
"_" ) );
154 if ( path.isEmpty() )
158 QFileInfo fi( path );
160 currentPath = fi.dir();
162 currentPath = QDir( path );
164 QSet< QString > visited;
165 while ( !currentPath.exists() )
167 const QString parentPath = QDir::cleanPath( currentPath.absolutePath() + QStringLiteral(
"/.." ) );
168 if ( visited.contains( parentPath ) )
171 if ( parentPath.isEmpty() || parentPath == QLatin1String(
"." ) )
173 currentPath = QDir( parentPath );
174 visited << parentPath;
177 const QString res = QDir::cleanPath( currentPath.absolutePath() );
179 if ( res == QDir::currentPath() )
182 return res == QLatin1String(
"." ) ? QString() : res;
185 QStringList
QgsFileUtils::findFile(
const QString &file,
const QString &basePath,
int maxClimbs,
int searchCeilling,
const QString ¤tDir )
188 QString originalFolder;
190 const QString fileName( basePath.isEmpty() ? QFileInfo( file ).fileName() : file );
191 const QString baseFolder( basePath.isEmpty() ? QFileInfo( file ).path() : basePath );
193 if ( QFileInfo( baseFolder ).isDir() )
195 folder = QDir( baseFolder ) ;
196 originalFolder = folder.absolutePath();
200 folder = QDir( QFileInfo( baseFolder ).absolutePath() );
201 originalFolder = folder.absolutePath();
204 QStringList searchedFolder = QStringList();
205 QString existingBase;
206 QString backupDirectory = QDir::currentPath();
207 QStringList foundFiles;
209 if ( !currentDir.isEmpty() && backupDirectory != currentDir && QDir( currentDir ).exists() )
210 QDir::setCurrent( currentDir );
213 while ( !folder.exists() && folder.absolutePath().count(
'/' ) > searchCeilling )
216 existingBase = folder.path();
217 if ( !folder.cdUp() )
218 folder = QFileInfo( existingBase ).absoluteDir();
222 if ( depth > ( maxClimbs + 4 ) )
225 bool folderExists = folder.exists();
227 if ( depth > maxClimbs )
230 if ( folder.absolutePath().count(
'/' ) < searchCeilling )
231 searchCeilling = folder.absolutePath().count(
'/' ) - 1;
233 while ( depth <= maxClimbs && folderExists && folder.absolutePath().count(
'/' ) >= searchCeilling )
236 QDirIterator localFinder( folder.path(), QStringList() << fileName, QDir::Files, QDirIterator::NoIteratorFlags );
237 searchedFolder.append( folder.absolutePath() );
238 if ( localFinder.hasNext() )
240 foundFiles << localFinder.next();
245 const QFileInfoList subdirs = folder.entryInfoList( QDir::AllDirs );
246 for (
const QFileInfo &subdir : subdirs )
248 if ( ! searchedFolder.contains( subdir.absolutePath() ) )
250 QDirIterator subDirFinder( subdir.path(), QStringList() << fileName, QDir::Files, QDirIterator::Subdirectories );
251 if ( subDirFinder.hasNext() )
253 QString possibleFile = subDirFinder.next();
254 if ( !subDirFinder.hasNext() )
256 foundFiles << possibleFile;
260 foundFiles << possibleFile;
261 while ( subDirFinder.hasNext() )
263 foundFiles << subDirFinder.next();
271 if ( depth > maxClimbs )
274 folderExists = folder.cdUp();
277 if ( QDir::currentPath() == currentDir && currentDir != backupDirectory )
278 QDir::setCurrent( backupDirectory );
284 std::unique_ptr< wchar_t[] > pathToWChar(
const QString &path )
286 const QString nativePath = QDir::toNativeSeparators( path );
288 std::unique_ptr< wchar_t[] > pathArray(
new wchar_t[
static_cast< uint
>( nativePath.length() + 1 )] );
289 nativePath.toWCharArray( pathArray.get() );
290 pathArray[
static_cast< size_t >( nativePath.length() )] = 0;
298 auto pathType = [ = ](
const QString & path ) -> DriveType
300 std::unique_ptr< wchar_t[] > pathArray = pathToWChar( path );
301 const UINT type = GetDriveTypeW( pathArray.get() );
307 case DRIVE_NO_ROOT_DIR:
310 case DRIVE_REMOVABLE:
330 const QString originalPath = QDir::cleanPath( path );
331 QString currentPath = originalPath;
333 while ( currentPath != prevPath )
335 prevPath = currentPath;
336 currentPath = QFileInfo( currentPath ).path();
337 const DriveType type = pathType( currentPath );
338 if ( type != Unknown && type != Invalid )
352 if ( path.contains( QLatin1String(
"fake_slow_path_for_unit_tests" ) ) )
384 for (
const QString &provider : providers )
390 for (
const QString &possibleSidecar : possibleSidecars )
392 if ( QFile::exists( possibleSidecar ) )
393 res.insert( possibleSidecar );
402 if ( !QFile::exists( oldPath ) )
404 error = QObject::tr(
"File does not exist" );
408 const QFileInfo oldPathInfo( oldPath );
412 const QString qmdPath = oldPathInfo.dir().filePath( oldPathInfo.completeBaseName() + QStringLiteral(
".qmd" ) );
413 if ( QFile::exists( qmdPath ) )
414 sidecars.insert( qmdPath );
418 const QString qmlPath = oldPathInfo.dir().filePath( oldPathInfo.completeBaseName() + QStringLiteral(
".qml" ) );
419 if ( QFile::exists( qmlPath ) )
420 sidecars.insert( qmlPath );
423 const QFileInfo newPathInfo( newPath );
427 errors.reserve( sidecars.size() );
429 for (
const QString &sidecar : std::as_const( sidecars ) )
431 const QFileInfo sidecarInfo( sidecar );
432 const QString newSidecarName = newPathInfo.dir().filePath( newPathInfo.completeBaseName() +
'.' + sidecarInfo.suffix() );
433 if ( newSidecarName != sidecar && QFile::exists( newSidecarName ) )
436 errors.append( QDir::toNativeSeparators( newSidecarName ) );
441 error = QObject::tr(
"Destination files already exist %1" ).arg( errors.join( QLatin1String(
", " ) ) );
445 if ( !QFile::rename( oldPath, newPath ) )
447 error = QObject::tr(
"Could not rename %1" ).arg( QDir::toNativeSeparators( oldPath ) );
451 for (
const QString &sidecar : std::as_const( sidecars ) )
453 const QFileInfo sidecarInfo( sidecar );
454 const QString newSidecarName = newPathInfo.dir().filePath( newPathInfo.completeBaseName() +
'.' + sidecarInfo.suffix() );
455 if ( newSidecarName == sidecar )
458 if ( !QFile::rename( sidecar, newSidecarName ) )
460 errors.append( QDir::toNativeSeparators( sidecar ) );
466 error = QObject::tr(
"Could not rename %1" ).arg( errors.join( QLatin1String(
", " ) ) );
475 struct rlimit rescLimit;
476 if ( getrlimit( RLIMIT_NOFILE, &rescLimit ) == 0 )
478 return rescLimit.rlim_cur;
487 int res =
static_cast<int>( QDir(
"/proc/self/fd" ).entryList().size() );
501 constexpr
int SOME_MARGIN = 20;
502 return nFileCount > 0 && nFileLimit > 0 && nFileCount + filesToBeOpened > nFileLimit - SOME_MARGIN;