Add QFileInfo::readSymLink() to read the raw link path
The existing symLinkTarget() always resolves the symlink target to an absolute path; readSymLink() provides access to the relative path when that is how the symlink references its target. [ChangeLog][QtCore][QFileInfo] Added readSymLink() to read the symlink's raw target, without resolving to an absolute path. Fixes: QTBUG-96761 Change-Id: I360e55f1a3bdb00e2966229ea8de78cf29a29417 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
8844c6ef37
commit
936cae6b53
@ -225,6 +225,8 @@ QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
|
||||
the base name).
|
||||
\value AbsoluteLinkTarget The full file name of the file that this file is a
|
||||
link to. (This will be empty if this file is not a link.)
|
||||
\value RawLinkPath The raw link path of the file that this file is a
|
||||
link to. (This will be empty if this file is not a link.)
|
||||
\value CanonicalName Often very similar to AbsoluteLinkTarget. Will return the true path to the file.
|
||||
\value CanonicalPathName Same as CanonicalName, excluding the base name.
|
||||
\value BundleName Returns the name of the bundle implies BundleType is set.
|
||||
|
@ -73,6 +73,7 @@ public:
|
||||
CanonicalPathName,
|
||||
BundleName,
|
||||
JunctionName,
|
||||
RawLinkPath,
|
||||
NFileNames // Must be last.
|
||||
};
|
||||
enum FileOwner {
|
||||
|
@ -38,6 +38,9 @@ QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const
|
||||
case QAbstractFileEngine::AbsoluteLinkTarget:
|
||||
ret = QFileSystemEngine::getLinkTarget(fileEntry, metaData).filePath();
|
||||
break;
|
||||
case QAbstractFileEngine::RawLinkPath:
|
||||
ret = QFileSystemEngine::getRawLinkPath(fileEntry, metaData).filePath();
|
||||
break;
|
||||
case QAbstractFileEngine::JunctionName:
|
||||
ret = QFileSystemEngine::getJunctionTarget(fileEntry, metaData).filePath();
|
||||
break;
|
||||
@ -1221,6 +1224,25 @@ QString QFileInfo::symLinkTarget() const
|
||||
return d->getFileName(QAbstractFileEngine::AbsoluteLinkTarget);
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.6
|
||||
Read the path the symlink references.
|
||||
|
||||
Returns the raw path referenced by the symbolic link, without resolving a relative
|
||||
path relative to the directory containing the symbolic link. The returned string will
|
||||
only be an absolute path if the symbolic link actually references it as such. Returns
|
||||
an empty string if the object is not a symbolic link.
|
||||
|
||||
\sa symLinkTarget(), exists(), isSymLink(), isDir(), isFile()
|
||||
*/
|
||||
QString QFileInfo::readSymLink() const
|
||||
{
|
||||
Q_D(const QFileInfo);
|
||||
if (d->isDefaultConstructed)
|
||||
return {};
|
||||
return d->getFileName(QAbstractFileEngine::RawLinkPath);
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.2
|
||||
|
||||
|
@ -126,12 +126,16 @@ public:
|
||||
bool isBundle() const;
|
||||
|
||||
QString symLinkTarget() const;
|
||||
QString readSymLink() const;
|
||||
QString junctionTarget() const;
|
||||
|
||||
#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
|
||||
std::filesystem::path filesystemSymLinkTarget() const
|
||||
{ return QtPrivate::toFilesystemPath(symLinkTarget()); }
|
||||
|
||||
std::filesystem::path filesystemReadSymLink() const
|
||||
{ return QtPrivate::toFilesystemPath(readSymLink()); }
|
||||
|
||||
std::filesystem::path filesystemJunctionTarget() const
|
||||
{ return QtPrivate::toFilesystemPath(junctionTarget()); }
|
||||
#endif // QT_CONFIG(cxx17_filesystem)
|
||||
|
@ -67,6 +67,8 @@ public:
|
||||
}
|
||||
|
||||
static QFileSystemEntry getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data);
|
||||
static QFileSystemEntry getRawLinkPath(const QFileSystemEntry &link,
|
||||
QFileSystemMetaData &data);
|
||||
static QFileSystemEntry getJunctionTarget(const QFileSystemEntry &link, QFileSystemMetaData &data);
|
||||
static QFileSystemEntry canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data);
|
||||
static QFileSystemEntry absoluteName(const QFileSystemEntry &entry);
|
||||
|
@ -628,6 +628,16 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
|
||||
return QFileSystemEntry();
|
||||
}
|
||||
|
||||
//static
|
||||
QFileSystemEntry QFileSystemEngine::getRawLinkPath(const QFileSystemEntry &link,
|
||||
QFileSystemMetaData &data)
|
||||
{
|
||||
Q_UNUSED(data)
|
||||
const QByteArray path = qt_readlink(link.nativeFilePath().constData());
|
||||
const QString ret = QFile::decodeName(path);
|
||||
return QFileSystemEntry(ret);
|
||||
}
|
||||
|
||||
//static
|
||||
QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
|
||||
{
|
||||
|
@ -855,6 +855,18 @@ void QFileSystemEngine::clearWinStatData(QFileSystemMetaData &data)
|
||||
//static
|
||||
QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
|
||||
QFileSystemMetaData &data)
|
||||
{
|
||||
QFileSystemEntry ret = getRawLinkPath(link, data);
|
||||
if (!ret.isEmpty() && ret.isRelative()) {
|
||||
QString target = absoluteName(link).path() + u'/' + ret.filePath();
|
||||
ret = QFileSystemEntry(QDir::cleanPath(target));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//static
|
||||
QFileSystemEntry QFileSystemEngine::getRawLinkPath(const QFileSystemEntry &link,
|
||||
QFileSystemMetaData &data)
|
||||
{
|
||||
Q_CHECK_FILE_NAME(link, link);
|
||||
|
||||
@ -866,12 +878,7 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
|
||||
target = readLink(link);
|
||||
else if (data.isLink())
|
||||
target = readSymLink(link);
|
||||
QFileSystemEntry ret(target);
|
||||
if (!target.isEmpty() && ret.isRelative()) {
|
||||
target.prepend(absoluteName(link).path() + u'/');
|
||||
ret = QFileSystemEntry(QDir::cleanPath(target));
|
||||
}
|
||||
return ret;
|
||||
return QFileSystemEntry(target);
|
||||
}
|
||||
|
||||
//static
|
||||
|
@ -450,6 +450,12 @@ QString QFSFileEngine::fileName(FileName file) const
|
||||
return entry.filePath();
|
||||
}
|
||||
return QString();
|
||||
case RawLinkPath:
|
||||
if (d->isSymlink()) {
|
||||
QFileSystemEntry entry = QFileSystemEngine::getRawLinkPath(d->fileEntry, d->metaData);
|
||||
return entry.filePath();
|
||||
}
|
||||
return QString();
|
||||
case JunctionName:
|
||||
return QString();
|
||||
case DefaultName:
|
||||
|
@ -619,6 +619,8 @@ QString QFSFileEngine::fileName(FileName file) const
|
||||
}
|
||||
case AbsoluteLinkTarget:
|
||||
return QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData).filePath();
|
||||
case RawLinkPath:
|
||||
return QFileSystemEngine::getRawLinkPath(d->fileEntry, d->metaData).filePath();
|
||||
case BundleName:
|
||||
return QString();
|
||||
case JunctionName:
|
||||
|
@ -406,7 +406,7 @@ bool QTemporaryFileEngine::close()
|
||||
QString QTemporaryFileEngine::fileName(QAbstractFileEngine::FileName file) const
|
||||
{
|
||||
if (isUnnamedFile()) {
|
||||
if (file == AbsoluteLinkTarget) {
|
||||
if (file == AbsoluteLinkTarget || file == RawLinkPath) {
|
||||
// we know our file isn't (won't be) a symlink
|
||||
return QString();
|
||||
}
|
||||
|
@ -215,6 +215,8 @@ public:
|
||||
return QLatin1String("AbsolutePathName");
|
||||
case AbsoluteLinkTarget:
|
||||
return QLatin1String("AbsoluteLinkTarget");
|
||||
case RawLinkPath:
|
||||
return QLatin1String("RawLinkPath");
|
||||
case CanonicalName:
|
||||
return QLatin1String("CanonicalName");
|
||||
case CanonicalPathName:
|
||||
|
@ -242,6 +242,7 @@ private slots:
|
||||
void nonExistingFile();
|
||||
|
||||
void stdfilesystem();
|
||||
void readSymLink();
|
||||
|
||||
private:
|
||||
const QString m_currentDir;
|
||||
@ -2391,5 +2392,20 @@ void tst_QFileInfo::stdfilesystem()
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QFileInfo::readSymLink()
|
||||
{
|
||||
QString symLinkName("./a.link");
|
||||
const auto tidier = qScopeGuard([symLinkName]() { QFile::remove(symLinkName); });
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QVERIFY2(CreateSymbolicLink(L"a.link", L"..\\..\\a", SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)
|
||||
!= 0,
|
||||
"Failed to create symlink for test");
|
||||
#else
|
||||
QVERIFY2(QFile::link("../../a", symLinkName), "Failed to create symlink for test");
|
||||
#endif
|
||||
QFileInfo info(symLinkName);
|
||||
QCOMPARE(info.readSymLink(), QString("../../a"));
|
||||
}
|
||||
QTEST_MAIN(tst_QFileInfo)
|
||||
#include "tst_qfileinfo.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user