From f8982630473ea04f0106364c7d39fe07724383cd Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Tue, 26 Apr 2022 16:03:12 +0200 Subject: [PATCH] Update to 1.50.1 Resolves: #2078857 --- ...-not-lose-userinfo-when-copying-URIs.patch | 86 - dav-Fix-crashes-caused-by-extra-unref.patch | 30 - ...-to-libsoup-async-API-to-fix-crashes.patch | 2504 ----------------- gvfs.spec | 18 +- ...ore-EINVAL-for-kerberos-ccache-login.patch | 58 - sources | 2 +- 6 files changed, 6 insertions(+), 2692 deletions(-) delete mode 100644 dav-Do-not-lose-userinfo-when-copying-URIs.patch delete mode 100644 dav-Fix-crashes-caused-by-extra-unref.patch delete mode 100644 dav-Rewrite-to-libsoup-async-API-to-fix-crashes.patch delete mode 100644 smb-Ignore-EINVAL-for-kerberos-ccache-login.patch diff --git a/dav-Do-not-lose-userinfo-when-copying-URIs.patch b/dav-Do-not-lose-userinfo-when-copying-URIs.patch deleted file mode 100644 index 60d915e..0000000 --- a/dav-Do-not-lose-userinfo-when-copying-URIs.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 4b9d9442f4b465e9403c4da399ccf6d7cc652eae Mon Sep 17 00:00:00 2001 -From: Daniel Kolesa -Date: Sun, 27 Mar 2022 16:01:55 +0200 -Subject: [PATCH] dav: Do not lose userinfo when copying URIs - -The use of g_uri_build was also bad, since otherwise we would -run into this: https://gitlab.gnome.org/GNOME/glib/-/issues/2619 - -While this should be fixed in glib, we need to work around this -behavior for existing installations. - -Fixes: https://gitlab.gnome.org/GNOME/gvfs/-/issues/614 ---- - daemon/gvfsbackenddav.c | 28 +++++++--------------------- - 1 file changed, 7 insertions(+), 21 deletions(-) - -diff --git a/daemon/gvfsbackenddav.c b/daemon/gvfsbackenddav.c -index f9d10a40..3ece9a5f 100644 ---- a/daemon/gvfsbackenddav.c -+++ b/daemon/gvfsbackenddav.c -@@ -321,23 +321,6 @@ message_should_apply_redir_ref (SoupMessage *msg) - return TRUE; - } - --static GUri * --dav_uri_dup_with (GUri *uri, const char *path, const char *userinfo) --{ -- if (!path && !userinfo) -- return g_uri_ref (uri); -- -- return g_uri_build (g_uri_get_flags (uri), -- g_uri_get_scheme (uri), -- userinfo ? userinfo : g_uri_get_userinfo (uri), -- g_uri_get_host (uri), -- g_uri_get_port (uri), -- path ? path : g_uri_get_path (uri), -- g_uri_get_query (uri), -- g_uri_get_fragment (uri)); --} -- -- - static GUri * - g_vfs_backend_dav_uri_for_path (GVfsBackend *backend, - const char *path, -@@ -369,7 +352,7 @@ g_vfs_backend_dav_uri_for_path (GVfsBackend *backend, - else - new_path = g_build_path ("/", g_uri_get_path (mount_base), fn_encoded, "/", NULL); - -- uri = dav_uri_dup_with (mount_base, new_path, NULL); -+ uri = soup_uri_copy (mount_base, SOUP_URI_PATH, new_path, SOUP_URI_NONE); - - g_free (fn_encoded); - g_free (new_path); -@@ -432,7 +415,10 @@ g_vfs_backend_dav_redirect (SoupSession *session, - } - - tmp = new_uri; -- new_uri = dav_uri_dup_with (new_uri, NULL, g_uri_get_userinfo (old_uri)); -+ new_uri = soup_uri_copy (new_uri, -+ SOUP_URI_USER, g_uri_get_user (old_uri), -+ SOUP_URI_AUTH_PARAMS, g_uri_get_auth_params (old_uri), -+ SOUP_URI_NONE); - g_uri_unref (tmp); - - /* Check if this is a trailing slash redirect (i.e. /a/b to /a/b/), -@@ -2141,7 +2127,7 @@ do_mount (GVfsBackend *backend, - new_path = path_get_parent_dir (last_good_path); - - tmp = mount_base; -- mount_base = dav_uri_dup_with (mount_base, new_path, NULL); -+ mount_base = soup_uri_copy (mount_base, SOUP_URI_PATH, new_path, SOUP_URI_NONE); - g_uri_unref (tmp); - G_VFS_BACKEND_HTTP (backend)->mount_base = mount_base; - -@@ -2222,7 +2208,7 @@ do_mount (GVfsBackend *backend, - - /* Set the working path in mount path */ - tmp = mount_base; -- mount_base = dav_uri_dup_with (mount_base, last_good_path, NULL); -+ mount_base = soup_uri_copy (mount_base, SOUP_URI_PATH, last_good_path, SOUP_URI_NONE); - g_uri_unref (tmp); - G_VFS_BACKEND_HTTP (backend)->mount_base = mount_base; - g_free (last_good_path); --- -2.35.1 - diff --git a/dav-Fix-crashes-caused-by-extra-unref.patch b/dav-Fix-crashes-caused-by-extra-unref.patch deleted file mode 100644 index 158b008..0000000 --- a/dav-Fix-crashes-caused-by-extra-unref.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 2b5e3453ee0ab504eeecb8dbe76015e98ccbfcfb Mon Sep 17 00:00:00 2001 -From: Ondrej Holy -Date: Wed, 23 Mar 2022 16:23:49 +0100 -Subject: [PATCH] dav: Fix crashes caused by extra unref - -The `mount_base` uri is unreffed twice. First time over the local `mount_base` -pointer and for the second time over the `G_VFS_BACKEND_HTTP (backend)->mount_base` -pointer. This leads to `SIGABRT` from the `__pthread_kill_implementation` -function. Let's remove that extra unref to fix this crashes. - -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2066717 ---- - daemon/gvfsbackenddav.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/daemon/gvfsbackenddav.c b/daemon/gvfsbackenddav.c -index 559b8657..f9d10a40 100644 ---- a/daemon/gvfsbackenddav.c -+++ b/daemon/gvfsbackenddav.c -@@ -2224,7 +2224,6 @@ do_mount (GVfsBackend *backend, - tmp = mount_base; - mount_base = dav_uri_dup_with (mount_base, last_good_path, NULL); - g_uri_unref (tmp); -- g_clear_pointer (&G_VFS_BACKEND_HTTP (backend)->mount_base, g_uri_unref); - G_VFS_BACKEND_HTTP (backend)->mount_base = mount_base; - g_free (last_good_path); - --- -2.35.1 - diff --git a/dav-Rewrite-to-libsoup-async-API-to-fix-crashes.patch b/dav-Rewrite-to-libsoup-async-API-to-fix-crashes.patch deleted file mode 100644 index e498aeb..0000000 --- a/dav-Rewrite-to-libsoup-async-API-to-fix-crashes.patch +++ /dev/null @@ -1,2504 +0,0 @@ -From 9203fad575515fba715fcfc0cc8b08d01ef11737 Mon Sep 17 00:00:00 2001 -From: Daniel Kolesa -Date: Sun, 27 Mar 2022 16:33:55 +0200 -Subject: [PATCH] dav: Rewrite to libsoup async API to fix crashes - -Since libsoup3 cannot deal with threads, we cannot use the do_ -methods which execute in a thread pool. However, we can implement -these in an async manner, which will bypass the thread pool and -get rid of the issue. - -The write methods are left synchronous as they deal with a memory -output stream and do not actually call libsoup. Therefore, we do -not have to care whether they are threaded or not. - -Fixes: https://gitlab.gnome.org/GNOME/gvfs/-/issues/609 ---- - daemon/gvfsbackenddav.c | 1958 ++++++++++++++++++++++++--------------- - 1 file changed, 1211 insertions(+), 747 deletions(-) - -diff --git a/daemon/gvfsbackenddav.c b/daemon/gvfsbackenddav.c -index 3ece9a5f..fd58b2c9 100644 ---- a/daemon/gvfsbackenddav.c -+++ b/daemon/gvfsbackenddav.c -@@ -110,6 +110,7 @@ struct _GVfsBackendDav - GVfsBackendHttp parent_instance; - - MountAuthData auth_info; -+ gchar *last_good_path; - - /* Used for user-verified secure connections. */ - GTlsCertificate *certificate; -@@ -378,13 +379,86 @@ g_vfs_backend_dav_stream_skip (GInputStream *stream, GError **error) - return TRUE; - } - --/* redirection */ --static GInputStream * --g_vfs_backend_dav_redirect (SoupSession *session, -- SoupMessage *msg, -- GError **error) -+static void -+g_vfs_backend_dav_setup_display_name (GVfsBackend *backend) -+{ -+ GVfsBackendDav *dav_backend; -+ GUri *mount_base; -+ char *display_name; -+ char port[7] = {0, }; -+ gint gport; -+ -+ dav_backend = G_VFS_BACKEND_DAV (backend); -+ -+#ifdef HAVE_AVAHI -+ if (dav_backend->resolver != NULL) -+ { -+ const char *name; -+ name = g_vfs_dns_sd_resolver_get_service_name (dav_backend->resolver); -+ g_vfs_backend_set_display_name (backend, name); -+ return; -+ } -+#endif -+ -+ mount_base = http_backend_get_mount_base (backend); -+ -+ gport = g_uri_get_port (mount_base); -+ if ((gport > 0) && (gport != 80) && (gport != 443)) -+ g_snprintf (port, sizeof (port), ":%u", g_uri_get_port (mount_base)); -+ -+ if (g_uri_get_user (mount_base) != NULL) -+ /* Translators: This is the name of the WebDAV share constructed as -+ "WebDAV as on :"; the ":" part is -+ the second %s and only shown if it is not the default http(s) port. */ -+ display_name = g_strdup_printf (_("%s on %s%s"), -+ g_uri_get_user (mount_base), -+ g_uri_get_host (mount_base), -+ port); -+ else -+ display_name = g_strdup_printf ("%s%s", -+ g_uri_get_host (mount_base), -+ port); -+ -+ g_vfs_backend_set_display_name (backend, display_name); -+ g_free (display_name); -+} -+ -+static gboolean -+accept_certificate (SoupMessage *msg, -+ GTlsCertificate *certificate, -+ GTlsCertificateFlags errors, -+ gpointer user_data) -+{ -+ GVfsBackendDav *dav = G_VFS_BACKEND_DAV (user_data); -+ -+ return (errors == dav->certificate_errors && -+ g_tls_certificate_is_same (certificate, dav->certificate)); -+} -+ -+static void -+dav_message_connect_signals (SoupMessage *message, GVfsBackend *backend) -+{ -+ GVfsBackendDav *dav_backend = G_VFS_BACKEND_DAV (backend); -+ -+ /* we always have to connect this as the message can be -+ * re-sent with a differently set certificate_errors field -+ */ -+ g_signal_connect (message, "accept-certificate", -+ G_CALLBACK (accept_certificate), backend); -+ -+ g_signal_connect (message, "authenticate", -+ G_CALLBACK (soup_authenticate), -+ &dav_backend->auth_info); -+} -+ -+static void -+dav_send_async_with_redir_cb (GObject *source, GAsyncResult *ret, gpointer user_data) - { -- GInputStream *res; -+ SoupSession *session = SOUP_SESSION (source); -+ SoupMessage *msg = soup_session_get_async_result_message (session, ret); -+ GInputStream *body; -+ GError *error = NULL; -+ GTask *task = user_data; - const char *new_loc; - GUri *new_uri; - GUri *old_uri; -@@ -392,26 +466,28 @@ g_vfs_backend_dav_redirect (SoupSession *session, - guint status; - gboolean redirect; - -- res = soup_session_send (session, msg, NULL, error); -- if (!res) -- return NULL; -+ body = soup_session_send_finish (session, ret, &error); -+ -+ if (!body) -+ goto return_error; - - status = soup_message_get_status (msg); -+ - if (!SOUP_STATUS_IS_REDIRECTION (status)) -- return res; -+ goto return_body; - - new_loc = soup_message_headers_get_one (soup_message_get_response_headers (msg), - "Location"); - if (new_loc == NULL) -- return res; -+ goto return_body; - - old_uri = soup_message_get_uri (msg); - new_uri = g_uri_parse_relative (old_uri, new_loc, -- SOUP_HTTP_URI_FLAGS, error); -+ SOUP_HTTP_URI_FLAGS, &error); - if (new_uri == NULL) - { -- g_object_unref (res); -- return NULL; -+ g_object_unref (body); -+ goto return_error; - } - - tmp = new_uri; -@@ -475,125 +551,77 @@ g_vfs_backend_dav_redirect (SoupSession *session, - if (!redirect) - { - g_uri_unref (new_uri); -- return res; -+ goto return_body; - } - -- if (!g_vfs_backend_dav_stream_skip (res, error)) -+ if (!g_vfs_backend_dav_stream_skip (body, &error)) - { -- g_object_unref (res); -- return NULL; -+ g_object_unref (body); -+ goto return_error; - } - -- g_object_unref (res); -+ g_object_unref (body); - - soup_message_set_uri (msg, new_uri); -+ g_uri_unref (new_uri); - -- return g_vfs_backend_dav_redirect (session, msg, error); --} -- --static void --g_vfs_backend_dav_setup_display_name (GVfsBackend *backend) --{ -- GVfsBackendDav *dav_backend; -- GUri *mount_base; -- char *display_name; -- char port[7] = {0, }; -- gint gport; -- -- dav_backend = G_VFS_BACKEND_DAV (backend); -- --#ifdef HAVE_AVAHI -- if (dav_backend->resolver != NULL) -- { -- const char *name; -- name = g_vfs_dns_sd_resolver_get_service_name (dav_backend->resolver); -- g_vfs_backend_set_display_name (backend, name); -- return; -- } --#endif -- -- mount_base = http_backend_get_mount_base (backend); -- -- gport = g_uri_get_port (mount_base); -- if ((gport > 0) && (gport != 80) && (gport != 443)) -- g_snprintf (port, sizeof (port), ":%u", g_uri_get_port (mount_base)); -- -- if (g_uri_get_user (mount_base) != NULL) -- /* Translators: This is the name of the WebDAV share constructed as -- "WebDAV as on :"; the ":" part is -- the second %s and only shown if it is not the default http(s) port. */ -- display_name = g_strdup_printf (_("%s on %s%s"), -- g_uri_get_user (mount_base), -- g_uri_get_host (mount_base), -- port); -- else -- display_name = g_strdup_printf ("%s%s", -- g_uri_get_host (mount_base), -- port); -+ /* recurse */ -+ soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, NULL, -+ dav_send_async_with_redir_cb, g_object_ref (task)); -+ goto return_done; - -- g_vfs_backend_set_display_name (backend, display_name); -- g_free (display_name); --} -+return_body: -+ g_task_return_pointer (task, body, g_object_unref); -+ goto return_done; - --static gboolean --accept_certificate (SoupMessage *msg, -- GTlsCertificate *certificate, -- GTlsCertificateFlags errors, -- gpointer user_data) --{ -- GVfsBackendDav *dav = G_VFS_BACKEND_DAV (user_data); -+return_error: -+ g_task_return_error (task, error); - -- return (errors == dav->certificate_errors && -- g_tls_certificate_is_same (certificate, dav->certificate)); -+return_done: -+ g_object_unref (task); - } - - static void --dav_message_connect_signals (SoupMessage *message, GVfsBackend *backend) -+g_vfs_backend_dav_send_async (GVfsBackend *backend, -+ SoupMessage *message, -+ GAsyncReadyCallback callback, -+ gpointer user_data) - { -- GVfsBackendDav *dav_backend = G_VFS_BACKEND_DAV (backend); -+ SoupSession *session = G_VFS_BACKEND_HTTP (backend)->session; -+ GTask *task = g_task_new (backend, NULL, callback, user_data); - -- /* we always have to connect this as the message can be -- * re-sent with a differently set certificate_errors field -- */ -- g_signal_connect (message, "accept-certificate", -- G_CALLBACK (accept_certificate), backend); -+ g_task_set_source_tag (task, g_vfs_backend_dav_send_async); -+ g_task_set_task_data (task, g_object_ref (message), g_object_unref); - -- g_signal_connect (message, "authenticate", -- G_CALLBACK (soup_authenticate), -- &dav_backend->auth_info); -+ soup_message_set_flags (message, SOUP_MESSAGE_NO_REDIRECT); -+ -+ soup_session_send_async (session, message, G_PRIORITY_DEFAULT, NULL, -+ dav_send_async_with_redir_cb, task); - } - - static GInputStream * --g_vfs_backend_dav_send (GVfsBackend *backend, -- SoupMessage *message, -- gboolean cb_connect, -- GError **error) -+g_vfs_backend_dav_send_finish (GVfsBackend *backend, -+ GAsyncResult *result, -+ GError **error) - { -- SoupSession *session = G_VFS_BACKEND_HTTP (backend)->session; -- -- /* We have our own custom redirect handler */ -- soup_message_set_flags (message, SOUP_MESSAGE_NO_REDIRECT); -- -- if (cb_connect) -- dav_message_connect_signals (message, backend); -+ g_return_val_if_fail (G_VFS_IS_BACKEND (backend), NULL); -+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); -+ g_return_val_if_fail (error == NULL || *error == NULL, NULL); -+ g_return_val_if_fail (g_task_is_valid (result, backend), NULL); -+ g_return_val_if_fail (g_async_result_is_tagged (result, g_vfs_backend_dav_send_async), NULL); - -- return g_vfs_backend_dav_redirect (session, message, error); -+ return g_task_propagate_pointer (G_TASK (result), error); - } - --static void --g_vfs_backend_dav_send_async (GVfsBackend *backend, -- SoupMessage *message, -- gboolean cb_connect, -- GAsyncReadyCallback callback, -- gpointer user_data) -+static SoupMessage * -+g_vfs_backend_dav_get_async_result_message (GVfsBackend *backend, -+ GAsyncResult *result) - { -- SoupSession *session = G_VFS_BACKEND_HTTP (backend)->session; -- -- if (cb_connect) -- dav_message_connect_signals (message, backend); -+ g_return_val_if_fail (G_VFS_IS_BACKEND (backend), NULL); -+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); -+ g_return_val_if_fail (g_task_is_valid (result, backend), NULL); - -- soup_session_send_async (session, message, G_PRIORITY_DEFAULT, NULL, -- callback, user_data); -+ return g_task_get_task_data (G_TASK (result)); - } - - /* ************************************************************************* */ -@@ -1365,8 +1393,8 @@ propfind_request_new (GVfsBackend *backend, - } - - static SoupMessage * --stat_location_begin (GUri *uri, -- gboolean count_children) -+stat_location_start (GUri *uri, -+ gboolean count_children) - { - SoupMessage *msg; - const char *depth; -@@ -1406,11 +1434,11 @@ stat_location_begin (GUri *uri, - } - - static gboolean --stat_location_finish (SoupMessage *msg, -- GInputStream *body, -- GFileType *target_type, -- gint64 *target_size, -- guint *num_children) -+stat_location_end (SoupMessage *msg, -+ GInputStream *body, -+ GFileType *target_type, -+ gint64 *target_size, -+ guint *num_children) - { - Multistatus ms; - xmlNodeIter iter; -@@ -1465,56 +1493,143 @@ stat_location_finish (SoupMessage *msg, - return res; - } - --static gboolean --stat_location (GVfsBackend *backend, -- GUri *uri, -- GFileType *target_type, -- gint64 *target_size, -- guint *num_children, -- GError **error) -+typedef struct _StatLocationData { -+ GUri *uri; -+ GFileType target_type; -+ gint64 target_size; -+ guint num_children; -+} StatLocationData; -+ -+static void -+stat_location_data_free (gpointer p) - { -- SoupMessage *msg; -+ g_uri_unref (((StatLocationData *)p)->uri); -+ g_slice_free (StatLocationData, p); -+} -+ -+static void -+stat_location_cb (GObject *source, GAsyncResult *result, gpointer user_data) -+{ -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ SoupMessage *msg = g_vfs_backend_dav_get_async_result_message (backend, result); -+ GTask *task = user_data; -+ StatLocationData *data = g_task_get_task_data (task); - GInputStream *body; -+ GError *error = NULL; - guint status; -- gboolean count_children; - gboolean res; - -- count_children = num_children != NULL; -- msg = stat_location_begin (uri, count_children); -- if (msg == NULL) -- return FALSE; -- -- body = g_vfs_backend_dav_send (backend, msg, TRUE, error); -+ body = g_vfs_backend_dav_send_finish (backend, result, &error); - - if (!body) - { - g_object_unref (msg); -- return FALSE; -+ g_task_return_error (task, error); -+ g_object_unref (task); -+ return; - } - - status = soup_message_get_status (msg); - if (status != SOUP_STATUS_MULTI_STATUS) - { -- g_set_error_literal (error, -- G_IO_ERROR, -+ error = g_error_new (G_IO_ERROR, - http_error_code_from_status (status), -+ _("HTTP Error: %s"), - soup_message_get_reason_phrase (msg)); - - g_object_unref (msg); -+ g_task_return_error (task, error); - g_object_unref (body); -- return FALSE; -+ g_object_unref (task); -+ return; - } - -- res = stat_location_finish (msg, body, target_type, target_size, num_children); -+ res = stat_location_end (msg, body, &data->target_type, -+ &data->target_size, &data->num_children); - g_object_unref (msg); - g_object_unref (body); - - if (res == FALSE) -- g_set_error_literal (error, -- G_IO_ERROR, G_IO_ERROR_FAILED, -- _("Response invalid")); -+ { -+ error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, -+ _("Response invalid")); -+ g_task_return_error (task, error); -+ } -+ else -+ g_task_return_boolean (task, TRUE); -+ -+ g_object_unref (task); -+} -+ -+static void -+stat_location_async (GVfsBackend *backend, -+ GUri *uri, -+ gboolean count_children, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GTask *task; -+ SoupMessage *msg; -+ StatLocationData *data; -+ -+ task = g_task_new (backend, NULL, callback, user_data); -+ data = g_slice_new (StatLocationData); -+ data->uri = g_uri_ref (uri); -+ -+ g_task_set_source_tag (task, stat_location_async); -+ g_task_set_task_data (task, data, stat_location_data_free); -+ -+ msg = stat_location_start (uri, count_children); -+ if (msg == NULL) -+ { -+ g_task_return_boolean (task, FALSE); -+ g_object_unref (task); -+ return; -+ } -+ -+ dav_message_connect_signals (msg, backend); -+ -+ g_vfs_backend_dav_send_async (backend, msg, stat_location_cb, task); -+} -+ -+static gboolean -+stat_location_finish (GVfsBackend *backend, -+ GFileType *target_type, -+ gint64 *target_size, -+ guint *num_children, -+ GAsyncResult *result, -+ GError **error) -+{ -+ g_return_val_if_fail (G_VFS_IS_BACKEND (backend), FALSE); -+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); -+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE); -+ g_return_val_if_fail (g_task_is_valid (result, backend), FALSE); -+ g_return_val_if_fail (g_async_result_is_tagged (result, stat_location_async), FALSE); -+ -+ if (g_task_propagate_boolean (G_TASK (result), error)) -+ { -+ StatLocationData *data = g_task_get_task_data (G_TASK (result)); -+ if (target_type) *target_type = data->target_type; -+ if (target_size) *target_size = data->target_size; -+ if (num_children) *num_children = data->num_children; -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+static GUri * -+stat_location_async_get_uri (GVfsBackend *backend, GAsyncResult *result) -+{ -+ StatLocationData *data; -+ -+ g_return_val_if_fail (G_VFS_IS_BACKEND (backend), NULL); -+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); -+ g_return_val_if_fail (g_task_is_valid (result, backend), NULL); -+ -+ data = g_task_get_task_data (G_TASK (result)); -+ return data->uri; - -- return res; - } - - /* ************************************************************************* */ -@@ -1930,305 +2045,374 @@ dns_sd_resolver_changed (GVfsDnsSdResolver *resolver, - - /* ************************************************************************* */ - /* Backend Functions */ -+ - static void --do_mount (GVfsBackend *backend, -- GVfsJobMount *job, -- GMountSpec *mount_spec, -- GMountSource *mount_source, -- gboolean is_automount) -+mount_success (GVfsBackend *backend, GVfsJob *job) - { - GVfsBackendDav *dav_backend = G_VFS_BACKEND_DAV (backend); -- MountAuthData *data; -- SoupSession *session; -- SoupMessage *msg_opts; -- SoupMessage *msg_stat; -- GUri *mount_base; -- GUri *tmp; -- GError *error = NULL; -- guint status; -- gboolean is_success; -- gboolean is_webdav; -- gboolean is_collection; -- gboolean sig_opts = TRUE; -- gboolean sig_stat = TRUE; -- gboolean res; -- char *last_good_path; -- const char *host; -- const char *type; -+ GVfsBackendHttp *http_backend = G_VFS_BACKEND_HTTP (backend); -+ GMountSpec *mount_spec; -+ GUri *tmp; - -- g_debug ("+ mount\n"); -+ /* Save the auth info in the keyring */ -+ keyring_save_authinfo (&(dav_backend->auth_info.server_auth), http_backend->mount_base, FALSE); -+ /* TODO: save proxy auth */ - -- host = g_mount_spec_get (mount_spec, "host"); -- type = g_mount_spec_get (mount_spec, "type"); -+ /* Set the working path in mount path */ -+ tmp = http_backend->mount_base; -+ http_backend->mount_base = soup_uri_copy (tmp, SOUP_URI_PATH, -+ dav_backend->last_good_path, -+ SOUP_URI_NONE); -+ g_uri_unref (tmp); -+ g_clear_pointer (&dav_backend->last_good_path, g_free); - --#ifdef HAVE_AVAHI -- /* resolve DNS-SD style URIs */ -- if ((strcmp (type, "dav+sd") == 0 || strcmp (type, "davs+sd") == 0) && host != NULL) -- { -- dav_backend->resolver = g_vfs_dns_sd_resolver_new_for_encoded_triple (host, "u"); -+ /* dup the mountspec, but only copy known fields */ -+ mount_spec = g_mount_spec_from_dav_uri (dav_backend, http_backend->mount_base); - -- if (!g_vfs_dns_sd_resolver_resolve_sync (dav_backend->resolver, -- NULL, -- &error)) -- { -- g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -- g_error_free (error); -- return; -- } -- g_signal_connect (dav_backend->resolver, -- "changed", -- (GCallback) dns_sd_resolver_changed, -- dav_backend); -+ g_vfs_backend_set_mount_spec (backend, mount_spec); -+ g_vfs_backend_set_icon_name (backend, "folder-remote"); -+ g_vfs_backend_set_symbolic_icon_name (backend, "folder-remote-symbolic"); -+ -+ g_vfs_backend_dav_setup_display_name (backend); -+ -+ /* cleanup */ -+ g_mount_spec_unref (mount_spec); - -- mount_base = dav_uri_from_dns_sd_resolver (dav_backend); -- } -- else --#endif -+ g_vfs_job_succeeded (G_VFS_JOB (job)); -+ g_debug ("- mount\n"); -+} -+ -+static void try_mount_opts_cb (GObject *source, GAsyncResult *result, gpointer user_data); -+ -+static void -+try_mount_stat_cb (GObject *source, GAsyncResult *result, gpointer user_data) -+{ -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ GVfsBackendDav *dav_backend = G_VFS_BACKEND_DAV (backend); -+ GVfsBackendHttp *http_backend = G_VFS_BACKEND_HTTP (backend); -+ GVfsJobMount *job = user_data; -+ SoupMessage *msg_stat = g_vfs_backend_dav_get_async_result_message (backend, result); -+ SoupMessage *msg_opts; -+ GInputStream *body; -+ GError *error = NULL; -+ GFileType file_type; -+ gboolean res; -+ gboolean is_collection; -+ GUri *tmp; -+ char *new_path; -+ -+ body = g_vfs_backend_dav_send_finish (backend, result, &error); -+ -+ if (body == NULL) - { -- mount_base = g_mount_spec_to_dav_uri (mount_spec); -+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -+ g_error_free (error); -+ goto clear_msg; - } - -- if (mount_base == NULL) -+ res = stat_location_end (msg_stat, body, &file_type, NULL, NULL); -+ is_collection = res && file_type == G_FILE_TYPE_DIRECTORY; -+ -+ if (!g_vfs_backend_dav_stream_skip (body, &error)) - { -- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, -- G_IO_ERROR_INVALID_ARGUMENT, -- _("Invalid mount spec")); -- return; -+ g_object_unref (body); -+ if (dav_backend->last_good_path == NULL) -+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -+ else -+ mount_success (backend, G_VFS_JOB (job)); -+ g_error_free (error); -+ goto clear_msg; - } - -- session = G_VFS_BACKEND_HTTP (backend)->session; -- G_VFS_BACKEND_HTTP (backend)->mount_base = mount_base; -+ g_object_unref (body); - -- soup_session_add_feature_by_type (session, SOUP_TYPE_AUTH_NEGOTIATE); -- soup_session_add_feature_by_type (session, SOUP_TYPE_AUTH_NTLM); -+ soup_message_headers_clear (soup_message_get_response_headers (msg_stat)); - -- data = &(G_VFS_BACKEND_DAV (backend)->auth_info); -- data->mount_source = g_object_ref (mount_source); -- data->server_auth.username = g_strdup (g_uri_get_user (mount_base)); -- data->server_auth.pw_save = G_PASSWORD_SAVE_NEVER; -- data->proxy_auth.pw_save = G_PASSWORD_SAVE_NEVER; -- data->interactive = TRUE; -+ g_debug (" [%s] webdav: %d, collection %d [res: %d]\n", -+ g_uri_get_path (http_backend->mount_base), TRUE, is_collection, res); - -- last_good_path = NULL; -- msg_opts = soup_message_new_from_uri (SOUP_METHOD_OPTIONS, mount_base); -+ if ((is_collection == FALSE) && (dav_backend->last_good_path != NULL)) -+ { -+ mount_success (backend, G_VFS_JOB (job)); -+ goto clear_msg; -+ } -+ else if (res == FALSE) -+ { -+ int error_code = http_error_code_from_status (soup_message_get_status (msg_stat)); -+ g_vfs_job_failed (G_VFS_JOB (job), -+ G_IO_ERROR, error_code, -+ _("HTTP Error: %s"), -+ soup_message_get_reason_phrase (msg_stat)); -+ goto clear_msg; -+ } -+ else if (is_collection == FALSE) -+ { -+ g_vfs_job_failed (G_VFS_JOB (job), -+ G_IO_ERROR, G_IO_ERROR_FAILED, -+ _("Could not find an enclosing directory")); -+ goto clear_msg; -+ } - -- /* The count_children parameter is intentionally set to TRUE to be sure that -- enumeration is possible: https://gitlab.gnome.org/GNOME/gvfs/-/issues/468 */ -- msg_stat = stat_location_begin (mount_base, TRUE); -- -- do { -- GInputStream *body; -- GFileType file_type; -- GUri *cur_uri; -- char *new_path; -- -- res = TRUE; -- body = g_vfs_backend_dav_send (backend, msg_opts, sig_opts, &error); -- sig_opts = FALSE; -- status = body ? soup_message_get_status (msg_opts) : SOUP_STATUS_NONE; -- is_success = body && SOUP_STATUS_IS_SUCCESSFUL (status); -- is_webdav = sm_has_header (msg_opts, "DAV"); -- -- /* Workaround for servers which response with 403 instead of 401 in case of -- * wrong credentials to let the user specify its credentials again. */ -- if (status == SOUP_STATUS_FORBIDDEN && -- last_good_path == NULL && -- (data->server_auth.password != NULL || -- data->proxy_auth.password != NULL)) -- { -- SoupSessionFeature *auth_manager; -+ /* we have found a new good root, try the parent ... */ -+ g_free (dav_backend->last_good_path); -+ dav_backend->last_good_path = g_strdup (g_uri_get_path (http_backend->mount_base)); -+ new_path = path_get_parent_dir (dav_backend->last_good_path); - -- data->retrying_after_403 = TRUE; -+ tmp = http_backend->mount_base; -+ http_backend->mount_base = soup_uri_copy (tmp, SOUP_URI_PATH, new_path, SOUP_URI_NONE); -+ g_uri_unref (tmp); - -- g_clear_pointer (&data->server_auth.username, g_free); -- data->server_auth.username = g_strdup (g_uri_get_user (mount_base)); -- g_clear_pointer (&data->server_auth.password, g_free); -- g_clear_pointer (&data->proxy_auth.password, g_free); -+ g_free (new_path); - -- auth_manager = soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER); -- soup_auth_manager_clear_cached_credentials (SOUP_AUTH_MANAGER (auth_manager)); -+ /* if we have found a root that is good then we assume -+ that we also have obtained to correct credentials -+ and we switch the auth handler. This will prevent us -+ from asking for *different* credentials *again* if the -+ server should response with 401 for some of the parent -+ collections. See also bug #677753 */ -+ dav_backend->auth_info.interactive = FALSE; - -- g_object_unref (msg_opts); -- msg_opts = soup_message_new_from_uri (SOUP_METHOD_OPTIONS, mount_base); -+ /* break out */ -+ if (g_strcmp0 (dav_backend->last_good_path, "/") == 0) -+ { -+ mount_success (backend, G_VFS_JOB (job)); -+ goto clear_msg; -+ } - -- continue; -- } -+ /* else loop the whole thing from options */ - -- /* If SSL is used and the certificate verifies OK, then ssl-strict remains -- * on for all further connections. -- * If SSL is used and the certificate does not verify OK, then the user -- * gets a chance to override it. If they do, ssl-strict is disabled but -- * the certificate is stored, and checked on each subsequent connection to -- * ensure that it hasn't changed. */ -- if (g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE) && -- !dav_backend->certificate_errors) -- { -- GTlsCertificate *certificate; -- GTlsCertificateFlags errors; -- -- certificate = soup_message_get_tls_peer_certificate (msg_opts); -- errors = soup_message_get_tls_peer_certificate_errors (msg_opts); -- if (gvfs_accept_certificate (mount_source, certificate, errors)) -- { -- g_clear_error (&error); -- dav_backend->certificate = g_object_ref (certificate); -- dav_backend->certificate_errors = errors; -- continue; -- } -- else -- { -- /* break the loop, if last_good_path is NULL then the error is -- * propagated, otherwise it is cleared later by the else branch -- */ -- break; -- } -- } -+ msg_opts = soup_message_new_from_uri (SOUP_METHOD_OPTIONS, -+ http_backend->mount_base); - -- if (!is_success || !is_webdav) -- break; -+ dav_message_connect_signals (msg_opts, backend); - -- if (!g_vfs_backend_dav_stream_skip (body, &error)) -- { -- g_object_unref (body); -- break; -- } -+ g_vfs_backend_dav_send_async (backend, msg_opts, try_mount_opts_cb, job); - -- g_object_unref (body); -+clear_msg: -+ g_object_unref (msg_stat); -+} - -- soup_message_headers_clear (soup_message_get_response_headers (msg_opts)); -+static void -+try_mount_opts_cb (GObject *source, GAsyncResult *result, gpointer user_data) -+{ -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ GVfsBackendDav *dav_backend = G_VFS_BACKEND_DAV (backend); -+ GVfsBackendHttp *http_backend = G_VFS_BACKEND_HTTP (backend); -+ GVfsJobMount *job = user_data; -+ SoupMessage *msg_opts = g_vfs_backend_dav_get_async_result_message (backend, result); -+ SoupMessage *msg_stat; -+ GInputStream *body; -+ GError *error = NULL; -+ GUri *cur_uri; -+ guint status; -+ gboolean is_success, is_webdav; -+ -+ body = g_vfs_backend_dav_send_finish (backend, result, &error); -+ -+ /* If SSL is used and the certificate verifies OK, then ssl-strict remains -+ * on for all further connections. -+ * If SSL is used and the certificate does not verify OK, then the user -+ * gets a chance to override it. If they do, ssl-strict is disabled but -+ * the certificate is stored, and checked on each subsequent connection to -+ * ensure that it hasn't changed. */ -+ if (g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE) && -+ !dav_backend->certificate_errors) -+ { -+ GTlsCertificate *certificate; -+ GTlsCertificateFlags errors; - -- cur_uri = soup_message_get_uri (msg_opts); -- soup_message_set_uri (msg_stat, cur_uri); -+ certificate = soup_message_get_tls_peer_certificate (msg_opts); -+ errors = soup_message_get_tls_peer_certificate_errors (msg_opts); -+ if (gvfs_accept_certificate (dav_backend->auth_info.mount_source, certificate, errors)) -+ { -+ g_clear_error (&error); -+ dav_backend->certificate = g_object_ref (certificate); -+ dav_backend->certificate_errors = errors; - -- body = g_vfs_backend_dav_send (backend, msg_stat, sig_stat, NULL); -- sig_stat = FALSE; -- res = stat_location_finish (msg_stat, body, &file_type, NULL, NULL); -- is_collection = res && file_type == G_FILE_TYPE_DIRECTORY; -+ /* re-send the opts message; re-create since we're still in its cb */ -+ g_object_unref (msg_opts); -+ msg_opts = soup_message_new_from_uri (SOUP_METHOD_OPTIONS, -+ http_backend->mount_base); - -- if (body && !g_vfs_backend_dav_stream_skip (body, &error)) -- { -- g_object_unref (body); -- break; -- } -+ dav_message_connect_signals (msg_opts, backend); - -- g_clear_object (&body); -+ g_vfs_backend_dav_send_async (backend, msg_opts, -+ try_mount_opts_cb, job); -+ return; -+ } -+ } - -- soup_message_headers_clear (soup_message_get_response_headers (msg_stat)); -+ /* message failed, propagate the error */ -+ if (!body) -+ { -+ if (dav_backend->last_good_path == NULL) -+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -+ else -+ mount_success (backend, G_VFS_JOB (job)); -+ g_error_free (error); -+ goto clear_msgs; -+ } - -- g_debug (" [%s] webdav: %d, collection %d [res: %d]\n", -- g_uri_get_path (mount_base), is_webdav, is_collection, res); -+ status = soup_message_get_status (msg_opts); - -- if (is_collection == FALSE) -- break; -+ /* Workaround for servers which response with 403 instead of 401 in case of -+ * wrong credentials to let the user specify its credentials again. */ -+ if (status == SOUP_STATUS_FORBIDDEN && -+ dav_backend->last_good_path == NULL && -+ (dav_backend->auth_info.server_auth.password != NULL || -+ dav_backend->auth_info.proxy_auth.password != NULL)) -+ { -+ SoupSessionFeature *auth_manager; - -- /* we have found a new good root, try the parent ... */ -- g_free (last_good_path); -- last_good_path = g_strdup (g_uri_get_path (mount_base)); -- new_path = path_get_parent_dir (last_good_path); -+ dav_backend->auth_info.retrying_after_403 = TRUE; - -- tmp = mount_base; -- mount_base = soup_uri_copy (mount_base, SOUP_URI_PATH, new_path, SOUP_URI_NONE); -- g_uri_unref (tmp); -- G_VFS_BACKEND_HTTP (backend)->mount_base = mount_base; -+ g_clear_pointer (&dav_backend->auth_info.server_auth.username, g_free); -+ dav_backend->auth_info.server_auth.username = g_strdup (g_uri_get_user (http_backend->mount_base)); -+ g_clear_pointer (&dav_backend->auth_info.server_auth.password, g_free); -+ g_clear_pointer (&dav_backend->auth_info.proxy_auth.password, g_free); - -- g_free (new_path); -+ auth_manager = soup_session_get_feature (http_backend->session, SOUP_TYPE_AUTH_MANAGER); -+ soup_auth_manager_clear_cached_credentials (SOUP_AUTH_MANAGER (auth_manager)); - -- soup_message_set_uri (msg_opts, mount_base); -+ /* re-send the opts message; re-create since we're still in its cb */ -+ g_object_unref (msg_opts); -+ msg_opts = soup_message_new_from_uri (SOUP_METHOD_OPTIONS, -+ http_backend->mount_base); - -- /* if we have found a root that is good then we assume -- that we also have obtained to correct credentials -- and we switch the auth handler. This will prevent us -- from asking for *different* credentials *again* if the -- server should response with 401 for some of the parent -- collections. See also bug #677753 */ -- data->interactive = FALSE; -+ dav_message_connect_signals (msg_opts, backend); - -- } while (g_strcmp0 (last_good_path, "/") != 0); -+ g_vfs_backend_dav_send_async (backend, msg_opts, try_mount_opts_cb, job); -+ return; -+ } - -- /* we either encountered an error or we have -- reached the end of paths we are allowed to -- chdir up to (or couldn't chdir up at all) */ -+ is_success = SOUP_STATUS_IS_SUCCESSFUL (status); -+ is_webdav = sm_has_header (msg_opts, "DAV"); - -- /* check if we at all have a good path */ -- if (last_good_path == NULL) -+ if ((is_success && !is_webdav) || (status == SOUP_STATUS_METHOD_NOT_ALLOWED)) -+ { -+ if (dav_backend->last_good_path == NULL) -+ g_vfs_job_failed (G_VFS_JOB (job), -+ G_IO_ERROR, G_IO_ERROR_FAILED, -+ _("Not a WebDAV enabled share")); -+ else -+ mount_success (backend, G_VFS_JOB (job)); -+ goto clear_msgs; -+ } -+ else if (!is_success) - { -- if (error) -+ int error_code = http_error_code_from_status (soup_message_get_status (msg_opts)); -+ -+ if (dav_backend->last_good_path == NULL) -+ g_vfs_job_failed (G_VFS_JOB (job), -+ G_IO_ERROR, error_code, -+ _("HTTP Error: %s"), -+ soup_message_get_reason_phrase (msg_opts)); -+ else -+ mount_success (backend, G_VFS_JOB (job)); -+ goto clear_msgs; -+ } -+ -+ if (!g_vfs_backend_dav_stream_skip (body, &error)) -+ { -+ if (dav_backend->last_good_path == NULL) -+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -+ else -+ mount_success (backend, G_VFS_JOB (job)); -+ g_error_free (error); -+ goto clear_msgs; -+ } -+ -+ g_object_unref (body); -+ -+ cur_uri = soup_message_get_uri (msg_opts); -+ -+ /* The count_children parameter is intentionally set to TRUE to be sure that -+ enumeration is possible: https://gitlab.gnome.org/GNOME/gvfs/-/issues/468 */ -+ msg_stat = stat_location_start (cur_uri, TRUE); -+ -+ dav_message_connect_signals (msg_stat, backend); -+ -+ g_vfs_backend_dav_send_async (backend, msg_stat, try_mount_stat_cb, job); -+ -+clear_msgs: -+ g_object_unref (msg_opts); -+} -+ -+static gboolean -+try_mount (GVfsBackend *backend, -+ GVfsJobMount *job, -+ GMountSpec *mount_spec, -+ GMountSource *mount_source, -+ gboolean is_automount) -+{ -+ GVfsBackendDav *dav_backend = G_VFS_BACKEND_DAV (backend); -+ GVfsBackendHttp *http_backend = G_VFS_BACKEND_HTTP (backend); -+ SoupMessage *msg_opts; -+ GUri *mount_base; -+ const char *host; -+ const char *type; -+ -+ g_debug ("+ mount\n"); -+ -+ host = g_mount_spec_get (mount_spec, "host"); -+ type = g_mount_spec_get (mount_spec, "type"); -+ -+#ifdef HAVE_AVAHI -+ /* resolve DNS-SD style URIs */ -+ if ((strcmp (type, "dav+sd") == 0 || strcmp (type, "davs+sd") == 0) && host != NULL) -+ { -+ GError *error = NULL; -+ dav_backend->resolver = g_vfs_dns_sd_resolver_new_for_encoded_triple (host, "u"); -+ -+ if (!g_vfs_dns_sd_resolver_resolve_sync (dav_backend->resolver, -+ NULL, -+ &error)) - { - g_vfs_job_failed_from_error (G_VFS_JOB (job), error); - g_error_free (error); -+ return TRUE; - } -- else if ((is_success && !is_webdav) || -- soup_message_get_status (msg_opts) == SOUP_STATUS_METHOD_NOT_ALLOWED) -- { -- /* This means the either: a) OPTIONS request succeeded -- (which should be the case even for non-existent -- resources on a webdav enabled share) but we did not -- get the DAV header. Or b) the OPTIONS request was a -- METHOD_NOT_ALLOWED (405). -- Prioritize this error messages, because it seems most -- useful to the user. */ -- g_vfs_job_failed (G_VFS_JOB (job), -- G_IO_ERROR, G_IO_ERROR_FAILED, -- _("Not a WebDAV enabled share")); -- } -- else if (!is_success || !res) -- { -- /* Either the OPTIONS request (is_success) or the PROPFIND -- request (res) failed. */ -- SoupMessage *target = !is_success ? msg_opts : msg_stat; -- int error_code = http_error_code_from_status (soup_message_get_status (target)); -- -- g_vfs_job_failed (G_VFS_JOB (job), -- G_IO_ERROR, error_code, -- _("HTTP Error: %s"), -- soup_message_get_reason_phrase (target)); -- } -- else -- { -- /* This means, we have a valid DAV header, PROPFIND worked, -- but it is not a collection! */ -- g_vfs_job_failed (G_VFS_JOB (job), -- G_IO_ERROR, G_IO_ERROR_FAILED, -- _("Could not find an enclosing directory")); -- } -+ g_signal_connect (dav_backend->resolver, -+ "changed", -+ (GCallback) dns_sd_resolver_changed, -+ dav_backend); - -- g_object_unref (msg_opts); -- g_object_unref (msg_stat); -+ mount_base = dav_uri_from_dns_sd_resolver (dav_backend); -+ } -+ else -+#endif -+ { -+ mount_base = g_mount_spec_to_dav_uri (mount_spec); -+ } - -- return; -+ if (mount_base == NULL) -+ { -+ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, -+ G_IO_ERROR_INVALID_ARGUMENT, -+ _("Invalid mount spec")); -+ return TRUE; - } -- else if (error) -- g_error_free (error); - -- /* Success! We are mounted */ -- /* Save the auth info in the keyring */ -+ http_backend->mount_base = mount_base; - -- keyring_save_authinfo (&(data->server_auth), mount_base, FALSE); -- /* TODO: save proxy auth */ -+ soup_session_add_feature_by_type (http_backend->session, -+ SOUP_TYPE_AUTH_NEGOTIATE); -+ soup_session_add_feature_by_type (http_backend->session, -+ SOUP_TYPE_AUTH_NTLM); - -- /* Set the working path in mount path */ -- tmp = mount_base; -- mount_base = soup_uri_copy (mount_base, SOUP_URI_PATH, last_good_path, SOUP_URI_NONE); -- g_uri_unref (tmp); -- G_VFS_BACKEND_HTTP (backend)->mount_base = mount_base; -- g_free (last_good_path); -+ dav_backend->auth_info.mount_source = g_object_ref (mount_source); -+ dav_backend->auth_info.server_auth.username = g_strdup (g_uri_get_user (mount_base)); -+ dav_backend->auth_info.server_auth.pw_save = G_PASSWORD_SAVE_NEVER; -+ dav_backend->auth_info.proxy_auth.pw_save = G_PASSWORD_SAVE_NEVER; -+ dav_backend->auth_info.interactive = TRUE; - -- /* dup the mountspec, but only copy known fields */ -- mount_spec = g_mount_spec_from_dav_uri (dav_backend, mount_base); -+ dav_backend->last_good_path = NULL; - -- g_vfs_backend_set_mount_spec (backend, mount_spec); -- g_vfs_backend_set_icon_name (backend, "folder-remote"); -- g_vfs_backend_set_symbolic_icon_name (backend, "folder-remote-symbolic"); -- -- g_vfs_backend_dav_setup_display_name (backend); -- -- /* cleanup */ -- g_mount_spec_unref (mount_spec); -- g_object_unref (msg_opts); -- g_object_unref (msg_stat); -+ msg_opts = soup_message_new_from_uri (SOUP_METHOD_OPTIONS, mount_base); -+ dav_message_connect_signals (msg_opts, backend); - -- g_vfs_job_succeeded (G_VFS_JOB (job)); -- g_debug ("- mount\n"); -+ g_vfs_backend_dav_send_async (backend, msg_opts, try_mount_opts_cb, job); -+ return TRUE; - } - - static PropName ls_propnames[] = { -@@ -2244,34 +2428,18 @@ static PropName ls_propnames[] = { - - /* *** query_info () *** */ - static void --do_query_info (GVfsBackend *backend, -- GVfsJobQueryInfo *job, -- const char *filename, -- GFileQueryInfoFlags flags, -- GFileInfo *info, -- GFileAttributeMatcher *matcher) -+try_query_info_cb (GObject *source, GAsyncResult *result, gpointer user_data) - { -- SoupMessage *msg; -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ SoupMessage *msg = g_vfs_backend_dav_get_async_result_message (backend, result); -+ GVfsJobQueryInfo *job = user_data; - GInputStream *body; -+ GError *error = NULL; - Multistatus ms; - xmlNodeIter iter; - gboolean res; -- GError *error = NULL; - -- g_debug ("Query info %s\n", filename); -- -- msg = propfind_request_new (backend, filename, 0, ls_propnames); -- if (msg == NULL) -- { -- g_vfs_job_failed (G_VFS_JOB (job), -- G_IO_ERROR, G_IO_ERROR_FAILED, -- _("Could not create request")); -- return; -- } -- -- message_add_redirect_header (msg, flags); -- -- body = g_vfs_backend_dav_send (backend, msg, TRUE, &error); -+ body = g_vfs_backend_dav_send_finish (backend, result, &error); - - if (!body) - goto error; -@@ -2318,6 +2486,36 @@ do_query_info (GVfsBackend *backend, - g_object_unref (msg); - } - -+static gboolean -+try_query_info (GVfsBackend *backend, -+ GVfsJobQueryInfo *job, -+ const char *filename, -+ GFileQueryInfoFlags flags, -+ GFileInfo *info, -+ GFileAttributeMatcher *matcher) -+{ -+ SoupMessage *msg; -+ -+ g_debug ("Query info %s\n", filename); -+ -+ msg = propfind_request_new (backend, filename, 0, ls_propnames); -+ if (msg == NULL) -+ { -+ g_vfs_job_failed (G_VFS_JOB (job), -+ G_IO_ERROR, G_IO_ERROR_FAILED, -+ _("Could not create request")); -+ return TRUE; -+ } -+ -+ message_add_redirect_header (msg, flags); -+ -+ dav_message_connect_signals (msg, backend); -+ -+ g_vfs_backend_dav_send_async (backend, msg, try_query_info_cb, job); -+ -+ return TRUE; -+} -+ - static PropName fs_info_propnames[] = { - {"quota-available-bytes", NULL}, - {"quota-used-bytes", NULL}, -@@ -2325,51 +2523,18 @@ static PropName fs_info_propnames[] = { - }; - - static void --do_query_fs_info (GVfsBackend *backend, -- GVfsJobQueryFsInfo *job, -- const char *filename, -- GFileInfo *info, -- GFileAttributeMatcher *attribute_matcher) -+try_query_fs_info_cb (GObject *source, GAsyncResult *result, gpointer user_data) - { -- SoupMessage *msg; -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ SoupMessage *msg = g_vfs_backend_dav_get_async_result_message (backend, result); -+ GVfsJobQueryFsInfo *job = user_data; - GInputStream *body; -+ GError *error = NULL; - Multistatus ms; - xmlNodeIter iter; - gboolean res; -- GError *error = NULL; -- -- g_file_info_set_attribute_string (info, -- G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, -- "webdav"); -- g_file_info_set_attribute_boolean (info, -- G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, -- TRUE); -- g_file_info_set_attribute_uint32 (info, -- G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, -- G_FILESYSTEM_PREVIEW_TYPE_IF_ALWAYS); - -- if (! (g_file_attribute_matcher_matches (attribute_matcher, -- G_FILE_ATTRIBUTE_FILESYSTEM_SIZE) || -- g_file_attribute_matcher_matches (attribute_matcher, -- G_FILE_ATTRIBUTE_FILESYSTEM_USED) || -- g_file_attribute_matcher_matches (attribute_matcher, -- G_FILE_ATTRIBUTE_FILESYSTEM_FREE))) -- { -- g_vfs_job_succeeded (G_VFS_JOB (job)); -- return; -- } -- -- msg = propfind_request_new (backend, filename, 0, fs_info_propnames); -- if (msg == NULL) -- { -- g_vfs_job_failed (G_VFS_JOB (job), -- G_IO_ERROR, G_IO_ERROR_FAILED, -- _("Could not create request")); -- -- return; -- } -- -- body = g_vfs_backend_dav_send (backend, msg, TRUE, &error); -+ body = g_vfs_backend_dav_send_finish (backend, result, &error); - - if (!body) - goto error; -@@ -2392,7 +2557,7 @@ do_query_fs_info (GVfsBackend *backend, - - if (response.is_target) - { -- ms_response_to_fs_info (&response, info); -+ ms_response_to_fs_info (&response, job->file_info); - res = TRUE; - } - -@@ -2416,36 +2581,67 @@ do_query_fs_info (GVfsBackend *backend, - g_object_unref (msg); - } - --/* *** enumerate *** */ --static void --do_enumerate (GVfsBackend *backend, -- GVfsJobEnumerate *job, -- const char *filename, -- GFileAttributeMatcher *matcher, -- GFileQueryInfoFlags flags) -+static gboolean -+try_query_fs_info (GVfsBackend *backend, -+ GVfsJobQueryFsInfo *job, -+ const char *filename, -+ GFileInfo *info, -+ GFileAttributeMatcher *attribute_matcher) - { - SoupMessage *msg; -- GInputStream *body; -- Multistatus ms; -- xmlNodeIter iter; -- gboolean res; -- GError *error = NULL; - -- g_debug ("+ do_enumerate: %s\n", filename); -+ g_file_info_set_attribute_string (info, -+ G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, -+ "webdav"); -+ g_file_info_set_attribute_boolean (info, -+ G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, -+ TRUE); -+ g_file_info_set_attribute_uint32 (info, -+ G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, -+ G_FILESYSTEM_PREVIEW_TYPE_IF_ALWAYS); - -- msg = propfind_request_new (backend, filename, 1, ls_propnames); -+ if (! (g_file_attribute_matcher_matches (attribute_matcher, -+ G_FILE_ATTRIBUTE_FILESYSTEM_SIZE) || -+ g_file_attribute_matcher_matches (attribute_matcher, -+ G_FILE_ATTRIBUTE_FILESYSTEM_USED) || -+ g_file_attribute_matcher_matches (attribute_matcher, -+ G_FILE_ATTRIBUTE_FILESYSTEM_FREE))) -+ { -+ g_vfs_job_succeeded (G_VFS_JOB (job)); -+ return TRUE; -+ } -+ -+ msg = propfind_request_new (backend, filename, 0, fs_info_propnames); - if (msg == NULL) - { - g_vfs_job_failed (G_VFS_JOB (job), - G_IO_ERROR, G_IO_ERROR_FAILED, - _("Could not create request")); -- -- return; -+ return TRUE; - } - -- message_add_redirect_header (msg, flags); -+ dav_message_connect_signals (msg, backend); -+ -+ g_vfs_backend_dav_send_async (backend, msg, try_query_fs_info_cb, job); -+ -+ return TRUE; -+} -+ -+/* *** enumerate *** */ -+ -+static void -+try_enumerate_cb (GObject *source, GAsyncResult *result, gpointer user_data) -+{ -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ SoupMessage *msg = g_vfs_backend_dav_get_async_result_message (backend, result); -+ GVfsJobEnumerate *job = user_data; -+ GInputStream *body; -+ GError *error = NULL; -+ Multistatus ms; -+ xmlNodeIter iter; -+ gboolean res; - -- body = g_vfs_backend_dav_send (backend, msg, TRUE, &error); -+ body = g_vfs_backend_dav_send_finish (backend, result, &error); - - if (!body) - goto error; -@@ -2491,6 +2687,34 @@ do_enumerate (GVfsBackend *backend, - g_object_unref (msg); - } - -+static gboolean -+try_enumerate (GVfsBackend *backend, -+ GVfsJobEnumerate *job, -+ const char *filename, -+ GFileAttributeMatcher *matcher, -+ GFileQueryInfoFlags flags) -+{ -+ SoupMessage *msg; -+ -+ g_debug ("+ try_enumerate: %s\n", filename); -+ -+ msg = propfind_request_new (backend, filename, 1, ls_propnames); -+ if (msg == NULL) -+ { -+ g_vfs_job_failed (G_VFS_JOB (job), -+ G_IO_ERROR, G_IO_ERROR_FAILED, -+ _("Could not create request")); -+ return TRUE; -+ } -+ -+ message_add_redirect_header (msg, flags); -+ dav_message_connect_signals (msg, backend); -+ -+ g_vfs_backend_dav_send_async (backend, msg, try_enumerate_cb, job); -+ -+ return TRUE; -+} -+ - /* ************************************************************************* */ - /* */ - -@@ -2525,7 +2749,7 @@ try_open_stat_done (GObject *source, - return; - } - -- res = stat_location_finish (msg, body, &target_type, NULL, NULL); -+ res = stat_location_end (msg, body, &target_type, NULL, NULL); - g_object_unref (body); - - if (res == FALSE) -@@ -2559,7 +2783,7 @@ try_open_for_read (GVfsBackend *backend, - GUri *uri; - - uri = g_vfs_backend_dav_uri_for_path (backend, filename, FALSE); -- msg = stat_location_begin (uri, FALSE); -+ msg = stat_location_start (uri, FALSE); - g_uri_unref (uri); - - if (msg == NULL) -@@ -2571,8 +2795,11 @@ try_open_for_read (GVfsBackend *backend, - return FALSE; - } - -+ dav_message_connect_signals (msg, backend); -+ - g_vfs_job_set_backend_data (G_VFS_JOB (job), backend, NULL); -- g_vfs_backend_dav_send_async (backend, msg, TRUE, try_open_stat_done, job); -+ soup_session_send_async (G_VFS_BACKEND_HTTP (backend)->session, msg, -+ G_PRIORITY_DEFAULT, NULL, try_open_stat_done, job); - - return TRUE; - } -@@ -2651,7 +2878,11 @@ try_create (GVfsBackend *backend, - - g_vfs_job_set_backend_data (G_VFS_JOB (job), msg, NULL); - -- g_vfs_backend_dav_send_async (backend, msg, TRUE, try_create_tested_existence, job); -+ dav_message_connect_signals (msg, backend); -+ -+ soup_session_send_async (G_VFS_BACKEND_HTTP (backend)->session, msg, -+ G_PRIORITY_DEFAULT, NULL, -+ try_create_tested_existence, job); - - return TRUE; - } -@@ -2760,12 +2991,14 @@ try_replace (GVfsBackend *backend, - msg = soup_message_new_from_uri (SOUP_METHOD_HEAD, uri); - g_uri_unref (uri); - -+ dav_message_connect_signals (msg, backend); -+ - soup_message_headers_append (soup_message_get_request_headers (msg), - "If-Match", etag); - - g_vfs_job_set_backend_data (G_VFS_JOB (job), op_backend, NULL); -- g_vfs_backend_dav_send_async (backend, msg, TRUE, -- try_replace_checked_etag, job); -+ soup_session_send_async (op_backend->session, msg, G_PRIORITY_DEFAULT, -+ NULL, try_replace_checked_etag, job); - - return TRUE; - } -@@ -2829,6 +3062,7 @@ try_write (GVfsBackend *backend, - return TRUE; - } - -+/* this does not invoke libsoup API, so it can be synchronous/threaded */ - static void - do_seek_on_write (GVfsBackend *backend, - GVfsJobSeekWrite *job, -@@ -2851,6 +3085,7 @@ do_seek_on_write (GVfsBackend *backend, - } - } - -+/* this does not invoke libsoup API, so it can be synchronous/threaded */ - static void - do_truncate (GVfsBackend *backend, - GVfsJobTruncate *job, -@@ -2914,34 +3149,32 @@ try_close_write (GVfsBackend *backend, - g_object_ref (msg); - g_object_set_data (G_OBJECT (stream), "-gvfs-stream-msg", NULL); - -+ dav_message_connect_signals (msg, backend); -+ - g_output_stream_close (stream, NULL, NULL); - bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (stream)); - g_object_unref (stream); - - soup_message_set_request_body_from_bytes (msg, NULL, bytes); -- g_vfs_backend_dav_send_async (backend, msg, TRUE, -- try_close_write_sent, job); -+ soup_session_send_async (G_VFS_BACKEND_HTTP (backend)->session, msg, -+ G_PRIORITY_DEFAULT, NULL, try_close_write_sent, job); - g_bytes_unref (bytes); - - return TRUE; - } - - static void --do_make_directory (GVfsBackend *backend, -- GVfsJobMakeDirectory *job, -- const char *filename) -+make_directory_cb (GObject *source, GAsyncResult *result, gpointer user_data) - { -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ GVfsJobMakeDirectory *job = user_data; -+ SoupMessage *msg = g_vfs_backend_dav_get_async_result_message (backend, result); - GInputStream *body; -- SoupMessage *msg; -- GUri *uri; - GError *error = NULL; - guint status; - -- uri = g_vfs_backend_dav_uri_for_path (backend, filename, TRUE); -- msg = soup_message_new_from_uri (SOUP_METHOD_MKCOL, uri); -- g_uri_unref (uri); -+ body = g_vfs_backend_dav_send_finish (backend, result, &error); - -- body = g_vfs_backend_dav_send (backend, msg, TRUE, &error); - if (!body) - { - g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -@@ -2966,27 +3199,72 @@ do_make_directory (GVfsBackend *backend, - g_object_unref (msg); - } - --static void --do_delete (GVfsBackend *backend, -- GVfsJobDelete *job, -- const char *filename) -+static gboolean -+try_make_directory (GVfsBackend *backend, -+ GVfsJobMakeDirectory *job, -+ const char *filename) - { -- GInputStream *body; - SoupMessage *msg; - GUri *uri; -+ -+ uri = g_vfs_backend_dav_uri_for_path (backend, filename, TRUE); -+ msg = soup_message_new_from_uri (SOUP_METHOD_MKCOL, uri); -+ g_uri_unref (uri); -+ -+ dav_message_connect_signals (msg, backend); -+ -+ g_vfs_backend_dav_send_async (backend, msg, make_directory_cb, job); -+ return TRUE; -+} -+ -+static void -+try_delete_send_cb (GObject *source, GAsyncResult *result, gpointer user_data) -+{ -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ GVfsJobDelete *job = user_data; -+ SoupMessage *msg = g_vfs_backend_dav_get_async_result_message (backend, result); -+ GInputStream *body; -+ GError *error = NULL; -+ guint status; -+ -+ body = g_vfs_backend_dav_send_finish (backend, result, &error); -+ -+ if (!body) -+ { -+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -+ g_error_free (error); -+ g_object_unref (msg); -+ return; -+ } -+ -+ status = soup_message_get_status (msg); -+ if (!SOUP_STATUS_IS_SUCCESSFUL (status)) -+ http_job_failed (G_VFS_JOB (job), msg); -+ else -+ g_vfs_job_succeeded (G_VFS_JOB (job)); -+ -+ g_object_unref (msg); -+ g_object_unref (body); -+} -+ -+static void -+try_delete_cb (GObject *source, GAsyncResult *result, gpointer user_data) -+{ -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ GVfsJobDelete *job = user_data; -+ SoupMessage *msg = NULL; - GFileType file_type; -- gboolean res; - guint num_children; -- guint status; - GError *error = NULL; -+ gboolean res; -+ GUri *uri = stat_location_async_get_uri (backend, result); - -- uri = g_vfs_backend_dav_uri_for_path (backend, filename, FALSE); -- res = stat_location (backend, uri, &file_type, NULL, &num_children, &error); -+ res = stat_location_finish (backend, &file_type, NULL, -+ &num_children, result, &error); - if (res == FALSE) - { - g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -- g_error_free (error); -- g_uri_unref (uri); -+ g_clear_error (&error); - return; - } - -@@ -2995,377 +3273,559 @@ do_delete (GVfsBackend *backend, - g_vfs_job_failed (G_VFS_JOB (job), - G_IO_ERROR, G_IO_ERROR_NOT_EMPTY, - _("Directory not empty")); -- g_uri_unref (uri); - return; - } - - msg = soup_message_new_from_uri (SOUP_METHOD_DELETE, uri); -- body = g_vfs_backend_dav_send (backend, msg, TRUE, &error); -+ -+ dav_message_connect_signals (msg, backend); -+ -+ g_vfs_backend_dav_send_async (backend, msg, try_delete_send_cb, job); -+} -+ -+static gboolean -+try_delete (GVfsBackend *backend, GVfsJobDelete *job, const char *filename) -+{ -+ GUri *uri; -+ -+ uri = g_vfs_backend_dav_uri_for_path (backend, filename, FALSE); -+ stat_location_async (backend, uri, TRUE, try_delete_cb, job); -+ return TRUE; -+} -+ -+typedef struct _TrySetDisplayNameData { -+ GVfsJobSetDisplayName *job; -+ char *target_path; -+} TrySetDisplayNameData; -+ -+static void -+try_set_display_name_cb (GObject *source, GAsyncResult *result, -+ gpointer user_data) -+{ -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ TrySetDisplayNameData *data = user_data; -+ SoupMessage *msg = g_vfs_backend_dav_get_async_result_message (backend, result); -+ GInputStream *body; -+ GError *error = NULL; -+ guint status; -+ -+ body = g_vfs_backend_dav_send_finish (backend, result, &error); -+ - if (!body) - { -- g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -- g_error_free (error); -- g_object_unref (msg); -- g_uri_unref (uri); -- return; -+ http_job_failed (G_VFS_JOB (data->job), msg); -+ goto error; - } - - status = soup_message_get_status (msg); -- if (!SOUP_STATUS_IS_SUCCESSFUL (status)) -- http_job_failed (G_VFS_JOB (job), msg); -+ -+ /* -+ * The precondition of SOUP_STATUS_PRECONDITION_FAILED (412) in -+ * this case was triggered by the "Overwrite: F" header which -+ * means that the target already exists. -+ * Also if we get a REDIRECTION it means that there was no -+ * "Location" header, since otherwise that would have triggered -+ * our redirection handler. This probably means we are dealing -+ * with an web dav implementation (like mod_dav) that also sends -+ * redirects for the destionaion (i.e. "Destination: /foo" header) -+ * which very likely means that the target also exists (and is a -+ * directory). That or the webdav server is broken. -+ * We could find out by doing another stat and but I think this is -+ * such a corner case that we are totally fine with returning -+ * G_IO_ERROR_EXISTS. -+ * */ -+ -+ if (SOUP_STATUS_IS_SUCCESSFUL (status)) -+ { -+ g_debug ("new target_path: %s\n", data->target_path); -+ g_vfs_job_set_display_name_set_new_path (data->job, data->target_path); -+ g_vfs_job_succeeded (G_VFS_JOB (data->job)); -+ } -+ else if (status == SOUP_STATUS_PRECONDITION_FAILED || -+ SOUP_STATUS_IS_REDIRECTION (status)) -+ g_vfs_job_failed (G_VFS_JOB (data->job), G_IO_ERROR, -+ G_IO_ERROR_EXISTS, -+ _("Target file already exists")); - else -- g_vfs_job_succeeded (G_VFS_JOB (job)); -+ http_job_failed (G_VFS_JOB (data->job), msg); - -- g_uri_unref (uri); -- g_object_unref (msg); - g_object_unref (body); -+ -+error: -+ g_clear_error (&error); -+ g_object_unref (msg); -+ g_free (data->target_path); -+ g_slice_free (TrySetDisplayNameData, data); -+} -+ -+static gboolean -+try_set_display_name (GVfsBackend *backend, -+ GVfsJobSetDisplayName *job, -+ const char *filename, -+ const char *display_name) -+{ -+ SoupMessage *msg; -+ GUri *source; -+ GUri *target; -+ TrySetDisplayNameData *data = g_slice_new (TrySetDisplayNameData); -+ char *dirname; -+ -+ source = g_vfs_backend_dav_uri_for_path (backend, filename, FALSE); -+ msg = soup_message_new_from_uri (SOUP_METHOD_MOVE, source); -+ -+ dirname = g_path_get_dirname (filename); -+ data->target_path = g_build_filename (dirname, display_name, NULL); -+ target = g_vfs_backend_dav_uri_for_path (backend, data->target_path, FALSE); -+ -+ message_add_destination_header (msg, target); -+ message_add_overwrite_header (msg, FALSE); -+ -+ data->job = job; -+ g_free (dirname); -+ g_uri_unref (target); -+ g_uri_unref (source); -+ -+ dav_message_connect_signals (msg, backend); -+ -+ g_vfs_backend_dav_send_async (backend, msg, try_set_display_name_cb, data); -+ -+ return TRUE; -+} -+ -+typedef struct _CopyData { -+ GVfsJob *job; -+ SoupMessage *msg; -+ GUri *source_uri; -+ GUri *target_uri; -+ GFileProgressCallback progress_callback; -+ gpointer progress_callback_data; -+ gint64 file_size; -+ GFileType source_ft; -+ GFileType target_ft; -+ GFileCopyFlags flags; -+ gboolean source_res; -+ gboolean target_res; -+} CopyData; -+ -+static void -+copy_data_free (gpointer data) -+{ -+ CopyData *p = data; -+ g_clear_pointer (&p->source_uri, g_uri_unref); -+ g_clear_pointer (&p->target_uri, g_uri_unref); -+ g_clear_object (&p->msg); -+ g_slice_free (CopyData, p); - } - - static void --do_set_display_name (GVfsBackend *backend, -- GVfsJobSetDisplayName *job, -- const char *filename, -- const char *display_name) -+try_move_do_cb (GObject *source, GAsyncResult *result, gpointer user_data) - { -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ CopyData *data = user_data; - GInputStream *body; -- SoupMessage *msg; -- GUri *source; -- GUri *target; -- char *target_path; -- char *dirname; - GError *error = NULL; - guint status; - -- source = g_vfs_backend_dav_uri_for_path (backend, filename, FALSE); -- msg = soup_message_new_from_uri (SOUP_METHOD_MOVE, source); -- -- dirname = g_path_get_dirname (filename); -- target_path = g_build_filename (dirname, display_name, NULL); -- target = g_vfs_backend_dav_uri_for_path (backend, target_path, FALSE); -- -- message_add_destination_header (msg, target); -- message_add_overwrite_header (msg, FALSE); -+ body = g_vfs_backend_dav_send_finish (backend, result, &error); - -- body = g_vfs_backend_dav_send (backend, msg, TRUE, &error); - if (!body) - { -- http_job_failed (G_VFS_JOB (job), msg); -- goto error; -+ g_vfs_job_failed_from_error (data->job, error); -+ copy_data_free (data); -+ g_clear_error (&error); -+ return; - } - -- status = soup_message_get_status (msg); -- -- /* -- * The precondition of SOUP_STATUS_PRECONDITION_FAILED (412) in -- * this case was triggered by the "Overwrite: F" header which -- * means that the target already exists. -- * Also if we get a REDIRECTION it means that there was no -- * "Location" header, since otherwise that would have triggered -- * our redirection handler. This probably means we are dealing -- * with an web dav implementation (like mod_dav) that also sends -- * redirects for the destionaion (i.e. "Destination: /foo" header) -- * which very likely means that the target also exists (and is a -- * directory). That or the webdav server is broken. -- * We could find out by doing another stat and but I think this is -- * such a corner case that we are totally fine with returning -- * G_IO_ERROR_EXISTS. -- * */ -+ /* See try_set_display_name () for the explanation of the PRECONDITION_FAILED -+ * and IS_REDIRECTION handling below. */ -+ status = soup_message_get_status (data->msg); - - if (SOUP_STATUS_IS_SUCCESSFUL (status)) - { -- g_debug ("new target_path: %s\n", target_path); -- g_vfs_job_set_display_name_set_new_path (job, target_path); -- g_vfs_job_succeeded (G_VFS_JOB (job)); -+ if (data->source_res && data->progress_callback) -+ data->progress_callback (data->file_size, data->file_size, -+ data->progress_callback_data); -+ g_vfs_job_succeeded (data->job); - } - else if (status == SOUP_STATUS_PRECONDITION_FAILED || - SOUP_STATUS_IS_REDIRECTION (status)) -- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, -+ g_vfs_job_failed (data->job, G_IO_ERROR, - G_IO_ERROR_EXISTS, - _("Target file already exists")); - else -- http_job_failed (G_VFS_JOB (job), msg); -+ http_job_failed (data->job, data->msg); - -- g_object_unref (body); -+ copy_data_free (data); -+} - -- error: -- g_object_unref (msg); -- g_free (dirname); -- g_free (target_path); -- g_uri_unref (target); -- g_uri_unref (source); -+static void -+try_move_do (GVfsBackend *backend, CopyData *data) -+{ -+ message_add_destination_header (data->msg, data->target_uri); -+ message_add_overwrite_header (data->msg, data->flags & G_FILE_COPY_OVERWRITE); -+ g_vfs_backend_dav_send_async (backend, data->msg, try_move_do_cb, data); - } - - static void --do_move (GVfsBackend *backend, -- GVfsJobMove *job, -- const char *source, -- const char *destination, -- GFileCopyFlags flags, -- GFileProgressCallback progress_callback, -- gpointer progress_callback_data) --{ -- GInputStream *body = NULL; -- SoupMessage *msg; -- GUri *source_uri; -- GUri *target_uri; -- guint status; -- GFileType source_ft, target_ft; -+try_move_target_delete_cb (GObject *source, GAsyncResult *result, -+ gpointer user_data) -+{ -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ SoupMessage *msg = g_vfs_backend_dav_get_async_result_message (backend, result); -+ CopyData *data = user_data; -+ GInputStream *body; - GError *error = NULL; -- gboolean res, stat_res; -- gint64 file_size; -+ guint status; - -- if (flags & G_FILE_COPY_BACKUP) -- { -- if (flags & G_FILE_COPY_NO_FALLBACK_FOR_MOVE) -- { -- g_vfs_job_failed_literal (G_VFS_JOB (job), -- G_IO_ERROR, -- G_IO_ERROR_CANT_CREATE_BACKUP, -- _("Backups not supported")); -- } -- else -- { -- /* Return G_IO_ERROR_NOT_SUPPORTED instead of G_IO_ERROR_CANT_CREATE_BACKUP -- * to be proceeded with copy and delete fallback (see g_file_move). */ -- g_vfs_job_failed_literal (G_VFS_JOB (job), -- G_IO_ERROR, -- G_IO_ERROR_NOT_SUPPORTED, -- "Operation not supported"); -- } -+ body = g_vfs_backend_dav_send_finish (backend, result, &error); - -+ if (!body) -+ { -+ g_vfs_job_failed_from_error (data->job, error); -+ copy_data_free (data); -+ g_object_unref (msg); -+ g_clear_error (&error); - return; - } - -- source_uri = g_vfs_backend_dav_uri_for_path (backend, source, FALSE); -- msg = soup_message_new_from_uri (SOUP_METHOD_MOVE, source_uri); -- target_uri = g_vfs_backend_dav_uri_for_path (backend, destination, FALSE); -- -- res = stat_location (backend, target_uri, &target_ft, NULL, NULL, &error); -- if (!res && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) -+ status = soup_message_get_status (msg); -+ if (!SOUP_STATUS_IS_SUCCESSFUL (status)) - { -- g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -- goto error; -+ http_job_failed (data->job, msg); -+ g_object_unref (msg); -+ copy_data_free (data); -+ return; - } -- g_clear_error (&error); - -- stat_res = stat_location (backend, source_uri, &source_ft, &file_size, NULL, &error); -- if (res) -+ g_object_unref (body); -+ g_object_unref (msg); -+ -+ try_move_do (backend, data); -+} -+ -+static void -+try_move_source_stat_cb (GObject *source, GAsyncResult *result, -+ gpointer user_data) -+{ -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ CopyData *data = user_data; -+ GError *error = NULL; -+ -+ data->source_res = stat_location_finish (backend, &data->source_ft, -+ &data->file_size, NULL, -+ result, &error); -+ -+ if (data->target_res) - { -- if (flags & G_FILE_COPY_OVERWRITE) -+ if (data->flags & G_FILE_COPY_OVERWRITE) - { -- if (stat_res) -+ if (data->source_res) - { -- if (target_ft == G_FILE_TYPE_DIRECTORY) -+ if (data->target_ft == G_FILE_TYPE_DIRECTORY) - { -- if (source_ft == G_FILE_TYPE_DIRECTORY) -- g_vfs_job_failed_literal (G_VFS_JOB(job), -+ if (data->source_ft == G_FILE_TYPE_DIRECTORY) -+ g_vfs_job_failed_literal (G_VFS_JOB(data->job), - G_IO_ERROR, - G_IO_ERROR_WOULD_MERGE, - _("Can’t move directory over directory")); - else -- g_vfs_job_failed_literal (G_VFS_JOB(job), -+ g_vfs_job_failed_literal (G_VFS_JOB(data->job), - G_IO_ERROR, - G_IO_ERROR_IS_DIRECTORY, - _("Can’t move over directory")); -- goto error; -+ copy_data_free (data); -+ return; - } -- else if (source_ft == G_FILE_TYPE_DIRECTORY) -+ else if (data->source_ft == G_FILE_TYPE_DIRECTORY) - { - /* Overwriting a file with a directory, first remove the - * file */ - SoupMessage *msg; - - msg = soup_message_new_from_uri (SOUP_METHOD_DELETE, -- target_uri); -- body = g_vfs_backend_dav_send (backend, msg, TRUE, &error); -- if (!body) -- { -- g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -- goto error; -- } -- -- status = soup_message_get_status (msg); -- if (!SOUP_STATUS_IS_SUCCESSFUL (status)) -- { -- http_job_failed (G_VFS_JOB (job), msg); -- goto error; -- } -- g_object_unref (body); -- g_object_unref (msg); -+ data->target_uri); -+ -+ dav_message_connect_signals (msg, backend); -+ -+ g_vfs_backend_dav_send_async (backend, msg, -+ try_move_target_delete_cb, -+ data); -+ return; - } - } - else - { -- g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -- goto error; -+ g_vfs_job_failed_from_error (data->job, error); -+ copy_data_free (data); -+ g_clear_error (&error); -+ return; - } - } - else - { -- g_vfs_job_failed_literal (G_VFS_JOB(job), -+ g_vfs_job_failed_literal (G_VFS_JOB(data->job), - G_IO_ERROR, - G_IO_ERROR_EXISTS, - _("Target file exists")); -- goto error; -+ copy_data_free (data); -+ g_clear_error (&error); -+ return; -+ } -+ } -+ -+ try_move_do (backend, data); -+} -+ -+static void -+try_move_target_stat_cb (GObject *source, GAsyncResult *result, -+ gpointer user_data) -+{ -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ CopyData *data = user_data; -+ gboolean res; -+ GError *error = NULL; -+ -+ res = stat_location_finish (backend, &data->target_ft, NULL, NULL, -+ result, &error); -+ -+ if (!res && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) -+ { -+ g_vfs_job_failed_from_error (data->job, error); -+ g_clear_error (&error); -+ copy_data_free (data); -+ return; -+ } -+ -+ g_clear_error (&error); -+ -+ data->target_res = res; -+ -+ stat_location_async (backend, data->source_uri, FALSE, -+ try_move_source_stat_cb, data); -+} -+ -+static gboolean -+try_move (GVfsBackend *backend, -+ GVfsJobMove *job, -+ const char *source, -+ const char *destination, -+ GFileCopyFlags flags, -+ GFileProgressCallback progress_callback, -+ gpointer progress_callback_data) -+{ -+ CopyData *data = g_slice_new0 (CopyData); -+ data->job = G_VFS_JOB (job); -+ data->flags = flags; -+ data->progress_callback = progress_callback; -+ data->progress_callback_data = progress_callback_data; -+ -+ if (flags & G_FILE_COPY_BACKUP) -+ { -+ if (flags & G_FILE_COPY_NO_FALLBACK_FOR_MOVE) -+ { -+ g_vfs_job_failed_literal (G_VFS_JOB (job), -+ G_IO_ERROR, -+ G_IO_ERROR_CANT_CREATE_BACKUP, -+ _("Backups not supported")); -+ } -+ else -+ { -+ /* Return G_IO_ERROR_NOT_SUPPORTED instead of G_IO_ERROR_CANT_CREATE_BACKUP -+ * to be proceeded with copy and delete fallback (see g_file_move). */ -+ g_vfs_job_failed_literal (G_VFS_JOB (job), -+ G_IO_ERROR, -+ G_IO_ERROR_NOT_SUPPORTED, -+ "Operation not supported"); - } -+ -+ copy_data_free (data); -+ return TRUE; - } - -- message_add_destination_header (msg, target_uri); -- message_add_overwrite_header (msg, flags & G_FILE_COPY_OVERWRITE); -+ data->source_uri = g_vfs_backend_dav_uri_for_path (backend, source, FALSE); -+ data->msg = soup_message_new_from_uri (SOUP_METHOD_MOVE, data->source_uri); -+ data->target_uri = g_vfs_backend_dav_uri_for_path (backend, destination, FALSE); -+ -+ dav_message_connect_signals (data->msg, backend); -+ -+ stat_location_async (backend, data->target_uri, FALSE, -+ try_move_target_stat_cb, data); -+ return TRUE; -+} -+ -+static void -+try_copy_do_cb (GObject *source, GAsyncResult *result, gpointer user_data) -+{ -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ CopyData *data = user_data; -+ GInputStream *body; -+ GError *error = NULL; -+ guint status; -+ -+ body = g_vfs_backend_dav_send_finish (backend, result, &error); - -- body = g_vfs_backend_dav_send (backend, msg, TRUE, &error); - if (!body) - { -- g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -- goto error; -+ g_vfs_job_failed_from_error (data->job, error); -+ copy_data_free (data); -+ return; - } - -- /* See do_set_display_name () for the explanation of the PRECONDITION_FAILED -+ /* See try_set_display_name () for the explanation of the PRECONDITION_FAILED - * and IS_REDIRECTION handling below. */ -- status = soup_message_get_status (msg); -+ status = soup_message_get_status (data->msg); - if (SOUP_STATUS_IS_SUCCESSFUL (status)) - { -- if (stat_res && progress_callback) -- progress_callback (file_size, file_size, progress_callback_data); -- g_vfs_job_succeeded (G_VFS_JOB (job)); -+ if (data->progress_callback) -+ data->progress_callback (data->file_size, data->file_size, -+ data->progress_callback_data); -+ g_vfs_job_succeeded (data->job); - } - else if (status == SOUP_STATUS_PRECONDITION_FAILED || - SOUP_STATUS_IS_REDIRECTION (status)) -- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, -+ g_vfs_job_failed (data->job, G_IO_ERROR, - G_IO_ERROR_EXISTS, - _("Target file already exists")); - else -- http_job_failed (G_VFS_JOB (job), msg); -+ http_job_failed (data->job, data->msg); - -- error: -- g_clear_object (&body); -- g_object_unref (msg); -- g_clear_error (&error); -- g_uri_unref (source_uri); -- g_uri_unref (target_uri); -+ g_object_unref (body); -+ copy_data_free (data); - } - - static void --do_copy (GVfsBackend *backend, -- GVfsJobCopy *job, -- const char *source, -- const char *destination, -- GFileCopyFlags flags, -- GFileProgressCallback progress_callback, -- gpointer progress_callback_data) -+try_copy_target_stat_cb (GObject *source, GAsyncResult *result, -+ gpointer user_data) - { -- GInputStream *body; -- SoupMessage *msg; -- GUri *source_uri; -- GUri *target_uri; -- guint status; -- GFileType source_ft, target_ft; -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ CopyData *data = user_data; - GError *error = NULL; -- gboolean res; -- gint64 file_size; -- -- if (flags & G_FILE_COPY_BACKUP) -- { -- /* Return G_IO_ERROR_NOT_SUPPORTED instead of -- * G_IO_ERROR_CANT_CREATE_BACKUP to proceed with the GIO fallback -- * copy. */ -- g_vfs_job_failed_literal (G_VFS_JOB (job), -- G_IO_ERROR, -- G_IO_ERROR_NOT_SUPPORTED, -- "Operation not supported"); -- return; -- } -- -- source_uri = g_vfs_backend_dav_uri_for_path (backend, source, FALSE); -- target_uri = g_vfs_backend_dav_uri_for_path (backend, destination, FALSE); - -- res = stat_location (backend, source_uri, &source_ft, &file_size, NULL, &error); -- if (!res) -- { -- g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -- goto error; -- } -+ data->target_res = stat_location_finish (backend, &data->target_ft, -+ NULL, NULL, result, &error); - -- res = stat_location (backend, target_uri, &target_ft, NULL, NULL, &error); -- if (res) -+ if (data->target_res) - { -- if (flags & G_FILE_COPY_OVERWRITE) -+ if (data->flags & G_FILE_COPY_OVERWRITE) - { -- if (target_ft == G_FILE_TYPE_DIRECTORY) -+ if (data->target_ft == G_FILE_TYPE_DIRECTORY) - { -- if (source_ft == G_FILE_TYPE_DIRECTORY) -- g_vfs_job_failed_literal (G_VFS_JOB(job), -+ if (data->source_ft == G_FILE_TYPE_DIRECTORY) -+ g_vfs_job_failed_literal (G_VFS_JOB(data->job), - G_IO_ERROR, - G_IO_ERROR_WOULD_MERGE, - _("Can’t copy directory over directory")); - else -- g_vfs_job_failed_literal (G_VFS_JOB(job), -+ g_vfs_job_failed_literal (G_VFS_JOB(data->job), - G_IO_ERROR, - G_IO_ERROR_IS_DIRECTORY, - _("File is directory")); -- goto error; -+ copy_data_free (data); -+ return; - } - } - else - { -- g_vfs_job_failed_literal (G_VFS_JOB (job), -+ g_vfs_job_failed_literal (data->job, - G_IO_ERROR, - G_IO_ERROR_EXISTS, - _("Target file already exists")); -- goto error; -+ copy_data_free (data); -+ return; - } - } - else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) - { -- g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -- goto error; -+ g_vfs_job_failed_from_error (data->job, error); -+ g_clear_error (&error); -+ copy_data_free (data); -+ return; - } - -- if (source_ft == G_FILE_TYPE_DIRECTORY) -+ g_clear_error (&error); -+ -+ if (data->source_ft == G_FILE_TYPE_DIRECTORY) - { -- g_vfs_job_failed_literal (G_VFS_JOB (job), -+ g_vfs_job_failed_literal (data->job, - G_IO_ERROR, - G_IO_ERROR_WOULD_RECURSE, - _("Can’t recursively copy directory")); -- goto error; -+ copy_data_free (data); -+ return; - } - -- msg = soup_message_new_from_uri (SOUP_METHOD_COPY, source_uri); -- message_add_destination_header (msg, target_uri); -- message_add_overwrite_header (msg, flags & G_FILE_COPY_OVERWRITE); -+ data->msg = soup_message_new_from_uri (SOUP_METHOD_COPY, data->source_uri); -+ message_add_destination_header (data->msg, data->target_uri); -+ message_add_overwrite_header (data->msg, data->flags & G_FILE_COPY_OVERWRITE); - -- body = g_vfs_backend_dav_send (backend, msg, TRUE, &error); -- if (!body) -+ dav_message_connect_signals (data->msg, backend); -+ -+ g_vfs_backend_dav_send_async (backend, data->msg, try_copy_do_cb, data); -+} -+ -+static void -+try_copy_source_stat_cb (GObject *source, GAsyncResult *result, -+ gpointer user_data) -+{ -+ GVfsBackend *backend = G_VFS_BACKEND (source); -+ CopyData *data = user_data; -+ gboolean res; -+ GError *error = NULL; -+ -+ res = stat_location_finish (backend, &data->source_ft, &data->file_size, -+ NULL, result, &error); -+ -+ if (!res) - { -- g_vfs_job_failed_from_error (G_VFS_JOB (job), error); -- g_object_unref (msg); -- goto error; -+ g_vfs_job_failed_from_error (data->job, error); -+ g_clear_error (&error); -+ copy_data_free (data); -+ return; - } - -- /* See do_set_display_name () for the explanation of the PRECONDITION_FAILED -- * and IS_REDIRECTION handling below. */ -- status = soup_message_get_status (msg); -- if (SOUP_STATUS_IS_SUCCESSFUL (status)) -+ g_clear_error (&error); -+ -+ data->source_res = res; -+ -+ stat_location_async (backend, data->target_uri, FALSE, -+ try_copy_target_stat_cb, data); -+} -+ -+static gboolean -+try_copy (GVfsBackend *backend, -+ GVfsJobCopy *job, -+ const char *source, -+ const char *destination, -+ GFileCopyFlags flags, -+ GFileProgressCallback progress_callback, -+ gpointer progress_callback_data) -+{ -+ CopyData *data = g_slice_new0 (CopyData); -+ data->job = G_VFS_JOB (job); -+ data->flags = flags; -+ data->progress_callback = progress_callback; -+ data->progress_callback_data = progress_callback_data; -+ -+ if (flags & G_FILE_COPY_BACKUP) - { -- if (progress_callback) -- progress_callback (file_size, file_size, progress_callback_data); -- g_vfs_job_succeeded (G_VFS_JOB (job)); -+ /* Return G_IO_ERROR_NOT_SUPPORTED instead of -+ * G_IO_ERROR_CANT_CREATE_BACKUP to proceed with the GIO fallback -+ * copy. */ -+ g_vfs_job_failed_literal (G_VFS_JOB (job), -+ G_IO_ERROR, -+ G_IO_ERROR_NOT_SUPPORTED, -+ "Operation not supported"); -+ -+ copy_data_free (data); -+ return TRUE; - } -- else if (status == SOUP_STATUS_PRECONDITION_FAILED || -- SOUP_STATUS_IS_REDIRECTION (status)) -- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, -- G_IO_ERROR_EXISTS, -- _("Target file already exists")); -- else -- http_job_failed (G_VFS_JOB (job), msg); - -- g_object_unref (body); -- g_object_unref (msg); -+ data->source_uri = g_vfs_backend_dav_uri_for_path (backend, source, FALSE); -+ data->target_uri = g_vfs_backend_dav_uri_for_path (backend, destination, FALSE); - --error: -- g_clear_error (&error); -- g_uri_unref (source_uri); -- g_uri_unref (target_uri); -+ stat_location_async (backend, data->source_uri, FALSE, -+ try_copy_source_stat_cb, data); -+ return TRUE; - } - - #define CHUNK_SIZE 65536 -@@ -3459,7 +3919,7 @@ static void - push_done (GObject *source, GAsyncResult *result, gpointer user_data) - { - GInputStream *body; -- GVfsJob *job = G_VFS_JOB (user_data);; -+ GVfsJob *job = G_VFS_JOB (user_data); - GError *error = NULL; - - body = soup_session_send_finish (SOUP_SESSION (source), result, &error); -@@ -3488,7 +3948,7 @@ push_stat_dest_cb (GObject *source, GAsyncResult *result, gpointer user_data) - return; - } - -- if (stat_location_finish (handle->msg, body, &type, NULL, NULL)) -+ if (stat_location_end (handle->msg, body, &type, NULL, NULL)) - { - if (!(handle->op_job->flags & G_FILE_COPY_OVERWRITE)) - { -@@ -3527,8 +3987,11 @@ push_stat_dest_cb (GObject *source, GAsyncResult *result, gpointer user_data) - g_signal_connect (handle->msg, "finished", - G_CALLBACK (push_finished), handle); - -- g_vfs_backend_dav_send_async (handle->backend, handle->msg, TRUE, -- push_done, handle->job); -+ dav_message_connect_signals (handle->msg, handle->backend); -+ -+ soup_session_send_async (G_VFS_BACKEND_HTTP (handle->backend)->session, -+ handle->msg, G_PRIORITY_DEFAULT, -+ NULL, push_done, handle->job); - } - - static void -@@ -3545,9 +4008,13 @@ push_source_fstat_cb (GObject *source, GAsyncResult *res, gpointer user_data) - handle->size = g_file_info_get_size (info); - g_object_unref (info); - -- handle->msg = stat_location_begin (handle->uri, FALSE); -- g_vfs_backend_dav_send_async (handle->backend, handle->msg, TRUE, -- push_stat_dest_cb, handle); -+ handle->msg = stat_location_start (handle->uri, FALSE); -+ -+ dav_message_connect_signals (handle->msg, handle->backend); -+ -+ soup_session_send_async (G_VFS_BACKEND_HTTP (handle->backend)->session, -+ handle->msg, G_PRIORITY_DEFAULT, NULL, -+ push_stat_dest_cb, handle); - } - else - { -@@ -3675,26 +4142,23 @@ g_vfs_backend_dav_class_init (GVfsBackendDavClass *klass) - - backend_class = G_VFS_BACKEND_CLASS (klass); - -- backend_class->try_mount = NULL; -- backend_class->mount = do_mount; -- backend_class->try_query_info = NULL; -- backend_class->query_info = do_query_info; -- backend_class->try_query_fs_info = NULL; -- backend_class->query_fs_info = do_query_fs_info; -- backend_class->enumerate = do_enumerate; -- backend_class->try_open_for_read = try_open_for_read; -- backend_class->try_create = try_create; -- backend_class->try_replace = try_replace; -- backend_class->try_write = try_write; -- backend_class->seek_on_write = do_seek_on_write; -- backend_class->truncate = do_truncate; -- backend_class->try_close_write = try_close_write; -- backend_class->make_directory = do_make_directory; -- backend_class->delete = do_delete; -- backend_class->set_display_name = do_set_display_name; -- backend_class->move = do_move; -- backend_class->copy = do_copy; -- backend_class->try_push = try_push; -+ backend_class->try_mount = try_mount; -+ backend_class->try_query_info = try_query_info; -+ backend_class->try_query_fs_info = try_query_fs_info; -+ backend_class->try_enumerate = try_enumerate; -+ backend_class->try_open_for_read = try_open_for_read; -+ backend_class->try_create = try_create; -+ backend_class->try_replace = try_replace; -+ backend_class->try_write = try_write; -+ backend_class->seek_on_write = do_seek_on_write; -+ backend_class->truncate = do_truncate; -+ backend_class->try_close_write = try_close_write; -+ backend_class->try_make_directory = try_make_directory; -+ backend_class->try_delete = try_delete; -+ backend_class->try_set_display_name = try_set_display_name; -+ backend_class->try_move = try_move; -+ backend_class->try_copy = try_copy; -+ backend_class->try_push = try_push; - - /* override the maximum number of connections, since the libsoup defaults - * of 10 and 2 respectively are too low and may cause backend lockups when --- -2.35.1 - diff --git a/gvfs.spec b/gvfs.spec index 7680de6..3df3f5a 100644 --- a/gvfs.spec +++ b/gvfs.spec @@ -21,25 +21,14 @@ %global udisks2_version 1.97 Name: gvfs -Version: 1.50.0 -Release: 4%{?dist} +Version: 1.50.1 +Release: 1%{?dist} Summary: Backends for the gio framework in GLib License: GPLv3 and LGPLv2+ and BSD and MPLv2.0 URL: https://wiki.gnome.org/Projects/gvfs Source0: https://download.gnome.org/sources/gvfs/1.50/gvfs-%{version}.tar.xz -# https://bugzilla.redhat.com/show_bug.cgi?id=2066717 -Patch0: dav-Fix-crashes-caused-by-extra-unref.patch - -# https://bugzilla.redhat.com/show_bug.cgi?id=2062465 -Patch1: dav-Do-not-lose-userinfo-when-copying-URIs.patch -Patch2: dav-Rewrite-to-libsoup-async-API-to-fix-crashes.patch - -# https://bugzilla.redhat.com/show_bug.cgi?id=2068976 -# https://bugzilla.redhat.com/show_bug.cgi?id=2072885 -Patch3: smb-Ignore-EINVAL-for-kerberos-ccache-login.patch - BuildRequires: meson BuildRequires: gcc BuildRequires: pkgconfig(glib-2.0) >= %{glib2_version} @@ -432,6 +421,9 @@ killall -USR1 gvfsd >&/dev/null || : %{_datadir}/installed-tests %changelog +* Tue Apr 26 2022 Ondrej Holy - 1.50.1-1 +- Update to 1.50.1 (#2078857) + * Wed Apr 13 2022 Ondrej Holy - 1.50.0-4 - Ignore EINVAL for kerberos/ccache login to fix SMB mounting (#2068976, #2072885) diff --git a/smb-Ignore-EINVAL-for-kerberos-ccache-login.patch b/smb-Ignore-EINVAL-for-kerberos-ccache-login.patch deleted file mode 100644 index 28256c9..0000000 --- a/smb-Ignore-EINVAL-for-kerberos-ccache-login.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 747c7f6ea6c8b6a7ccd008bb47996ba7eb169bcc Mon Sep 17 00:00:00 2001 -From: Ondrej Holy -Date: Mon, 11 Apr 2022 10:54:04 +0200 -Subject: [PATCH] smb: Ignore EINVAL for kerberos/ccache login - -With samba 4.16.0, mount operation fails with the "Invalid Argument" error -when kerberos/ccache is misconfigured. Ignore this error, so user get a chance -to login using the password... - -Fixes: https://gitlab.gnome.org/GNOME/gvfs/-/issues/611 ---- - daemon/gvfsbackendsmb.c | 8 +++++++- - daemon/gvfsbackendsmbbrowse.c | 10 ++++++++-- - 2 files changed, 15 insertions(+), 3 deletions(-) - -diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c -index 33d1a209..776b67bc 100644 ---- a/daemon/gvfsbackendsmb.c -+++ b/daemon/gvfsbackendsmb.c -@@ -513,7 +513,13 @@ do_mount (GVfsBackend *backend, - if (res == 0) - break; - -- if (op_backend->mount_cancelled || (errsv != EACCES && errsv != EPERM)) -+ if (errsv == EINVAL && op_backend->mount_try <= 1 && op_backend->user == NULL) -+ { -+ /* EINVAL is "expected" when kerberos/ccache is misconfigured, see: -+ * https://gitlab.gnome.org/GNOME/gvfs/-/issues/611 -+ */ -+ } -+ else if (op_backend->mount_cancelled || (errsv != EACCES && errsv != EPERM)) - { - g_debug ("do_mount - (errno != EPERM && errno != EACCES), cancelled = %d, breaking\n", op_backend->mount_cancelled); - break; -diff --git a/daemon/gvfsbackendsmbbrowse.c b/daemon/gvfsbackendsmbbrowse.c -index 57bae9db..7e8facfb 100644 ---- a/daemon/gvfsbackendsmbbrowse.c -+++ b/daemon/gvfsbackendsmbbrowse.c -@@ -967,8 +967,14 @@ do_mount (GVfsBackend *backend, - uri, op_backend->mount_try, dir, op_backend->mount_cancelled, - errsv, g_strerror (errsv)); - -- if (dir == NULL && -- (op_backend->mount_cancelled || (errsv != EPERM && errsv != EACCES))) -+ if (errsv == EINVAL && op_backend->mount_try == 0 && op_backend->user == NULL) -+ { -+ /* EINVAL is "expected" when kerberos is misconfigured, see: -+ * https://gitlab.gnome.org/GNOME/gvfs/-/issues/611 -+ */ -+ } -+ else if (dir == NULL && -+ (op_backend->mount_cancelled || (errsv != EPERM && errsv != EACCES))) - { - g_debug ("do_mount - (errno != EPERM && errno != EACCES), cancelled = %d, breaking\n", op_backend->mount_cancelled); - break; --- -2.35.1 - diff --git a/sources b/sources index d371b30..4dfcb49 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (gvfs-1.50.0.tar.xz) = 6eea3c59b239fe9674a83db4e182c0ea2ab7d56e29f5d5c4a7af9cb3cb0fd9222721796754f2f502291049c158e8bd3771cbc5262d10bfa684c207cb3281dcce +SHA512 (gvfs-1.50.1.tar.xz) = 7a1ea47658dbd74673e1aea7c344d3f9e8a26fab844a26220cedcb19da6b4a0cac6b369d2b5107f649d6e7b2331894c89df04c6dce3630be4b289e23f56127a5