• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Christian Kellner <gicmo@gnome.org>
21  */
22 
23 #include "config.h"
24 #include "gbufferedoutputstream.h"
25 #include "goutputstream.h"
26 #include "gsimpleasyncresult.h"
27 #include "string.h"
28 #include "glibintl.h"
29 
30 #include <gioalias.h>
31 
32 /**
33  * SECTION:gbufferedoutputstream
34  * @short_description: Buffered Output Stream
35  * @include: gio/gio.h
36  * @see_also: #GFilterOutputStream, #GOutputStream
37  *
38  * Buffered output stream implements #GFilterOutputStream and provides
39  * for buffered writes.
40  *
41  * By default, #GBufferedOutputStream's buffer size is set at 4 kilobytes.
42  *
43  * To create a buffered output stream, use g_buffered_output_stream_new(),
44  * or g_buffered_output_stream_new_sized() to specify the buffer's size
45  * at construction.
46  *
47  * To get the size of a buffer within a buffered input stream, use
48  * g_buffered_output_stream_get_buffer_size(). To change the size of a
49  * buffered output stream's buffer, use
50  * g_buffered_output_stream_set_buffer_size(). Note that the buffer's
51  * size cannot be reduced below the size of the data within the buffer.
52  **/
53 
54 #define DEFAULT_BUFFER_SIZE 4096
55 
56 struct _GBufferedOutputStreamPrivate {
57   guint8 *buffer;
58   gsize   len;
59   goffset pos;
60   gboolean auto_grow;
61 };
62 
63 enum {
64   PROP_0,
65   PROP_BUFSIZE,
66   PROP_AUTO_GROW
67 };
68 
69 static void     g_buffered_output_stream_set_property (GObject      *object,
70                                                        guint         prop_id,
71                                                        const GValue *value,
72                                                        GParamSpec   *pspec);
73 
74 static void     g_buffered_output_stream_get_property (GObject    *object,
75                                                        guint       prop_id,
76                                                        GValue     *value,
77                                                        GParamSpec *pspec);
78 static void     g_buffered_output_stream_finalize     (GObject *object);
79 
80 
81 static gssize   g_buffered_output_stream_write        (GOutputStream *stream,
82                                                        const void    *buffer,
83                                                        gsize          count,
84                                                        GCancellable  *cancellable,
85                                                        GError       **error);
86 static gboolean g_buffered_output_stream_flush        (GOutputStream    *stream,
87                                                        GCancellable  *cancellable,
88                                                        GError          **error);
89 static gboolean g_buffered_output_stream_close        (GOutputStream  *stream,
90                                                        GCancellable   *cancellable,
91                                                        GError        **error);
92 
93 static void     g_buffered_output_stream_write_async  (GOutputStream        *stream,
94                                                        const void           *buffer,
95                                                        gsize                 count,
96                                                        int                   io_priority,
97                                                        GCancellable         *cancellable,
98                                                        GAsyncReadyCallback   callback,
99                                                        gpointer              data);
100 static gssize   g_buffered_output_stream_write_finish (GOutputStream        *stream,
101                                                        GAsyncResult         *result,
102                                                        GError              **error);
103 static void     g_buffered_output_stream_flush_async  (GOutputStream        *stream,
104                                                        int                   io_priority,
105                                                        GCancellable         *cancellable,
106                                                        GAsyncReadyCallback   callback,
107                                                        gpointer              data);
108 static gboolean g_buffered_output_stream_flush_finish (GOutputStream        *stream,
109                                                        GAsyncResult         *result,
110                                                        GError              **error);
111 static void     g_buffered_output_stream_close_async  (GOutputStream        *stream,
112                                                        int                   io_priority,
113                                                        GCancellable         *cancellable,
114                                                        GAsyncReadyCallback   callback,
115                                                        gpointer              data);
116 static gboolean g_buffered_output_stream_close_finish (GOutputStream        *stream,
117                                                        GAsyncResult         *result,
118                                                        GError              **error);
119 
G_DEFINE_TYPE(GBufferedOutputStream,g_buffered_output_stream,G_TYPE_FILTER_OUTPUT_STREAM)120 G_DEFINE_TYPE (GBufferedOutputStream,
121                g_buffered_output_stream,
122                G_TYPE_FILTER_OUTPUT_STREAM)
123 
124 
125 static void
126 g_buffered_output_stream_class_init (GBufferedOutputStreamClass *klass)
127 {
128   GObjectClass *object_class;
129   GOutputStreamClass *ostream_class;
130 
131   g_type_class_add_private (klass, sizeof (GBufferedOutputStreamPrivate));
132 
133   object_class = G_OBJECT_CLASS (klass);
134   object_class->get_property = g_buffered_output_stream_get_property;
135   object_class->set_property = g_buffered_output_stream_set_property;
136   object_class->finalize     = g_buffered_output_stream_finalize;
137 
138   ostream_class = G_OUTPUT_STREAM_CLASS (klass);
139   ostream_class->write_fn = g_buffered_output_stream_write;
140   ostream_class->flush = g_buffered_output_stream_flush;
141   ostream_class->close_fn = g_buffered_output_stream_close;
142   ostream_class->write_async  = g_buffered_output_stream_write_async;
143   ostream_class->write_finish = g_buffered_output_stream_write_finish;
144   ostream_class->flush_async  = g_buffered_output_stream_flush_async;
145   ostream_class->flush_finish = g_buffered_output_stream_flush_finish;
146   ostream_class->close_async  = g_buffered_output_stream_close_async;
147   ostream_class->close_finish = g_buffered_output_stream_close_finish;
148 
149   g_object_class_install_property (object_class,
150                                    PROP_BUFSIZE,
151                                    g_param_spec_uint ("buffer-size",
152                                                       P_("Buffer Size"),
153                                                       P_("The size of the backend buffer"),
154                                                       1,
155                                                       G_MAXUINT,
156                                                       DEFAULT_BUFFER_SIZE,
157                                                       G_PARAM_READWRITE|G_PARAM_CONSTRUCT|
158                                                       G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
159 
160   g_object_class_install_property (object_class,
161                                    PROP_AUTO_GROW,
162                                    g_param_spec_boolean ("auto-grow",
163                                                          P_("Auto-grow"),
164                                                          P_("Whether the buffer should automatically grow"),
165                                                          FALSE,
166                                                          G_PARAM_READWRITE|
167                                                          G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
168 
169 }
170 
171 /**
172  * g_buffered_output_stream_get_buffer_size:
173  * @stream: a #GBufferedOutputStream.
174  *
175  * Gets the size of the buffer in the @stream.
176  *
177  * Returns: the current size of the buffer.
178  **/
179 gsize
g_buffered_output_stream_get_buffer_size(GBufferedOutputStream * stream)180 g_buffered_output_stream_get_buffer_size (GBufferedOutputStream *stream)
181 {
182   g_return_val_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream), -1);
183 
184   return stream->priv->len;
185 }
186 
187 /**
188  * g_buffered_output_stream_set_buffer_size:
189  * @stream: a #GBufferedOutputStream.
190  * @size: a #gsize.
191  *
192  * Sets the size of the internal buffer to @size.
193  **/
194 void
g_buffered_output_stream_set_buffer_size(GBufferedOutputStream * stream,gsize size)195 g_buffered_output_stream_set_buffer_size (GBufferedOutputStream *stream,
196                                           gsize                  size)
197 {
198   GBufferedOutputStreamPrivate *priv;
199   guint8 *buffer;
200 
201   g_return_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream));
202 
203   priv = stream->priv;
204 
205   if (size == priv->len)
206     return;
207 
208   if (priv->buffer)
209     {
210       size = MAX (size, priv->pos);
211 
212       buffer = g_malloc (size);
213       memcpy (buffer, priv->buffer, priv->pos);
214       g_free (priv->buffer);
215       priv->buffer = buffer;
216       priv->len = size;
217       /* Keep old pos */
218     }
219   else
220     {
221       priv->buffer = g_malloc (size);
222       priv->len = size;
223       priv->pos = 0;
224     }
225 
226   g_object_notify (G_OBJECT (stream), "buffer-size");
227 }
228 
229 /**
230  * g_buffered_output_stream_get_auto_grow:
231  * @stream: a #GBufferedOutputStream.
232  *
233  * Checks if the buffer automatically grows as data is added.
234  *
235  * Returns: %TRUE if the @stream's buffer automatically grows,
236  * %FALSE otherwise.
237  **/
238 gboolean
g_buffered_output_stream_get_auto_grow(GBufferedOutputStream * stream)239 g_buffered_output_stream_get_auto_grow (GBufferedOutputStream *stream)
240 {
241   g_return_val_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream), FALSE);
242 
243   return stream->priv->auto_grow;
244 }
245 
246 /**
247  * g_buffered_output_stream_set_auto_grow:
248  * @stream: a #GBufferedOutputStream.
249  * @auto_grow: a #gboolean.
250  *
251  * Sets whether or not the @stream's buffer should automatically grow.
252  * If @auto_grow is true, then each write will just make the buffer
253  * larger, and you must manually flush the buffer to actually write out
254  * the data to the underlying stream.
255  **/
256 void
g_buffered_output_stream_set_auto_grow(GBufferedOutputStream * stream,gboolean auto_grow)257 g_buffered_output_stream_set_auto_grow (GBufferedOutputStream *stream,
258                                         gboolean               auto_grow)
259 {
260   GBufferedOutputStreamPrivate *priv;
261   g_return_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream));
262   priv = stream->priv;
263   auto_grow = auto_grow != FALSE;
264   if (priv->auto_grow != auto_grow)
265     {
266       priv->auto_grow = auto_grow;
267       g_object_notify (G_OBJECT (stream), "auto-grow");
268     }
269 }
270 
271 static void
g_buffered_output_stream_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)272 g_buffered_output_stream_set_property (GObject      *object,
273                                        guint         prop_id,
274                                        const GValue *value,
275                                        GParamSpec   *pspec)
276 {
277   GBufferedOutputStream *stream;
278 
279   stream = G_BUFFERED_OUTPUT_STREAM (object);
280 
281   switch (prop_id)
282     {
283     case PROP_BUFSIZE:
284       g_buffered_output_stream_set_buffer_size (stream, g_value_get_uint (value));
285       break;
286 
287     case PROP_AUTO_GROW:
288       g_buffered_output_stream_set_auto_grow (stream, g_value_get_boolean (value));
289       break;
290 
291     default:
292       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
293       break;
294     }
295 
296 }
297 
298 static void
g_buffered_output_stream_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)299 g_buffered_output_stream_get_property (GObject    *object,
300                                        guint       prop_id,
301                                        GValue     *value,
302                                        GParamSpec *pspec)
303 {
304   GBufferedOutputStream *buffered_stream;
305   GBufferedOutputStreamPrivate *priv;
306 
307   buffered_stream = G_BUFFERED_OUTPUT_STREAM (object);
308   priv = buffered_stream->priv;
309 
310   switch (prop_id)
311     {
312     case PROP_BUFSIZE:
313       g_value_set_uint (value, priv->len);
314       break;
315 
316     case PROP_AUTO_GROW:
317       g_value_set_boolean (value, priv->auto_grow);
318       break;
319 
320     default:
321       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
322       break;
323     }
324 
325 }
326 
327 static void
g_buffered_output_stream_finalize(GObject * object)328 g_buffered_output_stream_finalize (GObject *object)
329 {
330   GBufferedOutputStream *stream;
331   GBufferedOutputStreamPrivate *priv;
332 
333   stream = G_BUFFERED_OUTPUT_STREAM (object);
334   priv = stream->priv;
335 
336   g_free (priv->buffer);
337 
338   G_OBJECT_CLASS (g_buffered_output_stream_parent_class)->finalize (object);
339 }
340 
341 static void
g_buffered_output_stream_init(GBufferedOutputStream * stream)342 g_buffered_output_stream_init (GBufferedOutputStream *stream)
343 {
344   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
345                                               G_TYPE_BUFFERED_OUTPUT_STREAM,
346                                               GBufferedOutputStreamPrivate);
347 
348 }
349 
350 /**
351  * g_buffered_output_stream_new:
352  * @base_stream: a #GOutputStream.
353  *
354  * Creates a new buffered output stream for a base stream.
355  *
356  * Returns: a #GOutputStream for the given @base_stream.
357  **/
358 GOutputStream *
g_buffered_output_stream_new(GOutputStream * base_stream)359 g_buffered_output_stream_new (GOutputStream *base_stream)
360 {
361   GOutputStream *stream;
362 
363   g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), NULL);
364 
365   stream = g_object_new (G_TYPE_BUFFERED_OUTPUT_STREAM,
366                          "base-stream", base_stream,
367                          NULL);
368 
369   return stream;
370 }
371 
372 /**
373  * g_buffered_output_stream_new_sized:
374  * @base_stream: a #GOutputStream.
375  * @size: a #gsize.
376  *
377  * Creates a new buffered output stream with a given buffer size.
378  *
379  * Returns: a #GOutputStream with an internal buffer set to @size.
380  **/
381 GOutputStream *
g_buffered_output_stream_new_sized(GOutputStream * base_stream,gsize size)382 g_buffered_output_stream_new_sized (GOutputStream *base_stream,
383                                     gsize          size)
384 {
385   GOutputStream *stream;
386 
387   g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), NULL);
388 
389   stream = g_object_new (G_TYPE_BUFFERED_OUTPUT_STREAM,
390                          "base-stream", base_stream,
391                          "buffer-size", size,
392                          NULL);
393 
394   return stream;
395 }
396 
397 static gboolean
flush_buffer(GBufferedOutputStream * stream,GCancellable * cancellable,GError ** error)398 flush_buffer (GBufferedOutputStream  *stream,
399               GCancellable           *cancellable,
400               GError                 **error)
401 {
402   GBufferedOutputStreamPrivate *priv;
403   GOutputStream                *base_stream;
404   gboolean                      res;
405   gsize                         bytes_written;
406   gsize                         count;
407 
408   priv = stream->priv;
409   bytes_written = 0;
410   base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream;
411 
412   g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), FALSE);
413 
414   res = g_output_stream_write_all (base_stream,
415                                    priv->buffer,
416                                    priv->pos,
417                                    &bytes_written,
418                                    cancellable,
419                                    error);
420 
421   count = priv->pos - bytes_written;
422 
423   if (count > 0)
424     g_memmove (priv->buffer, priv->buffer + bytes_written, count);
425 
426   priv->pos -= bytes_written;
427 
428   return res;
429 }
430 
431 static gssize
g_buffered_output_stream_write(GOutputStream * stream,const void * buffer,gsize count,GCancellable * cancellable,GError ** error)432 g_buffered_output_stream_write  (GOutputStream *stream,
433                                  const void    *buffer,
434                                  gsize          count,
435                                  GCancellable  *cancellable,
436                                  GError       **error)
437 {
438   GBufferedOutputStream        *bstream;
439   GBufferedOutputStreamPrivate *priv;
440   gboolean res;
441   gsize    n;
442   gsize new_size;
443 
444   bstream = G_BUFFERED_OUTPUT_STREAM (stream);
445   priv = bstream->priv;
446 
447   n = priv->len - priv->pos;
448 
449   if (priv->auto_grow && n < count)
450     {
451       new_size = MAX (priv->len * 2, priv->len + count);
452       g_buffered_output_stream_set_buffer_size (bstream, new_size);
453     }
454   else if (n == 0)
455     {
456       res = flush_buffer (bstream, cancellable, error);
457 
458       if (res == FALSE)
459 	return -1;
460     }
461 
462   n = priv->len - priv->pos;
463 
464   count = MIN (count, n);
465   memcpy (priv->buffer + priv->pos, buffer, count);
466   priv->pos += count;
467 
468   return count;
469 }
470 
471 static gboolean
g_buffered_output_stream_flush(GOutputStream * stream,GCancellable * cancellable,GError ** error)472 g_buffered_output_stream_flush (GOutputStream  *stream,
473                                 GCancellable   *cancellable,
474                                 GError        **error)
475 {
476   GBufferedOutputStream *bstream;
477   GBufferedOutputStreamPrivate *priv;
478   GOutputStream                *base_stream;
479   gboolean res;
480 
481   bstream = G_BUFFERED_OUTPUT_STREAM (stream);
482   priv = bstream->priv;
483   base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream;
484 
485   res = flush_buffer (bstream, cancellable, error);
486 
487   if (res == FALSE)
488     return FALSE;
489 
490   res = g_output_stream_flush (base_stream, cancellable, error);
491 
492   return res;
493 }
494 
495 static gboolean
g_buffered_output_stream_close(GOutputStream * stream,GCancellable * cancellable,GError ** error)496 g_buffered_output_stream_close (GOutputStream  *stream,
497                                 GCancellable   *cancellable,
498                                 GError        **error)
499 {
500   GBufferedOutputStream        *bstream;
501   GBufferedOutputStreamPrivate *priv;
502   GOutputStream                *base_stream;
503   gboolean                      res;
504 
505   bstream = G_BUFFERED_OUTPUT_STREAM (stream);
506   priv = bstream->priv;
507   base_stream = G_FILTER_OUTPUT_STREAM (bstream)->base_stream;
508 
509   res = flush_buffer (bstream, cancellable, error);
510 
511   if (g_filter_output_stream_get_close_base_stream (G_FILTER_OUTPUT_STREAM (stream)))
512     {
513       /* report the first error but still close the stream */
514       if (res)
515         res = g_output_stream_close (base_stream, cancellable, error);
516       else
517         g_output_stream_close (base_stream, cancellable, NULL);
518     }
519 
520   return res;
521 }
522 
523 /* ************************** */
524 /* Async stuff implementation */
525 /* ************************** */
526 
527 /* TODO: This should be using the base class async ops, not threads */
528 
529 typedef struct {
530 
531   guint flush_stream : 1;
532   guint close_stream : 1;
533 
534 } FlushData;
535 
536 static void
free_flush_data(gpointer data)537 free_flush_data (gpointer data)
538 {
539   g_slice_free (FlushData, data);
540 }
541 
542 /* This function is used by all three (i.e.
543  * _write, _flush, _close) functions since
544  * all of them will need to flush the buffer
545  * and so closing and writing is just a special
546  * case of flushing + some addition stuff */
547 static void
flush_buffer_thread(GSimpleAsyncResult * result,GObject * object,GCancellable * cancellable)548 flush_buffer_thread (GSimpleAsyncResult *result,
549                      GObject            *object,
550                      GCancellable       *cancellable)
551 {
552   GBufferedOutputStream *stream;
553   GOutputStream *base_stream;
554   FlushData     *fdata;
555   gboolean       res;
556   GError        *error = NULL;
557 
558   stream = G_BUFFERED_OUTPUT_STREAM (object);
559   fdata = g_simple_async_result_get_op_res_gpointer (result);
560   base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream;
561 
562   res = flush_buffer (stream, cancellable, &error);
563 
564   /* if flushing the buffer didn't work don't even bother
565    * to flush the stream but just report that error */
566   if (res && fdata->flush_stream)
567     res = g_output_stream_flush (base_stream, cancellable, &error);
568 
569   if (fdata->close_stream)
570     {
571 
572       /* if flushing the buffer or the stream returned
573        * an error report that first error but still try
574        * close the stream */
575       if (g_filter_output_stream_get_close_base_stream (G_FILTER_OUTPUT_STREAM (stream)))
576         {
577           if (res == FALSE)
578             g_output_stream_close (base_stream, cancellable, NULL);
579           else
580             res = g_output_stream_close (base_stream, cancellable, &error);
581         }
582     }
583 
584   if (res == FALSE)
585     {
586       g_simple_async_result_set_from_error (result, error);
587       g_error_free (error);
588     }
589 }
590 
591 typedef struct {
592 
593   FlushData fdata;
594 
595   gsize  count;
596   const void  *buffer;
597 
598 } WriteData;
599 
600 static void
free_write_data(gpointer data)601 free_write_data (gpointer data)
602 {
603   g_slice_free (WriteData, data);
604 }
605 
606 static void
g_buffered_output_stream_write_async(GOutputStream * stream,const void * buffer,gsize count,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer data)607 g_buffered_output_stream_write_async (GOutputStream        *stream,
608                                       const void           *buffer,
609                                       gsize                 count,
610                                       int                   io_priority,
611                                       GCancellable         *cancellable,
612                                       GAsyncReadyCallback   callback,
613                                       gpointer              data)
614 {
615   GBufferedOutputStream *buffered_stream;
616   GBufferedOutputStreamPrivate *priv;
617   GSimpleAsyncResult *res;
618   WriteData *wdata;
619 
620   buffered_stream = G_BUFFERED_OUTPUT_STREAM (stream);
621   priv = buffered_stream->priv;
622 
623   wdata = g_slice_new (WriteData);
624   wdata->count  = count;
625   wdata->buffer = buffer;
626 
627   res = g_simple_async_result_new (G_OBJECT (stream),
628                                    callback,
629                                    data,
630                                    g_buffered_output_stream_write_async);
631 
632   g_simple_async_result_set_op_res_gpointer (res, wdata, free_write_data);
633 
634   /* if we have space left directly call the
635    * callback (from idle) otherwise schedule a buffer
636    * flush in the thread. In both cases the actual
637    * copying of the data to the buffer will be done in
638    * the write_finish () func since that should
639    * be fast enough */
640   if (priv->len - priv->pos > 0)
641     {
642       g_simple_async_result_complete_in_idle (res);
643     }
644   else
645     {
646       wdata->fdata.flush_stream = FALSE;
647       wdata->fdata.close_stream = FALSE;
648       g_simple_async_result_run_in_thread (res,
649                                            flush_buffer_thread,
650                                            io_priority,
651                                            cancellable);
652       g_object_unref (res);
653     }
654 }
655 
656 static gssize
g_buffered_output_stream_write_finish(GOutputStream * stream,GAsyncResult * result,GError ** error)657 g_buffered_output_stream_write_finish (GOutputStream        *stream,
658                                        GAsyncResult         *result,
659                                        GError              **error)
660 {
661   GBufferedOutputStreamPrivate *priv;
662   GBufferedOutputStream        *buffered_stream;
663   GSimpleAsyncResult *simple;
664   WriteData          *wdata;
665   gssize              count;
666 
667   simple = G_SIMPLE_ASYNC_RESULT (result);
668   buffered_stream = G_BUFFERED_OUTPUT_STREAM (stream);
669   priv = buffered_stream->priv;
670 
671   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
672             g_buffered_output_stream_write_async);
673 
674   wdata = g_simple_async_result_get_op_res_gpointer (simple);
675 
676   /* Now do the real copying of data to the buffer */
677   count = priv->len - priv->pos;
678   count = MIN (wdata->count, count);
679 
680   memcpy (priv->buffer + priv->pos, wdata->buffer, count);
681 
682   priv->pos += count;
683 
684   return count;
685 }
686 
687 static void
g_buffered_output_stream_flush_async(GOutputStream * stream,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer data)688 g_buffered_output_stream_flush_async (GOutputStream        *stream,
689                                       int                   io_priority,
690                                       GCancellable         *cancellable,
691                                       GAsyncReadyCallback   callback,
692                                       gpointer              data)
693 {
694   GSimpleAsyncResult *res;
695   FlushData          *fdata;
696 
697   fdata = g_slice_new (FlushData);
698   fdata->flush_stream = TRUE;
699   fdata->close_stream = FALSE;
700 
701   res = g_simple_async_result_new (G_OBJECT (stream),
702                                    callback,
703                                    data,
704                                    g_buffered_output_stream_flush_async);
705 
706   g_simple_async_result_set_op_res_gpointer (res, fdata, free_flush_data);
707 
708   g_simple_async_result_run_in_thread (res,
709                                        flush_buffer_thread,
710                                        io_priority,
711                                        cancellable);
712   g_object_unref (res);
713 }
714 
715 static gboolean
g_buffered_output_stream_flush_finish(GOutputStream * stream,GAsyncResult * result,GError ** error)716 g_buffered_output_stream_flush_finish (GOutputStream        *stream,
717                                        GAsyncResult         *result,
718                                        GError              **error)
719 {
720   GSimpleAsyncResult *simple;
721 
722   simple = G_SIMPLE_ASYNC_RESULT (result);
723 
724   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
725             g_buffered_output_stream_flush_async);
726 
727   return TRUE;
728 }
729 
730 static void
g_buffered_output_stream_close_async(GOutputStream * stream,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer data)731 g_buffered_output_stream_close_async (GOutputStream        *stream,
732                                       int                   io_priority,
733                                       GCancellable         *cancellable,
734                                       GAsyncReadyCallback   callback,
735                                       gpointer              data)
736 {
737   GSimpleAsyncResult *res;
738   FlushData          *fdata;
739 
740   fdata = g_slice_new (FlushData);
741   fdata->close_stream = TRUE;
742 
743   res = g_simple_async_result_new (G_OBJECT (stream),
744                                    callback,
745                                    data,
746                                    g_buffered_output_stream_close_async);
747 
748   g_simple_async_result_set_op_res_gpointer (res, fdata, free_flush_data);
749 
750   g_simple_async_result_run_in_thread (res,
751                                        flush_buffer_thread,
752                                        io_priority,
753                                        cancellable);
754   g_object_unref (res);
755 }
756 
757 static gboolean
g_buffered_output_stream_close_finish(GOutputStream * stream,GAsyncResult * result,GError ** error)758 g_buffered_output_stream_close_finish (GOutputStream        *stream,
759                                        GAsyncResult         *result,
760                                        GError              **error)
761 {
762   GSimpleAsyncResult *simple;
763 
764   simple = G_SIMPLE_ASYNC_RESULT (result);
765 
766   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
767             g_buffered_output_stream_close_async);
768 
769   return TRUE;
770 }
771 
772 #define __G_BUFFERED_OUTPUT_STREAM_C__
773 #include "gioaliasdef.c"
774