gio: more implementations of GFileDescriptorBased
[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
50  * UNIX file descriptor, including asynchronous operations. The file
51  * descriptor must be selectable, so it doesn't work with opened files.
52  *
53  * Note that <filename>&lt;gio/gunixoutputstream.h&gt;</filename> belongs
54  * to the UNIX-specific GIO interfaces, thus you have to use the
55  * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
56  */
57
58 enum {
59   PROP_0,
60   PROP_FD,
61   PROP_CLOSE_FD
62 };
63
64 static void g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface);
65 static void g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface);
66
67 G_DEFINE_TYPE_WITH_CODE (GUnixOutputStream, g_unix_output_stream, G_TYPE_OUTPUT_STREAM,
68                          G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM,
69                                                 g_unix_output_stream_pollable_iface_init)
70                          G_IMPLEMENT_INTERFACE (G_TYPE_FILE_DESCRIPTOR_BASED,
71                                                 g_unix_output_stream_file_descriptor_based_iface_init)
72                          )
73
74 struct _GUnixOutputStreamPrivate {
75   int fd;
76   gboolean close_fd;
77 };
78
79 static void     g_unix_output_stream_set_property (GObject              *object,
80                                                    guint                 prop_id,
81                                                    const GValue         *value,
82                                                    GParamSpec           *pspec);
83 static void     g_unix_output_stream_get_property (GObject              *object,
84                                                    guint                 prop_id,
85                                                    GValue               *value,
86                                                    GParamSpec           *pspec);
87 static gssize   g_unix_output_stream_write        (GOutputStream        *stream,
88                                                    const void           *buffer,
89                                                    gsize                 count,
90                                                    GCancellable         *cancellable,
91                                                    GError              **error);
92 static gboolean g_unix_output_stream_close        (GOutputStream        *stream,
93                                                    GCancellable         *cancellable,
94                                                    GError              **error);
95 static void     g_unix_output_stream_write_async  (GOutputStream        *stream,
96                                                    const void           *buffer,
97                                                    gsize                 count,
98                                                    int                   io_priority,
99                                                    GCancellable         *cancellable,
100                                                    GAsyncReadyCallback   callback,
101                                                    gpointer              data);
102 static gssize   g_unix_output_stream_write_finish (GOutputStream        *stream,
103                                                    GAsyncResult         *result,
104                                                    GError              **error);
105 static void     g_unix_output_stream_close_async  (GOutputStream        *stream,
106                                                    int                   io_priority,
107                                                    GCancellable         *cancellable,
108                                                    GAsyncReadyCallback   callback,
109                                                    gpointer              data);
110 static gboolean g_unix_output_stream_close_finish (GOutputStream        *stream,
111                                                    GAsyncResult         *result,
112                                                    GError              **error);
113
114 static gboolean g_unix_output_stream_pollable_is_writable   (GPollableOutputStream *stream);
115 static GSource *g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
116                                                              GCancellable         *cancellable);
117
118 static void
119 g_unix_output_stream_finalize (GObject *object)
120 {
121   G_OBJECT_CLASS (g_unix_output_stream_parent_class)->finalize (object);
122 }
123
124 static void
125 g_unix_output_stream_class_init (GUnixOutputStreamClass *klass)
126 {
127   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
128   GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
129   
130   g_type_class_add_private (klass, sizeof (GUnixOutputStreamPrivate));
131
132   gobject_class->get_property = g_unix_output_stream_get_property;
133   gobject_class->set_property = g_unix_output_stream_set_property;
134   gobject_class->finalize = g_unix_output_stream_finalize;
135
136   stream_class->write_fn = g_unix_output_stream_write;
137   stream_class->close_fn = g_unix_output_stream_close;
138   stream_class->write_async = g_unix_output_stream_write_async;
139   stream_class->write_finish = g_unix_output_stream_write_finish;
140   stream_class->close_async = g_unix_output_stream_close_async;
141   stream_class->close_finish = g_unix_output_stream_close_finish;
142
143    /**
144    * GUnixOutputStream:fd:
145    *
146    * The file descriptor that the stream writes to.
147    *
148    * Since: 2.20
149    */
150   g_object_class_install_property (gobject_class,
151                                    PROP_FD,
152                                    g_param_spec_int ("fd",
153                                                      P_("File descriptor"),
154                                                      P_("The file descriptor to write to"),
155                                                      G_MININT, G_MAXINT, -1,
156                                                      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
157
158   /**
159    * GUnixOutputStream:close-fd:
160    *
161    * Whether to close the file descriptor when the stream is closed.
162    *
163    * Since: 2.20
164    */
165   g_object_class_install_property (gobject_class,
166                                    PROP_CLOSE_FD,
167                                    g_param_spec_boolean ("close-fd",
168                                                          P_("Close file descriptor"),
169                                                          P_("Whether to close the file descriptor when the stream is closed"),
170                                                          TRUE,
171                                                          G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
172 }
173
174 static void
175 g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface)
176 {
177   iface->is_writable = g_unix_output_stream_pollable_is_writable;
178   iface->create_source = g_unix_output_stream_pollable_create_source;
179 }
180
181 static void
182 g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface)
183 {
184   iface->get_fd = (int (*) (GFileDescriptorBased *))g_unix_output_stream_get_fd;
185 }
186
187 static void
188 g_unix_output_stream_set_property (GObject         *object,
189                                    guint            prop_id,
190                                    const GValue    *value,
191                                    GParamSpec      *pspec)
192 {
193   GUnixOutputStream *unix_stream;
194
195   unix_stream = G_UNIX_OUTPUT_STREAM (object);
196
197   switch (prop_id)
198     {
199     case PROP_FD:
200       unix_stream->priv->fd = g_value_get_int (value);
201       break;
202     case PROP_CLOSE_FD:
203       unix_stream->priv->close_fd = g_value_get_boolean (value);
204       break;
205     default:
206       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
207       break;
208     }
209 }
210
211 static void
212 g_unix_output_stream_get_property (GObject    *object,
213                                    guint       prop_id,
214                                    GValue     *value,
215                                    GParamSpec *pspec)
216 {
217   GUnixOutputStream *unix_stream;
218
219   unix_stream = G_UNIX_OUTPUT_STREAM (object);
220
221   switch (prop_id)
222     {
223     case PROP_FD:
224       g_value_set_int (value, unix_stream->priv->fd);
225       break;
226     case PROP_CLOSE_FD:
227       g_value_set_boolean (value, unix_stream->priv->close_fd);
228       break;
229     default:
230       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
231     }
232 }
233
234 static void
235 g_unix_output_stream_init (GUnixOutputStream *unix_stream)
236 {
237   unix_stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (unix_stream,
238                                                    G_TYPE_UNIX_OUTPUT_STREAM,
239                                                    GUnixOutputStreamPrivate);
240
241   unix_stream->priv->fd = -1;
242   unix_stream->priv->close_fd = TRUE;
243 }
244
245 /**
246  * g_unix_output_stream_new:
247  * @fd: a UNIX file descriptor
248  * @close_fd: %TRUE to close the file descriptor when done
249  * 
250  * Creates a new #GUnixOutputStream for the given @fd. 
251  * 
252  * If @close_fd, is %TRUE, the file descriptor will be closed when 
253  * the output stream is destroyed.
254  * 
255  * Returns: a new #GOutputStream
256  **/
257 GOutputStream *
258 g_unix_output_stream_new (gint     fd,
259                           gboolean close_fd)
260 {
261   GUnixOutputStream *stream;
262
263   g_return_val_if_fail (fd != -1, NULL);
264
265   stream = g_object_new (G_TYPE_UNIX_OUTPUT_STREAM,
266                          "fd", fd,
267                          "close-fd", close_fd,
268                          NULL);
269   
270   return G_OUTPUT_STREAM (stream);
271 }
272
273 /**
274  * g_unix_output_stream_set_close_fd:
275  * @stream: a #GUnixOutputStream
276  * @close_fd: %TRUE to close the file descriptor when done
277  *
278  * Sets whether the file descriptor of @stream shall be closed
279  * when the stream is closed.
280  *
281  * Since: 2.20
282  */
283 void
284 g_unix_output_stream_set_close_fd (GUnixOutputStream *stream,
285                                    gboolean           close_fd)
286 {
287   g_return_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream));
288
289   close_fd = close_fd != FALSE;
290   if (stream->priv->close_fd != close_fd)
291     {
292       stream->priv->close_fd = close_fd;
293       g_object_notify (G_OBJECT (stream), "close-fd");
294     }
295 }
296
297 /**
298  * g_unix_output_stream_get_close_fd:
299  * @stream: a #GUnixOutputStream
300  *
301  * Returns whether the file descriptor of @stream will be
302  * closed when the stream is closed.
303  *
304  * Return value: %TRUE if the file descriptor is closed when done
305  *
306  * Since: 2.20
307  */
308 gboolean
309 g_unix_output_stream_get_close_fd (GUnixOutputStream *stream)
310 {
311   g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), FALSE);
312
313   return stream->priv->close_fd;
314 }
315
316 /**
317  * g_unix_output_stream_get_fd:
318  * @stream: a #GUnixOutputStream
319  *
320  * Return the UNIX file descriptor that the stream writes to.
321  *
322  * Return value: The file descriptor of @stream
323  *
324  * Since: 2.20
325  */
326 gint
327 g_unix_output_stream_get_fd (GUnixOutputStream *stream)
328 {
329   g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), -1);
330
331   return stream->priv->fd;
332 }
333
334 static gssize
335 g_unix_output_stream_write (GOutputStream  *stream,
336                             const void     *buffer,
337                             gsize           count,
338                             GCancellable   *cancellable,
339                             GError        **error)
340 {
341   GUnixOutputStream *unix_stream;
342   gssize res;
343   GPollFD poll_fds[2];
344   int poll_ret;
345
346   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
347
348   if (g_cancellable_make_pollfd (cancellable, &poll_fds[1]))
349     {
350       poll_fds[0].fd = unix_stream->priv->fd;
351       poll_fds[0].events = G_IO_OUT;
352       do
353         poll_ret = g_poll (poll_fds, 2, -1);
354       while (poll_ret == -1 && errno == EINTR);
355       g_cancellable_release_fd (cancellable);
356       
357       if (poll_ret == -1)
358         {
359           int errsv = errno;
360
361           g_set_error (error, G_IO_ERROR,
362                        g_io_error_from_errno (errsv),
363                        _("Error writing to unix: %s"),
364                        g_strerror (errsv));
365           return -1;
366         }
367     }
368       
369   while (1)
370     {
371       if (g_cancellable_set_error_if_cancelled (cancellable, error))
372         return -1;
373
374       res = write (unix_stream->priv->fd, buffer, count);
375       if (res == -1)
376         {
377           int errsv = errno;
378
379           if (errsv == EINTR)
380             continue;
381           
382           g_set_error (error, G_IO_ERROR,
383                        g_io_error_from_errno (errsv),
384                        _("Error writing to unix: %s"),
385                        g_strerror (errsv));
386         }
387       
388       break;
389     }
390   
391   return res;
392 }
393
394 static gboolean
395 g_unix_output_stream_close (GOutputStream  *stream,
396                             GCancellable   *cancellable,
397                             GError        **error)
398 {
399   GUnixOutputStream *unix_stream;
400   int res;
401
402   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
403
404   if (!unix_stream->priv->close_fd)
405     return TRUE;
406   
407   while (1)
408     {
409       /* This might block during the close. Doesn't seem to be a way to avoid it though. */
410       res = close (unix_stream->priv->fd);
411       if (res == -1)
412         {
413           int errsv = errno;
414
415           g_set_error (error, G_IO_ERROR,
416                        g_io_error_from_errno (errsv),
417                        _("Error closing unix: %s"),
418                        g_strerror (errsv));
419         }
420       break;
421     }
422
423   return res != -1;
424 }
425
426 typedef struct {
427   gsize count;
428   const void *buffer;
429   GAsyncReadyCallback callback;
430   gpointer user_data;
431   GCancellable *cancellable;
432   GUnixOutputStream *stream;
433 } WriteAsyncData;
434
435 static gboolean
436 write_async_cb (int             fd,
437                 GIOCondition    condition,
438                 WriteAsyncData *data)
439 {
440   GSimpleAsyncResult *simple;
441   GError *error = NULL;
442   gssize count_written;
443
444   while (1)
445     {
446       if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
447         {
448           count_written = -1;
449           break;
450         }
451       
452       count_written = write (data->stream->priv->fd, data->buffer, data->count);
453       if (count_written == -1)
454         {
455           int errsv = errno;
456
457           if (errsv == EINTR)
458             continue;
459           
460           g_set_error (&error, G_IO_ERROR,
461                        g_io_error_from_errno (errsv),
462                        _("Error writing to unix: %s"),
463                        g_strerror (errsv));
464         }
465       break;
466     }
467
468   simple = g_simple_async_result_new (G_OBJECT (data->stream),
469                                       data->callback,
470                                       data->user_data,
471                                       g_unix_output_stream_write_async);
472   
473   g_simple_async_result_set_op_res_gssize (simple, count_written);
474
475   if (count_written == -1)
476     g_simple_async_result_take_error (simple, error);
477
478   /* Complete immediately, not in idle, since we're already in a mainloop callout */
479   g_simple_async_result_complete (simple);
480   g_object_unref (simple);
481
482   return FALSE;
483 }
484
485 static void
486 g_unix_output_stream_write_async (GOutputStream       *stream,
487                                   const void          *buffer,
488                                   gsize                count,
489                                   int                  io_priority,
490                                   GCancellable        *cancellable,
491                                   GAsyncReadyCallback  callback,
492                                   gpointer             user_data)
493 {
494   GSource *source;
495   GUnixOutputStream *unix_stream;
496   WriteAsyncData *data;
497
498   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
499
500   data = g_new0 (WriteAsyncData, 1);
501   data->count = count;
502   data->buffer = buffer;
503   data->callback = callback;
504   data->user_data = user_data;
505   data->cancellable = cancellable;
506   data->stream = unix_stream;
507
508   source = _g_fd_source_new (unix_stream->priv->fd,
509                              G_IO_OUT,
510                              cancellable);
511   g_source_set_name (source, "GUnixOutputStream");
512   
513   g_source_set_callback (source, (GSourceFunc)write_async_cb, data, g_free);
514   g_source_attach (source, g_main_context_get_thread_default ());
515   
516   g_source_unref (source);
517 }
518
519 static gssize
520 g_unix_output_stream_write_finish (GOutputStream  *stream,
521                                    GAsyncResult   *result,
522                                    GError        **error)
523 {
524   GSimpleAsyncResult *simple;
525   gssize nwritten;
526
527   simple = G_SIMPLE_ASYNC_RESULT (result);
528   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_unix_output_stream_write_async);
529   
530   nwritten = g_simple_async_result_get_op_res_gssize (simple);
531   return nwritten;
532 }
533
534 typedef struct {
535   GOutputStream *stream;
536   GAsyncReadyCallback callback;
537   gpointer user_data;
538 } CloseAsyncData;
539
540 static gboolean
541 close_async_cb (CloseAsyncData *data)
542 {
543   GUnixOutputStream *unix_stream;
544   GSimpleAsyncResult *simple;
545   GError *error = NULL;
546   gboolean result;
547   int res;
548
549   unix_stream = G_UNIX_OUTPUT_STREAM (data->stream);
550
551   if (!unix_stream->priv->close_fd)
552     {
553       result = TRUE;
554       goto out;
555     }
556   
557   while (1)
558     {
559       res = close (unix_stream->priv->fd);
560       if (res == -1)
561         {
562           int errsv = errno;
563
564           g_set_error (&error, G_IO_ERROR,
565                        g_io_error_from_errno (errsv),
566                        _("Error closing unix: %s"),
567                        g_strerror (errsv));
568         }
569       break;
570     }
571   
572   result = res != -1;
573   
574  out:
575   simple = g_simple_async_result_new (G_OBJECT (data->stream),
576                                       data->callback,
577                                       data->user_data,
578                                       g_unix_output_stream_close_async);
579
580   if (!result)
581     g_simple_async_result_take_error (simple, error);
582
583   /* Complete immediately, not in idle, since we're already in a mainloop callout */
584   g_simple_async_result_complete (simple);
585   g_object_unref (simple);
586   
587   return FALSE;
588 }
589
590 static void
591 g_unix_output_stream_close_async (GOutputStream        *stream,
592                                   int                  io_priority,
593                                   GCancellable        *cancellable,
594                                   GAsyncReadyCallback  callback,
595                                   gpointer             user_data)
596 {
597   GSource *idle;
598   CloseAsyncData *data;
599
600   data = g_new0 (CloseAsyncData, 1);
601
602   data->stream = stream;
603   data->callback = callback;
604   data->user_data = user_data;
605   
606   idle = g_idle_source_new ();
607   g_source_set_callback (idle, (GSourceFunc)close_async_cb, data, g_free);
608   g_source_attach (idle, g_main_context_get_thread_default ());
609   g_source_unref (idle);
610 }
611
612 static gboolean
613 g_unix_output_stream_close_finish (GOutputStream  *stream,
614                                    GAsyncResult   *result,
615                                    GError        **error)
616 {
617   /* Failures handled in generic close_finish code */
618   return TRUE;
619 }
620
621 static gboolean
622 g_unix_output_stream_pollable_is_writable (GPollableOutputStream *stream)
623 {
624   GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
625   GPollFD poll_fd;
626   gint result;
627
628   poll_fd.fd = unix_stream->priv->fd;
629   poll_fd.events = G_IO_OUT;
630
631   do
632     result = g_poll (&poll_fd, 1, 0);
633   while (result == -1 && errno == EINTR);
634
635   return poll_fd.revents != 0;
636 }
637
638 static GSource *
639 g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
640                                              GCancellable          *cancellable)
641 {
642   GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
643   GSource *inner_source, *pollable_source;
644
645   pollable_source = g_pollable_source_new (G_OBJECT (stream));
646
647   inner_source = _g_fd_source_new (unix_stream->priv->fd, G_IO_OUT, cancellable);
648   g_source_set_dummy_callback (inner_source);
649   g_source_add_child_source (pollable_source, inner_source);
650   g_source_unref (inner_source);
651
652   return pollable_source;
653 }