Forgot to return the allocated data in async_op_wrapper_new
[platform/upstream/glib.git] / gio / gfileiostream.c
1 /* GIO - GLib Input, IO and Streaming Library
2  *
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <glib.h>
26 #include <gfileiostream.h>
27 #include <gseekable.h>
28 #include "gsimpleasyncresult.h"
29 #include "gasyncresult.h"
30 #include "gcancellable.h"
31 #include "gioerror.h"
32 #include "gfileoutputstream.h"
33 #include "glibintl.h"
34
35 #include "gioalias.h"
36
37 /**
38  * SECTION:gfileiostream
39  * @short_description: read write streams for File
40  * @include: gio/gio.h
41  * @see_also: #GIOStream, #GFileInputStream, #GFileOutputStream, #GSeekable
42  *
43  * GFileIOStream provides io streams that both read and write to the same
44  * file handle.
45  *
46  * GFileIOStream implements #GSeekable, which allows the io
47  * stream to jump to arbitrary positions in the file and to truncate
48  * the file, provided the filesystem of the file supports these
49  * operations. In addition to the generic g_seekable_ API,
50  * GFileIOStream has its own API for seeking and positioning.
51  * To find the position of a file io stream, use
52  * g_file_io_stream_tell(). To find out if a file io
53  * stream supports seeking, use g_file_io_stream_can_seek().
54  * To position a file io stream, use g_file_io_stream_seek().
55  * To find out if a file io stream supports truncating, use
56  * g_file_io_stream_can_truncate(). To truncate a file io
57  * stream, use g_file_io_stream_truncate().
58  *
59  * Since: 2.22
60  **/
61
62 static void       g_file_io_stream_seekable_iface_init    (GSeekableIface       *iface);
63 static goffset    g_file_io_stream_seekable_tell          (GSeekable            *seekable);
64 static gboolean   g_file_io_stream_seekable_can_seek      (GSeekable            *seekable);
65 static gboolean   g_file_io_stream_seekable_seek          (GSeekable            *seekable,
66                                                            goffset               offset,
67                                                            GSeekType             type,
68                                                            GCancellable         *cancellable,
69                                                            GError              **error);
70 static gboolean   g_file_io_stream_seekable_can_truncate  (GSeekable            *seekable);
71 static gboolean   g_file_io_stream_seekable_truncate      (GSeekable            *seekable,
72                                                            goffset               offset,
73                                                            GCancellable         *cancellable,
74                                                            GError              **error);
75 static void       g_file_io_stream_real_query_info_async  (GFileIOStream    *stream,
76                                                            const char           *attributes,
77                                                            int                   io_priority,
78                                                            GCancellable         *cancellable,
79                                                            GAsyncReadyCallback   callback,
80                                                            gpointer              user_data);
81 static GFileInfo *g_file_io_stream_real_query_info_finish (GFileIOStream    *stream,
82                                                            GAsyncResult         *result,
83                                                            GError              **error);
84
85 G_DEFINE_TYPE_WITH_CODE (GFileIOStream, g_file_io_stream, G_TYPE_IO_STREAM,
86                          G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
87                                                 g_file_io_stream_seekable_iface_init));
88
89 struct _GFileIOStreamPrivate {
90   GAsyncReadyCallback outstanding_callback;
91 };
92
93 static void
94 g_file_io_stream_seekable_iface_init (GSeekableIface *iface)
95 {
96   iface->tell = g_file_io_stream_seekable_tell;
97   iface->can_seek = g_file_io_stream_seekable_can_seek;
98   iface->seek = g_file_io_stream_seekable_seek;
99   iface->can_truncate = g_file_io_stream_seekable_can_truncate;
100   iface->truncate_fn = g_file_io_stream_seekable_truncate;
101 }
102
103 static void
104 g_file_io_stream_init (GFileIOStream *stream)
105 {
106   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
107                                               G_TYPE_FILE_IO_STREAM,
108                                               GFileIOStreamPrivate);
109 }
110
111 /**
112  * g_file_io_stream_query_info:
113  * @stream: a #GFileIOStream.
114  * @attributes: a file attribute query string.
115  * @cancellable: optional #GCancellable object, %NULL to ignore.
116  * @error: a #GError, %NULL to ignore.
117  *
118  * Queries a file io stream for the given @attributes.
119  * This function blocks while querying the stream. For the asynchronous
120  * version of this function, see g_file_io_stream_query_info_async().
121  * While the stream is blocked, the stream will set the pending flag
122  * internally, and any other operations on the stream will fail with
123  * %G_IO_ERROR_PENDING.
124  *
125  * Can fail if the stream was already closed (with @error being set to
126  * %G_IO_ERROR_CLOSED), the stream has pending operations (with @error being
127  * set to %G_IO_ERROR_PENDING), or if querying info is not supported for
128  * the stream's interface (with @error being set to %G_IO_ERROR_NOT_SUPPORTED). I
129  * all cases of failure, %NULL will be returned.
130  *
131  * If @cancellable is not %NULL, then the operation can be cancelled by
132  * triggering the cancellable object from another thread. If the operation
133  * was cancelled, the error %G_IO_ERROR_CANCELLED will be set, and %NULL will
134  * be returned.
135  *
136  * Returns: a #GFileInfo for the @stream, or %NULL on error.
137  *
138  * Since: 2.22
139  **/
140 GFileInfo *
141 g_file_io_stream_query_info (GFileIOStream      *stream,
142                              const char             *attributes,
143                              GCancellable           *cancellable,
144                              GError                **error)
145 {
146   GFileIOStreamClass *class;
147   GIOStream *io_stream;
148   GFileInfo *info;
149
150   g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), NULL);
151
152   io_stream = G_IO_STREAM (stream);
153
154   if (!g_io_stream_set_pending (io_stream, error))
155     return NULL;
156
157   info = NULL;
158
159   if (cancellable)
160     g_cancellable_push_current (cancellable);
161
162   class = G_FILE_IO_STREAM_GET_CLASS (stream);
163   if (class->query_info)
164     info = class->query_info (stream, attributes, cancellable, error);
165   else
166     g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
167                          _("Stream doesn't support query_info"));
168
169   if (cancellable)
170     g_cancellable_pop_current (cancellable);
171
172   g_io_stream_clear_pending (io_stream);
173
174   return info;
175 }
176
177 static void
178 async_ready_callback_wrapper (GObject *source_object,
179                               GAsyncResult *res,
180                               gpointer      user_data)
181 {
182   GFileIOStream *stream = G_FILE_IO_STREAM (source_object);
183
184   g_io_stream_clear_pending (G_IO_STREAM (stream));
185   if (stream->priv->outstanding_callback)
186     (*stream->priv->outstanding_callback) (source_object, res, user_data);
187   g_object_unref (stream);
188 }
189
190 /**
191  * g_file_io_stream_query_info_async:
192  * @stream: a #GFileIOStream.
193  * @attributes: a file attribute query string.
194  * @io_priority: the <link linkend="gio-GIOScheduler">I/O priority</link>
195  *     of the request.
196  * @cancellable: optional #GCancellable object, %NULL to ignore.
197  * @callback: callback to call when the request is satisfied
198  * @user_data: the data to pass to callback function
199  *
200  * Asynchronously queries the @stream for a #GFileInfo. When completed,
201  * @callback will be called with a #GAsyncResult which can be used to
202  * finish the operation with g_file_io_stream_query_info_finish().
203  *
204  * For the synchronous version of this function, see
205  * g_file_io_stream_query_info().
206  *
207  * Since: 2.22
208  **/
209 void
210 g_file_io_stream_query_info_async (GFileIOStream     *stream,
211                                           const char           *attributes,
212                                           int                   io_priority,
213                                           GCancellable         *cancellable,
214                                           GAsyncReadyCallback   callback,
215                                           gpointer              user_data)
216 {
217   GFileIOStreamClass *klass;
218   GIOStream *io_stream;
219   GError *error = NULL;
220
221   g_return_if_fail (G_IS_FILE_IO_STREAM (stream));
222
223   io_stream = G_IO_STREAM (stream);
224
225   if (!g_io_stream_set_pending (io_stream, &error))
226     {
227       g_simple_async_report_gerror_in_idle (G_OBJECT (stream),
228                                             callback,
229                                             user_data,
230                                             error);
231       g_error_free (error);
232       return;
233     }
234
235   klass = G_FILE_IO_STREAM_GET_CLASS (stream);
236
237   stream->priv->outstanding_callback = callback;
238   g_object_ref (stream);
239   klass->query_info_async (stream, attributes, io_priority, cancellable,
240                               async_ready_callback_wrapper, user_data);
241 }
242
243 /**
244  * g_file_io_stream_query_info_finish:
245  * @stream: a #GFileIOStream.
246  * @result: a #GAsyncResult.
247  * @error: a #GError, %NULL to ignore.
248  *
249  * Finalizes the asynchronous query started
250  * by g_file_io_stream_query_info_async().
251  *
252  * Returns: A #GFileInfo for the finished query.
253  *
254  * Since: 2.22
255  **/
256 GFileInfo *
257 g_file_io_stream_query_info_finish (GFileIOStream     *stream,
258                                            GAsyncResult         *result,
259                                            GError              **error)
260 {
261   GSimpleAsyncResult *simple;
262   GFileIOStreamClass *class;
263
264   g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), NULL);
265   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
266
267   if (G_IS_SIMPLE_ASYNC_RESULT (result))
268     {
269       simple = G_SIMPLE_ASYNC_RESULT (result);
270       if (g_simple_async_result_propagate_error (simple, error))
271         return NULL;
272     }
273
274   class = G_FILE_IO_STREAM_GET_CLASS (stream);
275   return class->query_info_finish (stream, result, error);
276 }
277
278 /**
279  * g_file_io_stream_get_etag:
280  * @stream: a #GFileIOStream.
281  *
282  * Gets the entity tag for the file when it has been written.
283  * This must be called after the stream has been written
284  * and closed, as the etag can change while writing.
285  *
286  * Returns: the entity tag for the stream.
287  *
288  * Since: 2.22
289  **/
290 char *
291 g_file_io_stream_get_etag (GFileIOStream  *stream)
292 {
293   GFileIOStreamClass *class;
294   GIOStream *io_stream;
295   char *etag;
296
297   g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), NULL);
298
299   io_stream = G_IO_STREAM (stream);
300
301   if (!g_io_stream_is_closed (io_stream))
302     {
303       g_warning ("stream is not closed yet, can't get etag");
304       return NULL;
305     }
306
307   etag = NULL;
308
309   class = G_FILE_IO_STREAM_GET_CLASS (stream);
310   if (class->get_etag)
311     etag = class->get_etag (stream);
312
313   return etag;
314 }
315
316 static goffset
317 g_file_io_stream_tell (GFileIOStream  *stream)
318 {
319   GFileIOStreamClass *class;
320   goffset offset;
321
322   g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), 0);
323
324   class = G_FILE_IO_STREAM_GET_CLASS (stream);
325
326   offset = 0;
327   if (class->tell)
328     offset = class->tell (stream);
329
330   return offset;
331 }
332
333 static goffset
334 g_file_io_stream_seekable_tell (GSeekable *seekable)
335 {
336   return g_file_io_stream_tell (G_FILE_IO_STREAM (seekable));
337 }
338
339 static gboolean
340 g_file_io_stream_can_seek (GFileIOStream  *stream)
341 {
342   GFileIOStreamClass *class;
343   gboolean can_seek;
344
345   g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), FALSE);
346
347   class = G_FILE_IO_STREAM_GET_CLASS (stream);
348
349   can_seek = FALSE;
350   if (class->seek)
351     {
352       can_seek = TRUE;
353       if (class->can_seek)
354         can_seek = class->can_seek (stream);
355     }
356
357   return can_seek;
358 }
359
360 static gboolean
361 g_file_io_stream_seekable_can_seek (GSeekable *seekable)
362 {
363   return g_file_io_stream_can_seek (G_FILE_IO_STREAM (seekable));
364 }
365
366 static gboolean
367 g_file_io_stream_seek (GFileIOStream  *stream,
368                        goffset             offset,
369                        GSeekType           type,
370                        GCancellable       *cancellable,
371                        GError            **error)
372 {
373   GFileIOStreamClass *class;
374   GIOStream *io_stream;
375   gboolean res;
376
377   g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), FALSE);
378
379   io_stream = G_IO_STREAM (stream);
380   class = G_FILE_IO_STREAM_GET_CLASS (stream);
381
382   if (!class->seek)
383     {
384       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
385                            _("Seek not supported on stream"));
386       return FALSE;
387     }
388
389   if (!g_io_stream_set_pending (io_stream, error))
390     return FALSE;
391
392   if (cancellable)
393     g_cancellable_push_current (cancellable);
394
395   res = class->seek (stream, offset, type, cancellable, error);
396
397   if (cancellable)
398     g_cancellable_pop_current (cancellable);
399
400   g_io_stream_clear_pending (io_stream);
401
402   return res;
403 }
404
405 static gboolean
406 g_file_io_stream_seekable_seek (GSeekable  *seekable,
407                                     goffset     offset,
408                                     GSeekType   type,
409                                     GCancellable  *cancellable,
410                                     GError    **error)
411 {
412   return g_file_io_stream_seek (G_FILE_IO_STREAM (seekable),
413                                 offset, type, cancellable, error);
414 }
415
416 static gboolean
417 g_file_io_stream_can_truncate (GFileIOStream  *stream)
418 {
419   GFileIOStreamClass *class;
420   gboolean can_truncate;
421
422   g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), FALSE);
423
424   class = G_FILE_IO_STREAM_GET_CLASS (stream);
425
426   can_truncate = FALSE;
427   if (class->truncate_fn)
428     {
429       can_truncate = TRUE;
430       if (class->can_truncate)
431         can_truncate = class->can_truncate (stream);
432     }
433
434   return can_truncate;
435 }
436
437 static gboolean
438 g_file_io_stream_seekable_can_truncate (GSeekable  *seekable)
439 {
440   return g_file_io_stream_can_truncate (G_FILE_IO_STREAM (seekable));
441 }
442
443 static gboolean
444 g_file_io_stream_truncate (GFileIOStream  *stream,
445                            goffset             size,
446                            GCancellable       *cancellable,
447                            GError            **error)
448 {
449   GFileIOStreamClass *class;
450   GIOStream *io_stream;
451   gboolean res;
452
453   g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), FALSE);
454
455   io_stream = G_IO_STREAM (stream);
456   class = G_FILE_IO_STREAM_GET_CLASS (stream);
457
458   if (!class->truncate_fn)
459     {
460       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
461                            _("Truncate not supported on stream"));
462       return FALSE;
463     }
464
465   if (!g_io_stream_set_pending (io_stream, error))
466     return FALSE;
467
468   if (cancellable)
469     g_cancellable_push_current (cancellable);
470
471   res = class->truncate_fn (stream, size, cancellable, error);
472
473   if (cancellable)
474     g_cancellable_pop_current (cancellable);
475
476   g_io_stream_clear_pending (io_stream);
477
478   return res;
479 }
480
481 static gboolean
482 g_file_io_stream_seekable_truncate (GSeekable     *seekable,
483                                     goffset        size,
484                                     GCancellable  *cancellable,
485                                     GError       **error)
486 {
487   return g_file_io_stream_truncate (G_FILE_IO_STREAM (seekable),
488                                         size, cancellable, error);
489 }
490 /*****************************************************
491  *   Default implementations based on output stream  *
492  *****************************************************/
493
494 static goffset
495 g_file_io_stream_real_tell (GFileIOStream    *stream)
496 {
497   GOutputStream *out;
498   GSeekable *seekable;
499
500   out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
501   seekable = G_SEEKABLE (out);
502
503   return g_seekable_tell (seekable);
504 }
505
506 static gboolean
507 g_file_io_stream_real_can_seek (GFileIOStream    *stream)
508 {
509   GOutputStream *out;
510   GSeekable *seekable;
511
512   out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
513   seekable = G_SEEKABLE (out);
514
515   return g_seekable_can_seek (seekable);
516 }
517
518 static gboolean
519 g_file_io_stream_real_seek (GFileIOStream    *stream,
520                             goffset           offset,
521                             GSeekType         type,
522                             GCancellable     *cancellable,
523                             GError          **error)
524 {
525   GOutputStream *out;
526   GSeekable *seekable;
527
528   out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
529   seekable = G_SEEKABLE (out);
530
531   return g_seekable_seek (seekable, offset, type, cancellable, error);
532 }
533
534 static  gboolean
535 g_file_io_stream_real_can_truncate (GFileIOStream    *stream)
536 {
537   GOutputStream *out;
538   GSeekable *seekable;
539
540   out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
541   seekable = G_SEEKABLE (out);
542
543   return g_seekable_can_truncate (seekable);
544 }
545
546 static gboolean
547 g_file_io_stream_real_truncate_fn (GFileIOStream    *stream,
548                                    goffset               size,
549                                    GCancellable         *cancellable,
550                                    GError              **error)
551 {
552   GOutputStream *out;
553   GSeekable *seekable;
554
555   out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
556   seekable = G_SEEKABLE (out);
557
558   return g_seekable_truncate (seekable, size, cancellable, error);
559 }
560
561 static char *
562 g_file_io_stream_real_get_etag (GFileIOStream    *stream)
563 {
564   GOutputStream *out;
565   GFileOutputStream *file_out;
566
567   out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
568   file_out = G_FILE_OUTPUT_STREAM (out);
569
570   return g_file_output_stream_get_etag (file_out);
571 }
572
573 static GFileInfo *
574 g_file_io_stream_real_query_info (GFileIOStream    *stream,
575                                   const char           *attributes,
576                                   GCancellable         *cancellable,
577                                   GError              **error)
578 {
579   GOutputStream *out;
580   GFileOutputStream *file_out;
581
582   out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
583   file_out = G_FILE_OUTPUT_STREAM (out);
584
585   return g_file_output_stream_query_info (file_out,
586                                           attributes, cancellable, error);
587 }
588
589 typedef struct {
590   GObject *object;
591   GAsyncReadyCallback callback;
592   gpointer user_data;
593 } AsyncOpWrapper;
594
595 static AsyncOpWrapper *
596 async_op_wrapper_new (gpointer object,
597                       GAsyncReadyCallback callback,
598                       gpointer user_data)
599 {
600   AsyncOpWrapper *data;
601
602   data = g_new0 (AsyncOpWrapper, 1);
603   data->object = g_object_ref (object);
604   data->callback = callback;
605   data->user_data = user_data;
606
607   return data;
608 }
609
610 static void
611 async_op_wrapper_callback (GObject *source_object,
612                            GAsyncResult *res,
613                            gpointer user_data)
614 {
615   AsyncOpWrapper *data  = user_data;
616   data->callback (data->object, res, data->user_data);
617   g_object_unref (data->object);
618   g_free (data);
619 }
620
621 static void
622 g_file_io_stream_real_query_info_async (GFileIOStream     *stream,
623                                         const char           *attributes,
624                                         int                   io_priority,
625                                         GCancellable         *cancellable,
626                                         GAsyncReadyCallback   callback,
627                                         gpointer              user_data)
628 {
629   GOutputStream *out;
630   GFileOutputStream *file_out;
631   AsyncOpWrapper *data;
632
633   out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
634   file_out = G_FILE_OUTPUT_STREAM (out);
635
636   data = async_op_wrapper_new (stream, callback, user_data);
637   g_file_output_stream_query_info_async (file_out,
638                                          attributes, io_priority,
639                                          cancellable, async_op_wrapper_callback, data);
640 }
641
642 static GFileInfo *
643 g_file_io_stream_real_query_info_finish (GFileIOStream     *stream,
644                                          GAsyncResult      *res,
645                                          GError           **error)
646 {
647   GOutputStream *out;
648   GFileOutputStream *file_out;
649
650   out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
651   file_out = G_FILE_OUTPUT_STREAM (out);
652
653   return g_file_output_stream_query_info_finish (file_out, res, error);
654 }
655
656 static void
657 g_file_io_stream_class_init (GFileIOStreamClass *klass)
658 {
659   g_type_class_add_private (klass, sizeof (GFileIOStreamPrivate));
660
661   klass->tell = g_file_io_stream_real_tell;
662   klass->can_seek = g_file_io_stream_real_can_seek;
663   klass->seek = g_file_io_stream_real_seek;
664   klass->can_truncate = g_file_io_stream_real_can_truncate;
665   klass->truncate_fn = g_file_io_stream_real_truncate_fn;
666   klass->query_info = g_file_io_stream_real_query_info;
667   klass->query_info_async = g_file_io_stream_real_query_info_async;
668   klass->query_info_finish = g_file_io_stream_real_query_info_finish;
669   klass->get_etag = g_file_io_stream_real_get_etag;
670 }
671
672 #define __G_FILE_IO_STREAM_C__
673 #include "gioaliasdef.c"