moveToTrash/Unix: trust freeDesktopTrashLocation() to find the directory

Make it receive the QSystemError so it can set the error condition
properly in case the suitable location for this input file can't be
found. This also includes the case when the input file does not exist in
the first place, which I moved into the function because upcoming
commits will imply this check anyway.

Change-Id: I9d43e5b91eb142d6945cfffd1786c6e59d3b0204
Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Thiago Macieira 2023-09-20 18:49:59 -07:00
parent ba0b4a1dc8
commit 1c5575f194

View File

@ -1194,9 +1194,9 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &, QFileSystemEnt
Implementing as per https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html Implementing as per https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html
*/ */
static QString freeDesktopTrashLocation(const QString &sourcePath) static QString freeDesktopTrashLocation(const QFileSystemEntry &source, QSystemError &error)
{ {
auto makeTrashDir = [](const QDir &topDir, const QString &trashDir = QString()) { auto makeTrashDir = [](const QDir &topDir, const QString &trashDir, QSystemError &error) {
auto ownerPerms = QFileDevice::ReadOwner auto ownerPerms = QFileDevice::ReadOwner
| QFileDevice::WriteOwner | QFileDevice::WriteOwner
| QFileDevice::ExeOwner; | QFileDevice::ExeOwner;
@ -1205,13 +1205,22 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
bool created = QFileSystemEngine::createDirectory(QFileSystemEntry(targetDir), false, ownerPerms); bool created = QFileSystemEngine::createDirectory(QFileSystemEntry(targetDir), false, ownerPerms);
if (created) if (created)
return targetDir; return targetDir;
error = QSystemError(errno, QSystemError::StandardLibraryError);
// maybe it already exists and is a directory // maybe it already exists and is a directory
if (QFileInfo(targetDir).isDir()) if (QFileInfo(targetDir).isDir())
return targetDir; return targetDir;
return QString(); return QString();
}; };
if (QFileSystemMetaData md; !QFileSystemEngine::fillMetaData(source, md, QFileSystemMetaData::ExistsAttribute)
|| !md.exists()) {
error = QSystemError(ENOENT, QSystemError::StandardLibraryError);
return QString();
}
QString trash; QString trash;
const QString sourcePath = source.filePath();
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
@ -1238,10 +1247,12 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
qCritical("Warning: '%s' is a symlink to '%s'", qCritical("Warning: '%s' is a symlink to '%s'",
dotTrashDir.nativeFilePath().constData(), dotTrashDir.nativeFilePath().constData(),
qt_readlink(dotTrashDir.nativeFilePath()).constData()); qt_readlink(dotTrashDir.nativeFilePath()).constData());
error = QSystemError(ELOOP, QSystemError::StandardLibraryError);
} else if ((st.st_mode & S_ISVTX) == 0) { } 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!",
dotTrashDir.nativeFilePath().constData()); dotTrashDir.nativeFilePath().constData());
error = QSystemError(EPERM, QSystemError::StandardLibraryError);
} else if (S_ISDIR(st.st_mode)) { } 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
@ -1252,7 +1263,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(dotTrashDir.filePath(), userID); trash = makeTrashDir(dotTrashDir.filePath(), userID, error);
} }
} }
/* /*
@ -1264,7 +1275,7 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
*/ */
if (trash.isEmpty()) { if (trash.isEmpty()) {
const QString userTrashDir = dotTrash + u'-' + userID; const QString userTrashDir = dotTrash + u'-' + userID;
trash = makeTrashDir(QDir(sourceStorage.rootPath() + userTrashDir)); trash = makeTrashDir(QDir(sourceStorage.rootPath() + userTrashDir), QString(), error);
} }
} }
/* /*
@ -1279,8 +1290,8 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
*/ */
if (trash.isEmpty()) { if (trash.isEmpty()) {
QDir topDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); QDir topDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
trash = makeTrashDir(topDir, "Trash"_L1); trash = makeTrashDir(topDir, "Trash"_L1, error);
if (!QFileInfo(trash).isDir()) { if (trash.isEmpty()) {
qWarning("Unable to establish trash directory in %s", qWarning("Unable to establish trash directory in %s",
topDir.path().toLocal8Bit().constData()); topDir.path().toLocal8Bit().constData());
} }
@ -1293,11 +1304,6 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source, bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
QFileSystemEntry &newLocation, QSystemError &error) QFileSystemEntry &newLocation, QSystemError &error)
{ {
const QFileInfo sourceInfo(source.filePath());
if (!sourceInfo.exists()) {
error = QSystemError(ENOENT, QSystemError::StandardLibraryError);
return false;
}
const QFileSystemEntry sourcePath = [&] { const QFileSystemEntry sourcePath = [&] {
if (QString path = source.filePath(); path.size() > 1 && path.endsWith(u'/')) { if (QString path = source.filePath(); path.size() > 1 && path.endsWith(u'/')) {
path.chop(1); path.chop(1);
@ -1305,10 +1311,10 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
} }
return absoluteName(source); return absoluteName(source);
}(); }();
QString trashPath = freeDesktopTrashLocation(sourcePath, error);
QDir trashDir(freeDesktopTrashLocation(sourcePath.filePath())); if (trashPath.isEmpty())
if (!trashDir.exists())
return false; return false;
QDir trashDir(trashPath);
/* /*
"A trash directory contains two subdirectories, named info and files." "A trash directory contains two subdirectories, named info and files."
*/ */