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