moveToTrash/Unix: use lstat() to confirm $root/.Trash is suitable
We can't use QFileSystemEngine::fillMetaData() because there's no bit in QFileSystemMetaData to indicate the sticky flag, so we must make a at least one stat() or lstat() call ourselves. Given that we need to know if $root/.Trash is a symlink, that system call must be lstat(). And it turns out that system call provides everything we need to confirm its suitability. This avoids QDir overhead just to manipulate strings. Pick-to: 6.6 Change-Id: I9d43e5b91eb142d6945cfffd1786c5e54199ecb2 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
6c504f2519
commit
36a169e31e
@ -1187,7 +1187,7 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy
|
|||||||
#ifndef QT_BOOTSTRAPPED
|
#ifndef QT_BOOTSTRAPPED
|
||||||
static QString freeDesktopTrashLocation(const QString &sourcePath)
|
static QString freeDesktopTrashLocation(const QString &sourcePath)
|
||||||
{
|
{
|
||||||
auto makeTrashDir = [](const QDir &topDir, const QString &trashDir) -> QString {
|
auto makeTrashDir = [](const QDir &topDir, const QString &trashDir = QString()) {
|
||||||
auto ownerPerms = QFileDevice::ReadOwner
|
auto ownerPerms = QFileDevice::ReadOwner
|
||||||
| QFileDevice::WriteOwner
|
| QFileDevice::WriteOwner
|
||||||
| QFileDevice::ExeOwner;
|
| QFileDevice::ExeOwner;
|
||||||
@ -1201,21 +1201,15 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
|
|||||||
return targetDir;
|
return targetDir;
|
||||||
return QString();
|
return QString();
|
||||||
};
|
};
|
||||||
auto isSticky = [](const QFileInfo &fileInfo) -> bool {
|
|
||||||
struct stat st;
|
|
||||||
if (stat(QFile::encodeName(fileInfo.absoluteFilePath()).constData(), &st) == 0)
|
|
||||||
return st.st_mode & S_ISVTX;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
QString trash;
|
QString trash;
|
||||||
const QStorageInfo sourceStorage(sourcePath);
|
const QStorageInfo sourceStorage(sourcePath);
|
||||||
const QStorageInfo homeStorage(QDir::home());
|
const QStorageInfo homeStorage(QDir::home());
|
||||||
// We support trashing of files outside the users home partition
|
// We support trashing of files outside the users home partition
|
||||||
if (sourceStorage != homeStorage) {
|
if (sourceStorage != homeStorage) {
|
||||||
const auto dotTrash = ".Trash"_L1;
|
const auto dotTrash = "/.Trash"_L1;
|
||||||
QDir topDir(sourceStorage.rootPath());
|
QFileSystemEntry dotTrashDir(sourceStorage.rootPath() + dotTrash);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Method 1:
|
Method 1:
|
||||||
"An administrator can create an $topdir/.Trash directory. The permissions on this
|
"An administrator can create an $topdir/.Trash directory. The permissions on this
|
||||||
@ -1226,21 +1220,20 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
|
|||||||
(if it supports trashing in top directories) MUST check for the presence
|
(if it supports trashing in top directories) MUST check for the presence
|
||||||
of $topdir/.Trash."
|
of $topdir/.Trash."
|
||||||
*/
|
*/
|
||||||
const QString userID = QString::number(::getuid());
|
|
||||||
if (topDir.cd(dotTrash)) {
|
|
||||||
const QFileInfo trashInfo(topDir.path());
|
|
||||||
|
|
||||||
|
const QString userID = QString::number(::getuid());
|
||||||
|
if (QT_STATBUF st; QT_LSTAT(dotTrashDir.nativeFilePath(), &st) == 0) {
|
||||||
// we MUST check that the sticky bit is set, and that it is not a symlink
|
// we MUST check that the sticky bit is set, and that it is not a symlink
|
||||||
if (trashInfo.isSymLink()) {
|
if (S_ISLNK(st.st_mode)) {
|
||||||
// we SHOULD report the failed check to the administrator
|
// we SHOULD report the failed check to the administrator
|
||||||
qCritical("Warning: '%s' is a symlink to '%s'",
|
qCritical("Warning: '%s' is a symlink to '%s'",
|
||||||
trashInfo.absoluteFilePath().toLocal8Bit().constData(),
|
dotTrashDir.nativeFilePath().constData(),
|
||||||
trashInfo.symLinkTarget().toLatin1().constData());
|
qt_readlink(dotTrashDir.nativeFilePath()).constData());
|
||||||
} else if (!isSticky(trashInfo)) {
|
} else if ((st.st_mode & S_ISVTX) == 0) {
|
||||||
// we SHOULD report the failed check to the administrator
|
// we SHOULD report the failed check to the administrator
|
||||||
qCritical("Warning: '%s' doesn't have sticky bit set!",
|
qCritical("Warning: '%s' doesn't have sticky bit set!",
|
||||||
trashInfo.absoluteFilePath().toLocal8Bit().constData());
|
dotTrashDir.nativeFilePath().constData());
|
||||||
} else if (trashInfo.isDir()) {
|
} else if (S_ISDIR(st.st_mode)) {
|
||||||
/*
|
/*
|
||||||
"If the directory exists and passes the checks, a subdirectory of the
|
"If the directory exists and passes the checks, a subdirectory of the
|
||||||
$topdir/.Trash directory is to be used as the user's trash directory
|
$topdir/.Trash directory is to be used as the user's trash directory
|
||||||
@ -1250,7 +1243,7 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
|
|||||||
the implementation MUST immediately create it, without any warnings or
|
the implementation MUST immediately create it, without any warnings or
|
||||||
delays for the user."
|
delays for the user."
|
||||||
*/
|
*/
|
||||||
trash = makeTrashDir(topDir, userID);
|
trash = makeTrashDir(dotTrashDir.filePath(), userID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -1261,9 +1254,8 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
|
|||||||
immediately create it, without any warnings or delays for the user."
|
immediately create it, without any warnings or delays for the user."
|
||||||
*/
|
*/
|
||||||
if (trash.isEmpty()) {
|
if (trash.isEmpty()) {
|
||||||
topDir = QDir(sourceStorage.rootPath());
|
|
||||||
const QString userTrashDir = dotTrash + u'-' + userID;
|
const QString userTrashDir = dotTrash + u'-' + userID;
|
||||||
trash = makeTrashDir(topDir, userTrashDir);
|
trash = makeTrashDir(QDir(sourceStorage.rootPath() + userTrashDir));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user