gio: port basic I/O classes from GSimpleAsyncResult to GTask
[platform/upstream/glib.git] / gio / gunixoutputstream.c
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., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <fcntl.h>
31
32 #include <glib.h>
33 #include <glib/gstdio.h>
34 #include "gioerror.h"
35 #include "gunixoutputstream.h"
36 #include "gcancellable.h"
37 #include "gsimpleasyncresult.h"
38 #include "gasynchelper.h"
39 #include "gfiledescriptorbased.h"
40 #include "glibintl.h"
41
42
43 /**
44  * SECTION:gunixoutputstream
45  * @short_description: Streaming output operations for UNIX file descriptors
46  * @include: gio/gunixoutputstream.h
47  * @see_also: #GOutputStream
48  *
49  * #GUnixOutputStream implements #GOutputStream for writing to a UNIX
50  * file descriptor, including asynchronous operations. (If the file
51  * descriptor refers to a socket or pipe, this will use poll() to do
52  * asynchronous I/O. If it refers to a regular file, it will fall back
53  * to doing asynchronous I/O in another thread.)
54  *
55  * Note that <filename>&lt;gio/gunixoutputstream.h&gt;</filename> belongs
56  * to the UNIX-specific GIO interfaces, thus you have to use the
57  * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
58  */
59
60 enum {
61   PROP_0,
62   PROP_FD,
63   PROP_CLOSE_FD
64 };
65
66 static void g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface);
67 static void g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface);
68
69 G_DEFINE_TYPE_WITH_CODE (GUnixOutputStream, g_unix_output_stream, G_TYPE_OUTPUT_STREAM,
70                          G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM,
71                                                 g_unix_output_stream_pollable_iface_init)
72                          G_IMPLEMENT_INTERFACE (G_TYPE_FILE_DESCRIPTOR_BASED,
73                                                 g_unix_output_stream_file_descriptor_based_iface_init)
74                          )
75
76 struct _GUnixOutputStreamPrivate {
77   int fd;
78   guint close_fd : 1;
79   guint is_pipe_or_socket : 1;
80 };
81
82 static void     g_unix_output_stream_set_property (GObject              *object,
83                                                    guint                 prop_id,
84                                                    const GValue         *value,
85                                                    GParamSpec           *pspec);
86 static void     g_unix_output_stream_get_property (GObject              *object,
87                                                    guint                 prop_id,
88                                                    GValue               *value,
89                                                    GParamSpec           *pspec);
90 static gssize   g_unix_output_stream_write        (GOutputStream        *stream,
91                                                    const void           *buffer,
92                                                    gsize                 count,
93                                                    GCancellable         *cancellable,
94                                                    GError              **error);
95 static gboolean g_unix_output_stream_close        (GOutputStream        *stream,
96                                                    GCancellable         *cancellable,
97                                                    GError              **error);
98 static void     g_unix_output_stream_close_async  (GOutputStream        *stream,
99                                                    int                   io_priority,
100                                                    GCancellable         *cancellable,
101                                                    GAsyncReadyCallback   callback,
102                                                    gpointer              data);
103 static gboolean g_unix_output_stream_close_finish (GOutputStream        *stream,
104                                                    GAsyncResult         *result,
105                                                    GError              **error);
106
107 static gboolean g_unix_output_stream_pollable_can_poll      (GPollableOutputStream *stream);
108 static gboolean g_unix_output_stream_pollable_is_writable   (GPollableOutputStream *stream);
109 static GSource *g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
110                                                              GCancellable         *cancellable);
111
112 static void
113 g_unix_output_stream_finalize (GObject *object)
114 {
115   G_OBJECT_CLASS (g_unix_output_stream_parent_class)->finalize (object);
116 }
117
118 static void
119 g_unix_output_stream_class_init (GUnixOutputStreamClass *klass)
120 {
121   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
122   GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
123   
124   g_type_class_add_private (klass, sizeof (GUnixOutputStreamPrivate));
125
126   gobject_class->get_property = g_unix_output_stream_get_property;
127   gobject_class->set_property = g_unix_output_stream_set_property;
128   gobject_class->finalize = g_unix_output_stream_finalize;
129
130   stream_class->write_fn = g_unix_output_stream_write;
131   stream_class->close_fn = g_unix_output_stream_close;
132   stream_class->close_async = g_unix_output_stream_close_async;
133   stream_class->close_finish = g_unix_output_stream_close_finish;
134
135    /**
136    * GUnixOutputStream:fd:
137    *
138    * The file descriptor that the stream writes to.
139    *
140    * Since: 2.20
141    */
142   g_object_class_install_property (gobject_class,
143                                    PROP_FD,
144                                    g_param_spec_int ("fd",
145                                                      P_("File descriptor"),
146                                                      P_("The file descriptor to write to"),
147                                                      G_MININT, G_MAXINT, -1,
148                                                      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
149
150   /**
151    * GUnixOutputStream:close-fd:
152    *
153    * Whether to close the file descriptor when the stream is closed.
154    *
155    * Since: 2.20
156    */
157   g_object_class_install_property (gobject_class,
158                                    PROP_CLOSE_FD,
159                                    g_param_spec_boolean ("close-fd",
160                                                          P_("Close file descriptor"),
161                                                          P_("Whether to close the file descriptor when the stream is closed"),
162                                                          TRUE,
163                                                          G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
164 }
165
166 static void
167 g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface)
168 {
169   iface->can_poll = g_unix_output_stream_pollable_can_poll;
170   iface->is_writable = g_unix_output_stream_pollable_is_writable;
171   iface->create_source = g_unix_output_stream_pollable_create_source;
172 }
173
174 static void
175 g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface)
176 {
177   iface->get_fd = (int (*) (GFileDescriptorBased *))g_unix_output_stream_get_fd;
178 }
179
180 static void
181 g_unix_output_stream_set_property (GObject         *object,
182                                    guint            prop_id,
183                                    const GValue    *value,
184                                    GParamSpec      *pspec)
185 {
186   GUnixOutputStream *unix_stream;
187
188   unix_stream = G_UNIX_OUTPUT_STREAM (object);
189
190   switch (prop_id)
191     {
192     case PROP_FD:
193       unix_stream->priv->fd = g_value_get_int (value);
194       if (lseek (unix_stream->priv->fd, 0, SEEK_CUR) == -1 && errno == ESPIPE)
195         unix_stream->priv->is_pipe_or_socket = TRUE;
196       else
197         unix_stream->priv->is_pipe_or_socket = FALSE;
198       break;
199     case PROP_CLOSE_FD:
200       unix_stream->priv->close_fd = g_value_get_boolean (value);
201       break;
202     default:
203       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
204       break;
205     }
206 }
207
208 static void
209 g_unix_output_stream_get_property (GObject    *object,
210                                    guint       prop_id,
211                                    GValue     *value,
212                                    GParamSpec *pspec)
213 {
214   GUnixOutputStream *unix_stream;
215
216   unix_stream = G_UNIX_OUTPUT_STREAM (object);
217
218   switch (prop_id)
219     {
220     case PROP_FD:
221       g_value_set_int (value, unix_stream->priv->fd);
222       break;
223     case PROP_CLOSE_FD:
224       g_value_set_boolean (value, unix_stream->priv->close_fd);
225       break;
226     default:
227       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
228     }
229 }
230
231 static void
232 g_unix_output_stream_init (GUnixOutputStream *unix_stream)
233 {
234   unix_stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (unix_stream,
235                                                    G_TYPE_UNIX_OUTPUT_STREAM,
236                                                    GUnixOutputStreamPrivate);
237
238   unix_stream->priv->fd = -1;
239   unix_stream->priv->close_fd = TRUE;
240 }
241
242 /**
243  * g_unix_output_stream_new:
244  * @fd: a UNIX file descriptor
245  * @close_fd: %TRUE to close the file descriptor when done
246  * 
247  * Creates a new #GUnixOutputStream for the given @fd. 
248  * 
249  * If @close_fd, is %TRUE, the file descriptor will be closed when 
250  * the output stream is destroyed.
251  * 
252  * Returns: a new #GOutputStream
253  **/
254 GOutputStream *
255 g_unix_output_stream_new (gint     fd,
256                           gboolean close_fd)
257 {
258   GUnixOutputStream *stream;
259
260   g_return_val_if_fail (fd != -1, NULL);
261
262   stream = g_object_new (G_TYPE_UNIX_OUTPUT_STREAM,
263                          "fd", fd,
264                          "close-fd", close_fd,
265                          NULL);
266   
267   return G_OUTPUT_STREAM (stream);
268 }
269
270 /**
271  * g_unix_output_stream_set_close_fd:
272  * @stream: a #GUnixOutputStream
273  * @close_fd: %TRUE to close the file descriptor when done
274  *
275  * Sets whether the file descriptor of @stream shall be closed
276  * when the stream is closed.
277  *
278  * Since: 2.20
279  */
280 void
281 g_unix_output_stream_set_close_fd (GUnixOutputStream *stream,
282                                    gboolean           close_fd)
283 {
284   g_return_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream));
285
286   close_fd = close_fd != FALSE;
287   if (stream->priv->close_fd != close_fd)
288     {
289       stream->priv->close_fd = close_fd;
290       g_object_notify (G_OBJECT (stream), "close-fd");
291     }
292 }
293
294 /**
295  * g_unix_output_stream_get_close_fd:
296  * @stream: a #GUnixOutputStream
297  *
298  * Returns whether the file descriptor of @stream will be
299  * closed when the stream is closed.
300  *
301  * Return value: %TRUE if the file descriptor is closed when done
302  *
303  * Since: 2.20
304  */
305 gboolean
306 g_unix_output_stream_get_close_fd (GUnixOutputStream *stream)
307 {
308   g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), FALSE);
309
310   return stream->priv->close_fd;
311 }
312
313 /**
314  * g_unix_output_stream_get_fd:
315  * @stream: a #GUnixOutputStream
316  *
317  * Return the UNIX file descriptor that the stream writes to.
318  *
319  * Return value: The file descriptor of @stream
320  *
321  * Since: 2.20
322  */
323 gint
324 g_unix_output_stream_get_fd (GUnixOutputStream *stream)
325 {
326   g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), -1);
327
328   return stream->priv->fd;
329 }
330
331 static gssize
332 g_unix_output_stream_write (GOutputStream  *stream,
333                             const void     *buffer,
334                             gsize           count,
335                             GCancellable   *cancellable,
336                             GError        **error)
337 {
338   GUnixOutputStream *unix_stream;
339   gssize res = -1;
340   GPollFD poll_fds[2];
341   int nfds;
342   int poll_ret;
343
344   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
345
346   poll_fds[0].fd = unix_stream->priv->fd;
347   poll_fds[0].events = G_IO_OUT;
348
349   if (unix_stream->priv->is_pipe_or_socket &&
350       g_cancellable_make_pollfd (cancellable, &poll_fds[1]))
351     nfds = 2;
352   else
353     nfds = 1;
354
355   while (1)
356     {
357       poll_fds[0].revents = poll_fds[1].revents = 0;
358       do
359         poll_ret = g_poll (poll_fds, nfds, -1);
360       while (poll_ret == -1 && errno == EINTR);
361
362       if (poll_ret == -1)
363         {
364           int errsv = errno;
365
366           g_set_error (error, G_IO_ERROR,
367                        g_io_error_from_errno (errsv),
368                        _("Error writing to file descriptor: %s"),
369                        g_strerror (errsv));
370           break;
371         }
372
373       if (g_cancellable_set_error_if_cancelled (cancellable, error))
374         break;
375
376       if (!poll_fds[0].revents)
377         continue;
378
379       res = write (unix_stream->priv->fd, buffer, count);
380       if (res == -1)
381         {
382           int errsv = errno;
383
384           if (errsv == EINTR || errsv == EAGAIN)
385             continue;
386
387           g_set_error (error, G_IO_ERROR,
388                        g_io_error_from_errno (errsv),
389                        _("Error writing to file descriptor: %s"),
390                        g_strerror (errsv));
391         }
392
393       break;
394     }
395
396   if (nfds == 2)
397     g_cancellable_release_fd (cancellable);
398   return res;
399 }
400
401 static gboolean
402 g_unix_output_stream_close (GOutputStream  *stream,
403                             GCancellable   *cancellable,
404                             GError        **error)
405 {
406   GUnixOutputStream *unix_stream;
407   int res;
408
409   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
410
411   if (!unix_stream->priv->close_fd)
412     return TRUE;
413   
414   /* This might block during the close. Doesn't seem to be a way to avoid it though. */
415   res = close (unix_stream->priv->fd);
416   if (res == -1)
417     {
418       int errsv = errno;
419
420       g_set_error (error, G_IO_ERROR,
421                    g_io_error_from_errno (errsv),
422                    _("Error closing file descriptor: %s"),
423                    g_strerror (errsv));
424     }
425
426   return res != -1;
427 }
428
429 static void
430 g_unix_output_stream_close_async (GOutputStream       *stream,
431                                   int                  io_priority,
432                                   GCancellable        *cancellable,
433                                   GAsyncReadyCallback  callback,
434                                   gpointer             user_data)
435 {
436   GTask *task;
437   GError *error = NULL;
438
439   task = g_task_new (stream, cancellable, callback, user_data);
440   g_task_set_priority (task, io_priority);
441
442   if (g_unix_output_stream_close (stream, cancellable, &error))
443     g_task_return_boolean (task, TRUE);
444   else
445     g_task_return_error (task, error);
446   g_object_unref (task);
447 }
448
449 static gboolean
450 g_unix_output_stream_close_finish (GOutputStream  *stream,
451                                    GAsyncResult   *result,
452                                    GError        **error)
453 {
454   g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
455
456   return g_task_propagate_boolean (G_TASK (result), error);
457 }
458
459 static gboolean
460 g_unix_output_stream_pollable_can_poll (GPollableOutputStream *stream)
461 {
462   return G_UNIX_OUTPUT_STREAM (stream)->priv->is_pipe_or_socket;
463 }
464
465 static gboolean
466 g_unix_output_stream_pollable_is_writable (GPollableOutputStream *stream)
467 {
468   GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
469   GPollFD poll_fd;
470   gint result;
471
472   poll_fd.fd = unix_stream->priv->fd;
473   poll_fd.events = G_IO_OUT;
474   poll_fd.revents = 0;
475
476   do
477     result = g_poll (&poll_fd, 1, 0);
478   while (result == -1 && errno == EINTR);
479
480   return poll_fd.revents != 0;
481 }
482
483 static GSource *
484 g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
485                                              GCancellable          *cancellable)
486 {
487   GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
488   GSource *inner_source, *pollable_source;
489
490   pollable_source = g_pollable_source_new (G_OBJECT (stream));
491
492   inner_source = _g_fd_source_new (unix_stream->priv->fd, G_IO_OUT, cancellable);
493   g_source_set_dummy_callback (inner_source);
494   g_source_add_child_source (pollable_source, inner_source);
495   g_source_unref (inner_source);
496
497   return pollable_source;
498 }