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