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