gio: port file/vfs-related classes from GSimpleAsyncResult to GTask
[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 "gfile.h"
26 #include "gioscheduler.h"
27 #include "gasyncresult.h"
28 #include "gasynchelper.h"
29 #include "gioerror.h"
30 #include "glibintl.h"
31
32
33 /**
34  * SECTION:gfileenumerator
35  * @short_description: Enumerated Files Routines
36  * @include: gio/gio.h
37  * 
38  * #GFileEnumerator allows you to operate on a set of #GFile<!-- -->s, 
39  * returning a #GFileInfo structure for each file enumerated (e.g. 
40  * g_file_enumerate_children() will return a #GFileEnumerator for each 
41  * of the children within a directory).
42  *
43  * To get the next file's information from a #GFileEnumerator, use 
44  * g_file_enumerator_next_file() or its asynchronous version, 
45  * g_file_enumerator_next_files_async(). Note that the asynchronous 
46  * version will return a list of #GFileInfo<!---->s, whereas the 
47  * synchronous will only return the next file in the enumerator.
48  *
49  * To close a #GFileEnumerator, use g_file_enumerator_close(), or 
50  * its asynchronous version, g_file_enumerator_close_async(). Once 
51  * a #GFileEnumerator is closed, no further actions may be performed 
52  * on it, and it should be freed with g_object_unref().
53  * 
54  **/ 
55
56 G_DEFINE_TYPE (GFileEnumerator, g_file_enumerator, G_TYPE_OBJECT);
57
58 struct _GFileEnumeratorPrivate {
59   /* TODO: Should be public for subclasses? */
60   GFile *container;
61   guint closed : 1;
62   guint pending : 1;
63   GAsyncReadyCallback outstanding_callback;
64   GError *outstanding_error;
65 };
66
67 enum {
68   PROP_0,
69   PROP_CONTAINER
70 };
71
72 static void     g_file_enumerator_real_next_files_async  (GFileEnumerator      *enumerator,
73                                                           int                   num_files,
74                                                           int                   io_priority,
75                                                           GCancellable         *cancellable,
76                                                           GAsyncReadyCallback   callback,
77                                                           gpointer              user_data);
78 static GList *  g_file_enumerator_real_next_files_finish (GFileEnumerator      *enumerator,
79                                                           GAsyncResult         *res,
80                                                           GError              **error);
81 static void     g_file_enumerator_real_close_async       (GFileEnumerator      *enumerator,
82                                                           int                   io_priority,
83                                                           GCancellable         *cancellable,
84                                                           GAsyncReadyCallback   callback,
85                                                           gpointer              user_data);
86 static gboolean g_file_enumerator_real_close_finish      (GFileEnumerator      *enumerator,
87                                                           GAsyncResult         *res,
88                                                           GError              **error);
89
90 static void
91 g_file_enumerator_set_property (GObject      *object,
92                                 guint         property_id,
93                                 const GValue *value,
94                                 GParamSpec   *pspec)
95 {
96   GFileEnumerator *enumerator;
97   
98   enumerator = G_FILE_ENUMERATOR (object);
99   
100   switch (property_id) {
101   case PROP_CONTAINER:
102     enumerator->priv->container = g_value_dup_object (value);
103     break;
104   default:
105     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
106     break;
107   }
108 }
109
110 static void
111 g_file_enumerator_dispose (GObject *object)
112 {
113   GFileEnumerator *enumerator;
114
115   enumerator = G_FILE_ENUMERATOR (object);
116   
117   if (enumerator->priv->container) {
118     g_object_unref (enumerator->priv->container);
119     enumerator->priv->container = NULL;
120   }
121
122   G_OBJECT_CLASS (g_file_enumerator_parent_class)->dispose (object);
123 }
124
125 static void
126 g_file_enumerator_finalize (GObject *object)
127 {
128   GFileEnumerator *enumerator;
129
130   enumerator = G_FILE_ENUMERATOR (object);
131   
132   if (!enumerator->priv->closed)
133     g_file_enumerator_close (enumerator, NULL, NULL);
134
135   G_OBJECT_CLASS (g_file_enumerator_parent_class)->finalize (object);
136 }
137
138 static void
139 g_file_enumerator_class_init (GFileEnumeratorClass *klass)
140 {
141   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
142   
143   g_type_class_add_private (klass, sizeof (GFileEnumeratorPrivate));
144   
145   gobject_class->set_property = g_file_enumerator_set_property;
146   gobject_class->dispose = g_file_enumerator_dispose;
147   gobject_class->finalize = g_file_enumerator_finalize;
148
149   klass->next_files_async = g_file_enumerator_real_next_files_async;
150   klass->next_files_finish = g_file_enumerator_real_next_files_finish;
151   klass->close_async = g_file_enumerator_real_close_async;
152   klass->close_finish = g_file_enumerator_real_close_finish;
153
154   g_object_class_install_property
155     (gobject_class, PROP_CONTAINER,
156      g_param_spec_object ("container", P_("Container"),
157                           P_("The container that is being enumerated"),
158                           G_TYPE_FILE,
159                           G_PARAM_WRITABLE |
160                           G_PARAM_CONSTRUCT_ONLY |
161                           G_PARAM_STATIC_STRINGS));
162 }
163
164 static void
165 g_file_enumerator_init (GFileEnumerator *enumerator)
166 {
167   enumerator->priv = G_TYPE_INSTANCE_GET_PRIVATE (enumerator,
168                                                   G_TYPE_FILE_ENUMERATOR,
169                                                   GFileEnumeratorPrivate);
170 }
171
172 /**
173  * g_file_enumerator_next_file:
174  * @enumerator: a #GFileEnumerator.
175  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore.
176  * @error: location to store the error occurring, or %NULL to ignore
177  *
178  * Returns information for the next file in the enumerated object.
179  * Will block until the information is available. The #GFileInfo 
180  * returned from this function will contain attributes that match the 
181  * attribute string that was passed when the #GFileEnumerator was created.
182  *
183  * On error, returns %NULL and sets @error to the error. If the
184  * enumerator is at the end, %NULL will be returned and @error will
185  * be unset.
186  *
187  * Return value: (transfer full): A #GFileInfo or %NULL on error or end of enumerator.
188  *    Free the returned object with g_object_unref() when no longer needed.
189  **/
190 GFileInfo *
191 g_file_enumerator_next_file (GFileEnumerator *enumerator,
192                              GCancellable *cancellable,
193                              GError **error)
194 {
195   GFileEnumeratorClass *class;
196   GFileInfo *info;
197   
198   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
199   g_return_val_if_fail (enumerator != NULL, NULL);
200   
201   if (enumerator->priv->closed)
202     {
203       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
204                            _("Enumerator is closed"));
205       return NULL;
206     }
207
208   if (enumerator->priv->pending)
209     {
210       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING,
211                            _("File enumerator has outstanding operation"));
212       return NULL;
213     }
214
215   if (enumerator->priv->outstanding_error)
216     {
217       g_propagate_error (error, enumerator->priv->outstanding_error);
218       enumerator->priv->outstanding_error = NULL;
219       return NULL;
220     }
221   
222   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
223
224   if (cancellable)
225     g_cancellable_push_current (cancellable);
226   
227   enumerator->priv->pending = TRUE;
228   info = (* class->next_file) (enumerator, cancellable, error);
229   enumerator->priv->pending = FALSE;
230
231   if (cancellable)
232     g_cancellable_pop_current (cancellable);
233   
234   return info;
235 }
236   
237 /**
238  * g_file_enumerator_close:
239  * @enumerator: a #GFileEnumerator.
240  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. 
241  * @error: location to store the error occurring, or %NULL to ignore
242  *
243  * Releases all resources used by this enumerator, making the
244  * enumerator return %G_IO_ERROR_CLOSED on all calls.
245  *
246  * This will be automatically called when the last reference
247  * is dropped, but you might want to call this function to make 
248  * sure resources are released as early as possible.
249  *
250  * Return value: #TRUE on success or #FALSE on error.
251  **/
252 gboolean
253 g_file_enumerator_close (GFileEnumerator  *enumerator,
254                          GCancellable     *cancellable,
255                          GError          **error)
256 {
257   GFileEnumeratorClass *class;
258
259   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
260   g_return_val_if_fail (enumerator != NULL, FALSE);
261   
262   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
263
264   if (enumerator->priv->closed)
265     return TRUE;
266   
267   if (enumerator->priv->pending)
268     {
269       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING,
270                            _("File enumerator has outstanding operation"));
271       return FALSE;
272     }
273
274   if (cancellable)
275     g_cancellable_push_current (cancellable);
276   
277   enumerator->priv->pending = TRUE;
278   (* class->close_fn) (enumerator, cancellable, error);
279   enumerator->priv->pending = FALSE;
280   enumerator->priv->closed = TRUE;
281
282   if (cancellable)
283     g_cancellable_pop_current (cancellable);
284   
285   return TRUE;
286 }
287
288 static void
289 next_async_callback_wrapper (GObject      *source_object,
290                              GAsyncResult *res,
291                              gpointer      user_data)
292 {
293   GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object);
294
295   enumerator->priv->pending = FALSE;
296   if (enumerator->priv->outstanding_callback)
297     (*enumerator->priv->outstanding_callback) (source_object, res, user_data);
298   g_object_unref (enumerator);
299 }
300
301 /**
302  * g_file_enumerator_next_files_async:
303  * @enumerator: a #GFileEnumerator.
304  * @num_files: the number of file info objects to request
305  * @io_priority: the <link linkend="io-priority">io priority</link>
306  *     of the request. 
307  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore.
308  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
309  * @user_data: (closure): the data to pass to callback function
310  *
311  * Request information for a number of files from the enumerator asynchronously.
312  * When all i/o for the operation is finished the @callback will be called with
313  * the requested information. 
314  *
315  * The callback can be called with less than @num_files files in case of error
316  * or at the end of the enumerator. In case of a partial error the callback will
317  * be called with any succeeding items and no error, and on the next request the
318  * error will be reported. If a request is cancelled the callback will be called
319  * with %G_IO_ERROR_CANCELLED.
320  *
321  * During an async request no other sync and async calls are allowed, and will
322  * result in %G_IO_ERROR_PENDING errors. 
323  *
324  * Any outstanding i/o request with higher priority (lower numerical value) will
325  * be executed before an outstanding request with lower priority. Default
326  * priority is %G_PRIORITY_DEFAULT.
327  **/
328 void
329 g_file_enumerator_next_files_async (GFileEnumerator     *enumerator,
330                                     int                  num_files,
331                                     int                  io_priority,
332                                     GCancellable        *cancellable,
333                                     GAsyncReadyCallback  callback,
334                                     gpointer             user_data)
335 {
336   GFileEnumeratorClass *class;
337
338   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
339   g_return_if_fail (enumerator != NULL);
340   g_return_if_fail (num_files >= 0);
341
342   if (num_files == 0)
343     {
344       GTask *task;
345
346       task = g_task_new (enumerator, cancellable, callback, user_data);
347       g_task_set_source_tag (task, g_file_enumerator_next_files_async);
348       g_task_return_pointer (task, NULL, NULL);
349       g_object_unref (task);
350       return;
351     }
352   
353   if (enumerator->priv->closed)
354     {
355       g_task_report_new_error (enumerator, callback, user_data,
356                                g_file_enumerator_next_files_async,
357                                G_IO_ERROR, G_IO_ERROR_CLOSED,
358                                _("File enumerator is already closed"));
359       return;
360     }
361   
362   if (enumerator->priv->pending)
363     {
364       g_task_report_new_error (enumerator, callback, user_data,
365                                g_file_enumerator_next_files_async,
366                                G_IO_ERROR, G_IO_ERROR_PENDING,
367                                _("File enumerator has outstanding operation"));
368       return;
369     }
370
371   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
372   
373   enumerator->priv->pending = TRUE;
374   enumerator->priv->outstanding_callback = callback;
375   g_object_ref (enumerator);
376   (* class->next_files_async) (enumerator, num_files, io_priority, cancellable, 
377                                next_async_callback_wrapper, user_data);
378 }
379
380 /**
381  * g_file_enumerator_next_files_finish:
382  * @enumerator: a #GFileEnumerator.
383  * @result: a #GAsyncResult.
384  * @error: a #GError location to store the error occurring, or %NULL to 
385  * ignore.
386  * 
387  * Finishes the asynchronous operation started with g_file_enumerator_next_files_async().
388  * 
389  * Returns: (transfer full) (element-type Gio.FileInfo): a #GList of #GFileInfo<!---->s. You must free the list with 
390  *     g_list_free() and unref the infos with g_object_unref() when you're 
391  *     done with them.
392  **/
393 GList *
394 g_file_enumerator_next_files_finish (GFileEnumerator  *enumerator,
395                                      GAsyncResult     *result,
396                                      GError          **error)
397 {
398   GFileEnumeratorClass *class;
399   
400   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
401   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
402   
403   if (g_async_result_legacy_propagate_error (result, error))
404     return NULL;
405   else if (g_async_result_is_tagged (result, g_file_enumerator_next_files_async))
406     return g_task_propagate_pointer (G_TASK (result), error);
407   
408   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
409   return class->next_files_finish (enumerator, result, error);
410 }
411
412 static void
413 close_async_callback_wrapper (GObject      *source_object,
414                               GAsyncResult *res,
415                               gpointer      user_data)
416 {
417   GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object);
418   
419   enumerator->priv->pending = FALSE;
420   enumerator->priv->closed = TRUE;
421   if (enumerator->priv->outstanding_callback)
422     (*enumerator->priv->outstanding_callback) (source_object, res, user_data);
423   g_object_unref (enumerator);
424 }
425
426 /**
427  * g_file_enumerator_close_async:
428  * @enumerator: a #GFileEnumerator.
429  * @io_priority: the <link linkend="io-priority">I/O priority</link> 
430  *     of the request.
431  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. 
432  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
433  * @user_data: (closure): the data to pass to callback function
434  *
435  * Asynchronously closes the file enumerator. 
436  *
437  * If @cancellable is not %NULL, then the operation can be cancelled by
438  * triggering the cancellable object from another thread. If the operation
439  * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned in 
440  * g_file_enumerator_close_finish(). 
441  **/
442 void
443 g_file_enumerator_close_async (GFileEnumerator     *enumerator,
444                                int                  io_priority,
445                                GCancellable        *cancellable,
446                                GAsyncReadyCallback  callback,
447                                gpointer             user_data)
448 {
449   GFileEnumeratorClass *class;
450
451   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
452
453   if (enumerator->priv->closed)
454     {
455       g_task_report_new_error (enumerator, callback, user_data,
456                                g_file_enumerator_close_async,
457                                G_IO_ERROR, G_IO_ERROR_CLOSED,
458                                _("File enumerator is already closed"));
459       return;
460     }
461   
462   if (enumerator->priv->pending)
463     {
464       g_task_report_new_error (enumerator, callback, user_data,
465                                g_file_enumerator_close_async,
466                                G_IO_ERROR, G_IO_ERROR_PENDING,
467                                _("File enumerator has outstanding operation"));
468       return;
469     }
470
471   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
472   
473   enumerator->priv->pending = TRUE;
474   enumerator->priv->outstanding_callback = callback;
475   g_object_ref (enumerator);
476   (* class->close_async) (enumerator, io_priority, cancellable,
477                           close_async_callback_wrapper, user_data);
478 }
479
480 /**
481  * g_file_enumerator_close_finish:
482  * @enumerator: a #GFileEnumerator.
483  * @result: a #GAsyncResult.
484  * @error: a #GError location to store the error occurring, or %NULL to 
485  * ignore.
486  * 
487  * Finishes closing a file enumerator, started from g_file_enumerator_close_async().
488  * 
489  * If the file enumerator was already closed when g_file_enumerator_close_async() 
490  * was called, then this function will report %G_IO_ERROR_CLOSED in @error, and 
491  * return %FALSE. If the file enumerator had pending operation when the close 
492  * operation was started, then this function will report %G_IO_ERROR_PENDING, and
493  * return %FALSE.  If @cancellable was not %NULL, then the operation may have been 
494  * cancelled by triggering the cancellable object from another thread. If the operation
495  * was cancelled, the error %G_IO_ERROR_CANCELLED will be set, and %FALSE will be 
496  * returned. 
497  * 
498  * Returns: %TRUE if the close operation has finished successfully.
499  **/
500 gboolean
501 g_file_enumerator_close_finish (GFileEnumerator  *enumerator,
502                                 GAsyncResult     *result,
503                                 GError          **error)
504 {
505   GFileEnumeratorClass *class;
506
507   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
508   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
509   
510   if (g_async_result_legacy_propagate_error (result, error))
511     return FALSE;
512   else if (g_async_result_is_tagged (result, g_file_enumerator_close_async))
513     return g_task_propagate_boolean (G_TASK (result), error);
514
515   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
516   return class->close_finish (enumerator, result, error);
517 }
518
519 /**
520  * g_file_enumerator_is_closed:
521  * @enumerator: a #GFileEnumerator.
522  *
523  * Checks if the file enumerator has been closed.
524  * 
525  * Returns: %TRUE if the @enumerator is closed.
526  **/
527 gboolean
528 g_file_enumerator_is_closed (GFileEnumerator *enumerator)
529 {
530   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
531   
532   return enumerator->priv->closed;
533 }
534
535 /**
536  * g_file_enumerator_has_pending:
537  * @enumerator: a #GFileEnumerator.
538  * 
539  * Checks if the file enumerator has pending operations.
540  *
541  * Returns: %TRUE if the @enumerator has pending operations.
542  **/
543 gboolean
544 g_file_enumerator_has_pending (GFileEnumerator *enumerator)
545 {
546   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
547   
548   return enumerator->priv->pending;
549 }
550
551 /**
552  * g_file_enumerator_set_pending:
553  * @enumerator: a #GFileEnumerator.
554  * @pending: a boolean value.
555  * 
556  * Sets the file enumerator as having pending operations.
557  **/
558 void
559 g_file_enumerator_set_pending (GFileEnumerator *enumerator,
560                                gboolean         pending)
561 {
562   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
563   
564   enumerator->priv->pending = pending;
565 }
566
567 /**
568  * g_file_enumerator_get_container:
569  * @enumerator: a #GFileEnumerator
570  *
571  * Get the #GFile container which is being enumerated.
572  *
573  * Returns: (transfer none): the #GFile which is being enumerated.
574  *
575  * Since: 2.18
576  */
577 GFile *
578 g_file_enumerator_get_container (GFileEnumerator *enumerator)
579 {
580   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
581
582   return enumerator->priv->container;
583 }
584
585 /**
586  * g_file_enumerator_get_child:
587  * @enumerator: a #GFileEnumerator
588  * @info: a #GFileInfo gotten from g_file_enumerator_next_file()
589  *   or the async equivalents.
590  *
591  * Return a new #GFile which refers to the file named by @info in the source
592  * directory of @enumerator.  This function is primarily intended to be used
593  * inside loops with g_file_enumerator_next_file().
594  *
595  * This is a convenience method that's equivalent to:
596  * |[
597  *   gchar *name = g_file_info_get_name (info);
598  *   GFile *child = g_file_get_child (g_file_enumerator_get_container (enumr),
599  *                                    name);
600  * ]|
601  *
602  * Returns: (transfer full): a #GFile for the #GFileInfo passed it.
603  *
604  * Since: 2.36
605  */
606 GFile *
607 g_file_enumerator_get_child (GFileEnumerator *enumerator,
608                              GFileInfo       *info)
609 {
610   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
611
612   return g_file_get_child (enumerator->priv->container,
613                            g_file_info_get_name (info));
614 }
615
616 static void
617 next_async_op_free (GList *files)
618 {
619   g_list_free_full (files, g_object_unref);
620 }
621
622 static void
623 next_files_thread (GTask        *task,
624                    gpointer      source_object,
625                    gpointer      task_data,
626                    GCancellable *cancellable)
627 {
628   GFileEnumerator *enumerator = source_object;
629   int num_files = GPOINTER_TO_INT (task_data);
630   GFileEnumeratorClass *class;
631   GList *files = NULL;
632   GError *error = NULL;
633   GFileInfo *info;
634   int i;
635
636   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
637
638   for (i = 0; i < num_files; i++)
639     {
640       if (g_cancellable_set_error_if_cancelled (cancellable, &error))
641         info = NULL;
642       else
643         info = class->next_file (enumerator, cancellable, &error);
644       
645       if (info == NULL)
646         {
647           /* If we get an error after first file, return that on next operation */
648           if (error != NULL && i > 0)
649             {
650               if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
651                 g_error_free (error); /* Never propagate cancel errors to other call */
652               else
653                 enumerator->priv->outstanding_error = error;
654               error = NULL;
655             }
656               
657           break;
658         }
659       else
660         files = g_list_prepend (files, info);
661     }
662
663   if (error)
664     g_task_return_error (task, error);
665   else
666     g_task_return_pointer (task, files, (GDestroyNotify)next_async_op_free);
667 }
668
669 static void
670 g_file_enumerator_real_next_files_async (GFileEnumerator     *enumerator,
671                                          int                  num_files,
672                                          int                  io_priority,
673                                          GCancellable        *cancellable,
674                                          GAsyncReadyCallback  callback,
675                                          gpointer             user_data)
676 {
677   GTask *task;
678
679   task = g_task_new (enumerator, cancellable, callback, user_data);
680   g_task_set_task_data (task, GINT_TO_POINTER (num_files), NULL);
681   g_task_set_priority (task, io_priority);
682
683   g_task_run_in_thread (task, next_files_thread);
684   g_object_unref (task);
685 }
686
687 static GList *
688 g_file_enumerator_real_next_files_finish (GFileEnumerator                *enumerator,
689                                           GAsyncResult                   *result,
690                                           GError                        **error)
691 {
692   g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
693
694   return g_task_propagate_pointer (G_TASK (result), error);
695 }
696
697 static void
698 close_async_thread (GTask        *task,
699                     gpointer      source_object,
700                     gpointer      task_data,
701                     GCancellable *cancellable)
702 {
703   GFileEnumerator *enumerator = source_object;
704   GFileEnumeratorClass *class;
705   GError *error = NULL;
706   gboolean result;
707
708   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
709   result = class->close_fn (enumerator, cancellable, &error);
710   if (result)
711     g_task_return_boolean (task, TRUE);
712   else
713     g_task_return_error (task, error);
714 }
715
716 static void
717 g_file_enumerator_real_close_async (GFileEnumerator     *enumerator,
718                                     int                  io_priority,
719                                     GCancellable        *cancellable,
720                                     GAsyncReadyCallback  callback,
721                                     gpointer             user_data)
722 {
723   GTask *task;
724
725   task = g_task_new (enumerator, cancellable, callback, user_data);
726   g_task_set_priority (task, io_priority);
727   
728   g_task_run_in_thread (task, close_async_thread);
729   g_object_unref (task);
730 }
731
732 static gboolean
733 g_file_enumerator_real_close_finish (GFileEnumerator  *enumerator,
734                                      GAsyncResult     *result,
735                                      GError          **error)
736 {
737   g_return_val_if_fail (g_task_is_valid (result, enumerator), FALSE);
738
739   return g_task_propagate_boolean (G_TASK (result), error);
740 }