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