Doc updates
[platform/upstream/glib.git] / gio / gfileoutputstream.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 <gfileoutputstream.h>
27 #include <gseekable.h>
28 #include "gsimpleasyncresult.h"
29 #include "glibintl.h"
30
31 #include "gioalias.h"
32
33 /**
34  * SECTION:gfileoutputstream
35  * @short_description: File output streaming operations
36  * @include: gio.h
37  * @see_also: #GOutputStream, #GDataOutputStream, #GSeekable
38  * 
39  * GFileOutputStream provides output streams that write their
40  * content to a file.
41  *
42  * GFileOutputStream implements #GSeekable, which allows
43  * the output stream to jump to arbitrary positions in the file.
44  **/
45
46 static void       g_file_output_stream_seekable_iface_init    (GSeekableIface       *iface);
47 static goffset    g_file_output_stream_seekable_tell          (GSeekable            *seekable);
48 static gboolean   g_file_output_stream_seekable_can_seek      (GSeekable            *seekable);
49 static gboolean   g_file_output_stream_seekable_seek          (GSeekable            *seekable,
50                                                                goffset               offset,
51                                                                GSeekType             type,
52                                                                GCancellable         *cancellable,
53                                                                GError              **error);
54 static gboolean   g_file_output_stream_seekable_can_truncate  (GSeekable            *seekable);
55 static gboolean   g_file_output_stream_seekable_truncate      (GSeekable            *seekable,
56                                                                goffset               offset,
57                                                                GCancellable         *cancellable,
58                                                                GError              **error);
59 static void       g_file_output_stream_real_query_info_async  (GFileOutputStream    *stream,
60                                                                char                 *attributes,
61                                                                int                   io_priority,
62                                                                GCancellable         *cancellable,
63                                                                GAsyncReadyCallback   callback,
64                                                                gpointer              user_data);
65 static GFileInfo *g_file_output_stream_real_query_info_finish (GFileOutputStream    *stream,
66                                                                GAsyncResult         *result,
67                                                                GError              **error);
68
69 G_DEFINE_TYPE_WITH_CODE (GFileOutputStream, g_file_output_stream, G_TYPE_OUTPUT_STREAM,
70                          G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
71                                                 g_file_output_stream_seekable_iface_init));
72
73 struct _GFileOutputStreamPrivate {
74   GAsyncReadyCallback outstanding_callback;
75 };
76
77 static void
78 g_file_output_stream_class_init (GFileOutputStreamClass *klass)
79 {
80   g_type_class_add_private (klass, sizeof (GFileOutputStreamPrivate));
81
82   klass->query_info_async = g_file_output_stream_real_query_info_async;
83   klass->query_info_finish = g_file_output_stream_real_query_info_finish;
84 }
85
86 static void
87 g_file_output_stream_seekable_iface_init (GSeekableIface *iface)
88 {
89   iface->tell = g_file_output_stream_seekable_tell;
90   iface->can_seek = g_file_output_stream_seekable_can_seek;
91   iface->seek = g_file_output_stream_seekable_seek;
92   iface->can_truncate = g_file_output_stream_seekable_can_truncate;
93   iface->truncate_fn = g_file_output_stream_seekable_truncate;
94 }
95
96 static void
97 g_file_output_stream_init (GFileOutputStream *stream)
98 {
99   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
100                                               G_TYPE_FILE_OUTPUT_STREAM,
101                                               GFileOutputStreamPrivate);
102 }
103
104 /**
105  * g_file_output_stream_query_info:
106  * @stream: a #GFileOutputStream.
107  * @attributes: a file attribute query string.
108  * @cancellable: optional #GCancellable object, %NULL to ignore. 
109  * @error: a #GError, %NULL to ignore.
110  *
111  * Queries a file output stream for the given @attributes. 
112  * This function blocks while querying the stream. For the asynchronous 
113  * version of this function, see g_file_output_stream_query_info_async(). 
114  * While the stream is blocked, the stream will set the pending flag 
115  * internally, and any other operations on the stream will fail with 
116  * %G_IO_ERROR_PENDING.
117  * 
118  * Can fail if the stream was already closed (with @error being set to 
119  * %G_IO_ERROR_CLOSED), the stream has pending operations (with @error being
120  * set to %G_IO_ERROR_PENDING), or if querying info is not supported for 
121  * the stream's interface (with @error being set to %G_IO_ERROR_NOT_SUPPORTED). In
122  * all cases of failure, %NULL will be returned.
123  * 
124  * If @cancellable is not %NULL, then the operation can be cancelled by
125  * triggering the cancellable object from another thread. If the operation
126  * was cancelled, the error %G_IO_ERROR_CANCELLED will be set, and %NULL will 
127  * be returned. 
128  * 
129  * Returns: a #GFileInfo for the @stream, or %NULL on error.
130  **/
131 GFileInfo *
132 g_file_output_stream_query_info (GFileOutputStream      *stream,
133                                     char                   *attributes,
134                                     GCancellable           *cancellable,
135                                     GError                **error)
136 {
137   GFileOutputStreamClass *class;
138   GOutputStream *output_stream;
139   GFileInfo *info;
140   
141   g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), NULL);
142   
143   output_stream = G_OUTPUT_STREAM (stream);
144   
145   if (!g_output_stream_set_pending (output_stream, error))
146     return NULL;
147       
148   info = NULL;
149   
150   if (cancellable)
151     g_cancellable_push_current (cancellable);
152   
153   class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
154   if (class->query_info)
155     info = class->query_info (stream, attributes, cancellable, error);
156   else
157     g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
158                  _("Stream doesn't support query_info"));
159   
160   if (cancellable)
161     g_cancellable_pop_current (cancellable);
162   
163   g_output_stream_clear_pending (output_stream);
164   
165   return info;
166 }
167
168 static void
169 async_ready_callback_wrapper (GObject *source_object,
170                               GAsyncResult *res,
171                               gpointer      user_data)
172 {
173   GFileOutputStream *stream = G_FILE_OUTPUT_STREAM (source_object);
174
175   g_output_stream_clear_pending (G_OUTPUT_STREAM (stream));
176   if (stream->priv->outstanding_callback)
177     (*stream->priv->outstanding_callback) (source_object, res, user_data);
178   g_object_unref (stream);
179 }
180
181 /**
182  * g_file_output_stream_query_info_async:
183  * @stream: a #GFileOutputStream.
184  * @attributes: a file attribute query string.
185  * @io_priority: the <link linkend="gio-GIOScheduler">I/O priority</link> 
186  *     of the request.
187  * @cancellable: optional #GCancellable object, %NULL to ignore. 
188  * @callback: callback to call when the request is satisfied
189  * @user_data: the data to pass to callback function
190  * 
191  * Asynchronously queries the @stream for a #GFileInfo. When completed,
192  * @callback will be called with a #GAsyncResult which can be used to 
193  * finish the operation with g_file_output_stream_query_info_finish().
194  * 
195  * For the synchronous version of this function, see 
196  * g_file_output_stream_query_info().
197  *
198  **/
199 void
200 g_file_output_stream_query_info_async (GFileOutputStream     *stream,
201                                           char                 *attributes,
202                                           int                   io_priority,
203                                           GCancellable         *cancellable,
204                                           GAsyncReadyCallback   callback,
205                                           gpointer              user_data)
206 {
207   GFileOutputStreamClass *klass;
208   GOutputStream *output_stream;
209   GError *error = NULL;
210
211   g_return_if_fail (G_IS_FILE_OUTPUT_STREAM (stream));
212
213   output_stream = G_OUTPUT_STREAM (stream);
214  
215   if (!g_output_stream_set_pending (output_stream, &error))
216     {
217       g_simple_async_report_gerror_in_idle (G_OBJECT (stream),
218                                             callback,
219                                             user_data,
220                                             error);
221       g_error_free (error);
222       return;
223     }
224
225   klass = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
226
227   stream->priv->outstanding_callback = callback;
228   g_object_ref (stream);
229   klass->query_info_async (stream, attributes, io_priority, cancellable,
230                               async_ready_callback_wrapper, user_data);
231 }
232
233 /**
234  * g_file_output_stream_query_info_finish:
235  * @stream: a #GFileOutputStream.
236  * @result: a #GAsyncResult.
237  * @error: a #GError, %NULL to ignore.
238  * 
239  * Finalizes the asynchronous query started 
240  * by g_file_output_stream_query_info_async().
241  * 
242  * Returns: A #GFileInfo for the finished query.
243  **/
244 GFileInfo *
245 g_file_output_stream_query_info_finish (GFileOutputStream     *stream,
246                                            GAsyncResult         *result,
247                                            GError              **error)
248 {
249   GSimpleAsyncResult *simple;
250   GFileOutputStreamClass *class;
251
252   g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), NULL);
253   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
254   
255   if (G_IS_SIMPLE_ASYNC_RESULT (result))
256     {
257       simple = G_SIMPLE_ASYNC_RESULT (result);
258       if (g_simple_async_result_propagate_error (simple, error))
259         return NULL;
260     }
261
262   class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
263   return class->query_info_finish (stream, result, error);
264 }
265
266 /**
267  * g_file_output_stream_get_etag:
268  * @stream: a #GFileOutputStream.
269  * 
270  * Gets the entity tag for the file when its been written.
271  * This must be called after the stream has been written
272  * and closed. As the etag can change while writing.
273  * 
274  * Returns: the entity tag for the stream.
275  **/
276 char *
277 g_file_output_stream_get_etag (GFileOutputStream  *stream)
278 {
279   GFileOutputStreamClass *class;
280   GOutputStream *output_stream;
281   char *etag;
282   
283   g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), NULL);
284   
285   output_stream = G_OUTPUT_STREAM (stream);
286   
287   if (!g_output_stream_is_closed (output_stream))
288     {
289       g_warning ("stream is not closed yet, can't get etag");
290       return NULL;
291     }
292
293   etag = NULL;
294   
295   class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
296   if (class->get_etag)
297     etag = class->get_etag (stream);
298   
299   return etag;
300 }
301
302 /**
303  * g_file_output_stream_tell:
304  * @stream: a #GFileOutputStream.
305  * 
306  * Gets the current location within the stream.
307  * 
308  * Returns: a #goffset of the location within the stream.
309  **/
310 goffset
311 g_file_output_stream_tell (GFileOutputStream  *stream)
312 {
313   GFileOutputStreamClass *class;
314   goffset offset;
315   
316   g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), 0);  
317
318   class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
319
320   offset = 0;
321   if (class->tell)
322     offset = class->tell (stream);
323
324   return offset;
325 }
326
327 static goffset
328 g_file_output_stream_seekable_tell (GSeekable *seekable)
329 {
330   return g_file_output_stream_tell (G_FILE_OUTPUT_STREAM (seekable));
331 }
332
333 /**
334  * g_file_output_stream_can_seek:
335  * @stream: a #GFileOutputStream.
336  * 
337  * Checks if the stream can be seeked.
338  * 
339  * Returns: %TRUE if seeking is supported by the stream.
340  **/
341 gboolean
342 g_file_output_stream_can_seek (GFileOutputStream  *stream)
343 {
344   GFileOutputStreamClass *class;
345   gboolean can_seek;
346
347   g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), FALSE);
348
349   class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
350
351   can_seek = FALSE;
352   if (class->seek)
353     {
354       can_seek = TRUE;
355       if (class->can_seek)
356         can_seek = class->can_seek (stream);
357     }
358   
359   return can_seek;
360 }
361
362 static gboolean
363 g_file_output_stream_seekable_can_seek (GSeekable *seekable)
364 {
365   return g_file_output_stream_can_seek (G_FILE_OUTPUT_STREAM (seekable));
366 }
367
368 /**
369  * g_file_output_stream_seek:
370  * @stream: a #GFileOutputStream.
371  * @offset: a #goffset to seek.
372  * @type: a #GSeekType.
373  * @cancellable: optional #GCancellable object, %NULL to ignore. 
374  * @error: a #GError, %NULL to ignore.
375  * 
376  * Seeks to a location in a file output stream.
377  * 
378  * Returns: %TRUE if the seek was successful. %FALSE otherwise.
379  **/
380 gboolean
381 g_file_output_stream_seek (GFileOutputStream  *stream,
382                            goffset             offset,
383                            GSeekType           type,
384                            GCancellable       *cancellable,
385                            GError            **error)
386 {
387   GFileOutputStreamClass *class;
388   GOutputStream *output_stream;
389   gboolean res;
390
391   g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), FALSE);
392
393   output_stream = G_OUTPUT_STREAM (stream);
394   class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
395
396   if (!class->seek)
397     {
398       g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
399                    _("Seek not supported on stream"));
400       return FALSE;
401     }
402
403   if (!g_output_stream_set_pending (output_stream, error))
404     return FALSE;
405   
406   if (cancellable)
407     g_cancellable_push_current (cancellable);
408   
409   res = class->seek (stream, offset, type, cancellable, error);
410   
411   if (cancellable)
412     g_cancellable_pop_current (cancellable);
413
414   g_output_stream_clear_pending (output_stream);
415   
416   return res;
417 }
418
419 static gboolean
420 g_file_output_stream_seekable_seek (GSeekable  *seekable,
421                                     goffset     offset,
422                                     GSeekType   type,
423                                     GCancellable  *cancellable,
424                                     GError    **error)
425 {
426   return g_file_output_stream_seek (G_FILE_OUTPUT_STREAM (seekable),
427                                     offset, type, cancellable, error);
428 }
429
430 /**
431  * g_file_output_stream_can_truncate:
432  * @stream: a #GFileOutputStream.
433  * 
434  * Checks if the stream can be truncated.
435  * 
436  * Returns: %TRUE if stream can be truncated.
437  **/
438 gboolean
439 g_file_output_stream_can_truncate (GFileOutputStream  *stream)
440 {
441   GFileOutputStreamClass *class;
442   gboolean can_truncate;
443
444   g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), FALSE);
445
446   class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
447
448   can_truncate = FALSE;
449   if (class->truncate_fn)
450     {
451       can_truncate = TRUE;
452       if (class->can_truncate)
453         can_truncate = class->can_truncate (stream);
454     }
455   
456   return can_truncate;
457 }
458
459 static gboolean
460 g_file_output_stream_seekable_can_truncate (GSeekable  *seekable)
461 {
462   return g_file_output_stream_can_truncate (G_FILE_OUTPUT_STREAM (seekable));
463 }
464
465 /**
466  * g_file_output_stream_truncate:
467  * @stream: a #GFileOutputStream.
468  * @size: a #goffset to truncate the stream at.
469  * @cancellable: optional #GCancellable object, %NULL to ignore. 
470  * @error: a #GError, %NULL to ignore.
471  * 
472  * Truncates a file output stream.
473  * 
474  * Returns: %TRUE if @stream is truncated successfully.
475  **/
476 gboolean
477 g_file_output_stream_truncate (GFileOutputStream  *stream,
478                                goffset             size,
479                                GCancellable       *cancellable,
480                                GError            **error)
481 {
482   GFileOutputStreamClass *class;
483   GOutputStream *output_stream;
484   gboolean res;
485
486   g_return_val_if_fail (G_IS_FILE_OUTPUT_STREAM (stream), FALSE);
487
488   output_stream = G_OUTPUT_STREAM (stream);
489   class = G_FILE_OUTPUT_STREAM_GET_CLASS (stream);
490
491   if (!class->truncate_fn)
492     {
493       g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
494                    _("Truncate not supported on stream"));
495       return FALSE;
496     }
497
498   if (!g_output_stream_set_pending (output_stream, error))
499     return FALSE;
500   
501   if (cancellable)
502     g_cancellable_push_current (cancellable);
503   
504   res = class->truncate_fn (stream, size, cancellable, error);
505   
506   if (cancellable)
507     g_cancellable_pop_current (cancellable);
508
509   g_output_stream_clear_pending (output_stream);
510   
511   return res;
512 }
513
514 static gboolean
515 g_file_output_stream_seekable_truncate (GSeekable     *seekable,
516                                         goffset        size,
517                                         GCancellable  *cancellable,
518                                         GError       **error)
519 {
520   return g_file_output_stream_truncate (G_FILE_OUTPUT_STREAM (seekable),
521                                         size, cancellable, error);
522 }
523 /********************************************
524  *   Default implementation of async ops    *
525  ********************************************/
526
527 typedef struct {
528   char *attributes;
529   GFileInfo *info;
530 } QueryInfoAsyncData;
531
532 static void
533 query_info_data_free (QueryInfoAsyncData *data)
534 {
535   if (data->info)
536     g_object_unref (data->info);
537   g_free (data->attributes);
538   g_free (data);
539 }
540
541 static void
542 query_info_async_thread (GSimpleAsyncResult *res,
543                        GObject *object,
544                        GCancellable *cancellable)
545 {
546   GFileOutputStreamClass *class;
547   GError *error = NULL;
548   QueryInfoAsyncData *data;
549   GFileInfo *info;
550   
551   data = g_simple_async_result_get_op_res_gpointer (res);
552
553   info = NULL;
554   
555   class = G_FILE_OUTPUT_STREAM_GET_CLASS (object);
556   if (class->query_info)
557     info = class->query_info (G_FILE_OUTPUT_STREAM (object), data->attributes, cancellable, &error);
558   else
559     g_set_error (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
560                  _("Stream doesn't support query_info"));
561
562   if (info == NULL)
563     {
564       g_simple_async_result_set_from_error (res, error);
565       g_error_free (error);
566     }
567   else
568     data->info = info;
569 }
570
571 static void
572 g_file_output_stream_real_query_info_async (GFileOutputStream     *stream,
573                                                char                 *attributes,
574                                                int                   io_priority,
575                                                GCancellable         *cancellable,
576                                                GAsyncReadyCallback   callback,
577                                                gpointer              user_data)
578 {
579   GSimpleAsyncResult *res;
580   QueryInfoAsyncData *data;
581
582   data = g_new0 (QueryInfoAsyncData, 1);
583   data->attributes = g_strdup (attributes);
584   
585   res = g_simple_async_result_new (G_OBJECT (stream), callback, user_data, g_file_output_stream_real_query_info_async);
586   g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)query_info_data_free);
587   
588   g_simple_async_result_run_in_thread (res, query_info_async_thread, io_priority, cancellable);
589   g_object_unref (res);
590 }
591
592 static GFileInfo *
593 g_file_output_stream_real_query_info_finish (GFileOutputStream     *stream,
594                                                 GAsyncResult         *res,
595                                                 GError              **error)
596 {
597   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
598   QueryInfoAsyncData *data;
599
600   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_file_output_stream_real_query_info_async);
601
602   data = g_simple_async_result_get_op_res_gpointer (simple);
603   if (data->info)
604     return g_object_ref (data->info);
605   
606   return NULL;
607 }
608
609 #define __G_FILE_OUTPUT_STREAM_C__
610 #include "gioaliasdef.c"