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;