gfileinputstream.c revision 117de38f04de4f546215957b95d3c5b3f104fa42
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 42static void g_file_input_stream_seekable_iface_init (GSeekableIface *iface); 43static goffset g_file_input_stream_seekable_tell (GSeekable *seekable); 44static gboolean g_file_input_stream_seekable_can_seek (GSeekable *seekable); 45static gboolean g_file_input_stream_seekable_seek (GSeekable *seekable, 46 goffset offset, 47 GSeekType type, 48 GCancellable *cancellable, 49 GError **error); 50static gboolean g_file_input_stream_seekable_can_truncate (GSeekable *seekable); 51static gboolean g_file_input_stream_seekable_truncate (GSeekable *seekable, 52 goffset offset, 53 GCancellable *cancellable, 54 GError **error); 55static 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); 61static GFileInfo *g_file_input_stream_real_query_info_finish (GFileInputStream *stream, 62 GAsyncResult *result, 63 GError **error); 64 65 66G_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 70struct _GFileInputStreamPrivate { 71 GAsyncReadyCallback outstanding_callback; 72}; 73 74static void 75g_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 83static void 84g_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 93static void 94g_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 **/ 117GFileInfo * 118g_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 154static void 155async_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 **/ 185void 186g_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 **/ 230GFileInfo * 231g_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 **/ 260goffset 261g_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 277static goffset 278g_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 **/ 291gboolean 292g_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 312static gboolean 313g_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 **/ 336gboolean 337g_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 375static gboolean 376g_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 386static gboolean 387g_file_input_stream_seekable_can_truncate (GSeekable *seekable) 388{ 389 return FALSE; 390} 391 392static gboolean 393g_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 407typedef struct { 408 char *attributes; 409 GFileInfo *info; 410} QueryInfoAsyncData; 411 412static void 413query_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 421static void 422query_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 451static void 452g_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 472static GFileInfo * 473g_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 492