Commit 390731d7 authored by Harald Sitter's avatar Harald Sitter 🏳️‍🌈
Browse files

reverse url fusing

this actually was defective even with local urls...
as we pass files through the portal the sandbox gets irrelevant portal
paths a la /run/foo/bar/yolo.txt when the sandbox then gives us that
path back, the directory isn't meant to be written to, much less shown
to the user to begin with.

to deal with this scenario we now do a reverse resolution dance on
savefile. notably we first ask the portal to translate the portal file
name in /run to the actual file name underneath it. we then run that
path through kio-fuse in case it was fuse mounted

this renders /run to /home/foo/yolo.txt or when it was fuse mounted for
example smb:///foo/yolo.txt

the effective end result is that when you open a file in okular from a
samba share and then save-as, the file save dialog will show the smb://
url not the fake /run url

BUG: 452968
parent 0520e04b
Pipeline #168412 passed with stage
in 46 seconds
"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
SPDX-License-Identifier: CC0-1.0
SPDX-FileCopyrightText: none
<node name="/" xmlns:doc="">
<interface name='org.freedesktop.portal.Documents'>
<method name="GetMountPoint">
<arg type='ay' name='path' direction='out'/>
<method name="Info">
<arg type='s' name='doc_id' direction='in'/>
<arg type='ay' name='path' direction='out'/>
......@@ -84,6 +84,9 @@ endif()
set_source_files_properties(../data/org.freedesktop.Accounts.User.xml PROPERTIES NO_NAMESPACE TRUE)
qt_add_dbus_interface(xdg_desktop_portal_kde_SRCS ../data/org.freedesktop.Accounts.User.xml user_interface)
set_source_files_properties(../data/org.freedesktop.portal.Documents.xml PROPERTIES NO_NAMESPACE TRUE)
qt_add_dbus_interface(xdg_desktop_portal_kde_SRCS ../data/org.freedesktop.portal.Documents.xml documents_interface)
set_source_files_properties(../data/org.kde.KIOFuse.VFS.xml PROPERTIES NO_NAMESPACE TRUE)
qt_add_dbus_interface(xdg_desktop_portal_kde_SRCS ../data/org.kde.KIOFuse.VFS.xml fuse_interface)
......@@ -32,6 +32,7 @@
#include <KSharedConfig>
#include <KWindowConfig>
#include "documents_interface.h"
#include "fuse_interface.h"
#include "request.h"
#include <mobilefiledialog.h>
......@@ -413,6 +414,59 @@ uint FileChooserPortal::OpenFile(const QDBusObjectPath &handle,
return 1;
enum class Entity { File, Folder };
static QUrl kioUrlFromSandboxPath(const QString &path, Entity entity)
if (path.isEmpty()) {
return {};
static QString mountPoint;
if (!mountPoint.isEmpty() && !path.startsWith(mountPoint)) {
return QUrl::fromLocalFile(path);
OrgFreedesktopPortalDocumentsInterface documents_iface(QStringLiteral("org.freedesktop.portal.Documents"),
if (mountPoint.isEmpty()) {
mountPoint = QString::fromUtf8(documents_iface.GetMountPoint());
if (!path.startsWith(mountPoint)) {
return QUrl::fromLocalFile(path);
QByteArray localFilePath;
switch (entity) {
case Entity::File: // basename of dirpath (= id of the shared document on the portal)
localFilePath = documents_iface.Info(QFileInfo(QFileInfo(path).path()).fileName());
case Entity::Folder: // basename of path
localFilePath = documents_iface.Info(QFileInfo(path).fileName());
if (localFilePath.isEmpty()) {
return QUrl::fromLocalFile(path);
if (!isKIOFuseAvailable()) {
return QUrl::fromLocalFile(localFilePath);
OrgKdeKIOFuseVFSInterface fuse_iface(QStringLiteral("org.kde.KIOFuse"), QStringLiteral("/org/kde/KIOFuse"), QDBusConnection::sessionBus());
QString remoteFilePath = fuse_iface.remoteUrl(localFilePath);
if (remoteFilePath.isEmpty()) {
return QUrl::fromLocalFile(path);
QUrl url(remoteFilePath);
qCDebug(XdgDesktopPortalKdeFileChooser) << "Translated portal url to" << url;
return url;
uint FileChooserPortal::SaveFile(const QDBusObjectPath &handle,
const QString &app_id,
const QString &parent_window,
......@@ -518,12 +572,21 @@ uint FileChooserPortal::SaveFile(const QDBusObjectPath &handle,
if (!currentFolder.isEmpty()) {
const QUrl translatedCurrentFolderUrl = kioUrlFromSandboxPath(currentFolder, Entity::Folder);
if (!translatedCurrentFolderUrl.isEmpty()) {
if (!currentFile.isEmpty()) {
// If we also had a currentfolder then recycle its URL, otherwise calculate from scratch.
// In either case append the basename to get to a complete file URL again.
QUrl kioUrl = translatedCurrentFolderUrl.isEmpty() ? kioUrlFromSandboxPath(currentFile, Entity::File) : translatedCurrentFolderUrl;
if (!kioUrl.isEmpty()) {
kioUrl.setPath(kioUrl.path() + QLatin1Char('/') + QFileInfo(currentFile).completeBaseName());
} else {
if (!currentName.isEmpty()) {
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment