Utils: Centralize FilePath case sensitivity handling

This could or possibly should the target device's file name case
sensitivity into account by diverting to IDevice. However, as this is
expensive and we are in time-critical path here, we go with "good
enough" for now.

The first approximation is "Anything unusual is not case sensitive"
which is better than "Any device equals the host".

Change-Id: Ib3d4a627abebd96a7285a855af66e0c800767767
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
hjk
2021-05-19 09:28:57 +02:00
parent 90ad902486
commit a71bb36682
3 changed files with 59 additions and 17 deletions

View File

@@ -210,6 +210,18 @@ bool FilePath::isNewerThan(const QDateTime &timeStamp) const
return false; return false;
} }
Qt::CaseSensitivity FilePath::caseSensitivity() const
{
if (m_scheme.isEmpty())
return HostOsInfo::fileNameCaseSensitivity();
// FIXME: This could or possibly should the target device's file name case sensitivity
// into account by diverting to IDevice. However, as this is expensive and we are
// in time-critical path here, we go with "good enough" for now:
// The first approximation is "Anything unusual is not case sensitive"
return Qt::CaseSensitive;
}
/*! /*!
Recursively resolves symlinks if \a filePath is a symlink. Recursively resolves symlinks if \a filePath is a symlink.
To resolve symlinks anywhere in the path, see canonicalPath. To resolve symlinks anywhere in the path, see canonicalPath.
@@ -994,12 +1006,9 @@ QDir FilePath::toDir() const
bool FilePath::operator==(const FilePath &other) const bool FilePath::operator==(const FilePath &other) const
{ {
if (m_scheme.isEmpty()) return QString::compare(m_data, other.m_data, caseSensitivity()) == 0
return QString::compare(m_data, other.m_data, HostOsInfo::fileNameCaseSensitivity()) == 0; && m_host == other.m_host
&& m_scheme == other.m_scheme;
// FIXME: This should take the host's file name case sensitivity into account.
// The first approximation here is "Anything unusual is not case sensitive"
return m_data == other.m_data && m_host == other.m_host && m_scheme == other.m_scheme;
} }
bool FilePath::operator!=(const FilePath &other) const bool FilePath::operator!=(const FilePath &other) const
@@ -1009,13 +1018,9 @@ bool FilePath::operator!=(const FilePath &other) const
bool FilePath::operator<(const FilePath &other) const bool FilePath::operator<(const FilePath &other) const
{ {
if (m_scheme.isEmpty()) const int cmp = QString::compare(m_data, other.m_data, caseSensitivity());
return QString::compare(m_data, other.m_data, HostOsInfo::fileNameCaseSensitivity()) < 0; if (cmp != 0)
return cmp < 0;
// FIXME: This should take the host's file name case sensitivity into account.
// The first approximation here is "Anything unusual is not case sensitive"
if (m_data != other.m_data)
return m_data < other.m_data;
if (m_host != other.m_host) if (m_host != other.m_host)
return m_host < other.m_host; return m_host < other.m_host;
return m_scheme < other.m_scheme; return m_scheme < other.m_scheme;
@@ -1046,7 +1051,7 @@ bool FilePath::isChildOf(const FilePath &s) const
{ {
if (s.isEmpty()) if (s.isEmpty())
return false; return false;
if (!m_data.startsWith(s.m_data, HostOsInfo::fileNameCaseSensitivity())) if (!m_data.startsWith(s.m_data, caseSensitivity()))
return false; return false;
if (m_data.size() <= s.m_data.size()) if (m_data.size() <= s.m_data.size())
return false; return false;
@@ -1066,13 +1071,13 @@ bool FilePath::isChildOf(const QDir &dir) const
/// \returns whether FilePath startsWith \a s /// \returns whether FilePath startsWith \a s
bool FilePath::startsWith(const QString &s) const bool FilePath::startsWith(const QString &s) const
{ {
return m_data.startsWith(s, HostOsInfo::fileNameCaseSensitivity()); return m_data.startsWith(s, caseSensitivity());
} }
/// \returns whether FilePath endsWith \a s /// \returns whether FilePath endsWith \a s
bool FilePath::endsWith(const QString &s) const bool FilePath::endsWith(const QString &s) const
{ {
return m_data.endsWith(s, HostOsInfo::fileNameCaseSensitivity()); return m_data.endsWith(s, caseSensitivity());
} }
bool FilePath::isDir() const bool FilePath::isDir() const
@@ -1307,7 +1312,7 @@ void withNtfsPermissions(const std::function<void()> &task)
std::hash<Utils::FilePath>::result_type std::hash<Utils::FilePath>::result_type
std::hash<Utils::FilePath>::operator()(const std::hash<Utils::FilePath>::argument_type &fn) const std::hash<Utils::FilePath>::operator()(const std::hash<Utils::FilePath>::argument_type &fn) const
{ {
if (Utils::HostOsInfo::fileNameCaseSensitivity() == Qt::CaseInsensitive) if (fn.caseSensitivity() == Qt::CaseInsensitive)
return hash<string>()(fn.toString().toUpper().toStdString()); return hash<string>()(fn.toString().toUpper().toStdString());
return hash<string>()(fn.toString().toStdString()); return hash<string>()(fn.toString().toStdString());
} }

View File

@@ -146,6 +146,8 @@ public:
bool isDir() const; bool isDir() const;
bool isNewerThan(const QDateTime &timeStamp) const; bool isNewerThan(const QDateTime &timeStamp) const;
Qt::CaseSensitivity caseSensitivity() const;
FilePath relativeChildPath(const FilePath &parent) const; FilePath relativeChildPath(const FilePath &parent) const;
FilePath relativePath(const FilePath &anchor) const; FilePath relativePath(const FilePath &anchor) const;
FilePath pathAppended(const QString &str) const; FilePath pathAppended(const QString &str) const;

View File

@@ -52,6 +52,8 @@ private slots:
void relativePath(); void relativePath();
void fromToString_data(); void fromToString_data();
void fromToString(); void fromToString();
void comparison_data();
void comparison();
private: private:
QTemporaryDir tempDir; QTemporaryDir tempDir;
@@ -329,5 +331,38 @@ void tst_fileutils::fromToString()
QCOMPARE(copy.toString(), full); QCOMPARE(copy.toString(), full);
} }
void tst_fileutils::comparison()
{
QFETCH(QString, left);
QFETCH(QString, right);
QFETCH(bool, hostSensitive);
QFETCH(bool, expected);
HostOsInfo::setOverrideFileNameCaseSensitivity(
hostSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
FilePath l = FilePath::fromString(left);
FilePath r = FilePath::fromString(right);
QCOMPARE(l == r, expected);
}
void tst_fileutils::comparison_data()
{
QTest::addColumn<QString>("left");
QTest::addColumn<QString>("right");
QTest::addColumn<bool>("hostSensitive");
QTest::addColumn<bool>("expected");
QTest::newRow("r1") << "Abc" << "abc" << true << false;
QTest::newRow("r2") << "Abc" << "abc" << false << true;
QTest::newRow("r3") << "x://y/Abc" << "x://y/abc" << true << false;
QTest::newRow("r4") << "x://y/Abc" << "x://y/abc" << false << false;
QTest::newRow("s1") << "abc" << "abc" << true << true;
QTest::newRow("s2") << "abc" << "abc" << false << true;
QTest::newRow("s3") << "x://y/abc" << "x://y/abc" << true << true;
QTest::newRow("s4") << "x://y/abc" << "x://y/abc" << false << true;
}
QTEST_APPLESS_MAIN(tst_fileutils) QTEST_APPLESS_MAIN(tst_fileutils)
#include "tst_fileutils.moc" #include "tst_fileutils.moc"