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