From 13707f6b18a004154d66dd0d7954e1e590679d92 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 2 Jun 2016 15:27:57 +0200 Subject: [PATCH] system-helper: Support directly pulling local remotes For a local (file:// uri) remote, do an (untrusted) direct pull instead of pulling into the users cached repo first. This way we do less copies, as well as guaranteeing the source of the data. The later means its mostly safe to also allow this for non-gpg signed remotes. --- common/flatpak-dir.c | 45 +++++++++++++++++++++++++-- common/flatpak-dir.h | 3 +- system-helper/flatpak-system-helper.c | 37 ++++++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c index f2b95752..83bc9311 100644 --- a/common/flatpak-dir.c +++ b/common/flatpak-dir.c @@ -2987,12 +2987,34 @@ flatpak_dir_install (FlatpakDir *self, g_autofree char *child_repo_path = NULL; FlatpakSystemHelper *system_helper; FlatpakHelperDeployFlags helper_flags = 0; + g_autofree char *url = NULL; system_helper = flatpak_dir_get_system_helper (self); g_assert (system_helper != NULL); - if (!no_pull) + if (!ostree_repo_remote_get_url (self->repo, + remote_name, + &url, + error)) + return FALSE; + + if (no_pull) { + /* Do nothing */ + } + else if (g_str_has_prefix (url, "file:")) + { + /* In the local case we let the system-helper do all the work. That way we can trust its + reading from the right source, and its not doing any network i/o. */ + + helper_flags |= FLATPAK_HELPER_DEPLOY_FLAGS_LOCAL_PULL; + } + else + { + /* We're pulling from a remote source, we do the network mirroring pull as a + user and hand back the resulting data to the system-helper, that trusts us + due to the GPG signatures in the repo */ + child_repo = flatpak_dir_create_system_child_repo (self, &child_repo_lock, error); if (child_repo == NULL) return FALSE; @@ -3061,6 +3083,7 @@ flatpak_dir_update (FlatpakDir *self, FlatpakSystemHelper *system_helper; g_autofree char *child_repo_path = NULL; FlatpakHelperDeployFlags helper_flags = 0; + g_autofree char *url = NULL; if (checksum_or_latest != NULL) return flatpak_fail (error, "Can't update to a specific commit without root permissions"); @@ -3068,13 +3091,32 @@ flatpak_dir_update (FlatpakDir *self, system_helper = flatpak_dir_get_system_helper (self); g_assert (system_helper != NULL); + if (!ostree_repo_remote_get_url (self->repo, + remote_name, + &url, + error)) + return FALSE; + + helper_flags = FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE; + if (no_pull) { if (!ostree_repo_resolve_rev (self->repo, ref, FALSE, &latest_checksum, error)) return FALSE; } + else if (g_str_has_prefix (url, "file:")) + { + /* In the local case we let the system-helper do all the work. That way we can trust its + reading from the right source, and its not doing any network i/o. */ + + helper_flags |= FLATPAK_HELPER_DEPLOY_FLAGS_LOCAL_PULL; + } else { + /* We're pulling from a remote source, we do the network mirroring pull as a + user and hand back the resulting data to the system-helper, that trusts us + due to the GPG signatures in the repo */ + child_repo = flatpak_dir_create_system_child_repo (self, &child_repo_lock, error); if (child_repo == NULL) return FALSE; @@ -3090,7 +3132,6 @@ flatpak_dir_update (FlatpakDir *self, child_repo_path = g_file_get_path (ostree_repo_get_path (child_repo)); } - helper_flags = FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE; if (no_deploy) helper_flags |= FLATPAK_HELPER_DEPLOY_FLAGS_NO_DEPLOY; diff --git a/common/flatpak-dir.h b/common/flatpak-dir.h index 541819b3..5532b408 100644 --- a/common/flatpak-dir.h +++ b/common/flatpak-dir.h @@ -44,9 +44,10 @@ typedef enum { FLATPAK_HELPER_DEPLOY_FLAGS_NONE = 0, FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE = 1 << 0, FLATPAK_HELPER_DEPLOY_FLAGS_NO_DEPLOY = 1 << 1, + FLATPAK_HELPER_DEPLOY_FLAGS_LOCAL_PULL = 1 << 2, } FlatpakHelperDeployFlags; -#define FLATPAK_HELPER_DEPLOY_FLAGS_ALL (FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE|FLATPAK_HELPER_DEPLOY_FLAGS_NO_DEPLOY) +#define FLATPAK_HELPER_DEPLOY_FLAGS_ALL (FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE|FLATPAK_HELPER_DEPLOY_FLAGS_NO_DEPLOY|FLATPAK_HELPER_DEPLOY_FLAGS_LOCAL_PULL) typedef enum { FLATPAK_HELPER_UNINSTALL_FLAGS_NONE = 0, diff --git a/system-helper/flatpak-system-helper.c b/system-helper/flatpak-system-helper.c index 08043c5c..e458c955 100644 --- a/system-helper/flatpak-system-helper.c +++ b/system-helper/flatpak-system-helper.c @@ -139,7 +139,9 @@ handle_deploy (FlatpakSystemHelper *object, g_autoptr(GFile) deploy_dir = NULL; gboolean is_update; gboolean no_deploy; + gboolean local_pull; g_autoptr(GMainContext) main_context = NULL; + g_autofree char *url = NULL; g_debug ("Deploy %s %u %s %s", arg_repo_path, arg_flags, arg_ref, arg_origin); @@ -158,6 +160,7 @@ handle_deploy (FlatpakSystemHelper *object, is_update = (arg_flags & FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE) != 0; no_deploy = (arg_flags & FLATPAK_HELPER_DEPLOY_FLAGS_NO_DEPLOY) != 0; + local_pull = (arg_flags & FLATPAK_HELPER_DEPLOY_FLAGS_LOCAL_PULL) != 0; deploy_dir = flatpak_dir_get_if_deployed (system, arg_ref, NULL, NULL); @@ -216,6 +219,40 @@ handle_deploy (FlatpakSystemHelper *object, } g_main_context_pop_thread_default (main_context); } + else if (local_pull) + { + if (!ostree_repo_remote_get_url (flatpak_dir_get_repo (system), + arg_origin, + &url, + &error)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Error getting remote url: %s", error->message); + return TRUE; + } + + if (!g_str_has_prefix (url, "file:")) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Local pull url doesn't start with file://"); + return TRUE; + } + + /* Work around ostree-pull spinning the default main context for the sync calls */ + main_context = g_main_context_new (); + g_main_context_push_thread_default (main_context); + + if (!flatpak_dir_pull (system, arg_origin, arg_ref, (char **)arg_subpaths, NULL, + OSTREE_REPO_PULL_FLAGS_UNTRUSTED, NULL, + NULL, &error)) + { + g_main_context_pop_thread_default (main_context); + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Error pulling from repo: %s", error->message); + return TRUE; + } + g_main_context_pop_thread_default (main_context); + } if (!no_deploy) {