forked from Mirrors/flatpak-builder
document portal: Add AddNamed method for host-side use
This is needed for the "save as" file selector portaltingping/wmclass
parent
9fd6ce1779
commit
3ce0c6f7f9
|
@ -40,12 +40,14 @@ gboolean opt_unique = FALSE;
|
|||
gboolean opt_allow_write = FALSE;
|
||||
gboolean opt_allow_delete = FALSE;
|
||||
gboolean opt_transient = FALSE;
|
||||
gboolean opt_noexist = FALSE;
|
||||
gboolean opt_allow_grant_permissions = FALSE;
|
||||
char **opt_apps = NULL;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "unique", 'u', 0, G_OPTION_ARG_NONE, &opt_unique, "Create a unique document reference", NULL },
|
||||
{ "transient", 't', 0, G_OPTION_ARG_NONE, &opt_transient, "Make the document transient for the current session", NULL },
|
||||
{ "noexist", 'n', 0, G_OPTION_ARG_NONE, &opt_noexist, "Don't require the file to exist already", NULL },
|
||||
{ "allow-write", 'w', 0, G_OPTION_ARG_NONE, &opt_allow_write, "Give the app write permissions", NULL },
|
||||
{ "allow-delete", 'd', 0, G_OPTION_ARG_NONE, &opt_allow_delete, "Give the app permissions to delete the document id", NULL },
|
||||
{ "allow-grant-permission", 'd', 0, G_OPTION_ARG_NONE, &opt_allow_grant_permissions, "Give the app permissions to grant furthern permissions", NULL },
|
||||
|
@ -65,6 +67,7 @@ xdg_app_builtin_export_file (int argc, char **argv,
|
|||
const char *file;
|
||||
g_autofree char *mountpoint = NULL;
|
||||
g_autofree char *basename = NULL;
|
||||
g_autofree char *dirname = NULL;
|
||||
g_autofree char *doc_path = NULL;
|
||||
XdpDbusDocuments *documents;
|
||||
int fd, fd_id;
|
||||
|
@ -83,6 +86,8 @@ xdg_app_builtin_export_file (int argc, char **argv,
|
|||
return usage_error (context, "FILE must be specified", error);
|
||||
|
||||
file = argv[1];
|
||||
dirname = g_path_get_dirname (file);
|
||||
basename = g_path_get_basename (file);
|
||||
|
||||
session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
|
||||
if (session_bus == NULL)
|
||||
|
@ -99,7 +104,11 @@ xdg_app_builtin_export_file (int argc, char **argv,
|
|||
NULL, error))
|
||||
return FALSE;
|
||||
|
||||
fd = open (file, O_PATH | O_CLOEXEC);
|
||||
if (opt_noexist)
|
||||
fd = open (dirname, O_PATH | O_CLOEXEC);
|
||||
else
|
||||
fd = open (file, O_PATH | O_CLOEXEC);
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
|
@ -110,18 +119,32 @@ xdg_app_builtin_export_file (int argc, char **argv,
|
|||
fd_id = g_unix_fd_list_append (fd_list, fd, error);
|
||||
close (fd);
|
||||
|
||||
reply = g_dbus_connection_call_with_unix_fd_list_sync (session_bus,
|
||||
"org.freedesktop.portal.Documents",
|
||||
"/org/freedesktop/portal/documents",
|
||||
"org.freedesktop.portal.Documents",
|
||||
"Add",
|
||||
g_variant_new ("(hbb)", fd_id, !opt_unique, !opt_transient),
|
||||
G_VARIANT_TYPE ("(s)"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
30000,
|
||||
fd_list, NULL,
|
||||
NULL,
|
||||
error);
|
||||
if (opt_noexist)
|
||||
reply = g_dbus_connection_call_with_unix_fd_list_sync (session_bus,
|
||||
"org.freedesktop.portal.Documents",
|
||||
"/org/freedesktop/portal/documents",
|
||||
"org.freedesktop.portal.Documents",
|
||||
"AddNamed",
|
||||
g_variant_new ("(h^aybb)", fd_id, basename, !opt_unique, !opt_transient),
|
||||
G_VARIANT_TYPE ("(s)"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
30000,
|
||||
fd_list, NULL,
|
||||
NULL,
|
||||
error);
|
||||
else
|
||||
reply = g_dbus_connection_call_with_unix_fd_list_sync (session_bus,
|
||||
"org.freedesktop.portal.Documents",
|
||||
"/org/freedesktop/portal/documents",
|
||||
"org.freedesktop.portal.Documents",
|
||||
"Add",
|
||||
g_variant_new ("(hbb)", fd_id, !opt_unique, !opt_transient),
|
||||
G_VARIANT_TYPE ("(s)"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
30000,
|
||||
fd_list, NULL,
|
||||
NULL,
|
||||
error);
|
||||
g_object_unref (fd_list);
|
||||
|
||||
if (reply == NULL)
|
||||
|
@ -152,7 +175,6 @@ xdg_app_builtin_export_file (int argc, char **argv,
|
|||
|
||||
}
|
||||
|
||||
basename = g_path_get_basename (file);
|
||||
doc_path = g_build_filename (mountpoint, doc_id, basename, NULL);
|
||||
g_print ("%s\n", doc_path);
|
||||
|
||||
|
|
|
@ -34,6 +34,13 @@
|
|||
<arg type='b' name='persistent' direction='in'/>
|
||||
<arg type='s' name='doc_id' direction='out'/>
|
||||
</method>
|
||||
<method name="AddNamed">
|
||||
<arg type='h' name='o_path_parent_fd' direction='in'/>
|
||||
<arg type='ay' name='filename' direction='in'/>
|
||||
<arg type='b' name='reuse_existing' direction='in'/>
|
||||
<arg type='b' name='persistent' direction='in'/>
|
||||
<arg type='s' name='doc_id' direction='out'/>
|
||||
</method>
|
||||
<method name="GrantPermissions">
|
||||
<arg type='s' name='doc_id' direction='in'/>
|
||||
<arg type='s' name='app_id' direction='in'/>
|
||||
|
|
|
@ -457,6 +457,101 @@ portal_add (GDBusMethodInvocation *invocation,
|
|||
g_variant_new ("(s)", id));
|
||||
}
|
||||
|
||||
static void
|
||||
portal_add_named (GDBusMethodInvocation *invocation,
|
||||
GVariant *parameters,
|
||||
const char *app_id)
|
||||
{
|
||||
GDBusMessage *message;
|
||||
GUnixFDList *fd_list;
|
||||
g_autofree char *id = NULL;
|
||||
g_autofree char *proc_path = NULL;
|
||||
int parent_fd_id, parent_fd, fds_len, fd_flags;
|
||||
const int *fds;
|
||||
char parent_path_buffer[PATH_MAX+1];
|
||||
g_autofree char *path = NULL;
|
||||
ssize_t symlink_size;
|
||||
struct stat parent_st_buf;
|
||||
const char *filename;
|
||||
gboolean reuse_existing, persistent;
|
||||
g_autoptr(GVariant) filename_v = NULL;
|
||||
|
||||
g_variant_get (parameters, "(h@aybb)", &parent_fd_id, &filename_v, &reuse_existing, &persistent);
|
||||
filename = g_variant_get_bytestring (filename_v);
|
||||
|
||||
/* This is only allowed from the host, or else we could leak existance of files */
|
||||
if (*app_id != 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, XDG_APP_ERROR, XDG_APP_ERROR_NOT_ALLOWED,
|
||||
"Not enough permissions");
|
||||
return;
|
||||
}
|
||||
|
||||
message = g_dbus_method_invocation_get_message (invocation);
|
||||
fd_list = g_dbus_message_get_unix_fd_list (message);
|
||||
|
||||
parent_fd = -1;
|
||||
if (fd_list != NULL)
|
||||
{
|
||||
fds = g_unix_fd_list_peek_fds (fd_list, &fds_len);
|
||||
if (parent_fd_id < fds_len)
|
||||
parent_fd = fds[parent_fd_id];
|
||||
}
|
||||
|
||||
if (strchr (filename, '/') != NULL)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
XDG_APP_ERROR, XDG_APP_ERROR_INVALID_ARGUMENT,
|
||||
"Invalid filename passed");
|
||||
return;
|
||||
}
|
||||
|
||||
proc_path = g_strdup_printf ("/proc/self/fd/%d", parent_fd);
|
||||
|
||||
if (parent_fd == -1 ||
|
||||
/* Must be able to get fd flags */
|
||||
(fd_flags = fcntl (parent_fd, F_GETFL)) == -1 ||
|
||||
/* Must be O_PATH */
|
||||
((fd_flags & O_PATH) != O_PATH) ||
|
||||
/* Must not be O_NOFOLLOW (because we want the target file) */
|
||||
((fd_flags & O_NOFOLLOW) == O_PATH) ||
|
||||
/* Must be able to fstat */
|
||||
fstat (parent_fd, &parent_st_buf) < 0 ||
|
||||
/* Must be a directory file */
|
||||
(parent_st_buf.st_mode & S_IFMT) != S_IFDIR ||
|
||||
/* Must be able to read path from /proc/self/fd */
|
||||
/* This is an absolute and (at least at open time) symlink-expanded path */
|
||||
(symlink_size = readlink (proc_path, parent_path_buffer, sizeof (parent_path_buffer) - 1)) < 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
XDG_APP_ERROR, XDG_APP_ERROR_INVALID_ARGUMENT,
|
||||
"Invalid fd passed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (parent_st_buf.st_dev == fuse_dev)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
XDG_APP_ERROR, XDG_APP_ERROR_INVALID_ARGUMENT,
|
||||
"Invalid fd passed");
|
||||
return;
|
||||
}
|
||||
|
||||
parent_path_buffer[symlink_size] = 0;
|
||||
|
||||
path = g_build_filename (parent_path_buffer, filename, NULL);
|
||||
|
||||
g_debug ("portal_add_named %s\n", path);
|
||||
|
||||
AUTOLOCK(db);
|
||||
|
||||
id = do_create_doc (&parent_st_buf, path, reuse_existing, persistent);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation,
|
||||
g_variant_new ("(s)", id));
|
||||
}
|
||||
|
||||
|
||||
typedef void (*PortalMethod) (GDBusMethodInvocation *invocation,
|
||||
GVariant *parameters,
|
||||
const char *app_id);
|
||||
|
@ -507,6 +602,7 @@ on_bus_acquired (GDBusConnection *connection,
|
|||
|
||||
g_signal_connect_swapped (helper, "handle-get-mount-point", G_CALLBACK (handle_get_mount_point), NULL);
|
||||
g_signal_connect_swapped (helper, "handle-add", G_CALLBACK (handle_method), portal_add);
|
||||
g_signal_connect_swapped (helper, "handle-add-named", G_CALLBACK (handle_method), portal_add_named);
|
||||
g_signal_connect_swapped (helper, "handle-grant-permissions", G_CALLBACK (handle_method), portal_grant_permissions);
|
||||
g_signal_connect_swapped (helper, "handle-revoke-permissions", G_CALLBACK (handle_method), portal_revoke_permissions);
|
||||
g_signal_connect_swapped (helper, "handle-delete", G_CALLBACK (handle_method), portal_delete);
|
||||
|
|
Loading…
Reference in New Issue