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