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).
|
the base name).
|
||||||
\value AbsoluteLinkTarget The full file name of the file that this file is a
|
\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.)
|
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 CanonicalName Often very similar to AbsoluteLinkTarget. Will return the true path to the file.
|
||||||
\value CanonicalPathName Same as CanonicalName, excluding the base name.
|
\value CanonicalPathName Same as CanonicalName, excluding the base name.
|
||||||
\value BundleName Returns the name of the bundle implies BundleType is set.
|
\value BundleName Returns the name of the bundle implies BundleType is set.
|
||||||
|
@ -73,6 +73,7 @@ public:
|
|||||||
CanonicalPathName,
|
CanonicalPathName,
|
||||||
BundleName,
|
BundleName,
|
||||||
JunctionName,
|
JunctionName,
|
||||||
|
RawLinkPath,
|
||||||
NFileNames // Must be last.
|
NFileNames // Must be last.
|
||||||
};
|
};
|
||||||
enum FileOwner {
|
enum FileOwner {
|
||||||
|
@ -38,6 +38,9 @@ QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const
|
|||||||
case QAbstractFileEngine::AbsoluteLinkTarget:
|
case QAbstractFileEngine::AbsoluteLinkTarget:
|
||||||
ret = QFileSystemEngine::getLinkTarget(fileEntry, metaData).filePath();
|
ret = QFileSystemEngine::getLinkTarget(fileEntry, metaData).filePath();
|
||||||
break;
|
break;
|
||||||
|
case QAbstractFileEngine::RawLinkPath:
|
||||||
|
ret = QFileSystemEngine::getRawLinkPath(fileEntry, metaData).filePath();
|
||||||
|
break;
|
||||||
case QAbstractFileEngine::JunctionName:
|
case QAbstractFileEngine::JunctionName:
|
||||||
ret = QFileSystemEngine::getJunctionTarget(fileEntry, metaData).filePath();
|
ret = QFileSystemEngine::getJunctionTarget(fileEntry, metaData).filePath();
|
||||||
break;
|
break;
|
||||||
@ -1221,6 +1224,25 @@ QString QFileInfo::symLinkTarget() const
|
|||||||
return d->getFileName(QAbstractFileEngine::AbsoluteLinkTarget);
|
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
|
\since 6.2
|
||||||
|
|
||||||
|
@ -126,12 +126,16 @@ public:
|
|||||||
bool isBundle() const;
|
bool isBundle() const;
|
||||||
|
|
||||||
QString symLinkTarget() const;
|
QString symLinkTarget() const;
|
||||||
|
QString readSymLink() const;
|
||||||
QString junctionTarget() const;
|
QString junctionTarget() const;
|
||||||
|
|
||||||
#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
|
#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
|
||||||
std::filesystem::path filesystemSymLinkTarget() const
|
std::filesystem::path filesystemSymLinkTarget() const
|
||||||
{ return QtPrivate::toFilesystemPath(symLinkTarget()); }
|
{ return QtPrivate::toFilesystemPath(symLinkTarget()); }
|
||||||
|
|
||||||
|
std::filesystem::path filesystemReadSymLink() const
|
||||||
|
{ return QtPrivate::toFilesystemPath(readSymLink()); }
|
||||||
|
|
||||||
std::filesystem::path filesystemJunctionTarget() const
|
std::filesystem::path filesystemJunctionTarget() const
|
||||||
{ return QtPrivate::toFilesystemPath(junctionTarget()); }
|
{ return QtPrivate::toFilesystemPath(junctionTarget()); }
|
||||||
#endif // QT_CONFIG(cxx17_filesystem)
|
#endif // QT_CONFIG(cxx17_filesystem)
|
||||||
|
@ -67,6 +67,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static QFileSystemEntry getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data);
|
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 getJunctionTarget(const QFileSystemEntry &link, QFileSystemMetaData &data);
|
||||||
static QFileSystemEntry canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data);
|
static QFileSystemEntry canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data);
|
||||||
static QFileSystemEntry absoluteName(const QFileSystemEntry &entry);
|
static QFileSystemEntry absoluteName(const QFileSystemEntry &entry);
|
||||||
|
@ -628,6 +628,16 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
|
|||||||
return QFileSystemEntry();
|
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
|
//static
|
||||||
QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
|
QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
|
||||||
{
|
{
|
||||||
|
@ -855,6 +855,18 @@ void QFileSystemEngine::clearWinStatData(QFileSystemMetaData &data)
|
|||||||
//static
|
//static
|
||||||
QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
|
QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
|
||||||
QFileSystemMetaData &data)
|
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);
|
Q_CHECK_FILE_NAME(link, link);
|
||||||
|
|
||||||
@ -866,12 +878,7 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
|
|||||||
target = readLink(link);
|
target = readLink(link);
|
||||||
else if (data.isLink())
|
else if (data.isLink())
|
||||||
target = readSymLink(link);
|
target = readSymLink(link);
|
||||||
QFileSystemEntry ret(target);
|
return QFileSystemEntry(target);
|
||||||
if (!target.isEmpty() && ret.isRelative()) {
|
|
||||||
target.prepend(absoluteName(link).path() + u'/');
|
|
||||||
ret = QFileSystemEntry(QDir::cleanPath(target));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
//static
|
||||||
|
@ -450,6 +450,12 @@ QString QFSFileEngine::fileName(FileName file) const
|
|||||||
return entry.filePath();
|
return entry.filePath();
|
||||||
}
|
}
|
||||||
return QString();
|
return QString();
|
||||||
|
case RawLinkPath:
|
||||||
|
if (d->isSymlink()) {
|
||||||
|
QFileSystemEntry entry = QFileSystemEngine::getRawLinkPath(d->fileEntry, d->metaData);
|
||||||
|
return entry.filePath();
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
case JunctionName:
|
case JunctionName:
|
||||||
return QString();
|
return QString();
|
||||||
case DefaultName:
|
case DefaultName:
|
||||||
|
@ -619,6 +619,8 @@ QString QFSFileEngine::fileName(FileName file) const
|
|||||||
}
|
}
|
||||||
case AbsoluteLinkTarget:
|
case AbsoluteLinkTarget:
|
||||||
return QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData).filePath();
|
return QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData).filePath();
|
||||||
|
case RawLinkPath:
|
||||||
|
return QFileSystemEngine::getRawLinkPath(d->fileEntry, d->metaData).filePath();
|
||||||
case BundleName:
|
case BundleName:
|
||||||
return QString();
|
return QString();
|
||||||
case JunctionName:
|
case JunctionName:
|
||||||
|
@ -406,7 +406,7 @@ bool QTemporaryFileEngine::close()
|
|||||||
QString QTemporaryFileEngine::fileName(QAbstractFileEngine::FileName file) const
|
QString QTemporaryFileEngine::fileName(QAbstractFileEngine::FileName file) const
|
||||||
{
|
{
|
||||||
if (isUnnamedFile()) {
|
if (isUnnamedFile()) {
|
||||||
if (file == AbsoluteLinkTarget) {
|
if (file == AbsoluteLinkTarget || file == RawLinkPath) {
|
||||||
// we know our file isn't (won't be) a symlink
|
// we know our file isn't (won't be) a symlink
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
@ -215,6 +215,8 @@ public:
|
|||||||
return QLatin1String("AbsolutePathName");
|
return QLatin1String("AbsolutePathName");
|
||||||
case AbsoluteLinkTarget:
|
case AbsoluteLinkTarget:
|
||||||
return QLatin1String("AbsoluteLinkTarget");
|
return QLatin1String("AbsoluteLinkTarget");
|
||||||
|
case RawLinkPath:
|
||||||
|
return QLatin1String("RawLinkPath");
|
||||||
case CanonicalName:
|
case CanonicalName:
|
||||||
return QLatin1String("CanonicalName");
|
return QLatin1String("CanonicalName");
|
||||||
case CanonicalPathName:
|
case CanonicalPathName:
|
||||||
|
@ -242,6 +242,7 @@ private slots:
|
|||||||
void nonExistingFile();
|
void nonExistingFile();
|
||||||
|
|
||||||
void stdfilesystem();
|
void stdfilesystem();
|
||||||
|
void readSymLink();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const QString m_currentDir;
|
const QString m_currentDir;
|
||||||
@ -2391,5 +2392,20 @@ void tst_QFileInfo::stdfilesystem()
|
|||||||
#endif
|
#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)
|
QTEST_MAIN(tst_QFileInfo)
|
||||||
#include "tst_qfileinfo.moc"
|
#include "tst_qfileinfo.moc"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user