hook gvariant vectors up to kdbus
[platform/upstream/glib.git] / gio / gunixinputstream.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, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: Alexander Larsson <alexl@redhat.com>
19  */
20
21 #include "config.h"
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <fcntl.h>
29
30 #include <glib.h>
31 #include <glib/gstdio.h>
32 #include <glib/glib-unix.h>
33 #include "gioerror.h"
34 #include "gsimpleasyncresult.h"
35 #include "gunixinputstream.h"
36 #include "gcancellable.h"
37 #include "gasynchelper.h"
38 #include "gfiledescriptorbased.h"
39 #include "glibintl.h"
40
41
42 /**
43  * SECTION:gunixinputstream
44  * @short_description: Streaming input operations for UNIX file descriptors
45  * @include: gio/gunixinputstream.h
46  * @see_also: #GInputStream
47  *
48  * #GUnixInputStream implements #GInputStream for reading from a UNIX
49  * file descriptor, including asynchronous operations. (If the file
50  * descriptor refers to a socket or pipe, this will use poll() to do
51  * asynchronous I/O. If it refers to a regular file, it will fall back
52  * to doing asynchronous I/O in another thread.)
53  *
54  * Note that `<gio/gunixinputstream.h>` belongs to the UNIX-specific GIO
55  * interfaces, thus you have to use the `gio-unix-2.0.pc` pkg-config
56  * file when using it.
57  */
58
59 enum {
60   PROP_0,
61   PROP_FD,
62   PROP_CLOSE_FD
63 };
64
65 struct _GUnixInputStreamPrivate {
66   int fd;
67   guint close_fd : 1;
68   guint is_pipe_or_socket : 1;
69 };
70
71 static void g_unix_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface);
72 static void g_unix_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface);
73
74 G_DEFINE_TYPE_WITH_CODE (GUnixInputStream, g_unix_input_stream, G_TYPE_INPUT_STREAM,
75                          G_ADD_PRIVATE (GUnixInputStream)
76                          G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
77                                                 g_unix_input_stream_pollable_iface_init)
78                          G_IMPLEMENT_INTERFACE (G_TYPE_FILE_DESCRIPTOR_BASED,
79                                                 g_unix_input_stream_file_descriptor_based_iface_init)
80                          )
81
82 static void     g_unix_input_stream_set_property (GObject              *object,
83                                                   guint                 prop_id,
84                                                   const GValue         *value,
85                                                   GParamSpec           *pspec);
86 static void     g_unix_input_stream_get_property (GObject              *object,
87                                                   guint                 prop_id,
88                                                   GValue               *value,
89                                                   GParamSpec           *pspec);
90 static gssize   g_unix_input_stream_read         (GInputStream         *stream,
91                                                   void                 *buffer,
92                                                   gsize                 count,
93                                                   GCancellable         *cancellable,
94                                                   GError              **error);
95 static gboolean g_unix_input_stream_close        (GInputStream         *stream,
96                                                   GCancellable         *cancellable,
97                                                   GError              **error);
98 static void     g_unix_input_stream_skip_async   (GInputStream         *stream,
99                                                   gsize                 count,
100                                                   int                   io_priority,
101                                                   GCancellable         *cancellable,
102                                                   GAsyncReadyCallback   callback,
103                                                   gpointer              data);
104 static gssize   g_unix_input_stream_skip_finish  (GInputStream         *stream,
105                                                   GAsyncResult         *result,
106                                                   GError              **error);
107 static void     g_unix_input_stream_close_async  (GInputStream         *stream,
108                                                   int                   io_priority,
109                                                   GCancellable         *cancellable,
110                                                   GAsyncReadyCallback   callback,
111                                                   gpointer              data);
112 static gboolean g_unix_input_stream_close_finish (GInputStream         *stream,
113                                                   GAsyncResult         *result,
114                                                   GError              **error);
115
116 static gboolean g_unix_input_stream_pollable_can_poll      (GPollableInputStream *stream);
117 static gboolean g_unix_input_stream_pollable_is_readable   (GPollableInputStream *stream);
118 static GSource *g_unix_input_stream_pollable_create_source (GPollableInputStream *stream,
119                                                             GCancellable         *cancellable);
120
121 static void
122 g_unix_input_stream_class_init (GUnixInputStreamClass *klass)
123 {
124   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
125   GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
126
127   gobject_class->get_property = g_unix_input_stream_get_property;
128   gobject_class->set_property = g_unix_input_stream_set_property;
129
130   stream_class->read_fn = g_unix_input_stream_read;
131   stream_class->close_fn = g_unix_input_stream_close;
132   if (0)
133     {
134       /* TODO: Implement instead of using fallbacks */
135       stream_class->skip_async = g_unix_input_stream_skip_async;
136       stream_class->skip_finish = g_unix_input_stream_skip_finish;
137     }
138   stream_class->close_async = g_unix_input_stream_close_async;
139   stream_class->close_finish = g_unix_input_stream_close_finish;
140
141   /**
142    * GUnixInputStream:fd:
143    *
144    * The file descriptor that the stream reads from.
145    *
146    * Since: 2.20
147    */
148   g_object_class_install_property (gobject_class,
149                                    PROP_FD,
150                                    g_param_spec_int ("fd",
151                                                      P_("File descriptor"),
152                                                      P_("The file descriptor to read from"),
153                                                      G_MININT, G_MAXINT, -1,
154                                                      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
155
156   /**
157    * GUnixInputStream:close-fd:
158    *
159    * Whether to close the file descriptor when the stream is closed.
160    *
161    * Since: 2.20
162    */
163   g_object_class_install_property (gobject_class,
164                                    PROP_CLOSE_FD,
165                                    g_param_spec_boolean ("close-fd",
166                                                          P_("Close file descriptor"),
167                                                          P_("Whether to close the file descriptor when the stream is closed"),
168                                                          TRUE,
169                                                          G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
170 }
171
172 static void
173 g_unix_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface)
174 {
175   iface->can_poll = g_unix_input_stream_pollable_can_poll;
176   iface->is_readable = g_unix_input_stream_pollable_is_readable;
177   iface->create_source = g_unix_input_stream_pollable_create_source;
178 }
179
180 static void
181 g_unix_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface)
182 {
183   iface->get_fd = (int (*) (GFileDescriptorBased *))g_unix_input_stream_get_fd;
184 }
185
186 static void
187 g_unix_input_stream_set_property (GObject         *object,
188                                   guint            prop_id,
189                                   const GValue    *value,
190                                   GParamSpec      *pspec)
191 {
192   GUnixInputStream *unix_stream;
193   
194   unix_stream = G_UNIX_INPUT_STREAM (object);
195
196   switch (prop_id)
197     {
198     case PROP_FD:
199       unix_stream->priv->fd = g_value_get_int (value);
200       if (lseek (unix_stream->priv->fd, 0, SEEK_CUR) == -1 && errno == ESPIPE)
201         unix_stream->priv->is_pipe_or_socket = TRUE;
202       else
203         unix_stream->priv->is_pipe_or_socket = FALSE;
204       break;
205     case PROP_CLOSE_FD:
206       unix_stream->priv->close_fd = g_value_get_boolean (value);
207       break;
208     default:
209       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
210       break;
211     }
212 }
213
214 static void
215 g_unix_input_stream_get_property (GObject    *object,
216                                   guint       prop_id,
217                                   GValue     *value,
218                                   GParamSpec *pspec)
219 {
220   GUnixInputStream *unix_stream;
221
222   unix_stream = G_UNIX_INPUT_STREAM (object);
223
224   switch (prop_id)
225     {
226     case PROP_FD:
227       g_value_set_int (value, unix_stream->priv->fd);
228       break;
229     case PROP_CLOSE_FD:
230       g_value_set_boolean (value, unix_stream->priv->close_fd);
231       break;
232     default:
233       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
234     }
235 }
236
237 static void
238 g_unix_input_stream_init (GUnixInputStream *unix_stream)
239 {
240   unix_stream->priv = g_unix_input_stream_get_instance_private (unix_stream);
241   unix_stream->priv->fd = -1;
242   unix_stream->priv->close_fd = TRUE;
243 }
244
245 /**
246  * g_unix_input_stream_new:
247  * @fd: a UNIX file descriptor
248  * @close_fd: %TRUE to close the file descriptor when done
249  * 
250  * Creates a new #GUnixInputStream for the given @fd. 
251  *
252  * If @close_fd is %TRUE, the file descriptor will be closed 
253  * when the stream is closed.
254  * 
255  * Returns: a new #GUnixInputStream
256  **/
257 GInputStream *
258 g_unix_input_stream_new (gint     fd,
259                          gboolean close_fd)
260 {
261   GUnixInputStream *stream;
262
263   g_return_val_if_fail (fd != -1, NULL);
264
265   stream = g_object_new (G_TYPE_UNIX_INPUT_STREAM,
266                          "fd", fd,
267                          "close-fd", close_fd,
268                          NULL);
269
270   return G_INPUT_STREAM (stream);
271 }
272
273 /**
274  * g_unix_input_stream_set_close_fd:
275  * @stream: a #GUnixInputStream
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_input_stream_set_close_fd (GUnixInputStream *stream,
285                                   gboolean          close_fd)
286 {
287   g_return_if_fail (G_IS_UNIX_INPUT_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_input_stream_get_close_fd:
299  * @stream: a #GUnixInputStream
300  *
301  * Returns whether the file descriptor of @stream will be
302  * closed when the stream is closed.
303  *
304  * Returns: %TRUE if the file descriptor is closed when done
305  *
306  * Since: 2.20
307  */
308 gboolean
309 g_unix_input_stream_get_close_fd (GUnixInputStream *stream)
310 {
311   g_return_val_if_fail (G_IS_UNIX_INPUT_STREAM (stream), FALSE);
312
313   return stream->priv->close_fd;
314 }
315
316 /**
317  * g_unix_input_stream_get_fd:
318  * @stream: a #GUnixInputStream
319  *
320  * Return the UNIX file descriptor that the stream reads from.
321  *
322  * Returns: The file descriptor of @stream
323  *
324  * Since: 2.20
325  */
326 gint
327 g_unix_input_stream_get_fd (GUnixInputStream *stream)
328 {
329   g_return_val_if_fail (G_IS_UNIX_INPUT_STREAM (stream), -1);
330   
331   return stream->priv->fd;
332 }
333
334 static gssize
335 g_unix_input_stream_read (GInputStream  *stream,
336                           void          *buffer,
337                           gsize          count,
338                           GCancellable  *cancellable,
339                           GError       **error)
340 {
341   GUnixInputStream *unix_stream;
342   gssize res = -1;
343   GPollFD poll_fds[2];
344   int nfds;
345   int poll_ret;
346
347   unix_stream = G_UNIX_INPUT_STREAM (stream);
348
349   poll_fds[0].fd = unix_stream->priv->fd;
350   poll_fds[0].events = G_IO_IN;
351   if (unix_stream->priv->is_pipe_or_socket &&
352       g_cancellable_make_pollfd (cancellable, &poll_fds[1]))
353     nfds = 2;
354   else
355     nfds = 1;
356
357   while (1)
358     {
359       poll_fds[0].revents = poll_fds[1].revents = 0;
360       do
361         poll_ret = g_poll (poll_fds, nfds, -1);
362       while (poll_ret == -1 && errno == EINTR);
363
364       if (poll_ret == -1)
365         {
366           int errsv = errno;
367
368           g_set_error (error, G_IO_ERROR,
369                        g_io_error_from_errno (errsv),
370                        _("Error reading from file descriptor: %s"),
371                        g_strerror (errsv));
372           break;
373         }
374
375       if (g_cancellable_set_error_if_cancelled (cancellable, error))
376         break;
377
378       if (!poll_fds[0].revents)
379         continue;
380
381       res = read (unix_stream->priv->fd, buffer, count);
382       if (res == -1)
383         {
384           int errsv = errno;
385
386           if (errsv == EINTR || errsv == EAGAIN)
387             continue;
388
389           g_set_error (error, G_IO_ERROR,
390                        g_io_error_from_errno (errsv),
391                        _("Error reading from file descriptor: %s"),
392                        g_strerror (errsv));
393         }
394
395       break;
396     }
397
398   if (nfds == 2)
399     g_cancellable_release_fd (cancellable);
400   return res;
401 }
402
403 static gboolean
404 g_unix_input_stream_close (GInputStream  *stream,
405                            GCancellable  *cancellable,
406                            GError       **error)
407 {
408   GUnixInputStream *unix_stream;
409   int res;
410
411   unix_stream = G_UNIX_INPUT_STREAM (stream);
412
413   if (!unix_stream->priv->close_fd)
414     return TRUE;
415   
416   /* This might block during the close. Doesn't seem to be a way to avoid it though. */
417   res = close (unix_stream->priv->fd);
418   if (res == -1)
419     {
420       int errsv = errno;
421
422       g_set_error (error, G_IO_ERROR,
423                    g_io_error_from_errno (errsv),
424                    _("Error closing file descriptor: %s"),
425                    g_strerror (errsv));
426     }
427   
428   return res != -1;
429 }
430
431 static void
432 g_unix_input_stream_skip_async (GInputStream        *stream,
433                                 gsize                count,
434                                 int                  io_priority,
435                                 GCancellable        *cancellable,
436                                 GAsyncReadyCallback  callback,
437                                 gpointer             data)
438 {
439   g_warn_if_reached ();
440   /* TODO: Not implemented */
441 }
442
443 static gssize
444 g_unix_input_stream_skip_finish  (GInputStream  *stream,
445                                   GAsyncResult  *result,
446                                   GError       **error)
447 {
448   g_warn_if_reached ();
449   return 0;
450   /* TODO: Not implemented */
451 }
452
453 static void
454 g_unix_input_stream_close_async (GInputStream        *stream,
455                                  int                  io_priority,
456                                  GCancellable        *cancellable,
457                                  GAsyncReadyCallback  callback,
458                                  gpointer             user_data)
459 {
460   GTask *task;
461   GError *error = NULL;
462
463   task = g_task_new (stream, cancellable, callback, user_data);
464   g_task_set_priority (task, io_priority);
465
466   if (g_unix_input_stream_close (stream, cancellable, &error))
467     g_task_return_boolean (task, TRUE);
468   else
469     g_task_return_error (task, error);
470   g_object_unref (task);
471 }
472
473 static gboolean
474 g_unix_input_stream_close_finish (GInputStream  *stream,
475                                   GAsyncResult  *result,
476                                   GError       **error)
477 {
478   g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
479
480   return g_task_propagate_boolean (G_TASK (result), error);
481 }
482
483 static gboolean
484 g_unix_input_stream_pollable_can_poll (GPollableInputStream *stream)
485 {
486   return G_UNIX_INPUT_STREAM (stream)->priv->is_pipe_or_socket;
487 }
488
489 static gboolean
490 g_unix_input_stream_pollable_is_readable (GPollableInputStream *stream)
491 {
492   GUnixInputStream *unix_stream = G_UNIX_INPUT_STREAM (stream);
493   GPollFD poll_fd;
494   gint result;
495
496   poll_fd.fd = unix_stream->priv->fd;
497   poll_fd.events = G_IO_IN;
498   poll_fd.revents = 0;
499
500   do
501     result = g_poll (&poll_fd, 1, 0);
502   while (result == -1 && errno == EINTR);
503
504   return poll_fd.revents != 0;
505 }
506
507 static GSource *
508 g_unix_input_stream_pollable_create_source (GPollableInputStream *stream,
509                                             GCancellable         *cancellable)
510 {
511   GUnixInputStream *unix_stream = G_UNIX_INPUT_STREAM (stream);
512   GSource *inner_source, *cancellable_source, *pollable_source;
513
514   pollable_source = g_pollable_source_new (G_OBJECT (stream));
515
516   inner_source = g_unix_fd_source_new (unix_stream->priv->fd, G_IO_IN);
517   g_source_set_dummy_callback (inner_source);
518   g_source_add_child_source (pollable_source, inner_source);
519   g_source_unref (inner_source);
520
521   if (cancellable)
522     {
523       cancellable_source = g_cancellable_source_new (cancellable);
524       g_source_set_dummy_callback (cancellable_source);
525       g_source_add_child_source (pollable_source, cancellable_source);
526       g_source_unref (cancellable_source);
527     }
528
529   return pollable_source;
530 }