Fix canonicalFilePath() for files with trailing slashes
Such files do not exist (as per QFileInfo::exists), but on some platforms that rely on realpath(), QFileInfo::canonicalFilePath did not return the empty string. Use the same logic on macOS as we already did on Android, and include a test case. Remove the unnecessary dynamic memory allocation and use a stack-allocated array instead, unless we use modern POSIX in which case realpath() will alloc the memory for the result for us. Change-Id: Ide987c68ebf00cbb7b1a66c2e9245a12c7807128 Fixes: QTBUG-44242 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
parent
bba44746f9
commit
bd55a9d912
@ -695,52 +695,36 @@ QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry,
|
|||||||
Q_UNUSED(data);
|
Q_UNUSED(data);
|
||||||
return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath()));
|
return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath()));
|
||||||
#else
|
#else
|
||||||
char *ret = 0;
|
char stack_result[PATH_MAX+1];
|
||||||
# if defined(Q_OS_DARWIN)
|
char *resolved_name = nullptr;
|
||||||
ret = (char*)malloc(PATH_MAX + 1);
|
# if defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID)
|
||||||
if (ret && realpath(entry.nativeFilePath().constData(), (char*)ret) == 0) {
|
// On some Android and macOS versions, realpath() will return a path even if
|
||||||
const int savedErrno = errno; // errno is checked below, and free() might change it
|
// it does not exist. To work around this, we check existence in advance.
|
||||||
free(ret);
|
|
||||||
errno = savedErrno;
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
# elif defined(Q_OS_ANDROID)
|
|
||||||
// On some Android versions, realpath() will return a path even if it does not exist
|
|
||||||
// To work around this, we check existence in advance.
|
|
||||||
if (!data.hasFlags(QFileSystemMetaData::ExistsAttribute))
|
if (!data.hasFlags(QFileSystemMetaData::ExistsAttribute))
|
||||||
fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute);
|
fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute);
|
||||||
|
|
||||||
if (!data.exists()) {
|
if (!data.exists()) {
|
||||||
ret = 0;
|
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
} else {
|
} else {
|
||||||
ret = (char*)malloc(PATH_MAX + 1);
|
resolved_name = stack_result;
|
||||||
if (realpath(entry.nativeFilePath().constData(), (char*)ret) == 0) {
|
|
||||||
const int savedErrno = errno; // errno is checked below, and free() might change it
|
|
||||||
free(ret);
|
|
||||||
errno = savedErrno;
|
|
||||||
ret = 0;
|
|
||||||
}
|
}
|
||||||
}
|
if (resolved_name && realpath(entry.nativeFilePath().constData(), resolved_name) == nullptr)
|
||||||
|
resolved_name = nullptr;
|
||||||
# else
|
# else
|
||||||
# if _POSIX_VERSION >= 200801L
|
# if _POSIX_VERSION >= 200801L // ask realpath to allocate memory
|
||||||
ret = realpath(entry.nativeFilePath().constData(), (char*)0);
|
resolved_name = realpath(entry.nativeFilePath().constData(), nullptr);
|
||||||
# else
|
# else
|
||||||
ret = (char*)malloc(PATH_MAX + 1);
|
resolved_name = stack_result;
|
||||||
if (realpath(entry.nativeFilePath().constData(), (char*)ret) == 0) {
|
if (realpath(entry.nativeFilePath().constData(), resolved_name) == nullptr)
|
||||||
const int savedErrno = errno; // errno is checked below, and free() might change it
|
resolved_name = nullptr;
|
||||||
free(ret);
|
|
||||||
errno = savedErrno;
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
if (ret) {
|
if (resolved_name) {
|
||||||
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
|
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
|
||||||
data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
|
data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
|
||||||
QString canonicalPath = QDir::cleanPath(QFile::decodeName(ret));
|
QString canonicalPath = QDir::cleanPath(QFile::decodeName(resolved_name));
|
||||||
free(ret);
|
if (resolved_name != stack_result)
|
||||||
|
free(resolved_name);
|
||||||
return QFileSystemEntry(canonicalPath);
|
return QFileSystemEntry(canonicalPath);
|
||||||
} else if (errno == ENOENT || errno == ENOTDIR) { // file doesn't exist
|
} else if (errno == ENOENT || errno == ENOTDIR) { // file doesn't exist
|
||||||
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
|
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
|
||||||
|
@ -655,6 +655,8 @@ void tst_QFileInfo::canonicalFilePath()
|
|||||||
QVERIFY(tempFile.open(QFile::WriteOnly));
|
QVERIFY(tempFile.open(QFile::WriteOnly));
|
||||||
QFileInfo fi(tempFile.fileName());
|
QFileInfo fi(tempFile.fileName());
|
||||||
QCOMPARE(fi.canonicalFilePath(), QDir::currentPath() + "/" + fileName);
|
QCOMPARE(fi.canonicalFilePath(), QDir::currentPath() + "/" + fileName);
|
||||||
|
fi = QFileInfo(tempFile.fileName() + QString::fromLatin1("/"));
|
||||||
|
QCOMPARE(fi.canonicalFilePath(), QString::fromLatin1(""));
|
||||||
tempFile.remove();
|
tempFile.remove();
|
||||||
|
|
||||||
// This used to crash on Mac, verify that it doesn't anymore.
|
// This used to crash on Mac, verify that it doesn't anymore.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user