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 : : #include <string.h>
25 : : #include "goutputstream.h"
26 : : #include "gcancellable.h"
27 : : #include "gasyncresult.h"
28 : : #include "gtask.h"
29 : : #include "ginputstream.h"
30 : : #include "gioerror.h"
31 : : #include "gioprivate.h"
32 : : #include "glibintl.h"
33 : : #include "gpollableoutputstream.h"
34 : :
35 : : /**
36 : : * GOutputStream:
37 : : *
38 : : * `GOutputStream` is a base class for implementing streaming output.
39 : : *
40 : : * It has functions to write to a stream ([method@Gio.OutputStream.write]),
41 : : * to close a stream ([method@Gio.OutputStream.close]) and to flush pending
42 : : * writes ([method@Gio.OutputStream.flush]).
43 : : *
44 : : * To copy the content of an input stream to an output stream without
45 : : * manually handling the reads and writes, use [method@Gio.OutputStream.splice].
46 : : *
47 : : * See the documentation for [class@Gio.IOStream] for details of thread safety
48 : : * of streaming APIs.
49 : : *
50 : : * All of these functions have async variants too.
51 : : *
52 : : * All classes derived from `GOutputStream` *should* implement synchronous
53 : : * writing, splicing, flushing and closing streams, but *may* implement
54 : : * asynchronous versions.
55 : : **/
56 : :
57 : : struct _GOutputStreamPrivate {
58 : : guint closed : 1;
59 : : guint pending : 1;
60 : : guint closing : 1;
61 : : GAsyncReadyCallback outstanding_callback;
62 : : };
63 : :
64 : 1107189 : G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GOutputStream, g_output_stream, G_TYPE_OBJECT)
65 : :
66 : : static gssize g_output_stream_real_splice (GOutputStream *stream,
67 : : GInputStream *source,
68 : : GOutputStreamSpliceFlags flags,
69 : : GCancellable *cancellable,
70 : : GError **error);
71 : : static void g_output_stream_real_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_output_stream_real_write_finish (GOutputStream *stream,
79 : : GAsyncResult *result,
80 : : GError **error);
81 : : static gboolean g_output_stream_real_writev (GOutputStream *stream,
82 : : const GOutputVector *vectors,
83 : : gsize n_vectors,
84 : : gsize *bytes_written,
85 : : GCancellable *cancellable,
86 : : GError **error);
87 : : static void g_output_stream_real_writev_async (GOutputStream *stream,
88 : : const GOutputVector *vectors,
89 : : gsize n_vectors,
90 : : int io_priority,
91 : : GCancellable *cancellable,
92 : : GAsyncReadyCallback callback,
93 : : gpointer data);
94 : : static gboolean g_output_stream_real_writev_finish (GOutputStream *stream,
95 : : GAsyncResult *result,
96 : : gsize *bytes_written,
97 : : GError **error);
98 : : static void g_output_stream_real_splice_async (GOutputStream *stream,
99 : : GInputStream *source,
100 : : GOutputStreamSpliceFlags flags,
101 : : int io_priority,
102 : : GCancellable *cancellable,
103 : : GAsyncReadyCallback callback,
104 : : gpointer data);
105 : : static gssize g_output_stream_real_splice_finish (GOutputStream *stream,
106 : : GAsyncResult *result,
107 : : GError **error);
108 : : static void g_output_stream_real_flush_async (GOutputStream *stream,
109 : : int io_priority,
110 : : GCancellable *cancellable,
111 : : GAsyncReadyCallback callback,
112 : : gpointer data);
113 : : static gboolean g_output_stream_real_flush_finish (GOutputStream *stream,
114 : : GAsyncResult *result,
115 : : GError **error);
116 : : static void g_output_stream_real_close_async (GOutputStream *stream,
117 : : int io_priority,
118 : : GCancellable *cancellable,
119 : : GAsyncReadyCallback callback,
120 : : gpointer data);
121 : : static gboolean g_output_stream_real_close_finish (GOutputStream *stream,
122 : : GAsyncResult *result,
123 : : GError **error);
124 : : static gboolean g_output_stream_internal_close (GOutputStream *stream,
125 : : GCancellable *cancellable,
126 : : GError **error);
127 : : static void g_output_stream_internal_close_async (GOutputStream *stream,
128 : : int io_priority,
129 : : GCancellable *cancellable,
130 : : GAsyncReadyCallback callback,
131 : : gpointer data);
132 : : static gboolean g_output_stream_internal_close_finish (GOutputStream *stream,
133 : : GAsyncResult *result,
134 : : GError **error);
135 : :
136 : : static void
137 : 6203 : g_output_stream_dispose (GObject *object)
138 : : {
139 : : GOutputStream *stream;
140 : :
141 : 6203 : stream = G_OUTPUT_STREAM (object);
142 : :
143 : 6203 : if (!stream->priv->closed)
144 : 3335 : g_output_stream_close (stream, NULL, NULL);
145 : :
146 : 6203 : G_OBJECT_CLASS (g_output_stream_parent_class)->dispose (object);
147 : 6203 : }
148 : :
149 : : static void
150 : 131 : g_output_stream_class_init (GOutputStreamClass *klass)
151 : : {
152 : 131 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
153 : :
154 : 131 : gobject_class->dispose = g_output_stream_dispose;
155 : :
156 : 131 : klass->splice = g_output_stream_real_splice;
157 : :
158 : 131 : klass->write_async = g_output_stream_real_write_async;
159 : 131 : klass->write_finish = g_output_stream_real_write_finish;
160 : 131 : klass->writev_fn = g_output_stream_real_writev;
161 : 131 : klass->writev_async = g_output_stream_real_writev_async;
162 : 131 : klass->writev_finish = g_output_stream_real_writev_finish;
163 : 131 : klass->splice_async = g_output_stream_real_splice_async;
164 : 131 : klass->splice_finish = g_output_stream_real_splice_finish;
165 : 131 : klass->flush_async = g_output_stream_real_flush_async;
166 : 131 : klass->flush_finish = g_output_stream_real_flush_finish;
167 : 131 : klass->close_async = g_output_stream_real_close_async;
168 : 131 : klass->close_finish = g_output_stream_real_close_finish;
169 : 131 : }
170 : :
171 : : static void
172 : 6478 : g_output_stream_init (GOutputStream *stream)
173 : : {
174 : 6478 : stream->priv = g_output_stream_get_instance_private (stream);
175 : 6478 : }
176 : :
177 : : /**
178 : : * g_output_stream_write: (virtual write_fn)
179 : : * @stream: a #GOutputStream.
180 : : * @buffer: (array length=count) (element-type guint8): the buffer containing the data to write.
181 : : * @count: the number of bytes to write
182 : : * @cancellable: (nullable): optional cancellable object
183 : : * @error: location to store the error occurring, or %NULL to ignore
184 : : *
185 : : * Tries to write @count bytes from @buffer into the stream. Will block
186 : : * during the operation.
187 : : *
188 : : * If count is 0, returns 0 and does nothing. A value of @count
189 : : * larger than %G_MAXSSIZE will cause a %G_IO_ERROR_INVALID_ARGUMENT error.
190 : : *
191 : : * On success, the number of bytes written to the stream is returned.
192 : : * It is not an error if this is not the same as the requested size, as it
193 : : * can happen e.g. on a partial I/O error, or if there is not enough
194 : : * storage in the stream. All writes block until at least one byte
195 : : * is written or an error occurs; 0 is never returned (unless
196 : : * @count is 0).
197 : : *
198 : : * If @cancellable is not %NULL, then the operation can be cancelled by
199 : : * triggering the cancellable object from another thread. If the operation
200 : : * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. If an
201 : : * operation was partially finished when the operation was cancelled the
202 : : * partial result will be returned, without an error.
203 : : *
204 : : * On error -1 is returned and @error is set accordingly.
205 : : *
206 : : * Returns: Number of bytes written, or -1 on error
207 : : **/
208 : : gssize
209 : 248677 : g_output_stream_write (GOutputStream *stream,
210 : : const void *buffer,
211 : : gsize count,
212 : : GCancellable *cancellable,
213 : : GError **error)
214 : : {
215 : : GOutputStreamClass *class;
216 : : gssize res;
217 : :
218 : 248677 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), -1);
219 : 248677 : g_return_val_if_fail (buffer != NULL || count == 0, 0);
220 : :
221 : 248677 : if (count == 0)
222 : 1 : return 0;
223 : :
224 : 248676 : if (((gssize) count) < 0)
225 : : {
226 : 0 : g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
227 : : _("Too large count value passed to %s"), G_STRFUNC);
228 : 0 : return -1;
229 : : }
230 : :
231 : 248676 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
232 : :
233 : 248676 : if (class->write_fn == NULL)
234 : : {
235 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
236 : : _("Output stream doesn’t implement write"));
237 : 0 : return -1;
238 : : }
239 : :
240 : 248676 : if (!g_output_stream_set_pending (stream, error))
241 : 3 : return -1;
242 : :
243 : 248673 : if (cancellable)
244 : 14125 : g_cancellable_push_current (cancellable);
245 : :
246 : 248673 : res = class->write_fn (stream, buffer, count, cancellable, error);
247 : :
248 : 248673 : if (cancellable)
249 : 14125 : g_cancellable_pop_current (cancellable);
250 : :
251 : 248673 : g_output_stream_clear_pending (stream);
252 : :
253 : 248673 : return res;
254 : : }
255 : :
256 : : /**
257 : : * g_output_stream_write_all:
258 : : * @stream: a #GOutputStream.
259 : : * @buffer: (array length=count) (element-type guint8): the buffer containing the data to write.
260 : : * @count: the number of bytes to write
261 : : * @bytes_written: (out) (optional): location to store the number of bytes that was
262 : : * written to the stream
263 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
264 : : * @error: location to store the error occurring, or %NULL to ignore
265 : : *
266 : : * Tries to write @count bytes from @buffer into the stream. Will block
267 : : * during the operation.
268 : : *
269 : : * This function is similar to g_output_stream_write(), except it tries to
270 : : * write as many bytes as requested, only stopping on an error.
271 : : *
272 : : * On a successful write of @count bytes, %TRUE is returned, and @bytes_written
273 : : * is set to @count.
274 : : *
275 : : * If there is an error during the operation %FALSE is returned and @error
276 : : * is set to indicate the error status.
277 : : *
278 : : * As a special exception to the normal conventions for functions that
279 : : * use #GError, if this function returns %FALSE (and sets @error) then
280 : : * @bytes_written will be set to the number of bytes that were
281 : : * successfully written before the error was encountered. This
282 : : * functionality is only available from C. If you need it from another
283 : : * language then you must write your own loop around
284 : : * g_output_stream_write().
285 : : *
286 : : * Returns: %TRUE on success, %FALSE if there was an error
287 : : **/
288 : : gboolean
289 : 95113 : g_output_stream_write_all (GOutputStream *stream,
290 : : const void *buffer,
291 : : gsize count,
292 : : gsize *bytes_written,
293 : : GCancellable *cancellable,
294 : : GError **error)
295 : : {
296 : : gsize _bytes_written;
297 : : gssize res;
298 : :
299 : 95113 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
300 : 95113 : g_return_val_if_fail (buffer != NULL || count == 0, FALSE);
301 : :
302 : 95113 : _bytes_written = 0;
303 : 190202 : while (_bytes_written < count)
304 : : {
305 : 95092 : res = g_output_stream_write (stream, (char *)buffer + _bytes_written, count - _bytes_written,
306 : : cancellable, error);
307 : 95092 : if (res == -1)
308 : : {
309 : 3 : if (bytes_written)
310 : 3 : *bytes_written = _bytes_written;
311 : 3 : return FALSE;
312 : : }
313 : 95089 : g_return_val_if_fail (res > 0, FALSE);
314 : :
315 : 95089 : _bytes_written += res;
316 : : }
317 : :
318 : 95110 : if (bytes_written)
319 : 95083 : *bytes_written = _bytes_written;
320 : :
321 : 95110 : return TRUE;
322 : : }
323 : :
324 : : /**
325 : : * g_output_stream_writev: (virtual writev_fn)
326 : : * @stream: a #GOutputStream.
327 : : * @vectors: (array length=n_vectors): the buffer containing the #GOutputVectors to write.
328 : : * @n_vectors: the number of vectors to write
329 : : * @bytes_written: (out) (optional): location to store the number of bytes that were
330 : : * written to the stream
331 : : * @cancellable: (nullable): optional cancellable object
332 : : * @error: location to store the error occurring, or %NULL to ignore
333 : : *
334 : : * Tries to write the bytes contained in the @n_vectors @vectors into the
335 : : * stream. Will block during the operation.
336 : : *
337 : : * If @n_vectors is 0 or the sum of all bytes in @vectors is 0, returns 0 and
338 : : * does nothing.
339 : : *
340 : : * On success, the number of bytes written to the stream is returned.
341 : : * It is not an error if this is not the same as the requested size, as it
342 : : * can happen e.g. on a partial I/O error, or if there is not enough
343 : : * storage in the stream. All writes block until at least one byte
344 : : * is written or an error occurs; 0 is never returned (unless
345 : : * @n_vectors is 0 or the sum of all bytes in @vectors is 0).
346 : : *
347 : : * If @cancellable is not %NULL, then the operation can be cancelled by
348 : : * triggering the cancellable object from another thread. If the operation
349 : : * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. If an
350 : : * operation was partially finished when the operation was cancelled the
351 : : * partial result will be returned, without an error.
352 : : *
353 : : * Some implementations of g_output_stream_writev() may have limitations on the
354 : : * aggregate buffer size, and will return %G_IO_ERROR_INVALID_ARGUMENT if these
355 : : * are exceeded. For example, when writing to a local file on UNIX platforms,
356 : : * the aggregate buffer size must not exceed %G_MAXSSIZE bytes.
357 : : *
358 : : * Returns: %TRUE on success, %FALSE if there was an error
359 : : *
360 : : * Since: 2.60
361 : : */
362 : : gboolean
363 : 7 : g_output_stream_writev (GOutputStream *stream,
364 : : const GOutputVector *vectors,
365 : : gsize n_vectors,
366 : : gsize *bytes_written,
367 : : GCancellable *cancellable,
368 : : GError **error)
369 : : {
370 : : GOutputStreamClass *class;
371 : : gboolean res;
372 : 7 : gsize _bytes_written = 0;
373 : :
374 : 7 : if (bytes_written)
375 : 7 : *bytes_written = 0;
376 : :
377 : 7 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
378 : 7 : g_return_val_if_fail (vectors != NULL || n_vectors == 0, FALSE);
379 : 7 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
380 : 7 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
381 : :
382 : 7 : if (n_vectors == 0)
383 : 0 : return TRUE;
384 : :
385 : 7 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
386 : :
387 : 7 : g_return_val_if_fail (class->writev_fn != NULL, FALSE);
388 : :
389 : 7 : if (!g_output_stream_set_pending (stream, error))
390 : 0 : return FALSE;
391 : :
392 : 7 : if (cancellable)
393 : 1 : g_cancellable_push_current (cancellable);
394 : :
395 : 7 : res = class->writev_fn (stream, vectors, n_vectors, &_bytes_written, cancellable, error);
396 : :
397 : 7 : g_warn_if_fail (res || _bytes_written == 0);
398 : 7 : g_warn_if_fail (res || (error == NULL || *error != NULL));
399 : :
400 : 7 : if (cancellable)
401 : 1 : g_cancellable_pop_current (cancellable);
402 : :
403 : 7 : g_output_stream_clear_pending (stream);
404 : :
405 : 7 : if (bytes_written)
406 : 7 : *bytes_written = _bytes_written;
407 : :
408 : 7 : return res;
409 : : }
410 : :
411 : : /**
412 : : * g_output_stream_writev_all:
413 : : * @stream: a #GOutputStream.
414 : : * @vectors: (array length=n_vectors): the buffer containing the #GOutputVectors to write.
415 : : * @n_vectors: the number of vectors to write
416 : : * @bytes_written: (out) (optional): location to store the number of bytes that were
417 : : * written to the stream
418 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
419 : : * @error: location to store the error occurring, or %NULL to ignore
420 : : *
421 : : * Tries to write the bytes contained in the @n_vectors @vectors into the
422 : : * stream. Will block during the operation.
423 : : *
424 : : * This function is similar to g_output_stream_writev(), except it tries to
425 : : * write as many bytes as requested, only stopping on an error.
426 : : *
427 : : * On a successful write of all @n_vectors vectors, %TRUE is returned, and
428 : : * @bytes_written is set to the sum of all the sizes of @vectors.
429 : : *
430 : : * If there is an error during the operation %FALSE is returned and @error
431 : : * is set to indicate the error status.
432 : : *
433 : : * As a special exception to the normal conventions for functions that
434 : : * use #GError, if this function returns %FALSE (and sets @error) then
435 : : * @bytes_written will be set to the number of bytes that were
436 : : * successfully written before the error was encountered. This
437 : : * functionality is only available from C. If you need it from another
438 : : * language then you must write your own loop around
439 : : * g_output_stream_write().
440 : : *
441 : : * The content of the individual elements of @vectors might be changed by this
442 : : * function.
443 : : *
444 : : * Returns: %TRUE on success, %FALSE if there was an error
445 : : *
446 : : * Since: 2.60
447 : : */
448 : : gboolean
449 : 12 : g_output_stream_writev_all (GOutputStream *stream,
450 : : GOutputVector *vectors,
451 : : gsize n_vectors,
452 : : gsize *bytes_written,
453 : : GCancellable *cancellable,
454 : : GError **error)
455 : : {
456 : 12 : gsize _bytes_written = 0;
457 : 12 : gsize i, to_be_written = 0;
458 : :
459 : 12 : if (bytes_written)
460 : 11 : *bytes_written = 0;
461 : :
462 : 12 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
463 : 12 : g_return_val_if_fail (vectors != NULL || n_vectors == 0, FALSE);
464 : 12 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
465 : 12 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
466 : :
467 : : /* We can't write more than G_MAXSIZE bytes overall, otherwise we
468 : : * would overflow the bytes_written counter */
469 : 41 : for (i = 0; i < n_vectors; i++)
470 : : {
471 : 30 : if (to_be_written > G_MAXSIZE - vectors[i].size)
472 : : {
473 : 1 : g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
474 : : _("Sum of vectors passed to %s too large"), G_STRFUNC);
475 : 1 : return FALSE;
476 : : }
477 : 29 : to_be_written += vectors[i].size;
478 : : }
479 : :
480 : 11 : _bytes_written = 0;
481 : 17 : while (n_vectors > 0 && to_be_written > 0)
482 : : {
483 : 7 : gsize n_written = 0;
484 : : gboolean res;
485 : :
486 : 7 : res = g_output_stream_writev (stream, vectors, n_vectors, &n_written, cancellable, error);
487 : :
488 : 7 : if (!res)
489 : : {
490 : 1 : if (bytes_written)
491 : 1 : *bytes_written = _bytes_written;
492 : 1 : return FALSE;
493 : : }
494 : :
495 : 6 : g_return_val_if_fail (n_written > 0, FALSE);
496 : 6 : _bytes_written += n_written;
497 : :
498 : : /* skip vectors that have been written in full */
499 : 24 : while (n_vectors > 0 && n_written >= vectors[0].size)
500 : : {
501 : 18 : n_written -= vectors[0].size;
502 : 18 : ++vectors;
503 : 18 : --n_vectors;
504 : : }
505 : : /* skip partially written vector data */
506 : 6 : if (n_written > 0 && n_vectors > 0)
507 : : {
508 : 0 : vectors[0].size -= n_written;
509 : 0 : vectors[0].buffer = ((guint8 *) vectors[0].buffer) + n_written;
510 : : }
511 : : }
512 : :
513 : 10 : if (bytes_written)
514 : 9 : *bytes_written = _bytes_written;
515 : :
516 : 10 : return TRUE;
517 : : }
518 : :
519 : : /**
520 : : * g_output_stream_printf:
521 : : * @stream: a #GOutputStream.
522 : : * @bytes_written: (out) (optional): location to store the number of bytes that was
523 : : * written to the stream
524 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
525 : : * @error: location to store the error occurring, or %NULL to ignore
526 : : * @format: the format string. See the printf() documentation
527 : : * @...: the parameters to insert into the format string
528 : : *
529 : : * This is a utility function around g_output_stream_write_all(). It
530 : : * uses g_strdup_vprintf() to turn @format and @... into a string that
531 : : * is then written to @stream.
532 : : *
533 : : * See the documentation of g_output_stream_write_all() about the
534 : : * behavior of the actual write operation.
535 : : *
536 : : * Note that partial writes cannot be properly checked with this
537 : : * function due to the variable length of the written string, if you
538 : : * need precise control over partial write failures, you need to
539 : : * create you own printf()-like wrapper around g_output_stream_write()
540 : : * or g_output_stream_write_all().
541 : : *
542 : : * Since: 2.40
543 : : *
544 : : * Returns: %TRUE on success, %FALSE if there was an error
545 : : **/
546 : : gboolean
547 : 0 : g_output_stream_printf (GOutputStream *stream,
548 : : gsize *bytes_written,
549 : : GCancellable *cancellable,
550 : : GError **error,
551 : : const gchar *format,
552 : : ...)
553 : : {
554 : : va_list args;
555 : : gboolean success;
556 : :
557 : 0 : va_start (args, format);
558 : 0 : success = g_output_stream_vprintf (stream, bytes_written, cancellable,
559 : : error, format, args);
560 : 0 : va_end (args);
561 : :
562 : 0 : return success;
563 : : }
564 : :
565 : : /**
566 : : * g_output_stream_vprintf:
567 : : * @stream: a #GOutputStream.
568 : : * @bytes_written: (out) (optional): location to store the number of bytes that was
569 : : * written to the stream
570 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
571 : : * @error: location to store the error occurring, or %NULL to ignore
572 : : * @format: the format string. See the printf() documentation
573 : : * @args: the parameters to insert into the format string
574 : : *
575 : : * This is a utility function around g_output_stream_write_all(). It
576 : : * uses g_strdup_vprintf() to turn @format and @args into a string that
577 : : * is then written to @stream.
578 : : *
579 : : * See the documentation of g_output_stream_write_all() about the
580 : : * behavior of the actual write operation.
581 : : *
582 : : * Note that partial writes cannot be properly checked with this
583 : : * function due to the variable length of the written string, if you
584 : : * need precise control over partial write failures, you need to
585 : : * create you own printf()-like wrapper around g_output_stream_write()
586 : : * or g_output_stream_write_all().
587 : : *
588 : : * Since: 2.40
589 : : *
590 : : * Returns: %TRUE on success, %FALSE if there was an error
591 : : **/
592 : : gboolean
593 : 0 : g_output_stream_vprintf (GOutputStream *stream,
594 : : gsize *bytes_written,
595 : : GCancellable *cancellable,
596 : : GError **error,
597 : : const gchar *format,
598 : : va_list args)
599 : : {
600 : : gchar *text;
601 : : gboolean success;
602 : :
603 : 0 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
604 : 0 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
605 : 0 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
606 : 0 : g_return_val_if_fail (format != NULL, FALSE);
607 : :
608 : 0 : text = g_strdup_vprintf (format, args);
609 : 0 : success = g_output_stream_write_all (stream,
610 : : text, strlen (text),
611 : : bytes_written, cancellable, error);
612 : 0 : g_free (text);
613 : :
614 : 0 : return success;
615 : : }
616 : :
617 : : /**
618 : : * g_output_stream_write_bytes:
619 : : * @stream: a #GOutputStream.
620 : : * @bytes: the #GBytes to write
621 : : * @cancellable: (nullable): optional cancellable object
622 : : * @error: location to store the error occurring, or %NULL to ignore
623 : : *
624 : : * A wrapper function for g_output_stream_write() which takes a
625 : : * #GBytes as input. This can be more convenient for use by language
626 : : * bindings or in other cases where the refcounted nature of #GBytes
627 : : * is helpful over a bare pointer interface.
628 : : *
629 : : * However, note that this function may still perform partial writes,
630 : : * just like g_output_stream_write(). If that occurs, to continue
631 : : * writing, you will need to create a new #GBytes containing just the
632 : : * remaining bytes, using g_bytes_new_from_bytes(). Passing the same
633 : : * #GBytes instance multiple times potentially can result in duplicated
634 : : * data in the output stream.
635 : : *
636 : : * Returns: Number of bytes written, or -1 on error
637 : : **/
638 : : gssize
639 : 1 : g_output_stream_write_bytes (GOutputStream *stream,
640 : : GBytes *bytes,
641 : : GCancellable *cancellable,
642 : : GError **error)
643 : : {
644 : : gsize size;
645 : : gconstpointer data;
646 : :
647 : 1 : data = g_bytes_get_data (bytes, &size);
648 : :
649 : 1 : return g_output_stream_write (stream,
650 : : data, size,
651 : : cancellable,
652 : : error);
653 : : }
654 : :
655 : : /**
656 : : * g_output_stream_flush:
657 : : * @stream: a #GOutputStream.
658 : : * @cancellable: (nullable): optional cancellable object
659 : : * @error: location to store the error occurring, or %NULL to ignore
660 : : *
661 : : * Forces a write of all user-space buffered data for the given
662 : : * @stream. Will block during the operation. Closing the stream will
663 : : * implicitly cause a flush.
664 : : *
665 : : * This function is optional for inherited classes.
666 : : *
667 : : * If @cancellable is not %NULL, then the operation can be cancelled by
668 : : * triggering the cancellable object from another thread. If the operation
669 : : * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
670 : : *
671 : : * Returns: %TRUE on success, %FALSE on error
672 : : **/
673 : : gboolean
674 : 3489 : g_output_stream_flush (GOutputStream *stream,
675 : : GCancellable *cancellable,
676 : : GError **error)
677 : : {
678 : : GOutputStreamClass *class;
679 : : gboolean res;
680 : :
681 : 3489 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
682 : :
683 : 3489 : if (!g_output_stream_set_pending (stream, error))
684 : 1 : return FALSE;
685 : :
686 : 3488 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
687 : :
688 : 3488 : res = TRUE;
689 : 3488 : if (class->flush)
690 : : {
691 : 409 : if (cancellable)
692 : 0 : g_cancellable_push_current (cancellable);
693 : :
694 : 409 : res = class->flush (stream, cancellable, error);
695 : :
696 : 409 : if (cancellable)
697 : 0 : g_cancellable_pop_current (cancellable);
698 : : }
699 : :
700 : 3488 : g_output_stream_clear_pending (stream);
701 : :
702 : 3488 : return res;
703 : : }
704 : :
705 : : /**
706 : : * g_output_stream_splice:
707 : : * @stream: a #GOutputStream.
708 : : * @source: a #GInputStream.
709 : : * @flags: a set of #GOutputStreamSpliceFlags.
710 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
711 : : * @error: a #GError location to store the error occurring, or %NULL to
712 : : * ignore.
713 : : *
714 : : * Splices an input stream into an output stream.
715 : : *
716 : : * Returns: a #gssize containing the size of the data spliced, or
717 : : * -1 if an error occurred. Note that if the number of bytes
718 : : * spliced is greater than %G_MAXSSIZE, then that will be
719 : : * returned, and there is no way to determine the actual number
720 : : * of bytes spliced.
721 : : **/
722 : : gssize
723 : 27 : g_output_stream_splice (GOutputStream *stream,
724 : : GInputStream *source,
725 : : GOutputStreamSpliceFlags flags,
726 : : GCancellable *cancellable,
727 : : GError **error)
728 : : {
729 : : GOutputStreamClass *class;
730 : : gssize bytes_copied;
731 : :
732 : 27 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), -1);
733 : 27 : g_return_val_if_fail (G_IS_INPUT_STREAM (source), -1);
734 : :
735 : 27 : if (g_input_stream_is_closed (source))
736 : : {
737 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
738 : : _("Source stream is already closed"));
739 : 0 : return -1;
740 : : }
741 : :
742 : 27 : if (!g_output_stream_set_pending (stream, error))
743 : 0 : return -1;
744 : :
745 : 27 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
746 : :
747 : 27 : if (cancellable)
748 : 0 : g_cancellable_push_current (cancellable);
749 : :
750 : 27 : bytes_copied = class->splice (stream, source, flags, cancellable, error);
751 : :
752 : 27 : if (cancellable)
753 : 0 : g_cancellable_pop_current (cancellable);
754 : :
755 : 27 : g_output_stream_clear_pending (stream);
756 : :
757 : 27 : return bytes_copied;
758 : : }
759 : :
760 : : static gssize
761 : 28 : g_output_stream_real_splice (GOutputStream *stream,
762 : : GInputStream *source,
763 : : GOutputStreamSpliceFlags flags,
764 : : GCancellable *cancellable,
765 : : GError **error)
766 : : {
767 : 28 : GOutputStreamClass *class = G_OUTPUT_STREAM_GET_CLASS (stream);
768 : : gssize n_read, n_written;
769 : : gsize bytes_copied;
770 : : char buffer[8192], *p;
771 : : gboolean res;
772 : :
773 : 28 : bytes_copied = 0;
774 : 28 : if (class->write_fn == NULL)
775 : : {
776 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
777 : : _("Output stream doesn’t implement write"));
778 : 0 : res = FALSE;
779 : 0 : goto notsupported;
780 : : }
781 : :
782 : 28 : res = TRUE;
783 : : do
784 : : {
785 : 8277 : n_read = g_input_stream_read (source, buffer, sizeof (buffer), cancellable, error);
786 : 8277 : if (n_read == -1)
787 : : {
788 : 3 : res = FALSE;
789 : 3 : break;
790 : : }
791 : :
792 : 8274 : if (n_read == 0)
793 : 23 : break;
794 : :
795 : 8251 : p = buffer;
796 : 16501 : while (n_read > 0)
797 : : {
798 : 8252 : n_written = class->write_fn (stream, p, n_read, cancellable, error);
799 : 8252 : if (n_written == -1)
800 : : {
801 : 2 : res = FALSE;
802 : 2 : break;
803 : : }
804 : :
805 : 8250 : p += n_written;
806 : 8250 : n_read -= n_written;
807 : 8250 : bytes_copied += n_written;
808 : : }
809 : :
810 : 8251 : if (bytes_copied > G_MAXSSIZE)
811 : 0 : bytes_copied = G_MAXSSIZE;
812 : : }
813 : 8251 : while (res);
814 : :
815 : 2 : notsupported:
816 : 28 : if (!res)
817 : 5 : error = NULL; /* Ignore further errors */
818 : :
819 : 28 : if (flags & G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE)
820 : : {
821 : : /* Don't care about errors in source here */
822 : 5 : g_input_stream_close (source, cancellable, NULL);
823 : : }
824 : :
825 : 28 : if (flags & G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET)
826 : : {
827 : : /* But write errors on close are bad! */
828 : 5 : if (!g_output_stream_internal_close (stream, cancellable, error))
829 : 1 : res = FALSE;
830 : : }
831 : :
832 : 28 : if (res)
833 : 23 : return bytes_copied;
834 : :
835 : 5 : return -1;
836 : : }
837 : :
838 : : /* Must always be called inside
839 : : * g_output_stream_set_pending()/g_output_stream_clear_pending(). */
840 : : static gboolean
841 : 5740 : g_output_stream_internal_close (GOutputStream *stream,
842 : : GCancellable *cancellable,
843 : : GError **error)
844 : : {
845 : : GOutputStreamClass *class;
846 : : gboolean res;
847 : :
848 : 5740 : if (stream->priv->closed)
849 : 0 : return TRUE;
850 : :
851 : 5740 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
852 : :
853 : 5740 : stream->priv->closing = TRUE;
854 : :
855 : 5740 : if (cancellable)
856 : 1 : g_cancellable_push_current (cancellable);
857 : :
858 : 5740 : if (class->flush)
859 : 2288 : res = class->flush (stream, cancellable, error);
860 : : else
861 : 3452 : res = TRUE;
862 : :
863 : 5740 : if (!res)
864 : : {
865 : : /* flushing caused the error that we want to return,
866 : : * but we still want to close the underlying stream if possible
867 : : */
868 : 2 : if (class->close_fn)
869 : 2 : class->close_fn (stream, cancellable, NULL);
870 : : }
871 : : else
872 : : {
873 : 5738 : res = TRUE;
874 : 5738 : if (class->close_fn)
875 : 4147 : res = class->close_fn (stream, cancellable, error);
876 : : }
877 : :
878 : 5740 : if (cancellable)
879 : 1 : g_cancellable_pop_current (cancellable);
880 : :
881 : 5740 : stream->priv->closing = FALSE;
882 : 5740 : stream->priv->closed = TRUE;
883 : :
884 : 5740 : return res;
885 : : }
886 : :
887 : : /**
888 : : * g_output_stream_close:
889 : : * @stream: A #GOutputStream.
890 : : * @cancellable: (nullable): optional cancellable object
891 : : * @error: location to store the error occurring, or %NULL to ignore
892 : : *
893 : : * Closes the stream, releasing resources related to it.
894 : : *
895 : : * Once the stream is closed, all other operations will return %G_IO_ERROR_CLOSED.
896 : : * Closing a stream multiple times will not return an error.
897 : : *
898 : : * Closing a stream will automatically flush any outstanding buffers in the
899 : : * stream.
900 : : *
901 : : * Streams will be automatically closed when the last reference
902 : : * is dropped, but you might want to call this function to make sure
903 : : * resources are released as early as possible.
904 : : *
905 : : * Some streams might keep the backing store of the stream (e.g. a file descriptor)
906 : : * open after the stream is closed. See the documentation for the individual
907 : : * stream for details.
908 : : *
909 : : * On failure the first error that happened will be reported, but the close
910 : : * operation will finish as much as possible. A stream that failed to
911 : : * close will still return %G_IO_ERROR_CLOSED for all operations. Still, it
912 : : * is important to check and report the error to the user, otherwise
913 : : * there might be a loss of data as all data might not be written.
914 : : *
915 : : * If @cancellable is not %NULL, then the operation can be cancelled by
916 : : * triggering the cancellable object from another thread. If the operation
917 : : * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
918 : : * Cancelling a close will still leave the stream closed, but there some streams
919 : : * can use a faster close that doesn't block to e.g. check errors. On
920 : : * cancellation (as with any error) there is no guarantee that all written
921 : : * data will reach the target.
922 : : *
923 : : * Returns: %TRUE on success, %FALSE on failure
924 : : **/
925 : : gboolean
926 : 5745 : g_output_stream_close (GOutputStream *stream,
927 : : GCancellable *cancellable,
928 : : GError **error)
929 : : {
930 : : gboolean res;
931 : :
932 : 5745 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
933 : :
934 : 5745 : if (stream->priv->closed)
935 : 10 : return TRUE;
936 : :
937 : 5735 : if (!g_output_stream_set_pending (stream, error))
938 : 0 : return FALSE;
939 : :
940 : 5735 : res = g_output_stream_internal_close (stream, cancellable, error);
941 : :
942 : 5735 : g_output_stream_clear_pending (stream);
943 : :
944 : 5735 : return res;
945 : : }
946 : :
947 : : static void
948 : 7722 : async_ready_write_callback_wrapper (GObject *source_object,
949 : : GAsyncResult *res,
950 : : gpointer user_data)
951 : : {
952 : 7722 : GOutputStream *stream = G_OUTPUT_STREAM (source_object);
953 : : GOutputStreamClass *class;
954 : 7722 : GTask *task = user_data;
955 : : gssize nwrote;
956 : 7722 : GError *error = NULL;
957 : :
958 : 7722 : g_output_stream_clear_pending (stream);
959 : :
960 : 7722 : if (g_async_result_legacy_propagate_error (res, &error))
961 : 0 : nwrote = -1;
962 : : else
963 : : {
964 : 7722 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
965 : 7722 : nwrote = class->write_finish (stream, res, &error);
966 : : }
967 : :
968 : 7722 : if (nwrote >= 0)
969 : 7608 : g_task_return_int (task, nwrote);
970 : : else
971 : 114 : g_task_return_error (task, error);
972 : 7722 : g_object_unref (task);
973 : 7722 : }
974 : :
975 : : /**
976 : : * g_output_stream_write_async:
977 : : * @stream: A #GOutputStream.
978 : : * @buffer: (array length=count) (element-type guint8): the buffer containing the data to write.
979 : : * @count: the number of bytes to write
980 : : * @io_priority: the io priority of the request.
981 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
982 : : * @callback: (scope async): a #GAsyncReadyCallback
983 : : * to call when the request is satisfied
984 : : * @user_data: the data to pass to callback function
985 : : *
986 : : * Request an asynchronous write of @count bytes from @buffer into
987 : : * the stream. When the operation is finished @callback will be called.
988 : : * You can then call g_output_stream_write_finish() to get the result of the
989 : : * operation.
990 : : *
991 : : * During an async request no other sync and async calls are allowed,
992 : : * and will result in %G_IO_ERROR_PENDING errors.
993 : : *
994 : : * A value of @count larger than %G_MAXSSIZE will cause a
995 : : * %G_IO_ERROR_INVALID_ARGUMENT error.
996 : : *
997 : : * On success, the number of bytes written will be passed to the
998 : : * @callback. It is not an error if this is not the same as the
999 : : * requested size, as it can happen e.g. on a partial I/O error,
1000 : : * but generally we try to write as many bytes as requested.
1001 : : *
1002 : : * You are guaranteed that this method will never fail with
1003 : : * %G_IO_ERROR_WOULD_BLOCK - if @stream can't accept more data, the
1004 : : * method will just wait until this changes.
1005 : : *
1006 : : * Any outstanding I/O request with higher priority (lower numerical
1007 : : * value) will be executed before an outstanding request with lower
1008 : : * priority. Default priority is %G_PRIORITY_DEFAULT.
1009 : : *
1010 : : * The asynchronous methods have a default fallback that uses threads
1011 : : * to implement asynchronicity, so they are optional for inheriting
1012 : : * classes. However, if you override one you must override all.
1013 : : *
1014 : : * For the synchronous, blocking version of this function, see
1015 : : * g_output_stream_write().
1016 : : *
1017 : : * Note that no copy of @buffer will be made, so it must stay valid
1018 : : * until @callback is called. See g_output_stream_write_bytes_async()
1019 : : * for a #GBytes version that will automatically hold a reference to
1020 : : * the contents (without copying) for the duration of the call.
1021 : : */
1022 : : void
1023 : 7727 : g_output_stream_write_async (GOutputStream *stream,
1024 : : const void *buffer,
1025 : : gsize count,
1026 : : int io_priority,
1027 : : GCancellable *cancellable,
1028 : : GAsyncReadyCallback callback,
1029 : : gpointer user_data)
1030 : : {
1031 : : GOutputStreamClass *class;
1032 : 7727 : GError *error = NULL;
1033 : : GTask *task;
1034 : :
1035 : 7732 : g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
1036 : 7727 : g_return_if_fail (buffer != NULL);
1037 : :
1038 : 7727 : task = g_task_new (stream, cancellable, callback, user_data);
1039 : 7727 : g_task_set_source_tag (task, g_output_stream_write_async);
1040 : 7727 : g_task_set_priority (task, io_priority);
1041 : :
1042 : 7727 : if (count == 0)
1043 : : {
1044 : 0 : g_task_return_int (task, 0);
1045 : 0 : g_object_unref (task);
1046 : 0 : return;
1047 : : }
1048 : :
1049 : 7727 : if (((gssize) count) < 0)
1050 : : {
1051 : 0 : g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
1052 : 0 : _("Too large count value passed to %s"),
1053 : : G_STRFUNC);
1054 : 0 : g_object_unref (task);
1055 : 0 : return;
1056 : : }
1057 : :
1058 : 7727 : if (!g_output_stream_set_pending (stream, &error))
1059 : : {
1060 : 5 : g_task_return_error (task, error);
1061 : 5 : g_object_unref (task);
1062 : 5 : return;
1063 : : }
1064 : :
1065 : 7722 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
1066 : :
1067 : 7722 : class->write_async (stream, buffer, count, io_priority, cancellable,
1068 : : async_ready_write_callback_wrapper, task);
1069 : : }
1070 : :
1071 : : /**
1072 : : * g_output_stream_write_finish:
1073 : : * @stream: a #GOutputStream.
1074 : : * @result: a #GAsyncResult.
1075 : : * @error: a #GError location to store the error occurring, or %NULL to
1076 : : * ignore.
1077 : : *
1078 : : * Finishes a stream write operation.
1079 : : *
1080 : : * Returns: a #gssize containing the number of bytes written to the stream.
1081 : : **/
1082 : : gssize
1083 : 7727 : g_output_stream_write_finish (GOutputStream *stream,
1084 : : GAsyncResult *result,
1085 : : GError **error)
1086 : : {
1087 : 7727 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
1088 : 7727 : g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
1089 : 7727 : g_return_val_if_fail (g_async_result_is_tagged (result, g_output_stream_write_async), FALSE);
1090 : :
1091 : : /* @result is always the GTask created by g_output_stream_write_async();
1092 : : * we called class->write_finish() from async_ready_write_callback_wrapper.
1093 : : */
1094 : 7727 : return g_task_propagate_int (G_TASK (result), error);
1095 : : }
1096 : :
1097 : : typedef struct
1098 : : {
1099 : : const guint8 *buffer;
1100 : : gsize to_write;
1101 : : gsize bytes_written;
1102 : : } AsyncWriteAll;
1103 : :
1104 : : static void
1105 : 8 : free_async_write_all (gpointer data)
1106 : : {
1107 : 8 : g_slice_free (AsyncWriteAll, data);
1108 : 8 : }
1109 : :
1110 : : static void
1111 : 20 : write_all_callback (GObject *stream,
1112 : : GAsyncResult *result,
1113 : : gpointer user_data)
1114 : : {
1115 : 20 : GTask *task = user_data;
1116 : 20 : AsyncWriteAll *data = g_task_get_task_data (task);
1117 : :
1118 : 20 : if (result)
1119 : : {
1120 : 12 : GError *error = NULL;
1121 : : gssize nwritten;
1122 : :
1123 : 12 : nwritten = g_output_stream_write_finish (G_OUTPUT_STREAM (stream), result, &error);
1124 : :
1125 : 12 : if (nwritten == -1)
1126 : : {
1127 : 3 : g_task_return_error (task, error);
1128 : 3 : g_object_unref (task);
1129 : 3 : return;
1130 : : }
1131 : :
1132 : 9 : g_assert_cmpint (nwritten, <=, data->to_write);
1133 : 9 : g_warn_if_fail (nwritten > 0);
1134 : :
1135 : 9 : data->to_write -= nwritten;
1136 : 9 : data->bytes_written += nwritten;
1137 : : }
1138 : :
1139 : 17 : if (data->to_write == 0)
1140 : : {
1141 : 5 : g_task_return_boolean (task, TRUE);
1142 : 5 : g_object_unref (task);
1143 : : }
1144 : : else
1145 : 24 : g_output_stream_write_async (G_OUTPUT_STREAM (stream),
1146 : 12 : data->buffer + data->bytes_written,
1147 : : data->to_write,
1148 : : g_task_get_priority (task),
1149 : : g_task_get_cancellable (task),
1150 : : write_all_callback, task);
1151 : : }
1152 : :
1153 : : static void
1154 : 0 : write_all_async_thread (GTask *task,
1155 : : gpointer source_object,
1156 : : gpointer task_data,
1157 : : GCancellable *cancellable)
1158 : : {
1159 : 0 : GOutputStream *stream = source_object;
1160 : 0 : AsyncWriteAll *data = task_data;
1161 : 0 : GError *error = NULL;
1162 : :
1163 : 0 : if (g_output_stream_write_all (stream, data->buffer, data->to_write, &data->bytes_written,
1164 : : g_task_get_cancellable (task), &error))
1165 : 0 : g_task_return_boolean (task, TRUE);
1166 : : else
1167 : 0 : g_task_return_error (task, error);
1168 : 0 : }
1169 : :
1170 : : /**
1171 : : * g_output_stream_write_all_async:
1172 : : * @stream: A #GOutputStream
1173 : : * @buffer: (array length=count) (element-type guint8): the buffer containing the data to write
1174 : : * @count: the number of bytes to write
1175 : : * @io_priority: the io priority of the request
1176 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore
1177 : : * @callback: (scope async): a #GAsyncReadyCallback
1178 : : * to call when the request is satisfied
1179 : : * @user_data: the data to pass to callback function
1180 : : *
1181 : : * Request an asynchronous write of @count bytes from @buffer into
1182 : : * the stream. When the operation is finished @callback will be called.
1183 : : * You can then call g_output_stream_write_all_finish() to get the result of the
1184 : : * operation.
1185 : : *
1186 : : * This is the asynchronous version of g_output_stream_write_all().
1187 : : *
1188 : : * Call g_output_stream_write_all_finish() to collect the result.
1189 : : *
1190 : : * Any outstanding I/O request with higher priority (lower numerical
1191 : : * value) will be executed before an outstanding request with lower
1192 : : * priority. Default priority is %G_PRIORITY_DEFAULT.
1193 : : *
1194 : : * Note that no copy of @buffer will be made, so it must stay valid
1195 : : * until @callback is called.
1196 : : *
1197 : : * Since: 2.44
1198 : : */
1199 : : void
1200 : 8 : g_output_stream_write_all_async (GOutputStream *stream,
1201 : : const void *buffer,
1202 : : gsize count,
1203 : : int io_priority,
1204 : : GCancellable *cancellable,
1205 : : GAsyncReadyCallback callback,
1206 : : gpointer user_data)
1207 : : {
1208 : : AsyncWriteAll *data;
1209 : : GTask *task;
1210 : :
1211 : 8 : g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
1212 : 8 : g_return_if_fail (buffer != NULL || count == 0);
1213 : :
1214 : 8 : task = g_task_new (stream, cancellable, callback, user_data);
1215 : 8 : data = g_slice_new0 (AsyncWriteAll);
1216 : 8 : data->buffer = buffer;
1217 : 8 : data->to_write = count;
1218 : :
1219 : 8 : g_task_set_source_tag (task, g_output_stream_write_all_async);
1220 : 8 : g_task_set_task_data (task, data, free_async_write_all);
1221 : 8 : g_task_set_priority (task, io_priority);
1222 : :
1223 : : /* If async writes are going to be handled via the threadpool anyway
1224 : : * then we may as well do it with a single dispatch instead of
1225 : : * bouncing in and out.
1226 : : */
1227 : 8 : if (g_output_stream_async_write_is_via_threads (stream))
1228 : : {
1229 : 0 : g_task_run_in_thread (task, write_all_async_thread);
1230 : 0 : g_object_unref (task);
1231 : : }
1232 : : else
1233 : 8 : write_all_callback (G_OBJECT (stream), NULL, task);
1234 : : }
1235 : :
1236 : : /**
1237 : : * g_output_stream_write_all_finish:
1238 : : * @stream: a #GOutputStream
1239 : : * @result: a #GAsyncResult
1240 : : * @bytes_written: (out) (optional): location to store the number of bytes that was written to the stream
1241 : : * @error: a #GError location to store the error occurring, or %NULL to ignore.
1242 : : *
1243 : : * Finishes an asynchronous stream write operation started with
1244 : : * g_output_stream_write_all_async().
1245 : : *
1246 : : * As a special exception to the normal conventions for functions that
1247 : : * use #GError, if this function returns %FALSE (and sets @error) then
1248 : : * @bytes_written will be set to the number of bytes that were
1249 : : * successfully written before the error was encountered. This
1250 : : * functionality is only available from C. If you need it from another
1251 : : * language then you must write your own loop around
1252 : : * g_output_stream_write_async().
1253 : : *
1254 : : * Returns: %TRUE on success, %FALSE if there was an error
1255 : : *
1256 : : * Since: 2.44
1257 : : **/
1258 : : gboolean
1259 : 8 : g_output_stream_write_all_finish (GOutputStream *stream,
1260 : : GAsyncResult *result,
1261 : : gsize *bytes_written,
1262 : : GError **error)
1263 : : {
1264 : : GTask *task;
1265 : :
1266 : 8 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
1267 : 8 : g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
1268 : :
1269 : 8 : task = G_TASK (result);
1270 : :
1271 : 8 : if (bytes_written)
1272 : : {
1273 : 8 : AsyncWriteAll *data = (AsyncWriteAll *)g_task_get_task_data (task);
1274 : :
1275 : 8 : *bytes_written = data->bytes_written;
1276 : : }
1277 : :
1278 : 8 : return g_task_propagate_boolean (task, error);
1279 : : }
1280 : :
1281 : : /**
1282 : : * g_output_stream_writev_async:
1283 : : * @stream: A #GOutputStream.
1284 : : * @vectors: (array length=n_vectors): the buffer containing the #GOutputVectors to write.
1285 : : * @n_vectors: the number of vectors to write
1286 : : * @io_priority: the I/O priority of the request.
1287 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
1288 : : * @callback: (scope async): a #GAsyncReadyCallback
1289 : : * to call when the request is satisfied
1290 : : * @user_data: the data to pass to callback function
1291 : : *
1292 : : * Request an asynchronous write of the bytes contained in @n_vectors @vectors into
1293 : : * the stream. When the operation is finished @callback will be called.
1294 : : * You can then call g_output_stream_writev_finish() to get the result of the
1295 : : * operation.
1296 : : *
1297 : : * During an async request no other sync and async calls are allowed,
1298 : : * and will result in %G_IO_ERROR_PENDING errors.
1299 : : *
1300 : : * On success, the number of bytes written will be passed to the
1301 : : * @callback. It is not an error if this is not the same as the
1302 : : * requested size, as it can happen e.g. on a partial I/O error,
1303 : : * but generally we try to write as many bytes as requested.
1304 : : *
1305 : : * You are guaranteed that this method will never fail with
1306 : : * %G_IO_ERROR_WOULD_BLOCK — if @stream can't accept more data, the
1307 : : * method will just wait until this changes.
1308 : : *
1309 : : * Any outstanding I/O request with higher priority (lower numerical
1310 : : * value) will be executed before an outstanding request with lower
1311 : : * priority. Default priority is %G_PRIORITY_DEFAULT.
1312 : : *
1313 : : * The asynchronous methods have a default fallback that uses threads
1314 : : * to implement asynchronicity, so they are optional for inheriting
1315 : : * classes. However, if you override one you must override all.
1316 : : *
1317 : : * For the synchronous, blocking version of this function, see
1318 : : * g_output_stream_writev().
1319 : : *
1320 : : * Note that no copy of @vectors will be made, so it must stay valid
1321 : : * until @callback is called.
1322 : : *
1323 : : * Since: 2.60
1324 : : */
1325 : : void
1326 : 6 : g_output_stream_writev_async (GOutputStream *stream,
1327 : : const GOutputVector *vectors,
1328 : : gsize n_vectors,
1329 : : int io_priority,
1330 : : GCancellable *cancellable,
1331 : : GAsyncReadyCallback callback,
1332 : : gpointer user_data)
1333 : : {
1334 : : GOutputStreamClass *class;
1335 : :
1336 : 6 : g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
1337 : 6 : g_return_if_fail (vectors != NULL || n_vectors == 0);
1338 : 6 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1339 : :
1340 : 6 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
1341 : 6 : g_return_if_fail (class->writev_async != NULL);
1342 : :
1343 : 6 : class->writev_async (stream, vectors, n_vectors, io_priority, cancellable,
1344 : : callback, user_data);
1345 : : }
1346 : :
1347 : : /**
1348 : : * g_output_stream_writev_finish:
1349 : : * @stream: a #GOutputStream.
1350 : : * @result: a #GAsyncResult.
1351 : : * @bytes_written: (out) (optional): location to store the number of bytes that were written to the stream
1352 : : * @error: a #GError location to store the error occurring, or %NULL to
1353 : : * ignore.
1354 : : *
1355 : : * Finishes a stream writev operation.
1356 : : *
1357 : : * Returns: %TRUE on success, %FALSE if there was an error
1358 : : *
1359 : : * Since: 2.60
1360 : : */
1361 : : gboolean
1362 : 6 : g_output_stream_writev_finish (GOutputStream *stream,
1363 : : GAsyncResult *result,
1364 : : gsize *bytes_written,
1365 : : GError **error)
1366 : : {
1367 : : GOutputStreamClass *class;
1368 : : gboolean res;
1369 : 6 : gsize _bytes_written = 0;
1370 : :
1371 : 6 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
1372 : 6 : g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
1373 : 6 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1374 : :
1375 : 6 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
1376 : 6 : g_return_val_if_fail (class->writev_finish != NULL, FALSE);
1377 : :
1378 : 6 : res = class->writev_finish (stream, result, &_bytes_written, error);
1379 : :
1380 : 6 : g_warn_if_fail (res || _bytes_written == 0);
1381 : 6 : g_warn_if_fail (res || (error == NULL || *error != NULL));
1382 : :
1383 : 6 : if (bytes_written)
1384 : 6 : *bytes_written = _bytes_written;
1385 : :
1386 : 6 : return res;
1387 : : }
1388 : :
1389 : : typedef struct
1390 : : {
1391 : : GOutputVector *vectors;
1392 : : gsize n_vectors; /* (unowned) */
1393 : : gsize bytes_written;
1394 : : } AsyncWritevAll;
1395 : :
1396 : : static void
1397 : 7 : free_async_writev_all (gpointer data)
1398 : : {
1399 : 7 : g_slice_free (AsyncWritevAll, data);
1400 : 7 : }
1401 : :
1402 : : static void
1403 : 7 : writev_all_callback (GObject *stream,
1404 : : GAsyncResult *result,
1405 : : gpointer user_data)
1406 : : {
1407 : 7 : GTask *task = user_data;
1408 : 7 : AsyncWritevAll *data = g_task_get_task_data (task);
1409 : 7 : gint priority = g_task_get_priority (task);
1410 : 7 : GCancellable *cancellable = g_task_get_cancellable (task);
1411 : :
1412 : 7 : if (result)
1413 : : {
1414 : 5 : GError *error = NULL;
1415 : : gboolean res;
1416 : 5 : gsize n_written = 0;
1417 : :
1418 : 5 : res = g_output_stream_writev_finish (G_OUTPUT_STREAM (stream), result, &n_written, &error);
1419 : :
1420 : 5 : if (!res)
1421 : : {
1422 : 0 : g_task_return_error (task, g_steal_pointer (&error));
1423 : 0 : g_object_unref (task);
1424 : 0 : return;
1425 : : }
1426 : :
1427 : 5 : g_warn_if_fail (n_written > 0);
1428 : 5 : data->bytes_written += n_written;
1429 : :
1430 : : /* skip vectors that have been written in full */
1431 : 12 : while (data->n_vectors > 0 && n_written >= data->vectors[0].size)
1432 : : {
1433 : 7 : n_written -= data->vectors[0].size;
1434 : 7 : ++data->vectors;
1435 : 7 : --data->n_vectors;
1436 : : }
1437 : : /* skip partially written vector data */
1438 : 5 : if (n_written > 0 && data->n_vectors > 0)
1439 : : {
1440 : 3 : data->vectors[0].size -= n_written;
1441 : 3 : data->vectors[0].buffer = ((guint8 *) data->vectors[0].buffer) + n_written;
1442 : : }
1443 : : }
1444 : :
1445 : 7 : if (data->n_vectors == 0)
1446 : : {
1447 : 2 : g_task_return_boolean (task, TRUE);
1448 : 2 : g_object_unref (task);
1449 : : }
1450 : : else
1451 : 10 : g_output_stream_writev_async (G_OUTPUT_STREAM (stream),
1452 : 5 : data->vectors,
1453 : : data->n_vectors,
1454 : : priority,
1455 : : cancellable,
1456 : : writev_all_callback, g_steal_pointer (&task));
1457 : : }
1458 : :
1459 : : static void
1460 : 4 : writev_all_async_thread (GTask *task,
1461 : : gpointer source_object,
1462 : : gpointer task_data,
1463 : : GCancellable *cancellable)
1464 : : {
1465 : 4 : GOutputStream *stream = G_OUTPUT_STREAM (source_object);
1466 : 4 : AsyncWritevAll *data = task_data;
1467 : 4 : GError *error = NULL;
1468 : :
1469 : 4 : if (g_output_stream_writev_all (stream, data->vectors, data->n_vectors, &data->bytes_written,
1470 : : g_task_get_cancellable (task), &error))
1471 : 3 : g_task_return_boolean (task, TRUE);
1472 : : else
1473 : 1 : g_task_return_error (task, g_steal_pointer (&error));
1474 : 4 : }
1475 : :
1476 : : /**
1477 : : * g_output_stream_writev_all_async:
1478 : : * @stream: A #GOutputStream
1479 : : * @vectors: (array length=n_vectors): the buffer containing the #GOutputVectors to write.
1480 : : * @n_vectors: the number of vectors to write
1481 : : * @io_priority: the I/O priority of the request
1482 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore
1483 : : * @callback: (scope async): a #GAsyncReadyCallback
1484 : : * to call when the request is satisfied
1485 : : * @user_data: the data to pass to callback function
1486 : : *
1487 : : * Request an asynchronous write of the bytes contained in the @n_vectors @vectors into
1488 : : * the stream. When the operation is finished @callback will be called.
1489 : : * You can then call g_output_stream_writev_all_finish() to get the result of the
1490 : : * operation.
1491 : : *
1492 : : * This is the asynchronous version of g_output_stream_writev_all().
1493 : : *
1494 : : * Call g_output_stream_writev_all_finish() to collect the result.
1495 : : *
1496 : : * Any outstanding I/O request with higher priority (lower numerical
1497 : : * value) will be executed before an outstanding request with lower
1498 : : * priority. Default priority is %G_PRIORITY_DEFAULT.
1499 : : *
1500 : : * Note that no copy of @vectors will be made, so it must stay valid
1501 : : * until @callback is called. The content of the individual elements
1502 : : * of @vectors might be changed by this function.
1503 : : *
1504 : : * Since: 2.60
1505 : : */
1506 : : void
1507 : 7 : g_output_stream_writev_all_async (GOutputStream *stream,
1508 : : GOutputVector *vectors,
1509 : : gsize n_vectors,
1510 : : int io_priority,
1511 : : GCancellable *cancellable,
1512 : : GAsyncReadyCallback callback,
1513 : : gpointer user_data)
1514 : : {
1515 : : AsyncWritevAll *data;
1516 : : GTask *task;
1517 : 7 : gsize i, to_be_written = 0;
1518 : :
1519 : 8 : g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
1520 : 7 : g_return_if_fail (vectors != NULL || n_vectors == 0);
1521 : 7 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1522 : :
1523 : 7 : task = g_task_new (stream, cancellable, callback, user_data);
1524 : 7 : data = g_slice_new0 (AsyncWritevAll);
1525 : 7 : data->vectors = vectors;
1526 : 7 : data->n_vectors = n_vectors;
1527 : :
1528 : 7 : g_task_set_source_tag (task, g_output_stream_writev_all_async);
1529 : 7 : g_task_set_task_data (task, data, free_async_writev_all);
1530 : 7 : g_task_set_priority (task, io_priority);
1531 : :
1532 : : /* We can't write more than G_MAXSIZE bytes overall, otherwise we
1533 : : * would overflow the bytes_written counter */
1534 : 25 : for (i = 0; i < n_vectors; i++)
1535 : : {
1536 : 19 : if (to_be_written > G_MAXSIZE - vectors[i].size)
1537 : : {
1538 : 1 : g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
1539 : 1 : _("Sum of vectors passed to %s too large"),
1540 : : G_STRFUNC);
1541 : 1 : g_object_unref (task);
1542 : 1 : return;
1543 : : }
1544 : 18 : to_be_written += vectors[i].size;
1545 : : }
1546 : :
1547 : : /* If async writes are going to be handled via the threadpool anyway
1548 : : * then we may as well do it with a single dispatch instead of
1549 : : * bouncing in and out.
1550 : : */
1551 : 6 : if (g_output_stream_async_writev_is_via_threads (stream))
1552 : : {
1553 : 4 : g_task_run_in_thread (task, writev_all_async_thread);
1554 : 4 : g_object_unref (task);
1555 : : }
1556 : : else
1557 : 2 : writev_all_callback (G_OBJECT (stream), NULL, g_steal_pointer (&task));
1558 : : }
1559 : :
1560 : : /**
1561 : : * g_output_stream_writev_all_finish:
1562 : : * @stream: a #GOutputStream
1563 : : * @result: a #GAsyncResult
1564 : : * @bytes_written: (out) (optional): location to store the number of bytes that were written to the stream
1565 : : * @error: a #GError location to store the error occurring, or %NULL to ignore.
1566 : : *
1567 : : * Finishes an asynchronous stream write operation started with
1568 : : * g_output_stream_writev_all_async().
1569 : : *
1570 : : * As a special exception to the normal conventions for functions that
1571 : : * use #GError, if this function returns %FALSE (and sets @error) then
1572 : : * @bytes_written will be set to the number of bytes that were
1573 : : * successfully written before the error was encountered. This
1574 : : * functionality is only available from C. If you need it from another
1575 : : * language then you must write your own loop around
1576 : : * g_output_stream_writev_async().
1577 : : *
1578 : : * Returns: %TRUE on success, %FALSE if there was an error
1579 : : *
1580 : : * Since: 2.60
1581 : : */
1582 : : gboolean
1583 : 7 : g_output_stream_writev_all_finish (GOutputStream *stream,
1584 : : GAsyncResult *result,
1585 : : gsize *bytes_written,
1586 : : GError **error)
1587 : : {
1588 : : GTask *task;
1589 : :
1590 : 7 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
1591 : 7 : g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
1592 : 7 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1593 : :
1594 : 7 : task = G_TASK (result);
1595 : :
1596 : 7 : if (bytes_written)
1597 : : {
1598 : 7 : AsyncWritevAll *data = (AsyncWritevAll *)g_task_get_task_data (task);
1599 : :
1600 : 7 : *bytes_written = data->bytes_written;
1601 : : }
1602 : :
1603 : 7 : return g_task_propagate_boolean (task, error);
1604 : : }
1605 : :
1606 : : static void
1607 : 0 : write_bytes_callback (GObject *stream,
1608 : : GAsyncResult *result,
1609 : : gpointer user_data)
1610 : : {
1611 : 0 : GTask *task = user_data;
1612 : 0 : GError *error = NULL;
1613 : : gssize nwrote;
1614 : :
1615 : 0 : nwrote = g_output_stream_write_finish (G_OUTPUT_STREAM (stream),
1616 : : result, &error);
1617 : 0 : if (nwrote == -1)
1618 : 0 : g_task_return_error (task, error);
1619 : : else
1620 : 0 : g_task_return_int (task, nwrote);
1621 : 0 : g_object_unref (task);
1622 : 0 : }
1623 : :
1624 : : /**
1625 : : * g_output_stream_write_bytes_async:
1626 : : * @stream: A #GOutputStream.
1627 : : * @bytes: The bytes to write
1628 : : * @io_priority: the io priority of the request.
1629 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
1630 : : * @callback: (scope async) (closure user_data): a #GAsyncReadyCallback
1631 : : * to call when the request is satisfied
1632 : : * @user_data: the data to pass to callback function
1633 : : *
1634 : : * This function is similar to g_output_stream_write_async(), but
1635 : : * takes a #GBytes as input. Due to the refcounted nature of #GBytes,
1636 : : * this allows the stream to avoid taking a copy of the data.
1637 : : *
1638 : : * However, note that this function may still perform partial writes,
1639 : : * just like g_output_stream_write_async(). If that occurs, to continue
1640 : : * writing, you will need to create a new #GBytes containing just the
1641 : : * remaining bytes, using g_bytes_new_from_bytes(). Passing the same
1642 : : * #GBytes instance multiple times potentially can result in duplicated
1643 : : * data in the output stream.
1644 : : *
1645 : : * For the synchronous, blocking version of this function, see
1646 : : * g_output_stream_write_bytes().
1647 : : **/
1648 : : void
1649 : 0 : g_output_stream_write_bytes_async (GOutputStream *stream,
1650 : : GBytes *bytes,
1651 : : int io_priority,
1652 : : GCancellable *cancellable,
1653 : : GAsyncReadyCallback callback,
1654 : : gpointer user_data)
1655 : : {
1656 : : GTask *task;
1657 : : gsize size;
1658 : : gconstpointer data;
1659 : :
1660 : 0 : data = g_bytes_get_data (bytes, &size);
1661 : :
1662 : 0 : task = g_task_new (stream, cancellable, callback, user_data);
1663 : 0 : g_task_set_source_tag (task, g_output_stream_write_bytes_async);
1664 : 0 : g_task_set_task_data (task, g_bytes_ref (bytes),
1665 : : (GDestroyNotify) g_bytes_unref);
1666 : :
1667 : 0 : g_output_stream_write_async (stream,
1668 : : data, size,
1669 : : io_priority,
1670 : : cancellable,
1671 : : write_bytes_callback,
1672 : : task);
1673 : 0 : }
1674 : :
1675 : : /**
1676 : : * g_output_stream_write_bytes_finish:
1677 : : * @stream: a #GOutputStream.
1678 : : * @result: a #GAsyncResult.
1679 : : * @error: a #GError location to store the error occurring, or %NULL to
1680 : : * ignore.
1681 : : *
1682 : : * Finishes a stream write-from-#GBytes operation.
1683 : : *
1684 : : * Returns: a #gssize containing the number of bytes written to the stream.
1685 : : **/
1686 : : gssize
1687 : 0 : g_output_stream_write_bytes_finish (GOutputStream *stream,
1688 : : GAsyncResult *result,
1689 : : GError **error)
1690 : : {
1691 : 0 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), -1);
1692 : 0 : g_return_val_if_fail (g_task_is_valid (result, stream), -1);
1693 : :
1694 : 0 : return g_task_propagate_int (G_TASK (result), error);
1695 : : }
1696 : :
1697 : : static void
1698 : 85 : async_ready_splice_callback_wrapper (GObject *source_object,
1699 : : GAsyncResult *res,
1700 : : gpointer _data)
1701 : : {
1702 : 85 : GOutputStream *stream = G_OUTPUT_STREAM (source_object);
1703 : : GOutputStreamClass *class;
1704 : 85 : GTask *task = _data;
1705 : : gssize nspliced;
1706 : 85 : GError *error = NULL;
1707 : :
1708 : 85 : g_output_stream_clear_pending (stream);
1709 : :
1710 : 85 : if (g_async_result_legacy_propagate_error (res, &error))
1711 : 0 : nspliced = -1;
1712 : : else
1713 : : {
1714 : 85 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
1715 : 85 : nspliced = class->splice_finish (stream, res, &error);
1716 : : }
1717 : :
1718 : 85 : if (nspliced >= 0)
1719 : 62 : g_task_return_int (task, nspliced);
1720 : : else
1721 : 23 : g_task_return_error (task, error);
1722 : 85 : g_object_unref (task);
1723 : 85 : }
1724 : :
1725 : : /**
1726 : : * g_output_stream_splice_async:
1727 : : * @stream: a #GOutputStream.
1728 : : * @source: a #GInputStream.
1729 : : * @flags: a set of #GOutputStreamSpliceFlags.
1730 : : * @io_priority: the io priority of the request.
1731 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
1732 : : * @callback: (scope async) (closure user_data): a #GAsyncReadyCallback
1733 : : * to call when the request is satisfied
1734 : : * @user_data: the data to pass to callback function
1735 : : *
1736 : : * Splices a stream asynchronously.
1737 : : * When the operation is finished @callback will be called.
1738 : : * You can then call g_output_stream_splice_finish() to get the
1739 : : * result of the operation.
1740 : : *
1741 : : * For the synchronous, blocking version of this function, see
1742 : : * g_output_stream_splice().
1743 : : **/
1744 : : void
1745 : 107 : g_output_stream_splice_async (GOutputStream *stream,
1746 : : GInputStream *source,
1747 : : GOutputStreamSpliceFlags flags,
1748 : : int io_priority,
1749 : : GCancellable *cancellable,
1750 : : GAsyncReadyCallback callback,
1751 : : gpointer user_data)
1752 : : {
1753 : : GOutputStreamClass *class;
1754 : : GTask *task;
1755 : 107 : GError *error = NULL;
1756 : :
1757 : 107 : g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
1758 : 107 : g_return_if_fail (G_IS_INPUT_STREAM (source));
1759 : :
1760 : 107 : task = g_task_new (stream, cancellable, callback, user_data);
1761 : 107 : g_task_set_source_tag (task, g_output_stream_splice_async);
1762 : 107 : g_task_set_priority (task, io_priority);
1763 : 107 : g_task_set_task_data (task, g_object_ref (source), g_object_unref);
1764 : :
1765 : 107 : if (g_input_stream_is_closed (source))
1766 : : {
1767 : 0 : g_task_return_new_error_literal (task,
1768 : : G_IO_ERROR, G_IO_ERROR_CLOSED,
1769 : 0 : _("Source stream is already closed"));
1770 : 0 : g_object_unref (task);
1771 : 0 : return;
1772 : : }
1773 : :
1774 : 107 : if (!g_output_stream_set_pending (stream, &error))
1775 : : {
1776 : 0 : g_task_return_error (task, error);
1777 : 0 : g_object_unref (task);
1778 : 0 : return;
1779 : : }
1780 : :
1781 : 107 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
1782 : :
1783 : 107 : class->splice_async (stream, source, flags, io_priority, cancellable,
1784 : : async_ready_splice_callback_wrapper, task);
1785 : : }
1786 : :
1787 : : /**
1788 : : * g_output_stream_splice_finish:
1789 : : * @stream: a #GOutputStream.
1790 : : * @result: a #GAsyncResult.
1791 : : * @error: a #GError location to store the error occurring, or %NULL to
1792 : : * ignore.
1793 : : *
1794 : : * Finishes an asynchronous stream splice operation.
1795 : : *
1796 : : * Returns: a #gssize of the number of bytes spliced. Note that if the
1797 : : * number of bytes spliced is greater than %G_MAXSSIZE, then that
1798 : : * will be returned, and there is no way to determine the actual
1799 : : * number of bytes spliced.
1800 : : **/
1801 : : gssize
1802 : 85 : g_output_stream_splice_finish (GOutputStream *stream,
1803 : : GAsyncResult *result,
1804 : : GError **error)
1805 : : {
1806 : 85 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
1807 : 85 : g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
1808 : 85 : g_return_val_if_fail (g_async_result_is_tagged (result, g_output_stream_splice_async), FALSE);
1809 : :
1810 : : /* @result is always the GTask created by g_output_stream_splice_async();
1811 : : * we called class->splice_finish() from async_ready_splice_callback_wrapper.
1812 : : */
1813 : 85 : return g_task_propagate_int (G_TASK (result), error);
1814 : : }
1815 : :
1816 : : static void
1817 : 109 : async_ready_flush_callback_wrapper (GObject *source_object,
1818 : : GAsyncResult *res,
1819 : : gpointer user_data)
1820 : : {
1821 : 109 : GOutputStream *stream = G_OUTPUT_STREAM (source_object);
1822 : : GOutputStreamClass *class;
1823 : 109 : GTask *task = user_data;
1824 : : gboolean flushed;
1825 : 109 : GError *error = NULL;
1826 : :
1827 : 109 : g_output_stream_clear_pending (stream);
1828 : :
1829 : 109 : if (g_async_result_legacy_propagate_error (res, &error))
1830 : 0 : flushed = FALSE;
1831 : : else
1832 : : {
1833 : 109 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
1834 : 109 : flushed = class->flush_finish (stream, res, &error);
1835 : : }
1836 : :
1837 : 109 : if (flushed)
1838 : 109 : g_task_return_boolean (task, TRUE);
1839 : : else
1840 : 0 : g_task_return_error (task, error);
1841 : 109 : g_object_unref (task);
1842 : 109 : }
1843 : :
1844 : : /**
1845 : : * g_output_stream_flush_async:
1846 : : * @stream: a #GOutputStream.
1847 : : * @io_priority: the io priority of the request.
1848 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
1849 : : * @callback: (scope async) (closure user_data): a #GAsyncReadyCallback
1850 : : * to call when the request is satisfied
1851 : : * @user_data: the data to pass to callback function
1852 : : *
1853 : : * Forces an asynchronous write of all user-space buffered data for
1854 : : * the given @stream.
1855 : : * For behaviour details see g_output_stream_flush().
1856 : : *
1857 : : * When the operation is finished @callback will be
1858 : : * called. You can then call g_output_stream_flush_finish() to get the
1859 : : * result of the operation.
1860 : : **/
1861 : : void
1862 : 109 : g_output_stream_flush_async (GOutputStream *stream,
1863 : : int io_priority,
1864 : : GCancellable *cancellable,
1865 : : GAsyncReadyCallback callback,
1866 : : gpointer user_data)
1867 : : {
1868 : : GOutputStreamClass *class;
1869 : : GTask *task;
1870 : 109 : GError *error = NULL;
1871 : :
1872 : 109 : g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
1873 : :
1874 : 109 : task = g_task_new (stream, cancellable, callback, user_data);
1875 : 109 : g_task_set_source_tag (task, g_output_stream_flush_async);
1876 : 109 : g_task_set_priority (task, io_priority);
1877 : :
1878 : 109 : if (!g_output_stream_set_pending (stream, &error))
1879 : : {
1880 : 0 : g_task_return_error (task, error);
1881 : 0 : g_object_unref (task);
1882 : 0 : return;
1883 : : }
1884 : :
1885 : 109 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
1886 : :
1887 : 109 : if (class->flush_async == NULL)
1888 : : {
1889 : 0 : g_output_stream_clear_pending (stream);
1890 : 0 : g_task_return_boolean (task, TRUE);
1891 : 0 : g_object_unref (task);
1892 : 0 : return;
1893 : : }
1894 : :
1895 : 109 : class->flush_async (stream, io_priority, cancellable,
1896 : : async_ready_flush_callback_wrapper, task);
1897 : : }
1898 : :
1899 : : /**
1900 : : * g_output_stream_flush_finish:
1901 : : * @stream: a #GOutputStream.
1902 : : * @result: a GAsyncResult.
1903 : : * @error: a #GError location to store the error occurring, or %NULL to
1904 : : * ignore.
1905 : : *
1906 : : * Finishes flushing an output stream.
1907 : : *
1908 : : * Returns: %TRUE if flush operation succeeded, %FALSE otherwise.
1909 : : **/
1910 : : gboolean
1911 : 109 : g_output_stream_flush_finish (GOutputStream *stream,
1912 : : GAsyncResult *result,
1913 : : GError **error)
1914 : : {
1915 : 109 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
1916 : 109 : g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
1917 : 109 : g_return_val_if_fail (g_async_result_is_tagged (result, g_output_stream_flush_async), FALSE);
1918 : :
1919 : : /* @result is always the GTask created by g_output_stream_flush_async();
1920 : : * we called class->flush_finish() from async_ready_flush_callback_wrapper.
1921 : : */
1922 : 109 : return g_task_propagate_boolean (G_TASK (result), error);
1923 : : }
1924 : :
1925 : :
1926 : : static void
1927 : 475 : async_ready_close_callback_wrapper (GObject *source_object,
1928 : : GAsyncResult *res,
1929 : : gpointer user_data)
1930 : : {
1931 : 475 : GOutputStream *stream = G_OUTPUT_STREAM (source_object);
1932 : : GOutputStreamClass *class;
1933 : 475 : GTask *task = user_data;
1934 : 475 : GError *error = g_task_get_task_data (task);
1935 : :
1936 : 475 : stream->priv->closing = FALSE;
1937 : 475 : stream->priv->closed = TRUE;
1938 : :
1939 : 475 : if (!error && !g_async_result_legacy_propagate_error (res, &error))
1940 : : {
1941 : 475 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
1942 : :
1943 : 475 : class->close_finish (stream, res,
1944 : 475 : error ? NULL : &error);
1945 : : }
1946 : :
1947 : 475 : if (error != NULL)
1948 : 25 : g_task_return_error (task, error);
1949 : : else
1950 : 450 : g_task_return_boolean (task, TRUE);
1951 : 475 : g_object_unref (task);
1952 : 475 : }
1953 : :
1954 : : static void
1955 : 404 : async_ready_close_flushed_callback_wrapper (GObject *source_object,
1956 : : GAsyncResult *res,
1957 : : gpointer user_data)
1958 : : {
1959 : 404 : GOutputStream *stream = G_OUTPUT_STREAM (source_object);
1960 : : GOutputStreamClass *class;
1961 : 404 : GTask *task = user_data;
1962 : 404 : GError *error = NULL;
1963 : :
1964 : 404 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
1965 : :
1966 : 404 : if (!g_async_result_legacy_propagate_error (res, &error))
1967 : : {
1968 : 404 : class->flush_finish (stream, res, &error);
1969 : : }
1970 : :
1971 : : /* propagate the possible error */
1972 : 404 : if (error)
1973 : 0 : g_task_set_task_data (task, error, NULL);
1974 : :
1975 : : /* we still close, even if there was a flush error */
1976 : 404 : class->close_async (stream,
1977 : : g_task_get_priority (task),
1978 : : g_task_get_cancellable (task),
1979 : : async_ready_close_callback_wrapper, task);
1980 : 404 : }
1981 : :
1982 : : static void
1983 : 415 : real_close_async_cb (GObject *source_object,
1984 : : GAsyncResult *res,
1985 : : gpointer user_data)
1986 : : {
1987 : 415 : GOutputStream *stream = G_OUTPUT_STREAM (source_object);
1988 : 415 : GTask *task = user_data;
1989 : 415 : GError *error = NULL;
1990 : : gboolean ret;
1991 : :
1992 : 415 : g_output_stream_clear_pending (stream);
1993 : :
1994 : 415 : ret = g_output_stream_internal_close_finish (stream, res, &error);
1995 : :
1996 : 415 : if (error != NULL)
1997 : 0 : g_task_return_error (task, error);
1998 : : else
1999 : 415 : g_task_return_boolean (task, ret);
2000 : :
2001 : 415 : g_object_unref (task);
2002 : 415 : }
2003 : :
2004 : : /**
2005 : : * g_output_stream_close_async:
2006 : : * @stream: A #GOutputStream.
2007 : : * @io_priority: the io priority of the request.
2008 : : * @cancellable: (nullable): optional cancellable object
2009 : : * @callback: (scope async) (closure user_data): a #GAsyncReadyCallback
2010 : : * to call when the request is satisfied
2011 : : * @user_data: the data to pass to callback function
2012 : : *
2013 : : * Requests an asynchronous close of the stream, releasing resources
2014 : : * related to it. When the operation is finished @callback will be
2015 : : * called. You can then call g_output_stream_close_finish() to get
2016 : : * the result of the operation.
2017 : : *
2018 : : * For behaviour details see g_output_stream_close().
2019 : : *
2020 : : * The asynchronous methods have a default fallback that uses threads
2021 : : * to implement asynchronicity, so they are optional for inheriting
2022 : : * classes. However, if you override one you must override all.
2023 : : **/
2024 : : void
2025 : 415 : g_output_stream_close_async (GOutputStream *stream,
2026 : : int io_priority,
2027 : : GCancellable *cancellable,
2028 : : GAsyncReadyCallback callback,
2029 : : gpointer user_data)
2030 : : {
2031 : : GTask *task;
2032 : 415 : GError *error = NULL;
2033 : :
2034 : 415 : g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
2035 : :
2036 : 415 : task = g_task_new (stream, cancellable, callback, user_data);
2037 : 415 : g_task_set_source_tag (task, g_output_stream_close_async);
2038 : 415 : g_task_set_priority (task, io_priority);
2039 : :
2040 : 415 : if (!g_output_stream_set_pending (stream, &error))
2041 : : {
2042 : 0 : g_task_return_error (task, error);
2043 : 0 : g_object_unref (task);
2044 : 0 : return;
2045 : : }
2046 : :
2047 : 415 : g_output_stream_internal_close_async (stream, io_priority, cancellable,
2048 : : real_close_async_cb, task);
2049 : : }
2050 : :
2051 : : /* Must always be called inside
2052 : : * g_output_stream_set_pending()/g_output_stream_clear_pending().
2053 : : */
2054 : : void
2055 : 475 : g_output_stream_internal_close_async (GOutputStream *stream,
2056 : : int io_priority,
2057 : : GCancellable *cancellable,
2058 : : GAsyncReadyCallback callback,
2059 : : gpointer user_data)
2060 : : {
2061 : : GOutputStreamClass *class;
2062 : : GTask *task;
2063 : :
2064 : 475 : task = g_task_new (stream, cancellable, callback, user_data);
2065 : 475 : g_task_set_source_tag (task, g_output_stream_internal_close_async);
2066 : 475 : g_task_set_priority (task, io_priority);
2067 : :
2068 : 475 : if (stream->priv->closed)
2069 : : {
2070 : 0 : g_task_return_boolean (task, TRUE);
2071 : 0 : g_object_unref (task);
2072 : 0 : return;
2073 : : }
2074 : :
2075 : 475 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
2076 : 475 : stream->priv->closing = TRUE;
2077 : :
2078 : : /* Call close_async directly if there is no need to flush, or if the flush
2079 : : can be done sync (in the output stream async close thread) */
2080 : 475 : if (class->flush_async == NULL ||
2081 : 475 : (class->flush_async == g_output_stream_real_flush_async &&
2082 : 471 : (class->flush == NULL || class->close_async == g_output_stream_real_close_async)))
2083 : : {
2084 : 71 : class->close_async (stream, io_priority, cancellable,
2085 : : async_ready_close_callback_wrapper, task);
2086 : : }
2087 : : else
2088 : : {
2089 : : /* First do an async flush, then do the async close in the callback
2090 : : wrapper (see async_ready_close_flushed_callback_wrapper) */
2091 : 404 : class->flush_async (stream, io_priority, cancellable,
2092 : : async_ready_close_flushed_callback_wrapper, task);
2093 : : }
2094 : : }
2095 : :
2096 : : static gboolean
2097 : 463 : g_output_stream_internal_close_finish (GOutputStream *stream,
2098 : : GAsyncResult *result,
2099 : : GError **error)
2100 : : {
2101 : 463 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
2102 : 463 : g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
2103 : 463 : g_return_val_if_fail (g_async_result_is_tagged (result, g_output_stream_internal_close_async), FALSE);
2104 : :
2105 : 463 : return g_task_propagate_boolean (G_TASK (result), error);
2106 : : }
2107 : :
2108 : : /**
2109 : : * g_output_stream_close_finish:
2110 : : * @stream: a #GOutputStream.
2111 : : * @result: a #GAsyncResult.
2112 : : * @error: a #GError location to store the error occurring, or %NULL to
2113 : : * ignore.
2114 : : *
2115 : : * Closes an output stream.
2116 : : *
2117 : : * Returns: %TRUE if stream was successfully closed, %FALSE otherwise.
2118 : : **/
2119 : : gboolean
2120 : 415 : g_output_stream_close_finish (GOutputStream *stream,
2121 : : GAsyncResult *result,
2122 : : GError **error)
2123 : : {
2124 : 415 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
2125 : 415 : g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
2126 : 415 : g_return_val_if_fail (g_async_result_is_tagged (result, g_output_stream_close_async), FALSE);
2127 : :
2128 : : /* @result is always the GTask created by g_output_stream_close_async();
2129 : : * we called class->close_finish() from async_ready_close_callback_wrapper.
2130 : : */
2131 : 415 : return g_task_propagate_boolean (G_TASK (result), error);
2132 : : }
2133 : :
2134 : : /**
2135 : : * g_output_stream_is_closed:
2136 : : * @stream: a #GOutputStream.
2137 : : *
2138 : : * Checks if an output stream has already been closed.
2139 : : *
2140 : : * Returns: %TRUE if @stream is closed. %FALSE otherwise.
2141 : : **/
2142 : : gboolean
2143 : 81 : g_output_stream_is_closed (GOutputStream *stream)
2144 : : {
2145 : 81 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), TRUE);
2146 : :
2147 : 81 : return stream->priv->closed;
2148 : : }
2149 : :
2150 : : /**
2151 : : * g_output_stream_is_closing:
2152 : : * @stream: a #GOutputStream.
2153 : : *
2154 : : * Checks if an output stream is being closed. This can be
2155 : : * used inside e.g. a flush implementation to see if the
2156 : : * flush (or other i/o operation) is called from within
2157 : : * the closing operation.
2158 : : *
2159 : : * Returns: %TRUE if @stream is being closed. %FALSE otherwise.
2160 : : *
2161 : : * Since: 2.24
2162 : : **/
2163 : : gboolean
2164 : 29 : g_output_stream_is_closing (GOutputStream *stream)
2165 : : {
2166 : 29 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), TRUE);
2167 : :
2168 : 29 : return stream->priv->closing;
2169 : : }
2170 : :
2171 : : /**
2172 : : * g_output_stream_has_pending:
2173 : : * @stream: a #GOutputStream.
2174 : : *
2175 : : * Checks if an output stream has pending actions.
2176 : : *
2177 : : * Returns: %TRUE if @stream has pending actions.
2178 : : **/
2179 : : gboolean
2180 : 15060 : g_output_stream_has_pending (GOutputStream *stream)
2181 : : {
2182 : 15060 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
2183 : :
2184 : 15060 : return stream->priv->pending;
2185 : : }
2186 : :
2187 : : /**
2188 : : * g_output_stream_set_pending:
2189 : : * @stream: a #GOutputStream.
2190 : : * @error: a #GError location to store the error occurring, or %NULL to
2191 : : * ignore.
2192 : : *
2193 : : * Sets @stream to have actions pending. If the pending flag is
2194 : : * already set or @stream is closed, it will return %FALSE and set
2195 : : * @error.
2196 : : *
2197 : : * Returns: %TRUE if pending was previously unset and is now set.
2198 : : **/
2199 : : gboolean
2200 : 266316 : g_output_stream_set_pending (GOutputStream *stream,
2201 : : GError **error)
2202 : : {
2203 : 266316 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
2204 : :
2205 : 266316 : if (stream->priv->closed)
2206 : : {
2207 : 4 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
2208 : : _("Stream is already closed"));
2209 : 4 : return FALSE;
2210 : : }
2211 : :
2212 : 266312 : if (stream->priv->pending)
2213 : : {
2214 : 5 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING,
2215 : : /* Translators: This is an error you get if there is
2216 : : * already an operation running against this stream when
2217 : : * you try to start one */
2218 : : _("Stream has outstanding operation"));
2219 : 5 : return FALSE;
2220 : : }
2221 : :
2222 : 266307 : stream->priv->pending = TRUE;
2223 : 266307 : return TRUE;
2224 : : }
2225 : :
2226 : : /**
2227 : : * g_output_stream_clear_pending:
2228 : : * @stream: output stream
2229 : : *
2230 : : * Clears the pending flag on @stream.
2231 : : **/
2232 : : void
2233 : 266285 : g_output_stream_clear_pending (GOutputStream *stream)
2234 : : {
2235 : 266285 : g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
2236 : :
2237 : 266285 : stream->priv->pending = FALSE;
2238 : : }
2239 : :
2240 : : /*< internal >
2241 : : * g_output_stream_async_write_is_via_threads:
2242 : : * @stream: a #GOutputStream.
2243 : : *
2244 : : * Checks if an output stream's write_async function uses threads.
2245 : : *
2246 : : * Returns: %TRUE if @stream's write_async function uses threads.
2247 : : **/
2248 : : gboolean
2249 : 7806 : g_output_stream_async_write_is_via_threads (GOutputStream *stream)
2250 : : {
2251 : : GOutputStreamClass *class;
2252 : :
2253 : 7806 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
2254 : :
2255 : 7806 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
2256 : :
2257 : 15612 : return (class->write_async == g_output_stream_real_write_async &&
2258 : 15422 : !(G_IS_POLLABLE_OUTPUT_STREAM (stream) &&
2259 : 7616 : g_pollable_output_stream_can_poll (G_POLLABLE_OUTPUT_STREAM (stream))));
2260 : : }
2261 : :
2262 : : /*< internal >
2263 : : * g_output_stream_async_writev_is_via_threads:
2264 : : * @stream: a #GOutputStream.
2265 : : *
2266 : : * Checks if an output stream's writev_async function uses threads.
2267 : : *
2268 : : * Returns: %TRUE if @stream's writev_async function uses threads.
2269 : : **/
2270 : : gboolean
2271 : 12 : g_output_stream_async_writev_is_via_threads (GOutputStream *stream)
2272 : : {
2273 : : GOutputStreamClass *class;
2274 : :
2275 : 12 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
2276 : :
2277 : 12 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
2278 : :
2279 : 24 : return (class->writev_async == g_output_stream_real_writev_async &&
2280 : 19 : !(G_IS_POLLABLE_OUTPUT_STREAM (stream) &&
2281 : 7 : g_pollable_output_stream_can_poll (G_POLLABLE_OUTPUT_STREAM (stream))));
2282 : : }
2283 : :
2284 : : /*< internal >
2285 : : * g_output_stream_async_close_is_via_threads:
2286 : : * @stream: output stream
2287 : : *
2288 : : * Checks if an output stream's close_async function uses threads.
2289 : : *
2290 : : * Returns: %TRUE if @stream's close_async function uses threads.
2291 : : **/
2292 : : gboolean
2293 : 406 : g_output_stream_async_close_is_via_threads (GOutputStream *stream)
2294 : : {
2295 : : GOutputStreamClass *class;
2296 : :
2297 : 406 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
2298 : :
2299 : 406 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
2300 : :
2301 : 406 : return class->close_async == g_output_stream_real_close_async;
2302 : : }
2303 : :
2304 : : /********************************************
2305 : : * Default implementation of sync ops *
2306 : : ********************************************/
2307 : : static gboolean
2308 : 1 : g_output_stream_real_writev (GOutputStream *stream,
2309 : : const GOutputVector *vectors,
2310 : : gsize n_vectors,
2311 : : gsize *bytes_written,
2312 : : GCancellable *cancellable,
2313 : : GError **error)
2314 : : {
2315 : : GOutputStreamClass *class;
2316 : 1 : gsize _bytes_written = 0;
2317 : : gsize i;
2318 : 1 : GError *err = NULL;
2319 : :
2320 : 1 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
2321 : :
2322 : 1 : if (bytes_written)
2323 : 1 : *bytes_written = 0;
2324 : :
2325 : 4 : for (i = 0; i < n_vectors; i++)
2326 : : {
2327 : 3 : gssize res = 0;
2328 : :
2329 : : /* Would we overflow here? In that case simply return and let the caller
2330 : : * handle this like a short write */
2331 : 3 : if (_bytes_written > G_MAXSIZE - vectors[i].size)
2332 : 0 : break;
2333 : :
2334 : 3 : res = class->write_fn (stream, vectors[i].buffer, vectors[i].size, cancellable, &err);
2335 : :
2336 : 3 : if (res == -1)
2337 : : {
2338 : : /* If we already wrote something we handle this like a short write
2339 : : * and assume that on the next call the same error happens again, or
2340 : : * everything finishes successfully without data loss then
2341 : : */
2342 : 0 : if (_bytes_written > 0)
2343 : : {
2344 : 0 : if (bytes_written)
2345 : 0 : *bytes_written = _bytes_written;
2346 : :
2347 : 0 : g_clear_error (&err);
2348 : 0 : return TRUE;
2349 : : }
2350 : :
2351 : 0 : g_propagate_error (error, err);
2352 : 0 : return FALSE;
2353 : : }
2354 : :
2355 : 3 : _bytes_written += res;
2356 : : /* if we had a short write break the loop here */
2357 : 3 : if ((gsize) res < vectors[i].size)
2358 : 0 : break;
2359 : : }
2360 : :
2361 : 1 : if (bytes_written)
2362 : 1 : *bytes_written = _bytes_written;
2363 : :
2364 : 1 : return TRUE;
2365 : : }
2366 : :
2367 : : /********************************************
2368 : : * Default implementation of async ops *
2369 : : ********************************************/
2370 : :
2371 : : typedef struct {
2372 : : const void *buffer;
2373 : : gsize count_requested;
2374 : : gssize count_written;
2375 : : } WriteData;
2376 : :
2377 : : static void
2378 : 7796 : free_write_data (WriteData *op)
2379 : : {
2380 : 7796 : g_slice_free (WriteData, op);
2381 : 7796 : }
2382 : :
2383 : : static void
2384 : 189 : write_async_thread (GTask *task,
2385 : : gpointer source_object,
2386 : : gpointer task_data,
2387 : : GCancellable *cancellable)
2388 : : {
2389 : 189 : GOutputStream *stream = source_object;
2390 : 189 : WriteData *op = task_data;
2391 : : GOutputStreamClass *class;
2392 : 189 : GError *error = NULL;
2393 : : gssize count_written;
2394 : :
2395 : 189 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
2396 : 189 : count_written = class->write_fn (stream, op->buffer, op->count_requested,
2397 : : cancellable, &error);
2398 : 189 : if (count_written == -1)
2399 : 111 : g_task_return_error (task, error);
2400 : : else
2401 : 78 : g_task_return_int (task, count_written);
2402 : 189 : }
2403 : :
2404 : : static void write_async_pollable (GPollableOutputStream *stream,
2405 : : GTask *task);
2406 : :
2407 : : static gboolean
2408 : 50 : write_async_pollable_ready (GPollableOutputStream *stream,
2409 : : gpointer user_data)
2410 : : {
2411 : 50 : GTask *task = user_data;
2412 : :
2413 : 50 : write_async_pollable (stream, task);
2414 : 50 : return FALSE;
2415 : : }
2416 : :
2417 : : static void
2418 : 7657 : write_async_pollable (GPollableOutputStream *stream,
2419 : : GTask *task)
2420 : : {
2421 : 7657 : GError *error = NULL;
2422 : 7657 : WriteData *op = g_task_get_task_data (task);
2423 : : gssize count_written;
2424 : :
2425 : 7657 : if (g_task_return_error_if_cancelled (task))
2426 : 51 : return;
2427 : :
2428 : 7656 : count_written = G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->
2429 : : write_nonblocking (stream, op->buffer, op->count_requested, &error);
2430 : :
2431 : 7656 : if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
2432 : : {
2433 : : GSource *source;
2434 : :
2435 : 50 : g_error_free (error);
2436 : :
2437 : 50 : source = g_pollable_output_stream_create_source (stream,
2438 : : g_task_get_cancellable (task));
2439 : 50 : g_task_attach_source (task, source,
2440 : : (GSourceFunc) write_async_pollable_ready);
2441 : 50 : g_source_unref (source);
2442 : 50 : return;
2443 : : }
2444 : :
2445 : 7606 : if (count_written == -1)
2446 : 2 : g_task_return_error (task, error);
2447 : : else
2448 : 7604 : g_task_return_int (task, count_written);
2449 : : }
2450 : :
2451 : : static void
2452 : 7796 : g_output_stream_real_write_async (GOutputStream *stream,
2453 : : const void *buffer,
2454 : : gsize count,
2455 : : int io_priority,
2456 : : GCancellable *cancellable,
2457 : : GAsyncReadyCallback callback,
2458 : : gpointer user_data)
2459 : : {
2460 : : GTask *task;
2461 : : WriteData *op;
2462 : :
2463 : 7796 : op = g_slice_new0 (WriteData);
2464 : 7796 : task = g_task_new (stream, cancellable, callback, user_data);
2465 : 7796 : g_task_set_check_cancellable (task, FALSE);
2466 : 7796 : g_task_set_task_data (task, op, (GDestroyNotify) free_write_data);
2467 : 7796 : op->buffer = buffer;
2468 : 7796 : op->count_requested = count;
2469 : :
2470 : 7796 : if (!g_output_stream_async_write_is_via_threads (stream))
2471 : 7607 : write_async_pollable (G_POLLABLE_OUTPUT_STREAM (stream), task);
2472 : : else
2473 : 189 : g_task_run_in_thread (task, write_async_thread);
2474 : 7796 : g_object_unref (task);
2475 : 7796 : }
2476 : :
2477 : : static gssize
2478 : 7796 : g_output_stream_real_write_finish (GOutputStream *stream,
2479 : : GAsyncResult *result,
2480 : : GError **error)
2481 : : {
2482 : 7796 : g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
2483 : :
2484 : 7796 : return g_task_propagate_int (G_TASK (result), error);
2485 : : }
2486 : :
2487 : : typedef struct {
2488 : : const GOutputVector *vectors;
2489 : : gsize n_vectors; /* (unowned) */
2490 : : gsize bytes_written;
2491 : : } WritevData;
2492 : :
2493 : : static void
2494 : 6 : free_writev_data (WritevData *op)
2495 : : {
2496 : 6 : g_slice_free (WritevData, op);
2497 : 6 : }
2498 : :
2499 : : static void
2500 : 1 : writev_async_thread (GTask *task,
2501 : : gpointer source_object,
2502 : : gpointer task_data,
2503 : : GCancellable *cancellable)
2504 : : {
2505 : 1 : GOutputStream *stream = source_object;
2506 : 1 : WritevData *op = task_data;
2507 : : GOutputStreamClass *class;
2508 : 1 : GError *error = NULL;
2509 : : gboolean res;
2510 : :
2511 : 1 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
2512 : 1 : res = class->writev_fn (stream, op->vectors, op->n_vectors,
2513 : : &op->bytes_written, cancellable, &error);
2514 : :
2515 : 1 : g_warn_if_fail (res || op->bytes_written == 0);
2516 : 1 : g_warn_if_fail (res || error != NULL);
2517 : :
2518 : 1 : if (!res)
2519 : 0 : g_task_return_error (task, g_steal_pointer (&error));
2520 : : else
2521 : 1 : g_task_return_boolean (task, TRUE);
2522 : 1 : }
2523 : :
2524 : : static void writev_async_pollable (GPollableOutputStream *stream,
2525 : : GTask *task);
2526 : :
2527 : : static gboolean
2528 : 0 : writev_async_pollable_ready (GPollableOutputStream *stream,
2529 : : gpointer user_data)
2530 : : {
2531 : 0 : GTask *task = user_data;
2532 : :
2533 : 0 : writev_async_pollable (stream, task);
2534 : 0 : return G_SOURCE_REMOVE;
2535 : : }
2536 : :
2537 : : static void
2538 : 5 : writev_async_pollable (GPollableOutputStream *stream,
2539 : : GTask *task)
2540 : : {
2541 : 5 : GError *error = NULL;
2542 : 5 : WritevData *op = g_task_get_task_data (task);
2543 : : GPollableReturn res;
2544 : 5 : gsize bytes_written = 0;
2545 : :
2546 : 5 : if (g_task_return_error_if_cancelled (task))
2547 : 0 : return;
2548 : :
2549 : 5 : res = G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->
2550 : : writev_nonblocking (stream, op->vectors, op->n_vectors, &bytes_written, &error);
2551 : :
2552 : 5 : switch (res)
2553 : : {
2554 : 0 : case G_POLLABLE_RETURN_WOULD_BLOCK:
2555 : : {
2556 : : GSource *source;
2557 : :
2558 : 0 : g_warn_if_fail (error == NULL);
2559 : 0 : g_warn_if_fail (bytes_written == 0);
2560 : :
2561 : 0 : source = g_pollable_output_stream_create_source (stream,
2562 : : g_task_get_cancellable (task));
2563 : 0 : g_task_attach_source (task, source,
2564 : : (GSourceFunc) writev_async_pollable_ready);
2565 : 0 : g_source_unref (source);
2566 : : }
2567 : 0 : break;
2568 : 5 : case G_POLLABLE_RETURN_OK:
2569 : 5 : g_warn_if_fail (error == NULL);
2570 : 5 : op->bytes_written = bytes_written;
2571 : 5 : g_task_return_boolean (task, TRUE);
2572 : 5 : break;
2573 : 0 : case G_POLLABLE_RETURN_FAILED:
2574 : 0 : g_warn_if_fail (bytes_written == 0);
2575 : 0 : g_warn_if_fail (error != NULL);
2576 : 0 : g_task_return_error (task, g_steal_pointer (&error));
2577 : 0 : break;
2578 : 0 : default:
2579 : : g_assert_not_reached ();
2580 : : }
2581 : : }
2582 : :
2583 : : static void
2584 : 6 : g_output_stream_real_writev_async (GOutputStream *stream,
2585 : : const GOutputVector *vectors,
2586 : : gsize n_vectors,
2587 : : int io_priority,
2588 : : GCancellable *cancellable,
2589 : : GAsyncReadyCallback callback,
2590 : : gpointer user_data)
2591 : : {
2592 : : GTask *task;
2593 : : WritevData *op;
2594 : 6 : GError *error = NULL;
2595 : :
2596 : 6 : op = g_slice_new0 (WritevData);
2597 : 6 : task = g_task_new (stream, cancellable, callback, user_data);
2598 : 6 : op->vectors = vectors;
2599 : 6 : op->n_vectors = n_vectors;
2600 : :
2601 : 6 : g_task_set_check_cancellable (task, FALSE);
2602 : 6 : g_task_set_source_tag (task, g_output_stream_writev_async);
2603 : 6 : g_task_set_priority (task, io_priority);
2604 : 6 : g_task_set_task_data (task, op, (GDestroyNotify) free_writev_data);
2605 : :
2606 : 6 : if (n_vectors == 0)
2607 : : {
2608 : 0 : g_task_return_boolean (task, TRUE);
2609 : 0 : g_object_unref (task);
2610 : 0 : return;
2611 : : }
2612 : :
2613 : 6 : if (!g_output_stream_set_pending (stream, &error))
2614 : : {
2615 : 0 : g_task_return_error (task, g_steal_pointer (&error));
2616 : 0 : g_object_unref (task);
2617 : 0 : return;
2618 : : }
2619 : :
2620 : 6 : if (!g_output_stream_async_writev_is_via_threads (stream))
2621 : 5 : writev_async_pollable (G_POLLABLE_OUTPUT_STREAM (stream), task);
2622 : : else
2623 : 1 : g_task_run_in_thread (task, writev_async_thread);
2624 : :
2625 : 6 : g_object_unref (task);
2626 : : }
2627 : :
2628 : : static gboolean
2629 : 6 : g_output_stream_real_writev_finish (GOutputStream *stream,
2630 : : GAsyncResult *result,
2631 : : gsize *bytes_written,
2632 : : GError **error)
2633 : : {
2634 : : GTask *task;
2635 : :
2636 : 6 : g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
2637 : 6 : g_return_val_if_fail (g_async_result_is_tagged (result, g_output_stream_writev_async), FALSE);
2638 : :
2639 : 6 : g_output_stream_clear_pending (stream);
2640 : :
2641 : 6 : task = G_TASK (result);
2642 : :
2643 : 6 : if (bytes_written)
2644 : : {
2645 : 6 : WritevData *op = g_task_get_task_data (task);
2646 : :
2647 : 6 : *bytes_written = op->bytes_written;
2648 : : }
2649 : :
2650 : 6 : return g_task_propagate_boolean (task, error);
2651 : : }
2652 : :
2653 : : typedef struct {
2654 : : GInputStream *source;
2655 : : GOutputStreamSpliceFlags flags;
2656 : : guint istream_closed : 1;
2657 : : guint ostream_closed : 1;
2658 : : gssize n_read;
2659 : : gssize n_written;
2660 : : gsize bytes_copied;
2661 : : GError *error;
2662 : : guint8 *buffer;
2663 : : } SpliceData;
2664 : :
2665 : : static void
2666 : 85 : free_splice_data (SpliceData *op)
2667 : : {
2668 : 85 : g_clear_pointer (&op->buffer, g_free);
2669 : 85 : g_object_unref (op->source);
2670 : 85 : g_clear_error (&op->error);
2671 : 85 : g_free (op);
2672 : 85 : }
2673 : :
2674 : : static void
2675 : 144 : real_splice_async_complete_cb (GTask *task)
2676 : : {
2677 : 144 : SpliceData *op = g_task_get_task_data (task);
2678 : :
2679 : 144 : if (op->flags & G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE &&
2680 : 142 : !op->istream_closed)
2681 : 5 : return;
2682 : :
2683 : 139 : if (op->flags & G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET &&
2684 : 103 : !op->ostream_closed)
2685 : 55 : return;
2686 : :
2687 : 84 : if (op->error != NULL)
2688 : : {
2689 : 23 : g_task_return_error (task, op->error);
2690 : 23 : op->error = NULL;
2691 : : }
2692 : : else
2693 : : {
2694 : 61 : g_task_return_int (task, op->bytes_copied);
2695 : : }
2696 : :
2697 : 84 : g_object_unref (task);
2698 : : }
2699 : :
2700 : : static void
2701 : 94 : real_splice_async_close_input_cb (GObject *source,
2702 : : GAsyncResult *res,
2703 : : gpointer user_data)
2704 : : {
2705 : 94 : GTask *task = user_data;
2706 : 94 : SpliceData *op = g_task_get_task_data (task);
2707 : :
2708 : 94 : g_input_stream_close_finish (G_INPUT_STREAM (source), res, NULL);
2709 : 94 : op->istream_closed = TRUE;
2710 : :
2711 : 94 : real_splice_async_complete_cb (task);
2712 : 94 : }
2713 : :
2714 : : static void
2715 : 48 : real_splice_async_close_output_cb (GObject *source,
2716 : : GAsyncResult *res,
2717 : : gpointer user_data)
2718 : : {
2719 : 48 : GTask *task = G_TASK (user_data);
2720 : 48 : SpliceData *op = g_task_get_task_data (task);
2721 : 48 : GError **error = (op->error == NULL) ? &op->error : NULL;
2722 : :
2723 : 48 : g_output_stream_internal_close_finish (G_OUTPUT_STREAM (source), res, error);
2724 : 48 : op->ostream_closed = TRUE;
2725 : :
2726 : 48 : real_splice_async_complete_cb (task);
2727 : 48 : }
2728 : :
2729 : : static void
2730 : 106 : real_splice_async_complete (GTask *task)
2731 : : {
2732 : 106 : SpliceData *op = g_task_get_task_data (task);
2733 : 106 : gboolean done = TRUE;
2734 : :
2735 : 106 : if (op->flags & G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE)
2736 : : {
2737 : 104 : done = FALSE;
2738 : 104 : g_input_stream_close_async (op->source, g_task_get_priority (task),
2739 : : g_task_get_cancellable (task),
2740 : : real_splice_async_close_input_cb, task);
2741 : : }
2742 : :
2743 : 106 : if (op->flags & G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET)
2744 : : {
2745 : 60 : done = FALSE;
2746 : 60 : g_output_stream_internal_close_async (g_task_get_source_object (task),
2747 : : g_task_get_priority (task),
2748 : : g_task_get_cancellable (task),
2749 : : real_splice_async_close_output_cb,
2750 : : task);
2751 : : }
2752 : :
2753 : 106 : if (done)
2754 : 2 : real_splice_async_complete_cb (task);
2755 : 106 : }
2756 : :
2757 : : static void real_splice_async_read_cb (GObject *source,
2758 : : GAsyncResult *res,
2759 : : gpointer user_data);
2760 : :
2761 : : static void
2762 : 74 : real_splice_async_write_cb (GObject *source,
2763 : : GAsyncResult *res,
2764 : : gpointer user_data)
2765 : : {
2766 : : GOutputStreamClass *class;
2767 : 74 : GTask *task = G_TASK (user_data);
2768 : 74 : SpliceData *op = g_task_get_task_data (task);
2769 : : gssize ret;
2770 : :
2771 : 74 : class = G_OUTPUT_STREAM_GET_CLASS (g_task_get_source_object (task));
2772 : :
2773 : 74 : ret = class->write_finish (G_OUTPUT_STREAM (source), res, &op->error);
2774 : :
2775 : 74 : if (ret == -1)
2776 : : {
2777 : 0 : real_splice_async_complete (task);
2778 : 0 : return;
2779 : : }
2780 : :
2781 : 74 : op->n_written += ret;
2782 : 74 : op->bytes_copied += ret;
2783 : 74 : if (op->bytes_copied > G_MAXSSIZE)
2784 : 0 : op->bytes_copied = G_MAXSSIZE;
2785 : :
2786 : 74 : if (op->n_written < op->n_read)
2787 : : {
2788 : 0 : class->write_async (g_task_get_source_object (task),
2789 : 0 : op->buffer + op->n_written,
2790 : 0 : op->n_read - op->n_written,
2791 : : g_task_get_priority (task),
2792 : : g_task_get_cancellable (task),
2793 : : real_splice_async_write_cb, task);
2794 : 0 : return;
2795 : : }
2796 : :
2797 : 74 : g_input_stream_read_async (op->source, op->buffer, 8192,
2798 : : g_task_get_priority (task),
2799 : : g_task_get_cancellable (task),
2800 : : real_splice_async_read_cb, task);
2801 : : }
2802 : :
2803 : : static void
2804 : 180 : real_splice_async_read_cb (GObject *source,
2805 : : GAsyncResult *res,
2806 : : gpointer user_data)
2807 : : {
2808 : : GOutputStreamClass *class;
2809 : 180 : GTask *task = G_TASK (user_data);
2810 : 180 : SpliceData *op = g_task_get_task_data (task);
2811 : : gssize ret;
2812 : :
2813 : 180 : class = G_OUTPUT_STREAM_GET_CLASS (g_task_get_source_object (task));
2814 : :
2815 : 180 : ret = g_input_stream_read_finish (op->source, res, &op->error);
2816 : 180 : if (ret == -1 || ret == 0)
2817 : : {
2818 : 106 : real_splice_async_complete (task);
2819 : 106 : return;
2820 : : }
2821 : :
2822 : 74 : op->n_read = ret;
2823 : 74 : op->n_written = 0;
2824 : :
2825 : 148 : class->write_async (g_task_get_source_object (task), op->buffer,
2826 : 74 : op->n_read, g_task_get_priority (task),
2827 : : g_task_get_cancellable (task),
2828 : : real_splice_async_write_cb, task);
2829 : : }
2830 : :
2831 : : static void
2832 : 1 : splice_async_thread (GTask *task,
2833 : : gpointer source_object,
2834 : : gpointer task_data,
2835 : : GCancellable *cancellable)
2836 : : {
2837 : 1 : GOutputStream *stream = source_object;
2838 : 1 : SpliceData *op = task_data;
2839 : : GOutputStreamClass *class;
2840 : 1 : GError *error = NULL;
2841 : : gssize bytes_copied;
2842 : :
2843 : 1 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
2844 : :
2845 : 1 : bytes_copied = class->splice (stream,
2846 : : op->source,
2847 : : op->flags,
2848 : : cancellable,
2849 : : &error);
2850 : 1 : if (bytes_copied == -1)
2851 : 0 : g_task_return_error (task, error);
2852 : : else
2853 : 1 : g_task_return_int (task, bytes_copied);
2854 : 1 : }
2855 : :
2856 : : static void
2857 : 107 : g_output_stream_real_splice_async (GOutputStream *stream,
2858 : : GInputStream *source,
2859 : : GOutputStreamSpliceFlags flags,
2860 : : int io_priority,
2861 : : GCancellable *cancellable,
2862 : : GAsyncReadyCallback callback,
2863 : : gpointer user_data)
2864 : : {
2865 : : GTask *task;
2866 : : SpliceData *op;
2867 : :
2868 : 107 : op = g_new0 (SpliceData, 1);
2869 : 107 : task = g_task_new (stream, cancellable, callback, user_data);
2870 : 107 : g_task_set_task_data (task, op, (GDestroyNotify)free_splice_data);
2871 : 107 : op->flags = flags;
2872 : 107 : op->source = g_object_ref (source);
2873 : :
2874 : 109 : if (g_input_stream_async_read_is_via_threads (source) &&
2875 : 2 : g_output_stream_async_write_is_via_threads (stream))
2876 : : {
2877 : 1 : g_task_run_in_thread (task, splice_async_thread);
2878 : 1 : g_object_unref (task);
2879 : : }
2880 : : else
2881 : : {
2882 : 106 : op->buffer = g_malloc (8192);
2883 : 106 : g_input_stream_read_async (op->source, op->buffer, 8192,
2884 : : g_task_get_priority (task),
2885 : : g_task_get_cancellable (task),
2886 : : real_splice_async_read_cb, task);
2887 : : }
2888 : 107 : }
2889 : :
2890 : : static gssize
2891 : 85 : g_output_stream_real_splice_finish (GOutputStream *stream,
2892 : : GAsyncResult *result,
2893 : : GError **error)
2894 : : {
2895 : 85 : g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
2896 : :
2897 : 85 : return g_task_propagate_int (G_TASK (result), error);
2898 : : }
2899 : :
2900 : :
2901 : : static void
2902 : 509 : flush_async_thread (GTask *task,
2903 : : gpointer source_object,
2904 : : gpointer task_data,
2905 : : GCancellable *cancellable)
2906 : : {
2907 : 509 : GOutputStream *stream = source_object;
2908 : : GOutputStreamClass *class;
2909 : : gboolean result;
2910 : 509 : GError *error = NULL;
2911 : :
2912 : 509 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
2913 : 509 : result = TRUE;
2914 : 509 : if (class->flush)
2915 : 403 : result = class->flush (stream, cancellable, &error);
2916 : :
2917 : 509 : if (result)
2918 : 509 : g_task_return_boolean (task, TRUE);
2919 : : else
2920 : 0 : g_task_return_error (task, error);
2921 : 509 : }
2922 : :
2923 : : static void
2924 : 509 : g_output_stream_real_flush_async (GOutputStream *stream,
2925 : : int io_priority,
2926 : : GCancellable *cancellable,
2927 : : GAsyncReadyCallback callback,
2928 : : gpointer user_data)
2929 : : {
2930 : : GTask *task;
2931 : :
2932 : 509 : task = g_task_new (stream, cancellable, callback, user_data);
2933 : 509 : g_task_set_priority (task, io_priority);
2934 : 509 : g_task_run_in_thread (task, flush_async_thread);
2935 : 509 : g_object_unref (task);
2936 : 509 : }
2937 : :
2938 : : static gboolean
2939 : 509 : g_output_stream_real_flush_finish (GOutputStream *stream,
2940 : : GAsyncResult *result,
2941 : : GError **error)
2942 : : {
2943 : 509 : g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
2944 : :
2945 : 509 : return g_task_propagate_boolean (G_TASK (result), error);
2946 : : }
2947 : :
2948 : : static void
2949 : 463 : close_async_thread (GTask *task,
2950 : : gpointer source_object,
2951 : : gpointer task_data,
2952 : : GCancellable *cancellable)
2953 : : {
2954 : 463 : GOutputStream *stream = source_object;
2955 : : GOutputStreamClass *class;
2956 : 463 : GError *error = NULL;
2957 : 463 : gboolean result = TRUE;
2958 : :
2959 : 463 : class = G_OUTPUT_STREAM_GET_CLASS (stream);
2960 : :
2961 : : /* Do a flush here if there is a flush function, and we did not have to do
2962 : : * an async flush before (see g_output_stream_close_async)
2963 : : */
2964 : 463 : if (class->flush != NULL &&
2965 : 405 : (class->flush_async == NULL ||
2966 : 405 : class->flush_async == g_output_stream_real_flush_async))
2967 : : {
2968 : 405 : result = class->flush (stream, cancellable, &error);
2969 : : }
2970 : :
2971 : : /* Auto handling of cancellation disabled, and ignore
2972 : : cancellation, since we want to close things anyway, although
2973 : : possibly in a quick-n-dirty way. At least we never want to leak
2974 : : open handles */
2975 : :
2976 : 463 : if (class->close_fn)
2977 : : {
2978 : : /* Make sure to close, even if the flush failed (see sync close) */
2979 : 463 : if (!result)
2980 : 0 : class->close_fn (stream, cancellable, NULL);
2981 : : else
2982 : 463 : result = class->close_fn (stream, cancellable, &error);
2983 : : }
2984 : :
2985 : 463 : if (result)
2986 : 463 : g_task_return_boolean (task, TRUE);
2987 : : else
2988 : 0 : g_task_return_error (task, error);
2989 : 463 : }
2990 : :
2991 : : static void
2992 : 463 : g_output_stream_real_close_async (GOutputStream *stream,
2993 : : int io_priority,
2994 : : GCancellable *cancellable,
2995 : : GAsyncReadyCallback callback,
2996 : : gpointer user_data)
2997 : : {
2998 : : GTask *task;
2999 : :
3000 : 463 : task = g_task_new (stream, cancellable, callback, user_data);
3001 : 463 : g_task_set_priority (task, io_priority);
3002 : 463 : g_task_run_in_thread (task, close_async_thread);
3003 : 463 : g_object_unref (task);
3004 : 463 : }
3005 : :
3006 : : static gboolean
3007 : 463 : g_output_stream_real_close_finish (GOutputStream *stream,
3008 : : GAsyncResult *result,
3009 : : GError **error)
3010 : : {
3011 : 463 : g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
3012 : :
3013 : 463 : return g_task_propagate_boolean (G_TASK (result), error);
3014 : : }
|