1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2006-2007 Red Hat, Inc.
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.
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.
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.
20 * Author: Alexander Larsson <alexl@redhat.com>
26 #include <gfileoutputstream.h>
27 #include <gseekable.h>
28 #include "gsimpleasyncresult.h"
32 * SECTION:gfileoutputstream
33 * @short_description: file output streaming operations
34 * @see_also: #GOutputStream, #GDataOutputStream, #GSeekable
40 static void g_file_output_stream_seekable_iface_init (GSeekableIface *iface);
41 static goffset g_file_output_stream_seekable_tell (GSeekable *seekable);
42 static gboolean g_file_output_stream_seekable_can_seek (GSeekable *seekable);
43 static gboolean g_file_output_stream_seekable_seek (GSeekable *seekable,
46 GCancellable *cancellable,
48 static gboolean g_file_output_stream_seekable_can_truncate (GSeekable *seekable);
49 static gboolean g_file_output_stream_seekable_truncate (GSeekable *seekable,
51 GCancellable *cancellable,
53 static void g_file_output_stream_real_query_info_async (GFileOutputStream *stream,
56 GCancellable *cancellable,
57 GAsyncReadyCallback callback,
59 static GFileInfo *g_file_output_stream_real_query_info_finish (GFileOutputStream *stream,
63 G_DEFINE_TYPE_WITH_CODE (GFileOutputStream, g_file_output_stream, G_TYPE_OUTPUT_STREAM,
64 G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
65 g_file_output_stream_seekable_iface_init));
67 struct _GFileOutputStreamPrivate {
68 GAsyncReadyCallback outstanding_callback;
72 g_file_output_stream_class_init (GFileOutputStreamClass *klass)
74 g_type_class_add_private (klass, sizeof (GFileOutputStreamPrivate));
76 klass->query_info_async = g_file_output_stream_real_query_info_async;
77 klass->query_info_finish = g_file_output_stream_real_query_info_finish;
81 g_file_output_stream_seekable_iface_init (GSeekableIface *iface)
83 iface->tell = g_file_output_stream_seekable_tell;
84 iface->can_seek = g_file_output_stream_seekable_can_seek;
85 iface->seek = g_file_output_stream_seekable_seek;
86 iface->can_truncate = g_file_output_stream_seekable_can_truncate;
87 iface->truncate = g_file_output_stream_seekable_truncate;
91 g_file_output_stream_init (GFileOutputStream *stream)
93 stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
94 G_TYPE_FILE_OUTPUT_STREAM,
95 GFileOutputStreamPrivate);
99 * g_file_output_stream_query_info:
100 * @stream: a #GFileOutputStream.
101 * @attributes: a file attribute query string.
102 * @cancellable: optional #GCancellable object, %NULL to ignore.
103 * @error: a #GError, %NULL to ignore.
105 * Queries a file output stream for the given @attributes.
106 * This function blocks while querying the stream. For the asynchronous
107 * version of this function, see g_file_output_stream_query_info_async().
108 * While the stream is blocked, the stream will set the pending flag
109 * internally, and any other operations on the stream will fail with
110 * %G_IO_ERROR_PENDING.
112 * Can fail if the stream was already closed (with @error being set to
113 * %G_IO_ERROR_CLOSED), the stream has pending operations (with @error being
114 * set to %G_IO_ERROR_PENDING), or if querying info is not supported for
115 * the stream's interface (with @error being set to %G_IO_ERROR_NOT_SUPPORTED). In
116 * all cases of failure, %NULL will be returned.
118 * If @cancellable is not %NULL, then the operation can be cancelled by
119 * triggering the cancellable object from another thread. If the operation
120 * was cancelled, the error %G_IO_ERROR_CANCELLED will be set, and %NULL will
123 * Returns: a #GFileInfo for the @stream, or %NULL on error.
126 g_file_output_stream_query_info (GFileOutputStream *stream,
128 GCancellable *cancellable,
131 GFileOutputStreamClass *class;
132 GOutputStream *output_stream;
135 g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), NULL);
137 output_stream = G_OUTPUT_STREAM (stream);
139 if (g_output_stream_is_closed (output_stream))
141 g_set_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
142 _("Stream is already closed"));
146 if (g_output_stream_has_pending (output_stream))
148 g_set_error (error, G_IO_ERROR, G_IO_ERROR_PENDING,
149 _("Stream has outstanding operation"));
155 g_output_stream_set_pending (output_stream, TRUE);
158 g_push_current_cancellable (cancellable);
160 class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
161 if (class->query_info)
162 info = class->query_info (stream, attributes, cancellable, error);
164 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
165 _("Stream doesn't support query_info"));
168 g_pop_current_cancellable (cancellable);
170 g_output_stream_set_pending (output_stream, FALSE);
176 async_ready_callback_wrapper (GObject *source_object,
180 GFileOutputStream *stream = G_FILE_OUTPUT_STREAM (source_object);
182 g_output_stream_set_pending (G_OUTPUT_STREAM (stream), FALSE);
183 if (stream->priv->outstanding_callback)
184 (*stream->priv->outstanding_callback) (source_object, res, user_data);
185 g_object_unref (stream);
189 * g_file_output_stream_query_info_async:
190 * @stream: a #GFileOutputStream.
191 * @attributes: a file attribute query string.
192 * @io_priority: the io priority of the request.
193 * @cancellable: optional #GCancellable object, %NULL to ignore.
194 * @callback: callback to call when the request is satisfied
195 * @user_data: the data to pass to callback function
197 * Asynchronously queries the @stream for a #GFileInfo. When completed,
198 * @callback will be called with a #GAsyncResult which can be used to
199 * finish the operation with g_file_output_stream_query_info_finish().
201 * For the synchronous version of this function, see
202 * g_file_output_stream_query_info().
206 g_file_output_stream_query_info_async (GFileOutputStream *stream,
209 GCancellable *cancellable,
210 GAsyncReadyCallback callback,
213 GFileOutputStreamClass *klass;
214 GOutputStream *output_stream;
216 g_return_if_fail (G_IS_FILE_OUTPUT_STREAM (stream));
218 output_stream = G_OUTPUT_STREAM (stream);
220 if (g_output_stream_is_closed (output_stream))
222 g_simple_async_report_error_in_idle (G_OBJECT (stream),
225 G_IO_ERROR, G_IO_ERROR_CLOSED,
226 _("Stream is already closed"));
230 if (g_output_stream_has_pending (output_stream))
232 g_simple_async_report_error_in_idle (G_OBJECT (stream),
235 G_IO_ERROR, G_IO_ERROR_PENDING,
236 _("Stream has outstanding operation"));
240 klass = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
242 g_output_stream_set_pending (output_stream, TRUE);
243 stream->priv->outstanding_callback = callback;
244 g_object_ref (stream);
245 klass->query_info_async (stream, attributes, io_priority, cancellable,
246 async_ready_callback_wrapper, user_data);
250 * g_file_output_stream_query_info_finish:
251 * @stream: a #GFileOutputStream.
252 * @result: a #GAsyncResult.
253 * @error: a #GError, %NULL to ignore.
255 * Finalizes the asynchronous query started
256 * by g_file_output_stream_query_info_async().
258 * Returns: A #GFileInfo for the finished query.
261 g_file_output_stream_query_info_finish (GFileOutputStream *stream,
262 GAsyncResult *result,
265 GSimpleAsyncResult *simple;
266 GFileOutputStreamClass *class;
268 g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), NULL);
269 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
271 if (G_IS_SIMPLE_ASYNC_RESULT (result))
273 simple = G_SIMPLE_ASYNC_RESULT (result);
274 if (g_simple_async_result_propagate_error (simple, error))
278 class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
279 return class->query_info_finish (stream, result, error);
283 * g_file_output_stream_get_etag:
284 * @stream: a #GFileOutputStream.
286 * Gets the entity tag for the file output stream.
288 * Returns: the entity tag for the stream.
291 g_file_output_stream_get_etag (GFileOutputStream *stream)
293 GFileOutputStreamClass *class;
294 GOutputStream *output_stream;
297 g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), NULL);
299 output_stream = G_OUTPUT_STREAM (stream);
301 if (!g_output_stream_is_closed (output_stream))
303 g_warning ("stream is not closed yet, can't get etag");
309 class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
311 etag = class->get_etag (stream);
317 * g_file_output_stream_tell:
318 * @stream: a #GFileOutputStream.
320 * Gets the current location within the stream.
322 * Returns: a #goffset of the location within the stream.
325 g_file_output_stream_tell (GFileOutputStream *stream)
327 GFileOutputStreamClass *class;
330 g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), 0);
332 class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
336 offset = class->tell (stream);
342 g_file_output_stream_seekable_tell (GSeekable *seekable)
344 return g_file_output_stream_tell (G_FILE_OUTPUT_STREAM (seekable));
348 * g_file_output_stream_can_seek:
349 * @stream: a #GFileOutputStream.
351 * Checks if the stream can be seeked.
353 * Returns: %TRUE if seeking is supported by the stream.
356 g_file_output_stream_can_seek (GFileOutputStream *stream)
358 GFileOutputStreamClass *class;
361 g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), FALSE);
363 class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
370 can_seek = class->can_seek (stream);
377 g_file_output_stream_seekable_can_seek (GSeekable *seekable)
379 return g_file_output_stream_can_seek (G_FILE_OUTPUT_STREAM (seekable));
383 * g_file_output_stream_seek:
384 * @stream: a #GFileOutputStream.
385 * @offset: a #goffset to seek.
386 * @type: a #GSeekType.
387 * @cancellable: optional #GCancellable object, %NULL to ignore.
388 * @error: a #GError, %NULL to ignore.
390 * Seeks to a location in a file output stream.
392 * Returns: %TRUE if the seek was successful. %FALSE otherwise.
395 g_file_output_stream_seek (GFileOutputStream *stream,
398 GCancellable *cancellable,
401 GFileOutputStreamClass *class;
402 GOutputStream *output_stream;
405 g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), FALSE);
407 output_stream = G_OUTPUT_STREAM (stream);
408 class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
410 if (g_output_stream_is_closed (output_stream))
412 g_set_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
413 _("Stream is already closed"));
417 if (g_output_stream_has_pending (output_stream))
419 g_set_error (error, G_IO_ERROR, G_IO_ERROR_PENDING,
420 _("Stream has outstanding operation"));
426 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
427 _("Seek not supported on stream"));
431 g_output_stream_set_pending (output_stream, TRUE);
434 g_push_current_cancellable (cancellable);
436 res = class->seek (stream, offset, type, cancellable, error);
439 g_pop_current_cancellable (cancellable);
441 g_output_stream_set_pending (output_stream, FALSE);
447 g_file_output_stream_seekable_seek (GSeekable *seekable,
450 GCancellable *cancellable,
453 return g_file_output_stream_seek (G_FILE_OUTPUT_STREAM (seekable),
454 offset, type, cancellable, error);
458 * g_file_output_stream_can_truncate:
459 * @stream: a #GFileOutputStream.
461 * Checks if the stream can be truncated.
463 * Returns: %TRUE if stream can be truncated.
466 g_file_output_stream_can_truncate (GFileOutputStream *stream)
468 GFileOutputStreamClass *class;
469 gboolean can_truncate;
471 g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), FALSE);
473 class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
475 can_truncate = FALSE;
479 if (class->can_truncate)
480 can_truncate = class->can_truncate (stream);
487 g_file_output_stream_seekable_can_truncate (GSeekable *seekable)
489 return g_file_output_stream_can_truncate (G_FILE_OUTPUT_STREAM (seekable));
493 * g_file_output_stream_truncate:
494 * @stream: a #GFileOutputStream.
495 * @size: a #goffset to truncate the stream at.
496 * @cancellable: optional #GCancellable object, %NULL to ignore.
497 * @error: a #GError, %NULL to ignore.
499 * Truncates a file output stream.
501 * Returns: %TRUE if @stream is truncated successfully.
504 g_file_output_stream_truncate (GFileOutputStream *stream,
506 GCancellable *cancellable,
509 GFileOutputStreamClass *class;
510 GOutputStream *output_stream;
513 g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), FALSE);
515 output_stream = G_OUTPUT_STREAM (stream);
516 class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
518 if (g_output_stream_is_closed (output_stream))
520 g_set_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
521 _("Stream is already closed"));
525 if (g_output_stream_has_pending (output_stream))
527 g_set_error (error, G_IO_ERROR, G_IO_ERROR_PENDING,
528 _("Stream has outstanding operation"));
532 if (!class->truncate)
534 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
535 _("Truncate not supported on stream"));
539 g_output_stream_set_pending (output_stream, TRUE);
542 g_push_current_cancellable (cancellable);
544 res = class->truncate (stream, size, cancellable, error);
547 g_pop_current_cancellable (cancellable);
549 g_output_stream_set_pending (output_stream, FALSE);
555 g_file_output_stream_seekable_truncate (GSeekable *seekable,
557 GCancellable *cancellable,
560 return g_file_output_stream_truncate (G_FILE_OUTPUT_STREAM (seekable),
561 size, cancellable, error);
563 /********************************************
564 * Default implementation of async ops *
565 ********************************************/
570 } QueryInfoAsyncData;
573 query_info_data_free (QueryInfoAsyncData *data)
576 g_object_unref (data->info);
577 g_free (data->attributes);
582 query_info_async_thread (GSimpleAsyncResult *res,
584 GCancellable *cancellable)
586 GFileOutputStreamClass *class;
587 GError *error = NULL;
588 QueryInfoAsyncData *data;
591 data = g_simple_async_result_get_op_res_gpointer (res);
595 class = G_FILE_OUTPUT_STREAM_GET_CLASS (object);
596 if (class->query_info)
597 info = class->query_info (G_FILE_OUTPUT_STREAM (object), data->attributes, cancellable, &error);
599 g_set_error (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
600 _("Stream doesn't support query_info"));
604 g_simple_async_result_set_from_error (res, error);
605 g_error_free (error);
612 g_file_output_stream_real_query_info_async (GFileOutputStream *stream,
615 GCancellable *cancellable,
616 GAsyncReadyCallback callback,
619 GSimpleAsyncResult *res;
620 QueryInfoAsyncData *data;
622 data = g_new0 (QueryInfoAsyncData, 1);
623 data->attributes = g_strdup (attributes);
625 res = g_simple_async_result_new (G_OBJECT (stream), callback, user_data, g_file_output_stream_real_query_info_async);
626 g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)query_info_data_free);
628 g_simple_async_result_run_in_thread (res, query_info_async_thread, io_priority, cancellable);
629 g_object_unref (res);
633 g_file_output_stream_real_query_info_finish (GFileOutputStream *stream,
637 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
638 QueryInfoAsyncData *data;
640 g_assert (g_simple_async_result_get_source_tag (simple) == g_file_output_stream_real_query_info_async);
642 data = g_simple_async_result_get_op_res_gpointer (simple);
644 return g_object_ref (data->info);