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