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