Bug 505361 - gunixinputstream.c assumes poll() available
[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 #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
54 G_DEFINE_TYPE (GUnixOutputStream, g_unix_output_stream, G_TYPE_OUTPUT_STREAM);
55
56
57 struct _GUnixOutputStreamPrivate {
58   int fd;
59   gboolean close_fd_at_close;
60 };
61
62 static gssize   g_unix_output_stream_write        (GOutputStream        *stream,
63                                                    const void           *buffer,
64                                                    gsize                 count,
65                                                    GCancellable         *cancellable,
66                                                    GError              **error);
67 static gboolean g_unix_output_stream_close        (GOutputStream        *stream,
68                                                    GCancellable         *cancellable,
69                                                    GError              **error);
70 static void     g_unix_output_stream_write_async  (GOutputStream        *stream,
71                                                    const void           *buffer,
72                                                    gsize                 count,
73                                                    int                   io_priority,
74                                                    GCancellable         *cancellable,
75                                                    GAsyncReadyCallback   callback,
76                                                    gpointer              data);
77 static gssize   g_unix_output_stream_write_finish (GOutputStream        *stream,
78                                                    GAsyncResult         *result,
79                                                    GError              **error);
80 static void     g_unix_output_stream_close_async  (GOutputStream        *stream,
81                                                    int                   io_priority,
82                                                    GCancellable         *cancellable,
83                                                    GAsyncReadyCallback   callback,
84                                                    gpointer              data);
85 static gboolean g_unix_output_stream_close_finish (GOutputStream        *stream,
86                                                    GAsyncResult         *result,
87                                                    GError              **error);
88
89
90 static void
91 g_unix_output_stream_finalize (GObject *object)
92 {
93   GUnixOutputStream *stream;
94   
95   stream = G_UNIX_OUTPUT_STREAM (object);
96
97   G_OBJECT_CLASS (g_unix_output_stream_parent_class)->finalize (object);
98 }
99
100 static void
101 g_unix_output_stream_class_init (GUnixOutputStreamClass *klass)
102 {
103   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
104   GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
105   
106   g_type_class_add_private (klass, sizeof (GUnixOutputStreamPrivate));
107   
108   gobject_class->finalize = g_unix_output_stream_finalize;
109
110   stream_class->write_fn = g_unix_output_stream_write;
111   stream_class->close_fn = g_unix_output_stream_close;
112   stream_class->write_async = g_unix_output_stream_write_async;
113   stream_class->write_finish = g_unix_output_stream_write_finish;
114   stream_class->close_async = g_unix_output_stream_close_async;
115   stream_class->close_finish = g_unix_output_stream_close_finish;
116 }
117
118 static void
119 g_unix_output_stream_init (GUnixOutputStream *unix_stream)
120 {
121   unix_stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (unix_stream,
122                                                    G_TYPE_UNIX_OUTPUT_STREAM,
123                                                    GUnixOutputStreamPrivate);
124 }
125
126
127 /**
128  * g_unix_output_stream_new:
129  * @fd: unix's file descriptor.
130  * @close_fd_at_close: a #gboolean.
131  * 
132  * Creates a new unix output stream for @fd. If @close_fd_at_close
133  * is %TRUE, the fd will be closed when the output stream is destroyed.
134  * 
135  * Returns: #GOutputStream. If @close_fd_at_close is %TRUE, then
136  * @fd will be closed when the #GOutputStream is closed.
137  **/
138 GOutputStream *
139 g_unix_output_stream_new (int      fd,
140                           gboolean close_fd_at_close)
141 {
142   GUnixOutputStream *stream;
143
144   g_return_val_if_fail (fd != -1, NULL);
145
146   stream = g_object_new (G_TYPE_UNIX_OUTPUT_STREAM, NULL);
147
148   stream->priv->fd = fd;
149   stream->priv->close_fd_at_close = close_fd_at_close;
150   
151   return G_OUTPUT_STREAM (stream);
152 }
153
154 static gssize
155 g_unix_output_stream_write (GOutputStream  *stream,
156                             const void     *buffer,
157                             gsize           count,
158                             GCancellable   *cancellable,
159                             GError        **error)
160 {
161   GUnixOutputStream *unix_stream;
162   gssize res;
163   GPollFD poll_fds[2];
164   int poll_ret;
165
166   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
167
168   if (cancellable)
169     {
170       poll_fds[0].fd = unix_stream->priv->fd;
171       poll_fds[0].events = G_IO_OUT;
172       g_cancellable_make_pollfd (cancellable, &poll_fds[1]);
173       do
174         poll_ret = g_poll (poll_fds, 2, -1);
175       while (poll_ret == -1 && errno == EINTR);
176       
177       if (poll_ret == -1)
178         {
179           int errsv = errno;
180
181           g_set_error (error, G_IO_ERROR,
182                        g_io_error_from_errno (errsv),
183                        _("Error writing to unix: %s"),
184                        g_strerror (errsv));
185           return -1;
186         }
187     }
188       
189   while (1)
190     {
191       if (g_cancellable_set_error_if_cancelled (cancellable, error))
192         return -1;
193
194       res = write (unix_stream->priv->fd, buffer, count);
195       if (res == -1)
196         {
197           int errsv = errno;
198
199           if (errsv == EINTR)
200             continue;
201           
202           g_set_error (error, G_IO_ERROR,
203                        g_io_error_from_errno (errsv),
204                        _("Error writing to unix: %s"),
205                        g_strerror (errsv));
206         }
207       
208       break;
209     }
210   
211   return res;
212 }
213
214 static gboolean
215 g_unix_output_stream_close (GOutputStream  *stream,
216                             GCancellable   *cancellable,
217                             GError        **error)
218 {
219   GUnixOutputStream *unix_stream;
220   int res;
221
222   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
223
224   if (!unix_stream->priv->close_fd_at_close)
225     return TRUE;
226   
227   while (1)
228     {
229       /* This might block during the close. Doesn't seem to be a way to avoid it though. */
230       res = close (unix_stream->priv->fd);
231       if (res == -1)
232         {
233           int errsv = errno;
234
235           g_set_error (error, G_IO_ERROR,
236                        g_io_error_from_errno (errsv),
237                        _("Error closing unix: %s"),
238                        g_strerror (errsv));
239         }
240       break;
241     }
242
243   return res != -1;
244 }
245
246 typedef struct {
247   gsize count;
248   const void *buffer;
249   GAsyncReadyCallback callback;
250   gpointer user_data;
251   GCancellable *cancellable;
252   GUnixOutputStream *stream;
253 } WriteAsyncData;
254
255 static gboolean
256 write_async_cb (WriteAsyncData *data,
257                 GIOCondition    condition,
258                 int             fd)
259 {
260   GSimpleAsyncResult *simple;
261   GError *error = NULL;
262   gssize count_written;
263
264   while (1)
265     {
266       if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
267         {
268           count_written = -1;
269           break;
270         }
271       
272       count_written = write (data->stream->priv->fd, data->buffer, data->count);
273       if (count_written == -1)
274         {
275           int errsv = errno;
276
277           if (errsv == EINTR)
278             continue;
279           
280           g_set_error (&error, G_IO_ERROR,
281                        g_io_error_from_errno (errsv),
282                        _("Error reading from unix: %s"),
283                        g_strerror (errsv));
284         }
285       break;
286     }
287
288   simple = g_simple_async_result_new (G_OBJECT (data->stream),
289                                       data->callback,
290                                       data->user_data,
291                                       g_unix_output_stream_write_async);
292   
293   g_simple_async_result_set_op_res_gssize (simple, count_written);
294
295   if (count_written == -1)
296     {
297       g_simple_async_result_set_from_error (simple, error);
298       g_error_free (error);
299     }
300
301   /* Complete immediately, not in idle, since we're already in a mainloop callout */
302   g_simple_async_result_complete (simple);
303   g_object_unref (simple);
304
305   return FALSE;
306 }
307
308 static void
309 g_unix_output_stream_write_async (GOutputStream       *stream,
310                                   const void          *buffer,
311                                   gsize                count,
312                                   int                  io_priority,
313                                   GCancellable        *cancellable,
314                                   GAsyncReadyCallback  callback,
315                                   gpointer             user_data)
316 {
317   GSource *source;
318   GUnixOutputStream *unix_stream;
319   WriteAsyncData *data;
320
321   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
322
323   data = g_new0 (WriteAsyncData, 1);
324   data->count = count;
325   data->buffer = buffer;
326   data->callback = callback;
327   data->user_data = user_data;
328   data->cancellable = cancellable;
329   data->stream = unix_stream;
330
331   source = _g_fd_source_new (unix_stream->priv->fd,
332                              G_IO_OUT,
333                              cancellable);
334   
335   g_source_set_callback (source, (GSourceFunc)write_async_cb, data, g_free);
336   g_source_attach (source, NULL);
337   
338   g_source_unref (source);
339 }
340
341 static gssize
342 g_unix_output_stream_write_finish (GOutputStream  *stream,
343                                    GAsyncResult   *result,
344                                    GError        **error)
345 {
346   GSimpleAsyncResult *simple;
347   gssize nwritten;
348
349   simple = G_SIMPLE_ASYNC_RESULT (result);
350   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_unix_output_stream_write_async);
351   
352   nwritten = g_simple_async_result_get_op_res_gssize (simple);
353   return nwritten;
354 }
355
356 typedef struct {
357   GOutputStream *stream;
358   GAsyncReadyCallback callback;
359   gpointer user_data;
360 } CloseAsyncData;
361
362 static gboolean
363 close_async_cb (CloseAsyncData *data)
364 {
365   GUnixOutputStream *unix_stream;
366   GSimpleAsyncResult *simple;
367   GError *error = NULL;
368   gboolean result;
369   int res;
370
371   unix_stream = G_UNIX_OUTPUT_STREAM (data->stream);
372
373   if (!unix_stream->priv->close_fd_at_close)
374     {
375       result = TRUE;
376       goto out;
377     }
378   
379   while (1)
380     {
381       res = close (unix_stream->priv->fd);
382       if (res == -1)
383         {
384           int errsv = errno;
385
386           g_set_error (&error, G_IO_ERROR,
387                        g_io_error_from_errno (errsv),
388                        _("Error closing unix: %s"),
389                        g_strerror (errsv));
390         }
391       break;
392     }
393   
394   result = res != -1;
395   
396  out:
397   simple = g_simple_async_result_new (G_OBJECT (data->stream),
398                                       data->callback,
399                                       data->user_data,
400                                       g_unix_output_stream_close_async);
401
402   if (!result)
403     {
404       g_simple_async_result_set_from_error (simple, error);
405       g_error_free (error);
406     }
407
408   /* Complete immediately, not in idle, since we're already in a mainloop callout */
409   g_simple_async_result_complete (simple);
410   g_object_unref (simple);
411   
412   return FALSE;
413 }
414
415 static void
416 g_unix_output_stream_close_async (GOutputStream        *stream,
417                                   int                  io_priority,
418                                   GCancellable        *cancellable,
419                                   GAsyncReadyCallback  callback,
420                                   gpointer             user_data)
421 {
422   GSource *idle;
423   CloseAsyncData *data;
424
425   data = g_new0 (CloseAsyncData, 1);
426
427   data->stream = stream;
428   data->callback = callback;
429   data->user_data = user_data;
430   
431   idle = g_idle_source_new ();
432   g_source_set_callback (idle, (GSourceFunc)close_async_cb, data, g_free);
433   g_source_attach (idle, NULL);
434   g_source_unref (idle);
435 }
436
437 static gboolean
438 g_unix_output_stream_close_finish (GOutputStream  *stream,
439                                    GAsyncResult   *result,
440                                    GError        **error)
441 {
442   /* Failures handled in generic close_finish code */
443   return TRUE;
444 }
445
446 #define __G_UNIX_OUTPUT_STREAM_C__
447 #include "gioaliasdef.c"