Added. Added. Added. Added.
[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, 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 #include <poll.h>
32
33 #include <glib.h>
34 #include <glib/gstdio.h>
35 #include "gioerror.h"
36 #include "gsimpleasyncresult.h"
37 #include "gunixinputstream.h"
38 #include "gcancellable.h"
39 #include "gasynchelper.h"
40 #include "glibintl.h"
41
42 #include "gioalias.h"
43
44 /**
45  * SECTION:gunixinputstream
46  * @short_description: Unix Input Stream
47  * @see_also: #GInputStream
48  *
49  * #GUnixInputStream implements #GInputStream for reading from a
50  * unix file descriptor, including asynchronous operations. The file
51  * descriptor much be selectable, so it doesn't work with opened files.
52  **/
53
54 G_DEFINE_TYPE (GUnixInputStream, g_unix_input_stream, G_TYPE_INPUT_STREAM);
55
56 struct _GUnixInputStreamPrivate {
57   int fd;
58   gboolean close_fd_at_close;
59 };
60
61 static gssize   g_unix_input_stream_read         (GInputStream         *stream,
62                                                   void                 *buffer,
63                                                   gsize                 count,
64                                                   GCancellable         *cancellable,
65                                                   GError              **error);
66 static gboolean g_unix_input_stream_close        (GInputStream         *stream,
67                                                   GCancellable         *cancellable,
68                                                   GError              **error);
69 static void     g_unix_input_stream_read_async   (GInputStream         *stream,
70                                                   void                 *buffer,
71                                                   gsize                 count,
72                                                   int                   io_priority,
73                                                   GCancellable         *cancellable,
74                                                   GAsyncReadyCallback   callback,
75                                                   gpointer              data);
76 static gssize   g_unix_input_stream_read_finish  (GInputStream         *stream,
77                                                   GAsyncResult         *result,
78                                                   GError              **error);
79 static void     g_unix_input_stream_skip_async   (GInputStream         *stream,
80                                                   gsize                 count,
81                                                   int                   io_priority,
82                                                   GCancellable         *cancellable,
83                                                   GAsyncReadyCallback   callback,
84                                                   gpointer              data);
85 static gssize   g_unix_input_stream_skip_finish  (GInputStream         *stream,
86                                                   GAsyncResult         *result,
87                                                   GError              **error);
88 static void     g_unix_input_stream_close_async  (GInputStream         *stream,
89                                                   int                   io_priority,
90                                                   GCancellable         *cancellable,
91                                                   GAsyncReadyCallback   callback,
92                                                   gpointer              data);
93 static gboolean g_unix_input_stream_close_finish (GInputStream         *stream,
94                                                   GAsyncResult         *result,
95                                                   GError              **error);
96
97
98 static void
99 g_unix_input_stream_finalize (GObject *object)
100 {
101   GUnixInputStream *stream;
102   
103   stream = G_UNIX_INPUT_STREAM (object);
104
105   if (G_OBJECT_CLASS (g_unix_input_stream_parent_class)->finalize)
106     (*G_OBJECT_CLASS (g_unix_input_stream_parent_class)->finalize) (object);
107 }
108
109 static void
110 g_unix_input_stream_class_init (GUnixInputStreamClass *klass)
111 {
112   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
113   GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
114   
115   g_type_class_add_private (klass, sizeof (GUnixInputStreamPrivate));
116   
117   gobject_class->finalize = g_unix_input_stream_finalize;
118
119   stream_class->read = g_unix_input_stream_read;
120   stream_class->close = g_unix_input_stream_close;
121   stream_class->read_async = g_unix_input_stream_read_async;
122   stream_class->read_finish = g_unix_input_stream_read_finish;
123   if (0)
124     {
125       /* TODO: Implement instead of using fallbacks */
126       stream_class->skip_async = g_unix_input_stream_skip_async;
127       stream_class->skip_finish = g_unix_input_stream_skip_finish;
128     }
129   stream_class->close_async = g_unix_input_stream_close_async;
130   stream_class->close_finish = g_unix_input_stream_close_finish;
131 }
132
133 static void
134 g_unix_input_stream_init (GUnixInputStream *unix_stream)
135 {
136   unix_stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (unix_stream,
137                                                    G_TYPE_UNIX_INPUT_STREAM,
138                                                    GUnixInputStreamPrivate);
139 }
140
141 /**
142  * g_unix_input_stream_new:
143  * @fd: unix file descriptor.
144  * @close_fd_at_close: a #gboolean.
145  * 
146  * Creates a new #GUnixInputStream for the given @fd. If @close_fd_at_close
147  * is %TRUE, the file descriptor will be closed when the stream is closed.
148  * 
149  * Returns: a #GUnixInputStream. 
150  **/
151 GInputStream *
152 g_unix_input_stream_new (int fd,
153                          gboolean close_fd_at_close)
154 {
155   GUnixInputStream *stream;
156
157   g_return_val_if_fail (fd != -1, NULL);
158
159   stream = g_object_new (G_TYPE_UNIX_INPUT_STREAM, NULL);
160
161   stream->priv->fd = fd;
162   stream->priv->close_fd_at_close = close_fd_at_close;
163   
164   return G_INPUT_STREAM (stream);
165 }
166
167 static gssize
168 g_unix_input_stream_read (GInputStream *stream,
169                           void         *buffer,
170                           gsize         count,
171                           GCancellable *cancellable,
172                           GError      **error)
173 {
174   GUnixInputStream *unix_stream;
175   gssize res;
176   struct pollfd poll_fds[2];
177   int poll_ret;
178   int cancel_fd;
179
180   unix_stream = G_UNIX_INPUT_STREAM (stream);
181
182   cancel_fd = g_cancellable_get_fd (cancellable);
183   if (cancel_fd != -1)
184     {
185       do
186         {
187           poll_fds[0].events = POLLIN;
188           poll_fds[0].fd = unix_stream->priv->fd;
189           poll_fds[1].events = POLLIN;
190           poll_fds[1].fd = cancel_fd;
191           poll_ret = poll (poll_fds, 2, -1);
192         }
193       while (poll_ret == -1 && errno == EINTR);
194       
195       if (poll_ret == -1)
196         {
197           g_set_error (error, G_IO_ERROR,
198                        g_io_error_from_errno (errno),
199                        _("Error reading from unix: %s"),
200                        g_strerror (errno));
201           return -1;
202         }
203     }
204
205   while (1)
206     {
207       if (g_cancellable_set_error_if_cancelled (cancellable, error))
208         break;
209       res = read (unix_stream->priv->fd, buffer, count);
210       if (res == -1)
211         {
212           if (errno == EINTR)
213             continue;
214           
215           g_set_error (error, G_IO_ERROR,
216                        g_io_error_from_errno (errno),
217                        _("Error reading from unix: %s"),
218                        g_strerror (errno));
219         }
220       
221       break;
222     }
223
224   return res;
225 }
226
227 static gboolean
228 g_unix_input_stream_close (GInputStream *stream,
229                            GCancellable *cancellable,
230                            GError      **error)
231 {
232   GUnixInputStream *unix_stream;
233   int res;
234
235   unix_stream = G_UNIX_INPUT_STREAM (stream);
236
237   if (!unix_stream->priv->close_fd_at_close)
238     return TRUE;
239   
240   while (1)
241     {
242       /* This might block during the close. Doesn't seem to be a way to avoid it though. */
243       res = close (unix_stream->priv->fd);
244       if (res == -1)
245         {
246           g_set_error (error, G_IO_ERROR,
247                        g_io_error_from_errno (errno),
248                        _("Error closing unix: %s"),
249                        g_strerror (errno));
250         }
251       break;
252     }
253   
254   return res != -1;
255 }
256
257 typedef struct {
258   gsize count;
259   void *buffer;
260   GAsyncReadyCallback callback;
261   gpointer user_data;
262   GCancellable *cancellable;
263   GUnixInputStream *stream;
264 } ReadAsyncData;
265
266 static gboolean
267 read_async_cb (ReadAsyncData *data,
268                GIOCondition condition,
269                int fd)
270 {
271   GSimpleAsyncResult *simple;
272   GError *error = NULL;
273   gssize count_read;
274
275   /* We know that we can read from fd once without blocking */
276   while (1)
277     {
278       if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
279         {
280           count_read = -1;
281           break;
282         }
283       count_read = read (data->stream->priv->fd, data->buffer, data->count);
284       if (count_read == -1)
285         {
286           if (errno == EINTR)
287             continue;
288           
289           g_set_error (&error, G_IO_ERROR,
290                        g_io_error_from_errno (errno),
291                        _("Error reading from unix: %s"),
292                        g_strerror (errno));
293         }
294       break;
295     }
296
297   simple = g_simple_async_result_new (G_OBJECT (data->stream),
298                                       data->callback,
299                                       data->user_data,
300                                       g_unix_input_stream_read_async);
301
302   g_simple_async_result_set_op_res_gssize (simple, count_read);
303
304   if (count_read == -1)
305     {
306       g_simple_async_result_set_from_error (simple, error);
307       g_error_free (error);
308     }
309
310   /* Complete immediately, not in idle, since we're already in a mainloop callout */
311   g_simple_async_result_complete (simple);
312   g_object_unref (simple);
313
314   return FALSE;
315 }
316
317 static void
318 g_unix_input_stream_read_async (GInputStream        *stream,
319                                 void                *buffer,
320                                 gsize                count,
321                                 int                  io_priority,
322                                 GCancellable        *cancellable,
323                                 GAsyncReadyCallback  callback,
324                                 gpointer             user_data)
325 {
326   GSource *source;
327   GUnixInputStream *unix_stream;
328   ReadAsyncData *data;
329
330   unix_stream = G_UNIX_INPUT_STREAM (stream);
331
332   data = g_new0 (ReadAsyncData, 1);
333   data->count = count;
334   data->buffer = buffer;
335   data->callback = callback;
336   data->user_data = user_data;
337   data->cancellable = cancellable;
338   data->stream = unix_stream;
339
340   source = _g_fd_source_new (unix_stream->priv->fd,
341                              POLLIN,
342                              cancellable);
343   
344   g_source_set_callback (source, (GSourceFunc)read_async_cb, data, g_free);
345   g_source_attach (source, NULL);
346  
347   g_source_unref (source);
348 }
349
350 static gssize
351 g_unix_input_stream_read_finish (GInputStream              *stream,
352                                  GAsyncResult              *result,
353                                  GError                   **error)
354 {
355   GSimpleAsyncResult *simple;
356   gssize nread;
357
358   simple = G_SIMPLE_ASYNC_RESULT (result);
359   g_assert (g_simple_async_result_get_source_tag (simple) == g_unix_input_stream_read_async);
360   
361   nread = g_simple_async_result_get_op_res_gssize (simple);
362   return nread;
363 }
364
365 static void
366 g_unix_input_stream_skip_async (GInputStream        *stream,
367                                 gsize                count,
368                                 int                  io_priority,
369                                 GCancellable        *cancellable,
370                                 GAsyncReadyCallback  callback,
371                                 gpointer             data)
372 {
373   g_assert_not_reached ();
374   /* TODO: Not implemented */
375 }
376
377 static gssize
378 g_unix_input_stream_skip_finish  (GInputStream              *stream,
379                                   GAsyncResult              *result,
380                                   GError                   **error)
381 {
382   g_assert_not_reached ();
383   /* TODO: Not implemented */
384 }
385
386
387 typedef struct {
388   GInputStream *stream;
389   GAsyncReadyCallback callback;
390   gpointer user_data;
391 } CloseAsyncData;
392
393 static void
394 close_async_data_free (gpointer _data)
395 {
396   CloseAsyncData *data = _data;
397
398   g_free (data);
399 }
400
401 static gboolean
402 close_async_cb (CloseAsyncData *data)
403 {
404   GUnixInputStream *unix_stream;
405   GSimpleAsyncResult *simple;
406   GError *error = NULL;
407   gboolean result;
408   int res;
409
410   unix_stream = G_UNIX_INPUT_STREAM (data->stream);
411
412   if (!unix_stream->priv->close_fd_at_close)
413     {
414       result = TRUE;
415       goto out;
416     }
417   
418   while (1)
419     {
420       res = close (unix_stream->priv->fd);
421       if (res == -1)
422         {
423           g_set_error (&error, G_IO_ERROR,
424                        g_io_error_from_errno (errno),
425                        _("Error closing unix: %s"),
426                        g_strerror (errno));
427         }
428       break;
429     }
430   
431   result = res != -1;
432
433  out:
434   simple = g_simple_async_result_new (G_OBJECT (data->stream),
435                                       data->callback,
436                                       data->user_data,
437                                       g_unix_input_stream_close_async);
438
439   if (!result)
440     {
441       g_simple_async_result_set_from_error (simple, error);
442       g_error_free (error);
443     }
444
445   /* Complete immediately, not in idle, since we're already in a mainloop callout */
446   g_simple_async_result_complete (simple);
447   g_object_unref (simple);
448   
449   return FALSE;
450 }
451
452 static void
453 g_unix_input_stream_close_async (GInputStream       *stream,
454                                  int                 io_priority,
455                                  GCancellable       *cancellable,
456                                  GAsyncReadyCallback callback,
457                                  gpointer            user_data)
458 {
459   GSource *idle;
460   CloseAsyncData *data;
461
462   data = g_new0 (CloseAsyncData, 1);
463
464   data->stream = stream;
465   data->callback = callback;
466   data->user_data = user_data;
467   
468   idle = g_idle_source_new ();
469   g_source_set_callback (idle, (GSourceFunc)close_async_cb, data, close_async_data_free);
470   g_source_attach (idle, NULL);
471   g_source_unref (idle);
472 }
473
474 static gboolean
475 g_unix_input_stream_close_finish (GInputStream              *stream,
476                                   GAsyncResult              *result,
477                                   GError                   **error)
478 {
479   /* Failures handled in generic close_finish code */
480   return TRUE;
481 }
482
483 #define __G_UNIX_INPUT_STREAM_C__
484 #include "gioaliasdef.c"