[gvfs/gnome-3-8] Fix daemon crash when cancelling channel operations
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gvfs/gnome-3-8] Fix daemon crash when cancelling channel operations
- Date: Thu, 4 Apr 2013 17:29:44 +0000 (UTC)
commit d667f6fe956d8661710f9fe5ad3e54d9b24aa04a
Author: Alexander Larsson <alexl redhat com>
Date: Thu Apr 4 10:25:29 2013 +0200
Fix daemon crash when cancelling channel operations
The error handling in gvfschannel.c:start_queued_request() when
there was an error creating the job or when the request was cancelled
caused problems. It didn't set current_job, yet it called
g_vfs_channel_send_error() which eventually resulted in a
call to send_reply_cb which crashed as it assumed current_job
was set.
Also, not returning TRUE for started_job when we sent an error
is problematic as we then could start the next job which caused
us to have two outstanding jobs on the same channel mixing things up
badly.
https://bugzilla.gnome.org/show_bug.cgi?id=675181
daemon/Makefile.am | 1 +
daemon/gvfsbackend.h | 1 +
daemon/gvfschannel.c | 52 ++++++++++++------------
daemon/gvfsjoberror.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++
daemon/gvfsjoberror.h | 61 +++++++++++++++++++++++++++
5 files changed, 199 insertions(+), 26 deletions(-)
---
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 71b8ad6..e53bd85 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -170,6 +170,7 @@ libdaemon_la_SOURCES = \
gvfsjobpollmountable.c gvfsjobpollmountable.h \
gvfsjobopenforread.c gvfsjobopenforread.h \
gvfsjobopeniconforread.c gvfsjobopeniconforread.h \
+ gvfsjoberror.c gvfsjoberror.h \
gvfsjobread.c gvfsjobread.h \
gvfsjobseekread.c gvfsjobseekread.h \
gvfsjobcloseread.c gvfsjobcloseread.h \
diff --git a/daemon/gvfsbackend.h b/daemon/gvfsbackend.h
index a69912b..e340cb9 100644
--- a/daemon/gvfsbackend.h
+++ b/daemon/gvfsbackend.h
@@ -74,6 +74,7 @@ typedef struct _GVfsJobPull GVfsJobPull;
typedef struct _GVfsJobSetAttribute GVfsJobSetAttribute;
typedef struct _GVfsJobQueryAttributes GVfsJobQueryAttributes;
typedef struct _GVfsJobCreateMonitor GVfsJobCreateMonitor;
+typedef struct _GVfsJobError GVfsJobError;
typedef gpointer GVfsBackendHandle;
diff --git a/daemon/gvfschannel.c b/daemon/gvfschannel.c
index 7a4ace6..ec87cb9 100644
--- a/daemon/gvfschannel.c
+++ b/daemon/gvfschannel.c
@@ -40,6 +40,7 @@
#include <gvfsdaemonutils.h>
#include <gvfsjobcloseread.h>
#include <gvfsjobclosewrite.h>
+#include <gvfsjoberror.h>
#include <gvfsfileinfo.h>
static void g_vfs_channel_job_source_iface_init (GVfsJobSourceIface *iface);
@@ -312,39 +313,38 @@ start_queued_request (GVfsChannel *channel)
channel->priv->queued_requests =
g_list_delete_link (channel->priv->queued_requests,
channel->priv->queued_requests);
-
+
error = NULL;
- job = NULL;
- if (req->cancelled)
+ /* This passes on ownership of req->data */
+ job = class->handle_request (channel,
+ req->command, req->seq_nr,
+ req->arg1, req->arg2,
+ req->data, req->data_len,
+ &error);
+ if (job == NULL)
+ {
+ job = g_vfs_job_error_new (channel, error);
+ g_error_free (error);
+ }
+
+
+ if (job != NULL && req->cancelled)
{
+ /* Ignore the job, although we need to create it to rely
+ on handle_request side effects like seek generations, etc */
+ g_object_unref (job);
error =
g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
_("Operation was cancelled"));
- g_free (req->data); /* Did no pass ownership */
- }
- else
- {
- /* This passes on ownership of req->data */
- job = class->handle_request (channel,
- req->command, req->seq_nr,
- req->arg1, req->arg2,
- req->data, req->data_len,
- &error);
- }
-
- if (job)
- {
- channel->priv->current_job = job;
- channel->priv->current_job_seq_nr = req->seq_nr;
- g_vfs_job_source_new_job (G_VFS_JOB_SOURCE (channel), channel->priv->current_job);
- started_job = TRUE;
- }
- else
- {
- g_vfs_channel_send_error (channel, error);
+ job = g_vfs_job_error_new (channel, error);
g_error_free (error);
}
-
+
+ channel->priv->current_job = job;
+ channel->priv->current_job_seq_nr = req->seq_nr;
+ g_vfs_job_source_new_job (G_VFS_JOB_SOURCE (channel), channel->priv->current_job);
+ started_job = TRUE;
+
g_free (req);
}
diff --git a/daemon/gvfsjoberror.c b/daemon/gvfsjoberror.c
new file mode 100644
index 0000000..c14626f
--- /dev/null
+++ b/daemon/gvfsjoberror.c
@@ -0,0 +1,110 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ */
+
+#include <config.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include "gvfsjoberror.h"
+#include "gvfsdaemonutils.h"
+
+G_DEFINE_TYPE (GVfsJobError, g_vfs_job_error, G_VFS_TYPE_JOB)
+
+static void run (GVfsJob *job);
+static gboolean try (GVfsJob *job);
+static void send_reply (GVfsJob *job);
+
+static void
+g_vfs_job_error_finalize (GObject *object)
+{
+ GVfsJobError *job;
+
+ job = G_VFS_JOB_ERROR (object);
+ g_object_unref (job->channel);
+ g_error_free (job->error);
+
+ if (G_OBJECT_CLASS (g_vfs_job_error_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_vfs_job_error_parent_class)->finalize) (object);
+}
+
+static void
+g_vfs_job_error_class_init (GVfsJobErrorClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GVfsJobClass *job_class = G_VFS_JOB_CLASS (klass);
+
+ gobject_class->finalize = g_vfs_job_error_finalize;
+
+ job_class->run = run;
+ job_class->try = try;
+ job_class->send_reply = send_reply;
+}
+
+static void
+g_vfs_job_error_init (GVfsJobError *job)
+{
+}
+
+GVfsJob *
+g_vfs_job_error_new (GVfsChannel *channel,
+ GError *error)
+{
+ GVfsJobError *job;
+
+ g_print ("g_vfs_job_error_new\n");
+
+ job = g_object_new (G_VFS_TYPE_JOB_ERROR,
+ NULL);
+ job->channel = g_object_ref (channel);
+ job->error = g_error_copy (error);
+
+ return G_VFS_JOB (job);
+}
+
+/* Might be called on an i/o thread */
+static void
+send_reply (GVfsJob *job)
+{
+ GVfsJobError *op_job = G_VFS_JOB_ERROR (job);
+
+ g_print ("g_vfs_job_error send_reply\n");
+
+ g_assert (job->failed);
+
+ g_vfs_channel_send_error (G_VFS_CHANNEL (op_job->channel), job->error);
+}
+
+static void
+run (GVfsJob *job)
+{
+}
+
+static gboolean
+try (GVfsJob *job)
+{
+ g_vfs_job_failed_from_error (job, G_VFS_JOB_ERROR (job)->error);
+}
diff --git a/daemon/gvfsjoberror.h b/daemon/gvfsjoberror.h
new file mode 100644
index 0000000..902e9f8
--- /dev/null
+++ b/daemon/gvfsjoberror.h
@@ -0,0 +1,61 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ */
+
+#ifndef __G_VFS_JOB_ERROR_H__
+#define __G_VFS_JOB_ERROR_H__
+
+#include <gvfsjob.h>
+#include <gvfsbackend.h>
+#include <gvfschannel.h>
+
+G_BEGIN_DECLS
+
+#define G_VFS_TYPE_JOB_ERROR (g_vfs_job_error_get_type ())
+#define G_VFS_JOB_ERROR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_VFS_TYPE_JOB_ERROR, GVfsJobError))
+#define G_VFS_JOB_ERROR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_JOB_ERROR, GVfsJobErrorClass))
+#define G_VFS_IS_JOB_ERROR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_VFS_TYPE_JOB_ERROR))
+#define G_VFS_IS_JOB_ERROR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_VFS_TYPE_JOB_ERROR))
+#define G_VFS_JOB_ERROR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_VFS_TYPE_JOB_ERROR,
GVfsJobErrorClass))
+
+typedef struct _GVfsJobErrorClass GVfsJobErrorClass;
+
+struct _GVfsJobError
+{
+ GVfsJob parent_instance;
+
+ GVfsChannel *channel;
+ GError *error;
+};
+
+struct _GVfsJobErrorClass
+{
+ GVfsJobClass parent_class;
+};
+
+GType g_vfs_job_error_get_type (void) G_GNUC_CONST;
+
+GVfsJob *g_vfs_job_error_new (GVfsChannel *channel,
+ GError *error);
+
+G_END_DECLS
+
+#endif /* __G_VFS_JOB_ERROR_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]