1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 * Author: Alexander Larsson <alexl@redhat.com>
21 */
22
23 #include <config.h>
24
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29
30 #include <glib.h>
31 #include <glib/gi18n.h>
32 #include <gio/gio.h>
33 #include "gvfsjob.h"
34 #include "gvfsjobsource.h"
35
36 /* TODO: Real P_() */
37 #define P_(_x) (_x)
38
39 enum {
40 PROP_0
41 };
42
43 enum {
44 CANCELLED,
45 SEND_REPLY,
46 FINISHED,
47 NEW_SOURCE,
48 LAST_SIGNAL
49 };
50
51 struct _GVfsJobPrivate
52 {
53 int dummy;
54 };
55
56 G_DEFINE_TYPE_WITH_PRIVATE (GVfsJob, g_vfs_job, G_TYPE_OBJECT)
57
58 static guint signals[LAST_SIGNAL] = { 0 };
59
60 static void g_vfs_job_get_property (GObject *object,
61 guint prop_id,
62 GValue *value,
63 GParamSpec *pspec);
64 static void g_vfs_job_set_property (GObject *object,
65 guint prop_id,
66 const GValue *value,
67 GParamSpec *pspec);
68
69 static void
g_vfs_job_finalize(GObject * object)70 g_vfs_job_finalize (GObject *object)
71 {
72 GVfsJob *job;
73
74 job = G_VFS_JOB (object);
75
76 if (job->error)
77 g_error_free (job->error);
78
79 if (job->backend_data_destroy)
80 job->backend_data_destroy (job->backend_data);
81
82 g_object_unref (job->cancellable);
83
84 if (G_OBJECT_CLASS (g_vfs_job_parent_class)->finalize)
85 (*G_OBJECT_CLASS (g_vfs_job_parent_class)->finalize) (object);
86 }
87
88 static void
g_vfs_job_class_init(GVfsJobClass * klass)89 g_vfs_job_class_init (GVfsJobClass *klass)
90 {
91 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
92
93 gobject_class->finalize = g_vfs_job_finalize;
94 gobject_class->set_property = g_vfs_job_set_property;
95 gobject_class->get_property = g_vfs_job_get_property;
96
97 signals[CANCELLED] =
98 g_signal_new ("cancelled",
99 G_TYPE_FROM_CLASS (gobject_class),
100 G_SIGNAL_RUN_LAST,
101 G_STRUCT_OFFSET (GVfsJobClass, cancelled),
102 NULL, NULL,
103 g_cclosure_marshal_VOID__VOID,
104 G_TYPE_NONE, 0);
105 signals[FINISHED] =
106 g_signal_new ("finished",
107 G_TYPE_FROM_CLASS (gobject_class),
108 G_SIGNAL_RUN_FIRST,
109 G_STRUCT_OFFSET (GVfsJobClass, finished),
110 NULL, NULL,
111 g_cclosure_marshal_VOID__VOID,
112 G_TYPE_NONE, 0);
113 signals[NEW_SOURCE] =
114 g_signal_new ("new-source",
115 G_TYPE_FROM_CLASS (gobject_class),
116 G_SIGNAL_RUN_LAST,
117 G_STRUCT_OFFSET (GVfsJobClass, new_source),
118 NULL, NULL,
119 g_cclosure_marshal_VOID__OBJECT,
120 G_TYPE_NONE, 1, G_VFS_TYPE_JOB_SOURCE);
121 signals[SEND_REPLY] =
122 g_signal_new ("send-reply",
123 G_TYPE_FROM_CLASS (gobject_class),
124 G_SIGNAL_RUN_LAST,
125 G_STRUCT_OFFSET (GVfsJobClass, send_reply),
126 NULL, NULL,
127 g_cclosure_marshal_VOID__VOID,
128 G_TYPE_NONE, 0);
129 }
130
131 static void
g_vfs_job_init(GVfsJob * job)132 g_vfs_job_init (GVfsJob *job)
133 {
134 job->priv = g_vfs_job_get_instance_private (job);
135
136 job->cancellable = g_cancellable_new ();
137
138 }
139
140 void
g_vfs_job_set_backend_data(GVfsJob * job,gpointer backend_data,GDestroyNotify destroy)141 g_vfs_job_set_backend_data (GVfsJob *job,
142 gpointer backend_data,
143 GDestroyNotify destroy)
144 {
145 if (job->backend_data_destroy)
146 {
147 job->backend_data_destroy (job->backend_data);
148 }
149
150 job->backend_data = backend_data;
151 job->backend_data_destroy = destroy;
152 }
153
154 static void
g_vfs_job_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)155 g_vfs_job_set_property (GObject *object,
156 guint prop_id,
157 const GValue *value,
158 GParamSpec *pspec)
159 {
160 switch (prop_id)
161 {
162 default:
163 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
164 break;
165 }
166 }
167
168 static void
g_vfs_job_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)169 g_vfs_job_get_property (GObject *object,
170 guint prop_id,
171 GValue *value,
172 GParamSpec *pspec)
173 {
174 switch (prop_id)
175 {
176 default:
177 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
178 break;
179 }
180 }
181
182 void
g_vfs_job_run(GVfsJob * job)183 g_vfs_job_run (GVfsJob *job)
184 {
185 GVfsJobClass *class;
186
187 class = G_VFS_JOB_GET_CLASS (job);
188
189 /* Ensure that the job lives durint the whole
190 * lifetime of the call, as it may disappear when
191 * we call g_vfs_job_succeed/fail()
192 */
193 g_object_ref (job);
194
195 class->run (job);
196
197 g_object_unref (job);
198 }
199
200 gboolean
g_vfs_job_try(GVfsJob * job)201 g_vfs_job_try (GVfsJob *job)
202 {
203 GVfsJobClass *class;
204 gboolean res;
205
206 class = G_VFS_JOB_GET_CLASS (job);
207
208 /* Ensure that the job lives during the whole
209 * lifetime of the call, as it may disappear when
210 * we call g_vfs_job_succeed/fail()
211 */
212 g_object_ref (job);
213 res = class->try (job);
214 g_object_unref (job);
215
216 return res;
217 }
218
219 void
g_vfs_job_cancel(GVfsJob * job)220 g_vfs_job_cancel (GVfsJob *job)
221 {
222 if (job->cancelled || job->finished)
223 return;
224
225 job->cancelled = TRUE;
226 g_signal_emit (job, signals[CANCELLED], 0);
227 g_cancellable_cancel (job->cancellable);
228 }
229
230 static void
g_vfs_job_send_reply(GVfsJob * job)231 g_vfs_job_send_reply (GVfsJob *job)
232 {
233 job->sent_reply = TRUE;
234 g_signal_emit (job, signals[SEND_REPLY], 0);
235 }
236
237 void
g_vfs_job_failed(GVfsJob * job,GQuark domain,gint code,const gchar * format,...)238 g_vfs_job_failed (GVfsJob *job,
239 GQuark domain,
240 gint code,
241 const gchar *format,
242 ...)
243 {
244 va_list args;
245 char *message;
246
247 va_start (args, format);
248 message = g_strdup_vprintf (format, args);
249 va_end (args);
250
251 g_vfs_job_failed_literal (job, domain, code, message);
252 g_free (message);
253 }
254
255 void
g_vfs_job_failed_literal(GVfsJob * job,GQuark domain,gint code,const gchar * message)256 g_vfs_job_failed_literal (GVfsJob *job,
257 GQuark domain,
258 gint code,
259 const gchar *message)
260 {
261 if (job->failed)
262 return;
263
264 job->failed = TRUE;
265
266 job->error = g_error_new_literal (domain, code, message);
267
268 g_vfs_job_send_reply (job);
269 }
270
271 void
g_vfs_job_failed_from_error(GVfsJob * job,const GError * error)272 g_vfs_job_failed_from_error (GVfsJob * job,
273 const GError *error)
274 {
275 if (job->failed)
276 return;
277
278 job->failed = TRUE;
279 job->error = g_error_copy (error);
280 g_vfs_job_send_reply (job);
281 }
282
283 void
g_vfs_job_failed_from_errno(GVfsJob * job,gint errno_arg)284 g_vfs_job_failed_from_errno (GVfsJob *job,
285 gint errno_arg)
286 {
287 GError *error = NULL;
288
289 g_set_error_literal (&error, G_IO_ERROR,
290 g_io_error_from_errno (errno_arg),
291 g_strerror (errno_arg));
292 g_vfs_job_failed_from_error (job, error);
293 g_error_free (error);
294 }
295
296 void
g_vfs_job_succeeded(GVfsJob * job)297 g_vfs_job_succeeded (GVfsJob *job)
298 {
299 job->failed = FALSE;
300 g_vfs_job_send_reply (job);
301 }
302
303
304 gboolean
g_vfs_job_is_finished(GVfsJob * job)305 g_vfs_job_is_finished (GVfsJob *job)
306 {
307 return job->finished;
308 }
309
310 gboolean
g_vfs_job_is_cancelled(GVfsJob * job)311 g_vfs_job_is_cancelled (GVfsJob *job)
312 {
313 return job->cancelled;
314 }
315
316 /* Might be called on an i/o thread */
317 void
g_vfs_job_emit_finished(GVfsJob * job)318 g_vfs_job_emit_finished (GVfsJob *job)
319 {
320 g_assert (!job->finished);
321
322 job->finished = TRUE;
323 g_signal_emit (job, signals[FINISHED], 0);
324 }
325