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 * Note that <filename><gio/gunixoutputstream.h></filename> belongs
54 * to the UNIX-specific GIO interfaces, thus you have to use the
55 * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
56 */
57
58 enum {
59 PROP_0,
60 PROP_FD,
61 PROP_CLOSE_FD
62 };
63
64 G_DEFINE_TYPE (GUnixOutputStream, g_unix_output_stream, G_TYPE_OUTPUT_STREAM);
65
66
67 struct _GUnixOutputStreamPrivate {
68 int fd;
69 gboolean close_fd;
70 };
71
72 static void g_unix_output_stream_set_property (GObject *object,
73 guint prop_id,
74 const GValue *value,
75 GParamSpec *pspec);
76 static void g_unix_output_stream_get_property (GObject *object,
77 guint prop_id,
78 GValue *value,
79 GParamSpec *pspec);
80 static gssize g_unix_output_stream_write (GOutputStream *stream,
81 const void *buffer,
82 gsize count,
83 GCancellable *cancellable,
84 GError **error);
85 static gboolean g_unix_output_stream_close (GOutputStream *stream,
86 GCancellable *cancellable,
87 GError **error);
88 static void g_unix_output_stream_write_async (GOutputStream *stream,
89 const void *buffer,
90 gsize count,
91 int io_priority,
92 GCancellable *cancellable,
93 GAsyncReadyCallback callback,
94 gpointer data);
95 static gssize g_unix_output_stream_write_finish (GOutputStream *stream,
96 GAsyncResult *result,
97 GError **error);
98 static void g_unix_output_stream_close_async (GOutputStream *stream,
99 int io_priority,
100 GCancellable *cancellable,
101 GAsyncReadyCallback callback,
102 gpointer data);
103 static gboolean g_unix_output_stream_close_finish (GOutputStream *stream,
104 GAsyncResult *result,
105 GError **error);
106
107
108 static void
g_unix_output_stream_finalize(GObject * object)109 g_unix_output_stream_finalize (GObject *object)
110 {
111 GUnixOutputStream *stream;
112
113 stream = G_UNIX_OUTPUT_STREAM (object);
114
115 G_OBJECT_CLASS (g_unix_output_stream_parent_class)->finalize (object);
116 }
117
118 static void
g_unix_output_stream_class_init(GUnixOutputStreamClass * klass)119 g_unix_output_stream_class_init (GUnixOutputStreamClass *klass)
120 {
121 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
122 GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
123
124 g_type_class_add_private (klass, sizeof (GUnixOutputStreamPrivate));
125
126 gobject_class->get_property = g_unix_output_stream_get_property;
127 gobject_class->set_property = g_unix_output_stream_set_property;
128 gobject_class->finalize = g_unix_output_stream_finalize;
129
130 stream_class->write_fn = g_unix_output_stream_write;
131 stream_class->close_fn = g_unix_output_stream_close;
132 stream_class->write_async = g_unix_output_stream_write_async;
133 stream_class->write_finish = g_unix_output_stream_write_finish;
134 stream_class->close_async = g_unix_output_stream_close_async;
135 stream_class->close_finish = g_unix_output_stream_close_finish;
136
137 /**
138 * GUnixOutputStream:fd:
139 *
140 * The file descriptor that the stream writes to.
141 *
142 * Since: 2.20
143 */
144 g_object_class_install_property (gobject_class,
145 PROP_FD,
146 g_param_spec_int ("fd",
147 _("File descriptor"),
148 _("The file descriptor to write to"),
149 G_MININT, G_MAXINT, -1,
150 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
151
152 /**
153 * GUnixOutputStream:close-fd:
154 *
155 * Whether to close the file descriptor when the stream is closed.
156 *
157 * Since: 2.20
158 */
159 g_object_class_install_property (gobject_class,
160 PROP_CLOSE_FD,
161 g_param_spec_boolean ("close-fd",
162 _("Close file descriptor"),
163 _("Whether to close the file descriptor when the stream is closed"),
164 TRUE,
165 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
166 }
167
168 static void
g_unix_output_stream_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)169 g_unix_output_stream_set_property (GObject *object,
170 guint prop_id,
171 const GValue *value,
172 GParamSpec *pspec)
173 {
174 GUnixOutputStream *unix_stream;
175
176 unix_stream = G_UNIX_OUTPUT_STREAM (object);
177
178 switch (prop_id)
179 {
180 case PROP_FD:
181 unix_stream->priv->fd = g_value_get_int (value);
182 break;
183 case PROP_CLOSE_FD:
184 unix_stream->priv->close_fd = g_value_get_boolean (value);
185 break;
186 default:
187 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
188 break;
189 }
190 }
191
192 static void
g_unix_output_stream_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)193 g_unix_output_stream_get_property (GObject *object,
194 guint prop_id,
195 GValue *value,
196 GParamSpec *pspec)
197 {
198 GUnixOutputStream *unix_stream;
199
200 unix_stream = G_UNIX_OUTPUT_STREAM (object);
201
202 switch (prop_id)
203 {
204 case PROP_FD:
205 g_value_set_int (value, unix_stream->priv->fd);
206 break;
207 case PROP_CLOSE_FD:
208 g_value_set_boolean (value, unix_stream->priv->close_fd);
209 break;
210 default:
211 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
212 }
213 }
214
215 static void
g_unix_output_stream_init(GUnixOutputStream * unix_stream)216 g_unix_output_stream_init (GUnixOutputStream *unix_stream)
217 {
218 unix_stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (unix_stream,
219 G_TYPE_UNIX_OUTPUT_STREAM,
220 GUnixOutputStreamPrivate);
221
222 unix_stream->priv->fd = -1;
223 unix_stream->priv->close_fd = TRUE;
224 }
225
226 /**
227 * g_unix_output_stream_new:
228 * @fd: a UNIX file descriptor
229 * @close_fd: %TRUE to close the file descriptor when done
230 *
231 * Creates a new #GUnixOutputStream for the given @fd.
232 *
233 * If @close_fd, is %TRUE, the file descriptor will be closed when
234 * the output stream is destroyed.
235 *
236 * Returns: a new #GOutputStream
237 **/
238 GOutputStream *
g_unix_output_stream_new(gint fd,gboolean close_fd)239 g_unix_output_stream_new (gint fd,
240 gboolean close_fd)
241 {
242 GUnixOutputStream *stream;
243
244 g_return_val_if_fail (fd != -1, NULL);
245
246 stream = g_object_new (G_TYPE_UNIX_OUTPUT_STREAM,
247 "fd", fd,
248 "close-fd", close_fd,
249 NULL);
250
251 return G_OUTPUT_STREAM (stream);
252 }
253
254 /**
255 * g_unix_output_stream_set_close_fd:
256 * @stream: a #GUnixOutputStream
257 * @close_fd: %TRUE to close the file descriptor when done
258 *
259 * Sets whether the file descriptor of @stream shall be closed
260 * when the stream is closed.
261 *
262 * Since: 2.20
263 */
264 void
g_unix_output_stream_set_close_fd(GUnixOutputStream * stream,gboolean close_fd)265 g_unix_output_stream_set_close_fd (GUnixOutputStream *stream,
266 gboolean close_fd)
267 {
268 g_return_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream));
269
270 close_fd = close_fd != FALSE;
271 if (stream->priv->close_fd != close_fd)
272 {
273 stream->priv->close_fd = close_fd;
274 g_object_notify (G_OBJECT (stream), "close-fd");
275 }
276 }
277
278 /**
279 * g_unix_output_stream_get_close_fd:
280 * @stream: a #GUnixOutputStream
281 *
282 * Returns whether the file descriptor of @stream will be
283 * closed when the stream is closed.
284 *
285 * Return value: %TRUE if the file descriptor is closed when done
286 *
287 * Since: 2.20
288 */
289 gboolean
g_unix_output_stream_get_close_fd(GUnixOutputStream * stream)290 g_unix_output_stream_get_close_fd (GUnixOutputStream *stream)
291 {
292 g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), FALSE);
293
294 return stream->priv->close_fd;
295 }
296
297 /**
298 * g_unix_output_stream_get_fd:
299 * @stream: a #GUnixOutputStream
300 *
301 * Return the UNIX file descriptor that the stream writes to.
302 *
303 * Return value: The file descriptor of @stream
304 *
305 * Since: 2.20
306 */
307 gint
g_unix_output_stream_get_fd(GUnixOutputStream * stream)308 g_unix_output_stream_get_fd (GUnixOutputStream *stream)
309 {
310 g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), -1);
311
312 return stream->priv->fd;
313 }
314
315 static gssize
g_unix_output_stream_write(GOutputStream * stream,const void * buffer,gsize count,GCancellable * cancellable,GError ** error)316 g_unix_output_stream_write (GOutputStream *stream,
317 const void *buffer,
318 gsize count,
319 GCancellable *cancellable,
320 GError **error)
321 {
322 GUnixOutputStream *unix_stream;
323 gssize res;
324 GPollFD poll_fds[2];
325 int poll_ret;
326
327 unix_stream = G_UNIX_OUTPUT_STREAM (stream);
328
329 if (cancellable)
330 {
331 poll_fds[0].fd = unix_stream->priv->fd;
332 poll_fds[0].events = G_IO_OUT;
333 g_cancellable_make_pollfd (cancellable, &poll_fds[1]);
334 do
335 poll_ret = g_poll (poll_fds, 2, -1);
336 while (poll_ret == -1 && errno == EINTR);
337
338 if (poll_ret == -1)
339 {
340 int errsv = errno;
341
342 g_set_error (error, G_IO_ERROR,
343 g_io_error_from_errno (errsv),
344 _("Error writing to unix: %s"),
345 g_strerror (errsv));
346 return -1;
347 }
348 }
349
350 while (1)
351 {
352 if (g_cancellable_set_error_if_cancelled (cancellable, error))
353 return -1;
354
355 res = write (unix_stream->priv->fd, buffer, count);
356 if (res == -1)
357 {
358 int errsv = errno;
359
360 if (errsv == EINTR)
361 continue;
362
363 g_set_error (error, G_IO_ERROR,
364 g_io_error_from_errno (errsv),
365 _("Error writing to unix: %s"),
366 g_strerror (errsv));
367 }
368
369 break;
370 }
371
372 return res;
373 }
374
375 static gboolean
g_unix_output_stream_close(GOutputStream * stream,GCancellable * cancellable,GError ** error)376 g_unix_output_stream_close (GOutputStream *stream,
377 GCancellable *cancellable,
378 GError **error)
379 {
380 GUnixOutputStream *unix_stream;
381 int res;
382
383 unix_stream = G_UNIX_OUTPUT_STREAM (stream);
384
385 if (!unix_stream->priv->close_fd)
386 return TRUE;
387
388 while (1)
389 {
390 /* This might block during the close. Doesn't seem to be a way to avoid it though. */
391 res = close (unix_stream->priv->fd);
392 if (res == -1)
393 {
394 int errsv = errno;
395
396 g_set_error (error, G_IO_ERROR,
397 g_io_error_from_errno (errsv),
398 _("Error closing unix: %s"),
399 g_strerror (errsv));
400 }
401 break;
402 }
403
404 return res != -1;
405 }
406
407 typedef struct {
408 gsize count;
409 const void *buffer;
410 GAsyncReadyCallback callback;
411 gpointer user_data;
412 GCancellable *cancellable;
413 GUnixOutputStream *stream;
414 } WriteAsyncData;
415
416 static gboolean
write_async_cb(WriteAsyncData * data,GIOCondition condition,int fd)417 write_async_cb (WriteAsyncData *data,
418 GIOCondition condition,
419 int fd)
420 {
421 GSimpleAsyncResult *simple;
422 GError *error = NULL;
423 gssize count_written;
424
425 while (1)
426 {
427 if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
428 {
429 count_written = -1;
430 break;
431 }
432
433 count_written = write (data->stream->priv->fd, data->buffer, data->count);
434 if (count_written == -1)
435 {
436 int errsv = errno;
437
438 if (errsv == EINTR)
439 continue;
440
441 g_set_error (&error, G_IO_ERROR,
442 g_io_error_from_errno (errsv),
443 _("Error reading from unix: %s"),
444 g_strerror (errsv));
445 }
446 break;
447 }
448
449 simple = g_simple_async_result_new (G_OBJECT (data->stream),
450 data->callback,
451 data->user_data,
452 g_unix_output_stream_write_async);
453
454 g_simple_async_result_set_op_res_gssize (simple, count_written);
455
456 if (count_written == -1)
457 {
458 g_simple_async_result_set_from_error (simple, error);
459 g_error_free (error);
460 }
461
462 /* Complete immediately, not in idle, since we're already in a mainloop callout */
463 g_simple_async_result_complete (simple);
464 g_object_unref (simple);
465
466 return FALSE;
467 }
468
469 static void
g_unix_output_stream_write_async(GOutputStream * stream,const void * buffer,gsize count,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)470 g_unix_output_stream_write_async (GOutputStream *stream,
471 const void *buffer,
472 gsize count,
473 int io_priority,
474 GCancellable *cancellable,
475 GAsyncReadyCallback callback,
476 gpointer user_data)
477 {
478 GSource *source;
479 GUnixOutputStream *unix_stream;
480 WriteAsyncData *data;
481
482 unix_stream = G_UNIX_OUTPUT_STREAM (stream);
483
484 data = g_new0 (WriteAsyncData, 1);
485 data->count = count;
486 data->buffer = buffer;
487 data->callback = callback;
488 data->user_data = user_data;
489 data->cancellable = cancellable;
490 data->stream = unix_stream;
491
492 source = _g_fd_source_new (unix_stream->priv->fd,
493 G_IO_OUT,
494 cancellable);
495
496 g_source_set_callback (source, (GSourceFunc)write_async_cb, data, g_free);
497 g_source_attach (source, NULL);
498
499 g_source_unref (source);
500 }
501
502 static gssize
g_unix_output_stream_write_finish(GOutputStream * stream,GAsyncResult * result,GError ** error)503 g_unix_output_stream_write_finish (GOutputStream *stream,
504 GAsyncResult *result,
505 GError **error)
506 {
507 GSimpleAsyncResult *simple;
508 gssize nwritten;
509
510 simple = G_SIMPLE_ASYNC_RESULT (result);
511 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_unix_output_stream_write_async);
512
513 nwritten = g_simple_async_result_get_op_res_gssize (simple);
514 return nwritten;
515 }
516
517 typedef struct {
518 GOutputStream *stream;
519 GAsyncReadyCallback callback;
520 gpointer user_data;
521 } CloseAsyncData;
522
523 static gboolean
close_async_cb(CloseAsyncData * data)524 close_async_cb (CloseAsyncData *data)
525 {
526 GUnixOutputStream *unix_stream;
527 GSimpleAsyncResult *simple;
528 GError *error = NULL;
529 gboolean result;
530 int res;
531
532 unix_stream = G_UNIX_OUTPUT_STREAM (data->stream);
533
534 if (!unix_stream->priv->close_fd)
535 {
536 result = TRUE;
537 goto out;
538 }
539
540 while (1)
541 {
542 res = close (unix_stream->priv->fd);
543 if (res == -1)
544 {
545 int errsv = errno;
546
547 g_set_error (&error, G_IO_ERROR,
548 g_io_error_from_errno (errsv),
549 _("Error closing unix: %s"),
550 g_strerror (errsv));
551 }
552 break;
553 }
554
555 result = res != -1;
556
557 out:
558 simple = g_simple_async_result_new (G_OBJECT (data->stream),
559 data->callback,
560 data->user_data,
561 g_unix_output_stream_close_async);
562
563 if (!result)
564 {
565 g_simple_async_result_set_from_error (simple, error);
566 g_error_free (error);
567 }
568
569 /* Complete immediately, not in idle, since we're already in a mainloop callout */
570 g_simple_async_result_complete (simple);
571 g_object_unref (simple);
572
573 return FALSE;
574 }
575
576 static void
g_unix_output_stream_close_async(GOutputStream * stream,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)577 g_unix_output_stream_close_async (GOutputStream *stream,
578 int io_priority,
579 GCancellable *cancellable,
580 GAsyncReadyCallback callback,
581 gpointer user_data)
582 {
583 GSource *idle;
584 CloseAsyncData *data;
585
586 data = g_new0 (CloseAsyncData, 1);
587
588 data->stream = stream;
589 data->callback = callback;
590 data->user_data = user_data;
591
592 idle = g_idle_source_new ();
593 g_source_set_callback (idle, (GSourceFunc)close_async_cb, data, g_free);
594 g_source_attach (idle, NULL);
595 g_source_unref (idle);
596 }
597
598 static gboolean
g_unix_output_stream_close_finish(GOutputStream * stream,GAsyncResult * result,GError ** error)599 g_unix_output_stream_close_finish (GOutputStream *stream,
600 GAsyncResult *result,
601 GError **error)
602 {
603 /* Failures handled in generic close_finish code */
604 return TRUE;
605 }
606
607 #define __G_UNIX_OUTPUT_STREAM_C__
608 #include "gioaliasdef.c"
609