Branch data Line data Source code
1 : : /* GIO - GLib Input, Output and Streaming Library
2 : : *
3 : : * Copyright (C) 2006-2007 Red Hat, Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : *
20 : : * Author: Alexander Larsson <alexl@redhat.com>
21 : : */
22 : :
23 : : #include "config.h"
24 : :
25 : : #include <unistd.h>
26 : : #include <errno.h>
27 : : #include <stdio.h>
28 : : #include <sys/uio.h>
29 : :
30 : : #include <glib.h>
31 : : #include <glib/gstdio.h>
32 : : #include <glib/glib-unix.h>
33 : : #include "gioerror.h"
34 : : #include "gunixoutputstream.h"
35 : : #include "gcancellable.h"
36 : : #include "gasynchelper.h"
37 : : #include "gfiledescriptorbased.h"
38 : : #include "glibintl.h"
39 : : #include "gioprivate.h"
40 : : #include "giounix-private.h"
41 : :
42 : :
43 : : /**
44 : : * GUnixOutputStream:
45 : : *
46 : : * `GUnixOutputStream` implements [class@Gio.OutputStream] for writing to a UNIX
47 : : * file descriptor, including asynchronous operations. (If the file
48 : : * descriptor refers to a socket or pipe, this will use `poll()` to do
49 : : * asynchronous I/O. If it refers to a regular file, it will fall back
50 : : * to doing asynchronous I/O in another thread.)
51 : : *
52 : : * Note that `<gio/gunixoutputstream.h>` belongs to the UNIX-specific GIO
53 : : * interfaces, thus you have to use the `gio-unix-2.0.pc` pkg-config file
54 : : * file or the `GioUnix-2.0` GIR namespace when using it.
55 : : */
56 : :
57 : : enum {
58 : : PROP_0,
59 : : PROP_FD,
60 : : PROP_CLOSE_FD
61 : : };
62 : :
63 : : struct _GUnixOutputStreamPrivate {
64 : : int fd;
65 : : guint close_fd : 1;
66 : : guint can_poll : 1;
67 : : };
68 : :
69 : : static void g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface);
70 : : static void g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface);
71 : :
72 : 42247 : G_DEFINE_TYPE_WITH_CODE (GUnixOutputStream, g_unix_output_stream, G_TYPE_OUTPUT_STREAM,
73 : : G_ADD_PRIVATE (GUnixOutputStream)
74 : : G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM,
75 : : g_unix_output_stream_pollable_iface_init)
76 : : G_IMPLEMENT_INTERFACE (G_TYPE_FILE_DESCRIPTOR_BASED,
77 : : g_unix_output_stream_file_descriptor_based_iface_init)
78 : : )
79 : :
80 : : static void g_unix_output_stream_set_property (GObject *object,
81 : : guint prop_id,
82 : : const GValue *value,
83 : : GParamSpec *pspec);
84 : : static void g_unix_output_stream_get_property (GObject *object,
85 : : guint prop_id,
86 : : GValue *value,
87 : : GParamSpec *pspec);
88 : : static gssize g_unix_output_stream_write (GOutputStream *stream,
89 : : const void *buffer,
90 : : gsize count,
91 : : GCancellable *cancellable,
92 : : GError **error);
93 : : static gboolean g_unix_output_stream_writev (GOutputStream *stream,
94 : : const GOutputVector *vectors,
95 : : gsize n_vectors,
96 : : gsize *bytes_written,
97 : : GCancellable *cancellable,
98 : : GError **error);
99 : : static gboolean g_unix_output_stream_close (GOutputStream *stream,
100 : : GCancellable *cancellable,
101 : : GError **error);
102 : :
103 : : static gboolean g_unix_output_stream_pollable_can_poll (GPollableOutputStream *stream);
104 : : static gboolean g_unix_output_stream_pollable_is_writable (GPollableOutputStream *stream);
105 : : static GSource *g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
106 : : GCancellable *cancellable);
107 : : static GPollableReturn g_unix_output_stream_pollable_writev_nonblocking (GPollableOutputStream *stream,
108 : : const GOutputVector *vectors,
109 : : gsize n_vectors,
110 : : gsize *bytes_written,
111 : : GError **error);
112 : :
113 : : static void
114 : 13 : g_unix_output_stream_class_init (GUnixOutputStreamClass *klass)
115 : : {
116 : 13 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
117 : 13 : GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
118 : :
119 : 13 : gobject_class->get_property = g_unix_output_stream_get_property;
120 : 13 : gobject_class->set_property = g_unix_output_stream_set_property;
121 : :
122 : 13 : stream_class->write_fn = g_unix_output_stream_write;
123 : 13 : stream_class->writev_fn = g_unix_output_stream_writev;
124 : 13 : stream_class->close_fn = g_unix_output_stream_close;
125 : :
126 : : /**
127 : : * GUnixOutputStream:fd:
128 : : *
129 : : * The file descriptor that the stream writes to.
130 : : *
131 : : * Since: 2.20
132 : : */
133 : 13 : g_object_class_install_property (gobject_class,
134 : : PROP_FD,
135 : : g_param_spec_int ("fd", NULL, NULL,
136 : : G_MININT, G_MAXINT, -1,
137 : : G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
138 : :
139 : : /**
140 : : * GUnixOutputStream:close-fd:
141 : : *
142 : : * Whether to close the file descriptor when the stream is closed.
143 : : *
144 : : * Since: 2.20
145 : : */
146 : 13 : g_object_class_install_property (gobject_class,
147 : : PROP_CLOSE_FD,
148 : : g_param_spec_boolean ("close-fd", NULL, NULL,
149 : : TRUE,
150 : : G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
151 : 13 : }
152 : :
153 : : static void
154 : 13 : g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface)
155 : : {
156 : 13 : iface->can_poll = g_unix_output_stream_pollable_can_poll;
157 : 13 : iface->is_writable = g_unix_output_stream_pollable_is_writable;
158 : 13 : iface->create_source = g_unix_output_stream_pollable_create_source;
159 : 13 : iface->writev_nonblocking = g_unix_output_stream_pollable_writev_nonblocking;
160 : 13 : }
161 : :
162 : : static void
163 : 13 : g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface)
164 : : {
165 : 13 : iface->get_fd = (int (*) (GFileDescriptorBased *))g_unix_output_stream_get_fd;
166 : 13 : }
167 : :
168 : : static void
169 : 970 : 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 : 970 : unix_stream = G_UNIX_OUTPUT_STREAM (object);
177 : :
178 : 970 : switch (prop_id)
179 : : {
180 : 485 : case PROP_FD:
181 : 485 : unix_stream->priv->fd = g_value_get_int (value);
182 : 485 : unix_stream->priv->can_poll = _g_fd_is_pollable (unix_stream->priv->fd);
183 : 485 : break;
184 : 485 : case PROP_CLOSE_FD:
185 : 485 : unix_stream->priv->close_fd = g_value_get_boolean (value);
186 : 485 : break;
187 : 0 : default:
188 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
189 : 0 : break;
190 : : }
191 : 970 : }
192 : :
193 : : static void
194 : 2 : g_unix_output_stream_get_property (GObject *object,
195 : : guint prop_id,
196 : : GValue *value,
197 : : GParamSpec *pspec)
198 : : {
199 : : GUnixOutputStream *unix_stream;
200 : :
201 : 2 : unix_stream = G_UNIX_OUTPUT_STREAM (object);
202 : :
203 : 2 : switch (prop_id)
204 : : {
205 : 1 : case PROP_FD:
206 : 1 : g_value_set_int (value, unix_stream->priv->fd);
207 : 1 : break;
208 : 1 : case PROP_CLOSE_FD:
209 : 1 : g_value_set_boolean (value, unix_stream->priv->close_fd);
210 : 1 : break;
211 : 0 : default:
212 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
213 : : }
214 : 2 : }
215 : :
216 : : static void
217 : 485 : g_unix_output_stream_init (GUnixOutputStream *unix_stream)
218 : : {
219 : 485 : unix_stream->priv = g_unix_output_stream_get_instance_private (unix_stream);
220 : 485 : unix_stream->priv->fd = -1;
221 : 485 : unix_stream->priv->close_fd = TRUE;
222 : 485 : }
223 : :
224 : : /**
225 : : * g_unix_output_stream_new:
226 : : * @fd: a UNIX file descriptor
227 : : * @close_fd: %TRUE to close the file descriptor when done
228 : : *
229 : : * Creates a new #GUnixOutputStream for the given @fd.
230 : : *
231 : : * If @close_fd, is %TRUE, the file descriptor will be closed when
232 : : * the output stream is destroyed.
233 : : *
234 : : * Returns: a new #GOutputStream
235 : : **/
236 : : GOutputStream *
237 : 485 : g_unix_output_stream_new (gint fd,
238 : : gboolean close_fd)
239 : : {
240 : : GUnixOutputStream *stream;
241 : :
242 : 485 : g_return_val_if_fail (fd != -1, NULL);
243 : :
244 : 485 : stream = g_object_new (G_TYPE_UNIX_OUTPUT_STREAM,
245 : : "fd", fd,
246 : : "close-fd", close_fd,
247 : : NULL);
248 : :
249 : 485 : return G_OUTPUT_STREAM (stream);
250 : : }
251 : :
252 : : /**
253 : : * g_unix_output_stream_set_close_fd:
254 : : * @stream: a #GUnixOutputStream
255 : : * @close_fd: %TRUE to close the file descriptor when done
256 : : *
257 : : * Sets whether the file descriptor of @stream shall be closed
258 : : * when the stream is closed.
259 : : *
260 : : * Since: 2.20
261 : : */
262 : : void
263 : 1 : g_unix_output_stream_set_close_fd (GUnixOutputStream *stream,
264 : : gboolean close_fd)
265 : : {
266 : 1 : g_return_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream));
267 : :
268 : 1 : close_fd = close_fd != FALSE;
269 : 1 : if (stream->priv->close_fd != close_fd)
270 : : {
271 : 1 : stream->priv->close_fd = close_fd;
272 : 1 : g_object_notify (G_OBJECT (stream), "close-fd");
273 : : }
274 : : }
275 : :
276 : : /**
277 : : * g_unix_output_stream_get_close_fd:
278 : : * @stream: a #GUnixOutputStream
279 : : *
280 : : * Returns whether the file descriptor of @stream will be
281 : : * closed when the stream is closed.
282 : : *
283 : : * Returns: %TRUE if the file descriptor is closed when done
284 : : *
285 : : * Since: 2.20
286 : : */
287 : : gboolean
288 : 1 : g_unix_output_stream_get_close_fd (GUnixOutputStream *stream)
289 : : {
290 : 1 : g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), FALSE);
291 : :
292 : 1 : return stream->priv->close_fd;
293 : : }
294 : :
295 : : /**
296 : : * g_unix_output_stream_get_fd:
297 : : * @stream: a #GUnixOutputStream
298 : : *
299 : : * Return the UNIX file descriptor that the stream writes to.
300 : : *
301 : : * Returns: The file descriptor of @stream
302 : : *
303 : : * Since: 2.20
304 : : */
305 : : gint
306 : 52 : g_unix_output_stream_get_fd (GUnixOutputStream *stream)
307 : : {
308 : 52 : g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), -1);
309 : :
310 : 52 : return stream->priv->fd;
311 : : }
312 : :
313 : : static gssize
314 : 24976 : g_unix_output_stream_write (GOutputStream *stream,
315 : : const void *buffer,
316 : : gsize count,
317 : : GCancellable *cancellable,
318 : : GError **error)
319 : : {
320 : : GUnixOutputStream *unix_stream;
321 : 24976 : gssize res = -1;
322 : : GPollFD poll_fds[2];
323 : 24976 : int nfds = 0;
324 : : int poll_ret;
325 : :
326 : 24976 : unix_stream = G_UNIX_OUTPUT_STREAM (stream);
327 : :
328 : 24976 : poll_fds[0].fd = unix_stream->priv->fd;
329 : 24976 : poll_fds[0].events = G_IO_OUT;
330 : 24976 : nfds++;
331 : :
332 : 49952 : if (unix_stream->priv->can_poll &&
333 : 24976 : g_cancellable_make_pollfd (cancellable, &poll_fds[1]))
334 : 14067 : nfds++;
335 : :
336 : : while (1)
337 : 0 : {
338 : : int errsv;
339 : :
340 : 24976 : poll_fds[0].revents = poll_fds[1].revents = 0;
341 : : do
342 : : {
343 : 24976 : poll_ret = g_poll (poll_fds, nfds, -1);
344 : 24976 : errsv = errno;
345 : : }
346 : 24976 : while (poll_ret == -1 && errsv == EINTR);
347 : :
348 : 24976 : if (poll_ret == -1)
349 : : {
350 : 0 : g_set_error (error, G_IO_ERROR,
351 : 0 : g_io_error_from_errno (errsv),
352 : : _("Error writing to file descriptor: %s"),
353 : : g_strerror (errsv));
354 : 0 : break;
355 : : }
356 : :
357 : 24976 : if (g_cancellable_set_error_if_cancelled (cancellable, error))
358 : 113 : break;
359 : :
360 : 24863 : if (!poll_fds[0].revents)
361 : 0 : continue;
362 : :
363 : 24863 : res = write (unix_stream->priv->fd, buffer, count);
364 : 24863 : errsv = errno;
365 : 24863 : if (res == -1)
366 : : {
367 : 0 : if (errsv == EINTR || errsv == EAGAIN)
368 : 0 : continue;
369 : :
370 : 0 : g_set_error (error, G_IO_ERROR,
371 : 0 : g_io_error_from_errno (errsv),
372 : : _("Error writing to file descriptor: %s"),
373 : : g_strerror (errsv));
374 : : }
375 : :
376 : 24863 : break;
377 : : }
378 : :
379 : 24976 : if (nfds == 2)
380 : 14067 : g_cancellable_release_fd (cancellable);
381 : 24976 : return res;
382 : : }
383 : :
384 : : /* Macro to check if struct iovec and GOutputVector have the same ABI */
385 : : #define G_OUTPUT_VECTOR_IS_IOVEC (sizeof (struct iovec) == sizeof (GOutputVector) && \
386 : : G_SIZEOF_MEMBER (struct iovec, iov_base) == G_SIZEOF_MEMBER (GOutputVector, buffer) && \
387 : : G_STRUCT_OFFSET (struct iovec, iov_base) == G_STRUCT_OFFSET (GOutputVector, buffer) && \
388 : : G_SIZEOF_MEMBER (struct iovec, iov_len) == G_SIZEOF_MEMBER (GOutputVector, size) && \
389 : : G_STRUCT_OFFSET (struct iovec, iov_len) == G_STRUCT_OFFSET (GOutputVector, size))
390 : :
391 : : static gboolean
392 : 1 : g_unix_output_stream_writev (GOutputStream *stream,
393 : : const GOutputVector *vectors,
394 : : gsize n_vectors,
395 : : gsize *bytes_written,
396 : : GCancellable *cancellable,
397 : : GError **error)
398 : : {
399 : : GUnixOutputStream *unix_stream;
400 : 1 : gssize res = -1;
401 : : GPollFD poll_fds[2];
402 : 1 : int nfds = 0;
403 : : int poll_ret;
404 : : struct iovec *iov;
405 : :
406 : 1 : if (bytes_written)
407 : 1 : *bytes_written = 0;
408 : :
409 : : /* Clamp the number of vectors if more given than we can write in one go.
410 : : * The caller has to handle short writes anyway.
411 : : */
412 : 1 : if (n_vectors > G_IOV_MAX)
413 : 0 : n_vectors = G_IOV_MAX;
414 : :
415 : 1 : unix_stream = G_UNIX_OUTPUT_STREAM (stream);
416 : :
417 : : if (G_OUTPUT_VECTOR_IS_IOVEC)
418 : : {
419 : : /* ABI is compatible */
420 : 1 : iov = (struct iovec *) vectors;
421 : : }
422 : : else
423 : : {
424 : : gsize i;
425 : :
426 : : /* ABI is incompatible */
427 : : iov = g_newa (struct iovec, n_vectors);
428 : : for (i = 0; i < n_vectors; i++)
429 : : {
430 : : iov[i].iov_base = (void *)vectors[i].buffer;
431 : : iov[i].iov_len = vectors[i].size;
432 : : }
433 : : }
434 : :
435 : 1 : poll_fds[0].fd = unix_stream->priv->fd;
436 : 1 : poll_fds[0].events = G_IO_OUT;
437 : 1 : nfds++;
438 : :
439 : 2 : if (unix_stream->priv->can_poll &&
440 : 1 : g_cancellable_make_pollfd (cancellable, &poll_fds[1]))
441 : 0 : nfds++;
442 : :
443 : : while (1)
444 : 0 : {
445 : : int errsv;
446 : :
447 : 1 : poll_fds[0].revents = poll_fds[1].revents = 0;
448 : : do
449 : : {
450 : 1 : poll_ret = g_poll (poll_fds, nfds, -1);
451 : 1 : errsv = errno;
452 : : }
453 : 1 : while (poll_ret == -1 && errsv == EINTR);
454 : :
455 : 1 : if (poll_ret == -1)
456 : : {
457 : 0 : g_set_error (error, G_IO_ERROR,
458 : 0 : g_io_error_from_errno (errsv),
459 : : _("Error writing to file descriptor: %s"),
460 : : g_strerror (errsv));
461 : 0 : break;
462 : : }
463 : :
464 : 1 : if (g_cancellable_set_error_if_cancelled (cancellable, error))
465 : 0 : break;
466 : :
467 : 1 : if (!poll_fds[0].revents)
468 : 0 : continue;
469 : :
470 : 1 : res = writev (unix_stream->priv->fd, iov, n_vectors);
471 : 1 : errsv = errno;
472 : 1 : if (res == -1)
473 : : {
474 : 0 : if (errsv == EINTR || errsv == EAGAIN)
475 : 0 : continue;
476 : :
477 : 0 : g_set_error (error, G_IO_ERROR,
478 : 0 : g_io_error_from_errno (errsv),
479 : : _("Error writing to file descriptor: %s"),
480 : : g_strerror (errsv));
481 : : }
482 : :
483 : 1 : if (bytes_written)
484 : 1 : *bytes_written = res;
485 : :
486 : 1 : break;
487 : : }
488 : :
489 : 1 : if (nfds == 2)
490 : 0 : g_cancellable_release_fd (cancellable);
491 : 1 : return res != -1;
492 : : }
493 : :
494 : : static gboolean
495 : 487 : g_unix_output_stream_close (GOutputStream *stream,
496 : : GCancellable *cancellable,
497 : : GError **error)
498 : : {
499 : : GUnixOutputStream *unix_stream;
500 : : int res;
501 : :
502 : 487 : unix_stream = G_UNIX_OUTPUT_STREAM (stream);
503 : :
504 : 487 : if (!unix_stream->priv->close_fd)
505 : 2 : return TRUE;
506 : :
507 : : /* This might block during the close. Doesn't seem to be a way to avoid it though. */
508 : 485 : res = close (unix_stream->priv->fd);
509 : 485 : if (res == -1)
510 : : {
511 : 0 : int errsv = errno;
512 : :
513 : 0 : g_set_error (error, G_IO_ERROR,
514 : 0 : g_io_error_from_errno (errsv),
515 : : _("Error closing file descriptor: %s"),
516 : : g_strerror (errsv));
517 : : }
518 : :
519 : 485 : return res != -1;
520 : : }
521 : :
522 : : static gboolean
523 : 7038 : g_unix_output_stream_pollable_can_poll (GPollableOutputStream *stream)
524 : : {
525 : 7038 : return G_UNIX_OUTPUT_STREAM (stream)->priv->can_poll;
526 : : }
527 : :
528 : : static gboolean
529 : 7651 : g_unix_output_stream_pollable_is_writable (GPollableOutputStream *stream)
530 : : {
531 : 7651 : GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
532 : : GPollFD poll_fd;
533 : : gint result;
534 : :
535 : 7651 : poll_fd.fd = unix_stream->priv->fd;
536 : 7651 : poll_fd.events = G_IO_OUT;
537 : 7651 : poll_fd.revents = 0;
538 : :
539 : : do
540 : 7651 : result = g_poll (&poll_fd, 1, 0);
541 : 7651 : while (result == -1 && errno == EINTR);
542 : :
543 : 7651 : return poll_fd.revents != 0;
544 : : }
545 : :
546 : : static GSource *
547 : 2 : g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
548 : : GCancellable *cancellable)
549 : : {
550 : 2 : GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
551 : : GSource *inner_source, *cancellable_source, *pollable_source;
552 : :
553 : 2 : pollable_source = g_pollable_source_new (G_OBJECT (stream));
554 : :
555 : 2 : inner_source = g_unix_fd_source_new (unix_stream->priv->fd, G_IO_OUT);
556 : 2 : g_source_set_dummy_callback (inner_source);
557 : 2 : g_source_add_child_source (pollable_source, inner_source);
558 : 2 : g_source_unref (inner_source);
559 : :
560 : 2 : if (cancellable)
561 : : {
562 : 1 : cancellable_source = g_cancellable_source_new (cancellable);
563 : 1 : g_source_set_dummy_callback (cancellable_source);
564 : 1 : g_source_add_child_source (pollable_source, cancellable_source);
565 : 1 : g_source_unref (cancellable_source);
566 : : }
567 : :
568 : 2 : return pollable_source;
569 : : }
570 : :
571 : : static GPollableReturn
572 : 10 : g_unix_output_stream_pollable_writev_nonblocking (GPollableOutputStream *stream,
573 : : const GOutputVector *vectors,
574 : : gsize n_vectors,
575 : : gsize *bytes_written,
576 : : GError **error)
577 : : {
578 : 10 : GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
579 : : struct iovec *iov;
580 : 10 : gssize res = -1;
581 : :
582 : 10 : if (!g_pollable_output_stream_is_writable (stream))
583 : : {
584 : 3 : *bytes_written = 0;
585 : 3 : return G_POLLABLE_RETURN_WOULD_BLOCK;
586 : : }
587 : :
588 : : /* Clamp the number of vectors if more given than we can write in one go.
589 : : * The caller has to handle short writes anyway.
590 : : */
591 : 7 : if (n_vectors > G_IOV_MAX)
592 : 0 : n_vectors = G_IOV_MAX;
593 : :
594 : : if (G_OUTPUT_VECTOR_IS_IOVEC)
595 : : {
596 : : /* ABI is compatible */
597 : 7 : iov = (struct iovec *) vectors;
598 : : }
599 : : else
600 : : {
601 : : gsize i;
602 : :
603 : : /* ABI is incompatible */
604 : : iov = g_newa (struct iovec, n_vectors);
605 : : for (i = 0; i < n_vectors; i++)
606 : : {
607 : : iov[i].iov_base = (void *)vectors[i].buffer;
608 : : iov[i].iov_len = vectors[i].size;
609 : : }
610 : : }
611 : :
612 : : while (1)
613 : 0 : {
614 : : int errsv;
615 : :
616 : 7 : res = writev (unix_stream->priv->fd, iov, n_vectors);
617 : 7 : errsv = errno;
618 : 7 : if (res == -1)
619 : : {
620 : 0 : if (errsv == EINTR)
621 : 0 : continue;
622 : :
623 : 0 : g_set_error (error, G_IO_ERROR,
624 : 0 : g_io_error_from_errno (errsv),
625 : : _("Error writing to file descriptor: %s"),
626 : : g_strerror (errsv));
627 : : }
628 : :
629 : 7 : if (bytes_written)
630 : 7 : *bytes_written = res;
631 : :
632 : 7 : break;
633 : : }
634 : :
635 : 7 : return res != -1 ? G_POLLABLE_RETURN_OK : G_POLLABLE_RETURN_FAILED;
636 : : }
|