Merge remote branch 'gvdb/master'
[platform/upstream/glib.git] / gio / gfileinputstream.c
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: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <glib.h>
26 #include <gfileinputstream.h>
27 #include <gseekable.h>
28 #include "gsimpleasyncresult.h"
29 #include "gcancellable.h"
30 #include "gasyncresult.h"
31 #include "gioerror.h"
32 #include "glibintl.h"
33
34 #include "gioalias.h"
35
36 /**
37  * SECTION:gfileinputstream
38  * @short_description: File input streaming operations
39  * @include: gio/gio.h
40  * @see_also: #GInputStream, #GDataInputStream, #GSeekable
41  *
42  * GFileInputStream provides input streams that take their
43  * content from a file.
44  *
45  * GFileInputStream implements #GSeekable, which allows the input 
46  * stream to jump to arbitrary positions in the file, provided the 
47  * filesystem of the file allows it. To find the position of a file
48  * input stream, use g_seekable_tell(). To find out if a file input
49  * stream supports seeking, use g_seekable_stream_can_seek().
50  * To position a file input stream, use g_seekable_seek().
51  **/
52
53 static void       g_file_input_stream_seekable_iface_init    (GSeekableIface       *iface);
54 static goffset    g_file_input_stream_seekable_tell          (GSeekable            *seekable);
55 static gboolean   g_file_input_stream_seekable_can_seek      (GSeekable            *seekable);
56 static gboolean   g_file_input_stream_seekable_seek          (GSeekable            *seekable,
57                                                               goffset               offset,
58                                                               GSeekType             type,
59                                                               GCancellable         *cancellable,
60                                                               GError              **error);
61 static gboolean   g_file_input_stream_seekable_can_truncate  (GSeekable            *seekable);
62 static gboolean   g_file_input_stream_seekable_truncate      (GSeekable            *seekable,
63                                                               goffset               offset,
64                                                               GCancellable         *cancellable,
65                                                               GError              **error);
66 static void       g_file_input_stream_real_query_info_async  (GFileInputStream     *stream,
67                                                               const char           *attributes,
68                                                               int                   io_priority,
69                                                               GCancellable         *cancellable,
70                                                               GAsyncReadyCallback   callback,
71                                                               gpointer              user_data);
72 static GFileInfo *g_file_input_stream_real_query_info_finish (GFileInputStream     *stream,
73                                                               GAsyncResult         *result,
74                                                               GError              **error);
75
76
77 G_DEFINE_TYPE_WITH_CODE (GFileInputStream, g_file_input_stream, G_TYPE_INPUT_STREAM,
78                          G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
79                                                 g_file_input_stream_seekable_iface_init))
80
81 struct _GFileInputStreamPrivate {
82   GAsyncReadyCallback outstanding_callback;
83 };
84
85 static void
86 g_file_input_stream_class_init (GFileInputStreamClass *klass)
87 {
88   g_type_class_add_private (klass, sizeof (GFileInputStreamPrivate));
89
90   klass->query_info_async = g_file_input_stream_real_query_info_async;
91   klass->query_info_finish = g_file_input_stream_real_query_info_finish;
92 }
93
94 static void
95 g_file_input_stream_seekable_iface_init (GSeekableIface *iface)
96 {
97   iface->tell = g_file_input_stream_seekable_tell;
98   iface->can_seek = g_file_input_stream_seekable_can_seek;
99   iface->seek = g_file_input_stream_seekable_seek;
100   iface->can_truncate = g_file_input_stream_seekable_can_truncate;
101   iface->truncate_fn = g_file_input_stream_seekable_truncate;
102 }
103
104 static void
105 g_file_input_stream_init (GFileInputStream *stream)
106 {
107   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
108                                               G_TYPE_FILE_INPUT_STREAM,
109                                               GFileInputStreamPrivate);
110 }
111
112 /**
113  * g_file_input_stream_query_info:
114  * @stream: a #GFileInputStream.
115  * @attributes: a file attribute query string.
116  * @cancellable: optional #GCancellable object, %NULL to ignore. 
117  * @error: a #GError location to store the error occuring, or %NULL to 
118  * ignore.
119  *
120  * Queries a file input stream the given @attributes. This function blocks 
121  * while querying the stream. For the asynchronous (non-blocking) version 
122  * of this function, see g_file_input_stream_query_info_async(). While the 
123  * stream is blocked, the stream will set the pending flag internally, and 
124  * any other operations on the stream will fail with %G_IO_ERROR_PENDING.
125  *
126  * Returns: a #GFileInfo, or %NULL on error.
127  **/
128 GFileInfo *
129 g_file_input_stream_query_info (GFileInputStream  *stream,
130                                 const char        *attributes,
131                                 GCancellable      *cancellable,
132                                 GError           **error)
133 {
134   GFileInputStreamClass *class;
135   GInputStream *input_stream;
136   GFileInfo *info;
137   
138   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), NULL);
139   
140   input_stream = G_INPUT_STREAM (stream);
141   
142   if (!g_input_stream_set_pending (input_stream, error))
143     return NULL;
144       
145   info = NULL;
146   
147   if (cancellable)
148     g_cancellable_push_current (cancellable);
149   
150   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
151   if (class->query_info)
152     info = class->query_info (stream, attributes, cancellable, error);
153   else
154     g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
155                          _("Stream doesn't support query_info"));
156
157   if (cancellable)
158     g_cancellable_pop_current (cancellable);
159   
160   g_input_stream_clear_pending (input_stream);
161   
162   return info;
163 }
164
165 static void
166 async_ready_callback_wrapper (GObject      *source_object,
167                               GAsyncResult *res,
168                               gpointer      user_data)
169 {
170   GFileInputStream *stream = G_FILE_INPUT_STREAM (source_object);
171
172   g_input_stream_clear_pending (G_INPUT_STREAM (stream));
173   if (stream->priv->outstanding_callback)
174     (*stream->priv->outstanding_callback) (source_object, res, user_data);
175   g_object_unref (stream);
176 }
177
178 /**
179  * g_file_input_stream_query_info_async:
180  * @stream: a #GFileInputStream.
181  * @attributes: a file attribute query string.
182  * @io_priority: the <link linkend="io-priority">I/O priority</link> 
183  *     of the request.
184  * @cancellable: optional #GCancellable object, %NULL to ignore. 
185  * @callback: callback to call when the request is satisfied
186  * @user_data: the data to pass to callback function
187  * 
188  * Queries the stream information asynchronously.
189  * When the operation is finished @callback will be called. 
190  * You can then call g_file_input_stream_query_info_finish() 
191  * to get the result of the operation.
192  *
193  * For the synchronous version of this function, 
194  * see g_file_input_stream_query_info(). 
195  * 
196  * If @cancellable is not %NULL, then the operation can be cancelled by
197  * triggering the cancellable object from another thread. If the operation
198  * was cancelled, the error %G_IO_ERROR_CANCELLED will be set
199  *  
200  **/
201 void
202 g_file_input_stream_query_info_async (GFileInputStream    *stream,
203                                       const char          *attributes,
204                                       int                  io_priority,
205                                       GCancellable        *cancellable,
206                                       GAsyncReadyCallback  callback,
207                                       gpointer             user_data)
208 {
209   GFileInputStreamClass *klass;
210   GInputStream *input_stream;
211   GError *error = NULL;
212
213   g_return_if_fail (G_IS_FILE_INPUT_STREAM (stream));
214
215   input_stream = G_INPUT_STREAM (stream);
216   
217   if (!g_input_stream_set_pending (input_stream, &error))
218     {
219       g_simple_async_report_gerror_in_idle (G_OBJECT (stream),
220                                             callback,
221                                             user_data,
222                                             error);
223       g_error_free (error);
224       return;
225     }
226
227   klass = G_FILE_INPUT_STREAM_GET_CLASS (stream);
228
229   stream->priv->outstanding_callback = callback;
230   g_object_ref (stream);
231   klass->query_info_async (stream, attributes, io_priority, cancellable,
232                               async_ready_callback_wrapper, user_data);
233 }
234
235 /**
236  * g_file_input_stream_query_info_finish:
237  * @stream: a #GFileInputStream.
238  * @result: a #GAsyncResult.
239  * @error: a #GError location to store the error occuring, 
240  *     or %NULL to ignore.
241  * 
242  * Finishes an asynchronous info query operation.
243  * 
244  * Returns: #GFileInfo. 
245  **/
246 GFileInfo *
247 g_file_input_stream_query_info_finish (GFileInputStream  *stream,
248                                        GAsyncResult      *result,
249                                        GError           **error)
250 {
251   GSimpleAsyncResult *simple;
252   GFileInputStreamClass *class;
253
254   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), NULL);
255   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
256
257   if (G_IS_SIMPLE_ASYNC_RESULT (result))
258     {
259       simple = G_SIMPLE_ASYNC_RESULT (result);
260       if (g_simple_async_result_propagate_error (simple, error))
261         return NULL;
262     }
263
264   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
265   return class->query_info_finish (stream, result, error);
266 }
267
268 static goffset
269 g_file_input_stream_tell (GFileInputStream *stream)
270 {
271   GFileInputStreamClass *class;
272   goffset offset;
273
274   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), 0);
275
276   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
277
278   offset = 0;
279   if (class->tell)
280     offset = class->tell (stream);
281
282   return offset;
283 }
284
285 static goffset
286 g_file_input_stream_seekable_tell (GSeekable *seekable)
287 {
288   return g_file_input_stream_tell (G_FILE_INPUT_STREAM (seekable));
289 }
290
291 static gboolean
292 g_file_input_stream_can_seek (GFileInputStream *stream)
293 {
294   GFileInputStreamClass *class;
295   gboolean can_seek;
296
297   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), FALSE);
298
299   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
300
301   can_seek = FALSE;
302   if (class->seek)
303     {
304       can_seek = TRUE;
305       if (class->can_seek)
306         can_seek = class->can_seek (stream);
307     }
308   
309   return can_seek;
310 }
311
312 static gboolean
313 g_file_input_stream_seekable_can_seek (GSeekable *seekable)
314 {
315   return g_file_input_stream_can_seek (G_FILE_INPUT_STREAM (seekable));
316 }
317
318 static gboolean
319 g_file_input_stream_seek (GFileInputStream  *stream,
320                           goffset            offset,
321                           GSeekType          type,
322                           GCancellable      *cancellable,
323                           GError           **error)
324 {
325   GFileInputStreamClass *class;
326   GInputStream *input_stream;
327   gboolean res;
328
329   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), FALSE);
330
331   input_stream = G_INPUT_STREAM (stream);
332   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
333
334   if (!class->seek)
335     {
336       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
337                            _("Seek not supported on stream"));
338       return FALSE;
339     }
340
341   if (!g_input_stream_set_pending (input_stream, error))
342     return FALSE;
343   
344   if (cancellable)
345     g_cancellable_push_current (cancellable);
346   
347   res = class->seek (stream, offset, type, cancellable, error);
348   
349   if (cancellable)
350     g_cancellable_pop_current (cancellable);
351
352   g_input_stream_clear_pending (input_stream);
353   
354   return res;
355 }
356
357 static gboolean
358 g_file_input_stream_seekable_seek (GSeekable     *seekable,
359                                    goffset        offset,
360                                    GSeekType      type,
361                                    GCancellable  *cancellable,
362                                    GError       **error)
363 {
364   return g_file_input_stream_seek (G_FILE_INPUT_STREAM (seekable),
365                                    offset, type, cancellable, error);
366 }
367
368 static gboolean
369 g_file_input_stream_seekable_can_truncate (GSeekable *seekable)
370 {
371   return FALSE;
372 }
373
374 static gboolean
375 g_file_input_stream_seekable_truncate (GSeekable     *seekable,
376                                        goffset        offset,
377                                        GCancellable  *cancellable,
378                                        GError       **error)
379 {
380   g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
381                        _("Truncate not allowed on input stream"));
382   return FALSE;
383 }
384
385 /********************************************
386  *   Default implementation of async ops    *
387  ********************************************/
388
389 typedef struct {
390   char *attributes;
391   GFileInfo *info;
392 } QueryInfoAsyncData;
393
394 static void
395 query_info_data_free (QueryInfoAsyncData *data)
396 {
397   if (data->info)
398     g_object_unref (data->info);
399   g_free (data->attributes);
400   g_free (data);
401 }
402
403 static void
404 query_info_async_thread (GSimpleAsyncResult *res,
405                          GObject            *object,
406                          GCancellable       *cancellable)
407 {
408   GFileInputStreamClass *class;
409   GError *error = NULL;
410   QueryInfoAsyncData *data;
411   GFileInfo *info;
412   
413   data = g_simple_async_result_get_op_res_gpointer (res);
414
415   info = NULL;
416   
417   class = G_FILE_INPUT_STREAM_GET_CLASS (object);
418   if (class->query_info)
419     info = class->query_info (G_FILE_INPUT_STREAM (object), data->attributes, cancellable, &error);
420   else
421     g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
422                          _("Stream doesn't support query_info"));
423
424   if (info == NULL)
425     {
426       g_simple_async_result_set_from_error (res, error);
427       g_error_free (error);
428     }
429   else
430     data->info = info;
431 }
432
433 static void
434 g_file_input_stream_real_query_info_async (GFileInputStream    *stream,
435                                            const char          *attributes,
436                                            int                  io_priority,
437                                            GCancellable        *cancellable,
438                                            GAsyncReadyCallback  callback,
439                                            gpointer             user_data)
440 {
441   GSimpleAsyncResult *res;
442   QueryInfoAsyncData *data;
443
444   data = g_new0 (QueryInfoAsyncData, 1);
445   data->attributes = g_strdup (attributes);
446   
447   res = g_simple_async_result_new (G_OBJECT (stream), callback, user_data, g_file_input_stream_real_query_info_async);
448   g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)query_info_data_free);
449   
450   g_simple_async_result_run_in_thread (res, query_info_async_thread, io_priority, cancellable);
451   g_object_unref (res);
452 }
453
454 static GFileInfo *
455 g_file_input_stream_real_query_info_finish (GFileInputStream  *stream,
456                                             GAsyncResult      *res,
457                                             GError           **error)
458 {
459   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
460   QueryInfoAsyncData *data;
461
462   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_file_input_stream_real_query_info_async);
463
464   data = g_simple_async_result_get_op_res_gpointer (simple);
465   if (data->info)
466     return g_object_ref (data->info);
467   
468   return NULL;
469 }
470
471 #define __G_FILE_INPUT_STREAM_C__
472 #include "gioaliasdef.c"
473