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