Add docs for etags
[platform/upstream/glib.git] / gio / gfileenumerator.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 #include "gfileenumerator.h"
25 #include "gioscheduler.h"
26 #include "gasynchelper.h"
27 #include "gsimpleasyncresult.h"
28 #include "glibintl.h"
29
30 #include "gioalias.h"
31
32 /**
33  * SECTION:gfileenumerator
34  * @short_description: Enumerated Files Routines
35  * 
36  * 
37  **/ 
38
39 G_DEFINE_TYPE (GFileEnumerator, g_file_enumerator, G_TYPE_OBJECT);
40
41 struct _GFileEnumeratorPrivate {
42   /* TODO: Should be public for subclasses? */
43   guint closed : 1;
44   guint pending : 1;
45   GAsyncReadyCallback outstanding_callback;
46   GError *outstanding_error;
47 };
48
49 static void     g_file_enumerator_real_next_files_async  (GFileEnumerator      *enumerator,
50                                                           int                   num_files,
51                                                           int                   io_priority,
52                                                           GCancellable         *cancellable,
53                                                           GAsyncReadyCallback   callback,
54                                                           gpointer              user_data);
55 static GList *  g_file_enumerator_real_next_files_finish (GFileEnumerator      *enumerator,
56                                                           GAsyncResult         *res,
57                                                           GError              **error);
58 static void     g_file_enumerator_real_close_async       (GFileEnumerator      *enumerator,
59                                                           int                   io_priority,
60                                                           GCancellable         *cancellable,
61                                                           GAsyncReadyCallback   callback,
62                                                           gpointer              user_data);
63 static gboolean g_file_enumerator_real_close_finish      (GFileEnumerator      *enumerator,
64                                                           GAsyncResult         *res,
65                                                           GError              **error);
66
67 static void
68 g_file_enumerator_finalize (GObject *object)
69 {
70   GFileEnumerator *enumerator;
71
72   enumerator = G_FILE_ENUMERATOR (object);
73   
74   if (!enumerator->priv->closed)
75     g_file_enumerator_close (enumerator, NULL, NULL);
76
77   if (G_OBJECT_CLASS (g_file_enumerator_parent_class)->finalize)
78     (*G_OBJECT_CLASS (g_file_enumerator_parent_class)->finalize) (object);
79 }
80
81 static void
82 g_file_enumerator_class_init (GFileEnumeratorClass *klass)
83 {
84   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
85   
86   g_type_class_add_private (klass, sizeof (GFileEnumeratorPrivate));
87   
88   gobject_class->finalize = g_file_enumerator_finalize;
89
90   klass->next_files_async = g_file_enumerator_real_next_files_async;
91   klass->next_files_finish = g_file_enumerator_real_next_files_finish;
92   klass->close_async = g_file_enumerator_real_close_async;
93   klass->close_finish = g_file_enumerator_real_close_finish;
94 }
95
96 static void
97 g_file_enumerator_init (GFileEnumerator *enumerator)
98 {
99   enumerator->priv = G_TYPE_INSTANCE_GET_PRIVATE (enumerator,
100                                                   G_TYPE_FILE_ENUMERATOR,
101                                                   GFileEnumeratorPrivate);
102 }
103
104 /**
105  * g_file_enumerator_next_file:
106  * @enumerator: a #GFileEnumerator.
107  * @cancellable: optional #GCancellable object, %NULL to ignore.
108  * @error: location to store the error occuring, or %NULL to ignore
109  *
110  * Returns information for the next file in the enumerated object.
111  * Will block until the information is available.
112  *
113  * On error, returns %NULL and sets @error to the error. If the
114  * enumerator is at the end, %NULL will be returned and @error will
115  * be unset.
116  *
117  * Return value: A #GFileInfo or %NULL on error or end of enumerator
118  **/
119 GFileInfo *
120 g_file_enumerator_next_file (GFileEnumerator *enumerator,
121                              GCancellable *cancellable,
122                              GError **error)
123 {
124   GFileEnumeratorClass *class;
125   GFileInfo *info;
126   
127   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
128   g_return_val_if_fail (enumerator != NULL, NULL);
129   
130   if (enumerator->priv->closed)
131     {
132       g_set_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
133                    _("Enumerator is closed"));
134       return NULL;
135     }
136
137   if (enumerator->priv->pending)
138     {
139       g_set_error (error, G_IO_ERROR, G_IO_ERROR_PENDING,
140                    _("File enumerator has outstanding operation"));
141       return NULL;
142     }
143
144   if (enumerator->priv->outstanding_error)
145     {
146       g_propagate_error (error, enumerator->priv->outstanding_error);
147       enumerator->priv->outstanding_error = NULL;
148       return NULL;
149     }
150   
151   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
152
153   if (cancellable)
154     g_push_current_cancellable (cancellable);
155   
156   enumerator->priv->pending = TRUE;
157   info = (* class->next_file) (enumerator, cancellable, error);
158   enumerator->priv->pending = FALSE;
159
160   if (cancellable)
161     g_pop_current_cancellable (cancellable);
162   
163   return info;
164 }
165   
166 /**
167  * g_file_enumerator_close:
168  * @enumerator: a #GFileEnumerator.
169  * @cancellable: optional #GCancellable object, %NULL to ignore. 
170  * @error: location to store the error occuring, or %NULL to ignore
171  *
172  * Releases all resources used by this enumerator, making the
173  * enumerator return %G_IO_ERROR_CLOSED on all calls.
174  *
175  * This will be automatically called when the last reference
176  * is dropped, but you might want to call make sure resources
177  * are released as early as possible.
178  *
179  * Return value: #TRUE on success or #FALSE on error.
180  **/
181 gboolean
182 g_file_enumerator_close (GFileEnumerator  *enumerator,
183                          GCancellable     *cancellable,
184                          GError          **error)
185 {
186   GFileEnumeratorClass *class;
187
188   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
189   g_return_val_if_fail (enumerator != NULL, FALSE);
190   
191   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
192
193   if (enumerator->priv->closed)
194     return TRUE;
195   
196   if (enumerator->priv->pending)
197     {
198       g_set_error (error, G_IO_ERROR, G_IO_ERROR_PENDING,
199                    _("File enumerator has outstanding operation"));
200       return FALSE;
201     }
202
203   if (cancellable)
204     g_push_current_cancellable (cancellable);
205   
206   enumerator->priv->pending = TRUE;
207   (* class->close) (enumerator, cancellable, error);
208   enumerator->priv->pending = FALSE;
209   enumerator->priv->closed = TRUE;
210
211   if (cancellable)
212     g_pop_current_cancellable (cancellable);
213   
214   return TRUE;
215 }
216
217 static void
218 next_async_callback_wrapper (GObject      *source_object,
219                              GAsyncResult *res,
220                              gpointer      user_data)
221 {
222   GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object);
223
224   enumerator->priv->pending = FALSE;
225   if (enumerator->priv->outstanding_callback)
226     (*enumerator->priv->outstanding_callback) (source_object, res, user_data);
227   g_object_unref (enumerator);
228 }
229
230 /**
231  * g_file_enumerator_next_files_async:
232  * @enumerator: a #GFileEnumerator.
233  * @num_files: the number of file info objects to request
234  * @io_priority: the <link linkend="gioscheduler">io priority</link> 
235  *     of the request. 
236  * @cancellable: optional #GCancellable object, %NULL to ignore.
237  * @callback: callback to call when the request is satisfied
238  * @user_data: the user_data to pass to callback function 
239  *
240  * Request information for a number of files from the enumerator asynchronously.
241  * When all i/o for the operation is finished the @callback will be called with
242  * the requested information.
243  *
244  * The callback can be called with less than @num_files files in case of error
245  * or at the end of the enumerator. In case of a partial error the callback will
246  * be called with any succeeding items and no error, and on the next request the
247  * error will be reported. If a request is cancelled the callback will be called
248  * with %G_IO_ERROR_CANCELLED.
249  *
250  * During an async request no other sync and async calls are allowed, and will
251  * result in %G_IO_ERROR_PENDING errors. 
252  *
253  * Any outstanding i/o request with higher priority (lower numerical value) will
254  * be executed before an outstanding request with lower priority. Default
255  * priority is %G_PRIORITY_DEFAULT.
256  **/
257 void
258 g_file_enumerator_next_files_async (GFileEnumerator     *enumerator,
259                                     int                  num_files,
260                                     int                  io_priority,
261                                     GCancellable        *cancellable,
262                                     GAsyncReadyCallback  callback,
263                                     gpointer             user_data)
264 {
265   GFileEnumeratorClass *class;
266   GSimpleAsyncResult *simple;
267
268   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
269   g_return_if_fail (enumerator != NULL);
270   g_return_if_fail (num_files >= 0);
271
272   if (num_files == 0)
273     {
274       simple = g_simple_async_result_new (G_OBJECT (enumerator),
275                                           callback,
276                                           user_data,
277                                           g_file_enumerator_next_files_async);
278       g_simple_async_result_complete_in_idle (simple);
279       g_object_unref (simple);
280       return;
281     }
282   
283   if (enumerator->priv->closed)
284     {
285       g_simple_async_report_error_in_idle (G_OBJECT (enumerator),
286                                            callback,
287                                            user_data,
288                                            G_IO_ERROR, G_IO_ERROR_CLOSED,
289                                            _("File enumerator is already closed"));
290       return;
291     }
292   
293   if (enumerator->priv->pending)
294     {
295       g_simple_async_report_error_in_idle (G_OBJECT (enumerator),
296                                            callback,
297                                            user_data,
298                                            G_IO_ERROR, G_IO_ERROR_PENDING,
299                                            _("File enumerator has outstanding operation"));
300       return;
301     }
302
303   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
304   
305   enumerator->priv->pending = TRUE;
306   enumerator->priv->outstanding_callback = callback;
307   g_object_ref (enumerator);
308   (* class->next_files_async) (enumerator, num_files, io_priority, cancellable, 
309                                next_async_callback_wrapper, user_data);
310 }
311
312 /**
313  * g_file_enumerator_next_files_finish:
314  * @enumerator: a #GFileEnumerator.
315  * @result: a #GAsyncResult.
316  * @error: a #GError location to store the error occuring, or %NULL to 
317  * ignore.
318  * 
319  * 
320  * 
321  * Returns: 
322  **/
323 GList *
324 g_file_enumerator_next_files_finish (GFileEnumerator  *enumerator,
325                                      GAsyncResult     *result,
326                                      GError          **error)
327 {
328   GFileEnumeratorClass *class;
329   GSimpleAsyncResult *simple;
330   
331   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
332   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
333   
334   if (G_IS_SIMPLE_ASYNC_RESULT (result))
335     {
336       simple = G_SIMPLE_ASYNC_RESULT (result);
337       if (g_simple_async_result_propagate_error (simple, error))
338         return NULL;
339       
340       /* Special case read of 0 files */
341       if (g_simple_async_result_get_source_tag (simple) == g_file_enumerator_next_files_async)
342         return NULL;
343     }
344   
345   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
346   return class->next_files_finish (enumerator, result, error);
347 }
348
349 static void
350 close_async_callback_wrapper (GObject      *source_object,
351                               GAsyncResult *res,
352                               gpointer      user_data)
353 {
354   GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object);
355   
356   enumerator->priv->pending = FALSE;
357   enumerator->priv->closed = TRUE;
358   if (enumerator->priv->outstanding_callback)
359     (*enumerator->priv->outstanding_callback) (source_object, res, user_data);
360   g_object_unref (enumerator);
361 }
362
363 /**
364  * g_file_enumerator_close_async:
365  * @enumerator: a #GFileEnumerator.
366  * @io_priority: the <link linkend="io-priority">I/O priority</link> 
367  *     of the request.
368  * @cancellable: optional #GCancellable object, %NULL to ignore. 
369  * @callback: callback to call when the request is satisfied
370  * @user_data: the user_data to pass to callback function 
371  * 
372  **/
373 void
374 g_file_enumerator_close_async (GFileEnumerator     *enumerator,
375                                int                  io_priority,
376                                GCancellable        *cancellable,
377                                GAsyncReadyCallback  callback,
378                                gpointer             user_data)
379 {
380   GFileEnumeratorClass *class;
381
382   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
383
384   if (enumerator->priv->closed)
385     {
386       g_simple_async_report_error_in_idle (G_OBJECT (enumerator),
387                                            callback,
388                                            user_data,
389                                            G_IO_ERROR, G_IO_ERROR_CLOSED,
390                                            _("File enumerator is already closed"));
391       return;
392     }
393   
394   if (enumerator->priv->pending)
395     {
396       g_simple_async_report_error_in_idle (G_OBJECT (enumerator),
397                                            callback,
398                                            user_data,
399                                            G_IO_ERROR, G_IO_ERROR_PENDING,
400                                            _("File enumerator has outstanding operation"));
401       return;
402     }
403
404   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
405   
406   enumerator->priv->pending = TRUE;
407   enumerator->priv->outstanding_callback = callback;
408   g_object_ref (enumerator);
409   (* class->close_async) (enumerator, io_priority, cancellable,
410                           close_async_callback_wrapper, user_data);
411 }
412
413 /**
414  * g_file_enumerator_close_finish:
415  * @enumerator: a #GFileEnumerator.
416  * @result: a #GAsyncResult.
417  * @error: a #GError location to store the error occuring, or %NULL to 
418  * ignore.
419  * 
420  * 
421  * 
422  * Returns: %TRUE if the close operation has finished successfully.
423  **/
424 gboolean
425 g_file_enumerator_close_finish (GFileEnumerator  *enumerator,
426                                 GAsyncResult     *result,
427                                 GError          **error)
428 {
429   GSimpleAsyncResult *simple;
430   GFileEnumeratorClass *class;
431
432   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
433   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
434   
435   if (G_IS_SIMPLE_ASYNC_RESULT (result))
436     {
437       simple = G_SIMPLE_ASYNC_RESULT (result);
438       if (g_simple_async_result_propagate_error (simple, error))
439         return FALSE;
440     }
441   
442   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
443   return class->close_finish (enumerator, result, error);
444 }
445
446 /**
447  * g_file_enumerator_is_closed:
448  * @enumerator: a #GFileEnumerator.
449  * 
450  * Returns: %TRUE if the @enumerator is closed.
451  **/
452 gboolean
453 g_file_enumerator_is_closed (GFileEnumerator *enumerator)
454 {
455   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
456   
457   return enumerator->priv->closed;
458 }
459
460 /**
461  * g_file_enumerator_has_pending:
462  * @enumerator: a #GFileEnumerator.
463  * 
464  * Returns: %TRUE if the @enumerator has pending operations.
465  **/
466 gboolean
467 g_file_enumerator_has_pending (GFileEnumerator *enumerator)
468 {
469   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
470   
471   return enumerator->priv->pending;
472 }
473
474 /**
475  * g_file_enumerator_set_pending:
476  * @enumerator: a #GFileEnumerator.
477  * @pending: a boolean value.
478  * 
479  **/
480 void
481 g_file_enumerator_set_pending (GFileEnumerator *enumerator,
482                                gboolean         pending)
483 {
484   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
485   
486   enumerator->priv->pending = pending;
487 }
488
489 typedef struct {
490   int                num_files;
491   GList             *files;
492 } NextAsyncOp;
493
494 static void
495 next_files_thread (GSimpleAsyncResult *res,
496                    GObject            *object,
497                    GCancellable       *cancellable)
498 {
499   NextAsyncOp *op;
500   GFileEnumeratorClass *class;
501   GError *error = NULL;
502   GFileInfo *info;
503   GFileEnumerator *enumerator;
504   int i;
505
506   enumerator = G_FILE_ENUMERATOR (object);
507   op = g_simple_async_result_get_op_res_gpointer (res);
508
509   class = G_FILE_ENUMERATOR_GET_CLASS (object);
510
511   for (i = 0; i < op->num_files; i++)
512     {
513       if (g_cancellable_set_error_if_cancelled (cancellable, &error))
514         info = NULL;
515       else
516         info = class->next_file (enumerator, cancellable, &error);
517       
518       if (info == NULL)
519         {
520           /* If we get an error after first file, return that on next operation */
521           if (error != NULL && i > 0)
522             {
523               if (error->domain == G_IO_ERROR &&
524                   error->code == G_IO_ERROR_CANCELLED)
525                 g_error_free (error); /* Never propagate cancel errors to other call */
526               else
527                 enumerator->priv->outstanding_error = error;
528               error = NULL;
529             }
530               
531           break;
532         }
533       else
534         op->files = g_list_prepend (op->files, info);
535     }
536 }
537
538
539 static void
540 g_file_enumerator_real_next_files_async (GFileEnumerator     *enumerator,
541                                          int                  num_files,
542                                          int                  io_priority,
543                                          GCancellable        *cancellable,
544                                          GAsyncReadyCallback  callback,
545                                          gpointer             user_data)
546 {
547   GSimpleAsyncResult *res;
548   NextAsyncOp *op;
549
550   op = g_new0 (NextAsyncOp, 1);
551
552   op->num_files = num_files;
553   op->files = NULL;
554
555   res = g_simple_async_result_new (G_OBJECT (enumerator), callback, user_data, g_file_enumerator_real_next_files_async);
556   g_simple_async_result_set_op_res_gpointer (res, op, g_free);
557   
558   g_simple_async_result_run_in_thread (res, next_files_thread, io_priority, cancellable);
559   g_object_unref (res);
560 }
561
562 static GList *
563 g_file_enumerator_real_next_files_finish (GFileEnumerator                *enumerator,
564                                           GAsyncResult                   *result,
565                                           GError                        **error)
566 {
567   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
568   NextAsyncOp *op;
569
570   g_assert (g_simple_async_result_get_source_tag (simple) == 
571             g_file_enumerator_real_next_files_async);
572
573   op = g_simple_async_result_get_op_res_gpointer (simple);
574
575   return op->files;
576 }
577
578 static void
579 close_async_thread (GSimpleAsyncResult *res,
580                     GObject            *object,
581                     GCancellable       *cancellable)
582 {
583   GFileEnumeratorClass *class;
584   GError *error = NULL;
585   gboolean result;
586
587   /* Auto handling of cancelation disabled, and ignore
588      cancellation, since we want to close things anyway, although
589      possibly in a quick-n-dirty way. At least we never want to leak
590      open handles */
591   
592   class = G_FILE_ENUMERATOR_GET_CLASS (object);
593   result = class->close (G_FILE_ENUMERATOR (object), cancellable, &error);
594   if (!result)
595     {
596       g_simple_async_result_set_from_error (res, error);
597       g_error_free (error);
598     }
599 }
600
601
602 static void
603 g_file_enumerator_real_close_async (GFileEnumerator     *enumerator,
604                                     int                  io_priority,
605                                     GCancellable        *cancellable,
606                                     GAsyncReadyCallback  callback,
607                                     gpointer             user_data)
608 {
609   GSimpleAsyncResult *res;
610   
611   res = g_simple_async_result_new (G_OBJECT (enumerator),
612                                    callback,
613                                    user_data,
614                                    g_file_enumerator_real_close_async);
615
616   g_simple_async_result_set_handle_cancellation (res, FALSE);
617   
618   g_simple_async_result_run_in_thread (res,
619                                        close_async_thread,
620                                        io_priority,
621                                        cancellable);
622   g_object_unref (res);
623 }
624
625 static gboolean
626 g_file_enumerator_real_close_finish (GFileEnumerator  *enumerator,
627                                      GAsyncResult     *result,
628                                      GError          **error)
629 {
630   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
631   g_assert (g_simple_async_result_get_source_tag (simple) == 
632             g_file_enumerator_real_close_async);
633   return TRUE;
634 }
635
636 #define __G_FILE_ENUMERATOR_C__
637 #include "gioaliasdef.c"