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