Fix AKS -> ASK typo
[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: Streaming input operations for Unix file descriptors
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_fn = g_unix_input_stream_read;
120   stream_class->close_fn = 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         g_set_error (error, G_IO_ERROR,
246                      g_io_error_from_errno (errno),
247                      _("Error closing unix: %s"),
248                      g_strerror (errno));
249       break;
250     }
251   
252   return res != -1;
253 }
254
255 typedef struct {
256   gsize count;
257   void *buffer;
258   GAsyncReadyCallback callback;
259   gpointer user_data;
260   GCancellable *cancellable;
261   GUnixInputStream *stream;
262 } ReadAsyncData;
263
264 static gboolean
265 read_async_cb (ReadAsyncData *data,
266                GIOCondition   condition,
267                int            fd)
268 {
269   GSimpleAsyncResult *simple;
270   GError *error = NULL;
271   gssize count_read;
272
273   /* We know that we can read from fd once without blocking */
274   while (1)
275     {
276       if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
277         {
278           count_read = -1;
279           break;
280         }
281       count_read = read (data->stream->priv->fd, data->buffer, data->count);
282       if (count_read == -1)
283         {
284           if (errno == EINTR)
285             continue;
286           
287           g_set_error (&error, G_IO_ERROR,
288                        g_io_error_from_errno (errno),
289                        _("Error reading from unix: %s"),
290                        g_strerror (errno));
291         }
292       break;
293     }
294
295   simple = g_simple_async_result_new (G_OBJECT (data->stream),
296                                       data->callback,
297                                       data->user_data,
298                                       g_unix_input_stream_read_async);
299
300   g_simple_async_result_set_op_res_gssize (simple, count_read);
301
302   if (count_read == -1)
303     {
304       g_simple_async_result_set_from_error (simple, error);
305       g_error_free (error);
306     }
307
308   /* Complete immediately, not in idle, since we're already in a mainloop callout */
309   g_simple_async_result_complete (simple);
310   g_object_unref (simple);
311
312   return FALSE;
313 }
314
315 static void
316 g_unix_input_stream_read_async (GInputStream        *stream,
317                                 void                *buffer,
318                                 gsize                count,
319                                 int                  io_priority,
320                                 GCancellable        *cancellable,
321                                 GAsyncReadyCallback  callback,
322                                 gpointer             user_data)
323 {
324   GSource *source;
325   GUnixInputStream *unix_stream;
326   ReadAsyncData *data;
327
328   unix_stream = G_UNIX_INPUT_STREAM (stream);
329
330   data = g_new0 (ReadAsyncData, 1);
331   data->count = count;
332   data->buffer = buffer;
333   data->callback = callback;
334   data->user_data = user_data;
335   data->cancellable = cancellable;
336   data->stream = unix_stream;
337
338   source = _g_fd_source_new (unix_stream->priv->fd,
339                              POLLIN,
340                              cancellable);
341   
342   g_source_set_callback (source, (GSourceFunc)read_async_cb, data, g_free);
343   g_source_attach (source, NULL);
344  
345   g_source_unref (source);
346 }
347
348 static gssize
349 g_unix_input_stream_read_finish (GInputStream  *stream,
350                                  GAsyncResult  *result,
351                                  GError       **error)
352 {
353   GSimpleAsyncResult *simple;
354   gssize nread;
355
356   simple = G_SIMPLE_ASYNC_RESULT (result);
357   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_unix_input_stream_read_async);
358   
359   nread = g_simple_async_result_get_op_res_gssize (simple);
360   return nread;
361 }
362
363 static void
364 g_unix_input_stream_skip_async (GInputStream        *stream,
365                                 gsize                count,
366                                 int                  io_priority,
367                                 GCancellable        *cancellable,
368                                 GAsyncReadyCallback  callback,
369                                 gpointer             data)
370 {
371   g_warn_if_reached ();
372   /* TODO: Not implemented */
373 }
374
375 static gssize
376 g_unix_input_stream_skip_finish  (GInputStream  *stream,
377                                   GAsyncResult  *result,
378                                   GError       **error)
379 {
380   g_warn_if_reached ();
381   /* TODO: Not implemented */
382 }
383
384
385 typedef struct {
386   GInputStream *stream;
387   GAsyncReadyCallback callback;
388   gpointer user_data;
389 } CloseAsyncData;
390
391 static void
392 close_async_data_free (gpointer _data)
393 {
394   CloseAsyncData *data = _data;
395
396   g_free (data);
397 }
398
399 static gboolean
400 close_async_cb (CloseAsyncData *data)
401 {
402   GUnixInputStream *unix_stream;
403   GSimpleAsyncResult *simple;
404   GError *error = NULL;
405   gboolean result;
406   int res;
407
408   unix_stream = G_UNIX_INPUT_STREAM (data->stream);
409
410   if (!unix_stream->priv->close_fd_at_close)
411     {
412       result = TRUE;
413       goto out;
414     }
415   
416   while (1)
417     {
418       res = close (unix_stream->priv->fd);
419       if (res == -1)
420         g_set_error (&error, G_IO_ERROR,
421                      g_io_error_from_errno (errno),
422                      _("Error closing unix: %s"),
423                      g_strerror (errno));
424       break;
425     }
426   
427   result = res != -1;
428
429  out:
430   simple = g_simple_async_result_new (G_OBJECT (data->stream),
431                                       data->callback,
432                                       data->user_data,
433                                       g_unix_input_stream_close_async);
434
435   if (!result)
436     {
437       g_simple_async_result_set_from_error (simple, error);
438       g_error_free (error);
439     }
440
441   /* Complete immediately, not in idle, since we're already in a mainloop callout */
442   g_simple_async_result_complete (simple);
443   g_object_unref (simple);
444   
445   return FALSE;
446 }
447
448 static void
449 g_unix_input_stream_close_async (GInputStream        *stream,
450                                  int                  io_priority,
451                                  GCancellable        *cancellable,
452                                  GAsyncReadyCallback  callback,
453                                  gpointer             user_data)
454 {
455   GSource *idle;
456   CloseAsyncData *data;
457
458   data = g_new0 (CloseAsyncData, 1);
459
460   data->stream = stream;
461   data->callback = callback;
462   data->user_data = user_data;
463   
464   idle = g_idle_source_new ();
465   g_source_set_callback (idle, (GSourceFunc)close_async_cb, data, close_async_data_free);
466   g_source_attach (idle, NULL);
467   g_source_unref (idle);
468 }
469
470 static gboolean
471 g_unix_input_stream_close_finish (GInputStream  *stream,
472                                   GAsyncResult  *result,
473                                   GError       **error)
474 {
475   /* Failures handled in generic close_finish code */
476   return TRUE;
477 }
478
479 #define __G_UNIX_INPUT_STREAM_C__
480 #include "gioaliasdef.c"