Fixed some minor typos in documentation.
[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
51  * unix file descriptor, including asynchronous operations. The file
52  * descriptor must 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           int errsv = errno;
187
188           g_set_error (error, G_IO_ERROR,
189                        g_io_error_from_errno (errsv),
190                        _("Error writing to unix: %s"),
191                        g_strerror (errsv));
192           return -1;
193         }
194     }
195       
196   while (1)
197     {
198       if (g_cancellable_set_error_if_cancelled (cancellable, error))
199         return -1;
200
201       res = write (unix_stream->priv->fd, buffer, count);
202       if (res == -1)
203         {
204           int errsv = errno;
205
206           if (errsv == EINTR)
207             continue;
208           
209           g_set_error (error, G_IO_ERROR,
210                        g_io_error_from_errno (errsv),
211                        _("Error writing to unix: %s"),
212                        g_strerror (errsv));
213         }
214       
215       break;
216     }
217   
218   return res;
219 }
220
221 static gboolean
222 g_unix_output_stream_close (GOutputStream  *stream,
223                             GCancellable   *cancellable,
224                             GError        **error)
225 {
226   GUnixOutputStream *unix_stream;
227   int res;
228
229   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
230
231   if (!unix_stream->priv->close_fd_at_close)
232     return TRUE;
233   
234   while (1)
235     {
236       /* This might block during the close. Doesn't seem to be a way to avoid it though. */
237       res = close (unix_stream->priv->fd);
238       if (res == -1)
239         {
240           int errsv = errno;
241
242           g_set_error (error, G_IO_ERROR,
243                        g_io_error_from_errno (errsv),
244                        _("Error closing unix: %s"),
245                        g_strerror (errsv));
246         }
247       break;
248     }
249
250   return res != -1;
251 }
252
253 typedef struct {
254   gsize count;
255   const void *buffer;
256   GAsyncReadyCallback callback;
257   gpointer user_data;
258   GCancellable *cancellable;
259   GUnixOutputStream *stream;
260 } WriteAsyncData;
261
262 static gboolean
263 write_async_cb (WriteAsyncData *data,
264                 GIOCondition    condition,
265                 int             fd)
266 {
267   GSimpleAsyncResult *simple;
268   GError *error = NULL;
269   gssize count_written;
270
271   while (1)
272     {
273       if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
274         {
275           count_written = -1;
276           break;
277         }
278       
279       count_written = write (data->stream->priv->fd, data->buffer, data->count);
280       if (count_written == -1)
281         {
282           int errsv = errno;
283
284           if (errsv == EINTR)
285             continue;
286           
287           g_set_error (&error, G_IO_ERROR,
288                        g_io_error_from_errno (errsv),
289                        _("Error reading from unix: %s"),
290                        g_strerror (errsv));
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_output_stream_write_async);
299   
300   g_simple_async_result_set_op_res_gssize (simple, count_written);
301
302   if (count_written == -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_output_stream_write_async (GOutputStream       *stream,
317                                   const void          *buffer,
318                                   gsize                count,
319                                   int                  io_priority,
320                                   GCancellable        *cancellable,
321                                   GAsyncReadyCallback  callback,
322                                   gpointer             user_data)
323 {
324   GSource *source;
325   GUnixOutputStream *unix_stream;
326   WriteAsyncData *data;
327
328   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
329
330   data = g_new0 (WriteAsyncData, 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                              POLLOUT,
340                              cancellable);
341   
342   g_source_set_callback (source, (GSourceFunc)write_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_output_stream_write_finish (GOutputStream  *stream,
350                                    GAsyncResult   *result,
351                                    GError        **error)
352 {
353   GSimpleAsyncResult *simple;
354   gssize nwritten;
355
356   simple = G_SIMPLE_ASYNC_RESULT (result);
357   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_unix_output_stream_write_async);
358   
359   nwritten = g_simple_async_result_get_op_res_gssize (simple);
360   return nwritten;
361 }
362
363 typedef struct {
364   GOutputStream *stream;
365   GAsyncReadyCallback callback;
366   gpointer user_data;
367 } CloseAsyncData;
368
369 static gboolean
370 close_async_cb (CloseAsyncData *data)
371 {
372   GUnixOutputStream *unix_stream;
373   GSimpleAsyncResult *simple;
374   GError *error = NULL;
375   gboolean result;
376   int res;
377
378   unix_stream = G_UNIX_OUTPUT_STREAM (data->stream);
379
380   if (!unix_stream->priv->close_fd_at_close)
381     {
382       result = TRUE;
383       goto out;
384     }
385   
386   while (1)
387     {
388       res = close (unix_stream->priv->fd);
389       if (res == -1)
390         {
391           int errsv = errno;
392
393           g_set_error (&error, G_IO_ERROR,
394                        g_io_error_from_errno (errsv),
395                        _("Error closing unix: %s"),
396                        g_strerror (errsv));
397         }
398       break;
399     }
400   
401   result = res != -1;
402   
403  out:
404   simple = g_simple_async_result_new (G_OBJECT (data->stream),
405                                       data->callback,
406                                       data->user_data,
407                                       g_unix_output_stream_close_async);
408
409   if (!result)
410     {
411       g_simple_async_result_set_from_error (simple, error);
412       g_error_free (error);
413     }
414
415   /* Complete immediately, not in idle, since we're already in a mainloop callout */
416   g_simple_async_result_complete (simple);
417   g_object_unref (simple);
418   
419   return FALSE;
420 }
421
422 static void
423 g_unix_output_stream_close_async (GOutputStream        *stream,
424                                   int                  io_priority,
425                                   GCancellable        *cancellable,
426                                   GAsyncReadyCallback  callback,
427                                   gpointer             user_data)
428 {
429   GSource *idle;
430   CloseAsyncData *data;
431
432   data = g_new0 (CloseAsyncData, 1);
433
434   data->stream = stream;
435   data->callback = callback;
436   data->user_data = user_data;
437   
438   idle = g_idle_source_new ();
439   g_source_set_callback (idle, (GSourceFunc)close_async_cb, data, g_free);
440   g_source_attach (idle, NULL);
441   g_source_unref (idle);
442 }
443
444 static gboolean
445 g_unix_output_stream_close_finish (GOutputStream  *stream,
446                                    GAsyncResult   *result,
447                                    GError        **error)
448 {
449   /* Failures handled in generic close_finish code */
450   return TRUE;
451 }
452
453 #define __G_UNIX_OUTPUT_STREAM_C__
454 #include "gioaliasdef.c"