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 (at) 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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