Bug 536252 – GFileEnumerator should allow access to the containing GFile
[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  * @include: gio/gio.h
36  * 
37  * #GFileEnumerator allows you to operate on a set of #GFile<!-- -->s, 
38  * returning a #GFileInfo structure for each file enumerated (e.g. 
39  * g_file_enumerate_children() will return a #GFileEnumerator for each 
40  * of the children within a directory).
41  *
42  * To get the next file's information from a #GFileEnumerator, use 
43  * g_file_enumerator_next_file() or its asynchronous version, 
44  * g_file_enumerator_next_file_async(). Note that the asynchronous 
45  * version will return a list of #GFileInfo<!---->s, whereas the 
46  * synchronous will only return the next file in the enumerator.
47  *
48  * To close a #GFileEnumerator, use g_file_enumerator_close(), or 
49  * its asynchronous version, g_file_enumerator_close_async(). Once 
50  * a #GFileEnumerator is closed, no further actions may be performed 
51  * on it, and it should be freed with g_object_unref().
52  * 
53  **/ 
54
55 G_DEFINE_TYPE (GFileEnumerator, g_file_enumerator, G_TYPE_OBJECT);
56
57 struct _GFileEnumeratorPrivate {
58   /* TODO: Should be public for subclasses? */
59   GFile *container;
60   guint closed : 1;
61   guint pending : 1;
62   GAsyncReadyCallback outstanding_callback;
63   GError *outstanding_error;
64 };
65
66 enum {
67   PROP_0,
68   PROP_CONTAINER
69 };
70
71 static void     g_file_enumerator_real_next_files_async  (GFileEnumerator      *enumerator,
72                                                           int                   num_files,
73                                                           int                   io_priority,
74                                                           GCancellable         *cancellable,
75                                                           GAsyncReadyCallback   callback,
76                                                           gpointer              user_data);
77 static GList *  g_file_enumerator_real_next_files_finish (GFileEnumerator      *enumerator,
78                                                           GAsyncResult         *res,
79                                                           GError              **error);
80 static void     g_file_enumerator_real_close_async       (GFileEnumerator      *enumerator,
81                                                           int                   io_priority,
82                                                           GCancellable         *cancellable,
83                                                           GAsyncReadyCallback   callback,
84                                                           gpointer              user_data);
85 static gboolean g_file_enumerator_real_close_finish      (GFileEnumerator      *enumerator,
86                                                           GAsyncResult         *res,
87                                                           GError              **error);
88
89 static void
90 g_file_enumerator_set_property (GObject      *object,
91                                 guint         property_id,
92                                 const GValue *value,
93                                 GParamSpec   *pspec)
94 {
95   GFileEnumerator *enumerator;
96   
97   enumerator = G_FILE_ENUMERATOR (object);
98   
99   switch (property_id) {
100   case PROP_CONTAINER:
101     enumerator->priv->container = g_value_dup_object (value);
102     break;
103   default:
104     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
105     break;
106   }
107 }
108
109 static void
110 g_file_enumerator_dispose (GObject *object)
111 {
112   GFileEnumerator *enumerator;
113
114   enumerator = G_FILE_ENUMERATOR (object);
115   
116   if (enumerator->priv->container) {
117     g_object_unref (enumerator->priv->container);
118     enumerator->priv->container = NULL;
119   }
120   
121   if (G_OBJECT_CLASS (g_file_enumerator_parent_class)->dispose)
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   if (G_OBJECT_CLASS (g_file_enumerator_parent_class)->finalize)
136     (*G_OBJECT_CLASS (g_file_enumerator_parent_class)->finalize) (object);
137 }
138
139 static void
140 g_file_enumerator_class_init (GFileEnumeratorClass *klass)
141 {
142   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
143   
144   g_type_class_add_private (klass, sizeof (GFileEnumeratorPrivate));
145   
146   gobject_class->set_property = g_file_enumerator_set_property;
147   gobject_class->dispose = g_file_enumerator_dispose;
148   gobject_class->finalize = g_file_enumerator_finalize;
149
150   klass->next_files_async = g_file_enumerator_real_next_files_async;
151   klass->next_files_finish = g_file_enumerator_real_next_files_finish;
152   klass->close_async = g_file_enumerator_real_close_async;
153   klass->close_finish = g_file_enumerator_real_close_finish;
154
155   g_object_class_install_property
156     (gobject_class, PROP_CONTAINER,
157      g_param_spec_object ("container", P_("Container"),
158                           P_("The container that is being enumerated"),
159                           G_TYPE_FILE,
160                           G_PARAM_WRITABLE |
161                           G_PARAM_CONSTRUCT_ONLY |
162                           G_PARAM_STATIC_STRINGS));
163 }
164
165 static void
166 g_file_enumerator_init (GFileEnumerator *enumerator)
167 {
168   enumerator->priv = G_TYPE_INSTANCE_GET_PRIVATE (enumerator,
169                                                   G_TYPE_FILE_ENUMERATOR,
170                                                   GFileEnumeratorPrivate);
171 }
172
173 /**
174  * g_file_enumerator_next_file:
175  * @enumerator: a #GFileEnumerator.
176  * @cancellable: optional #GCancellable object, %NULL to ignore.
177  * @error: location to store the error occuring, or %NULL to ignore
178  *
179  * Returns information for the next file in the enumerated object.
180  * Will block until the information is available. The #GFileInfo 
181  * returned from this function will contain attributes that match the 
182  * attribute string that was passed when the #GFileEnumerator was created.
183  *
184  * On error, returns %NULL and sets @error to the error. If the
185  * enumerator is at the end, %NULL will be returned and @error will
186  * be unset.
187  *
188  * Return value: A #GFileInfo or %NULL on error or end of enumerator
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 (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 (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: optional #GCancellable object, %NULL to ignore. 
241  * @error: location to store the error occuring, 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 (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="gioscheduler">io priority</link> 
306  *     of the request. 
307  * @cancellable: optional #GCancellable object, %NULL to ignore.
308  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
309  * @user_data: 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   GSimpleAsyncResult *simple;
338
339   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
340   g_return_if_fail (enumerator != NULL);
341   g_return_if_fail (num_files >= 0);
342
343   if (num_files == 0)
344     {
345       simple = g_simple_async_result_new (G_OBJECT (enumerator),
346                                           callback,
347                                           user_data,
348                                           g_file_enumerator_next_files_async);
349       g_simple_async_result_complete_in_idle (simple);
350       g_object_unref (simple);
351       return;
352     }
353   
354   if (enumerator->priv->closed)
355     {
356       g_simple_async_report_error_in_idle (G_OBJECT (enumerator),
357                                            callback,
358                                            user_data,
359                                            G_IO_ERROR, G_IO_ERROR_CLOSED,
360                                            _("File enumerator is already closed"));
361       return;
362     }
363   
364   if (enumerator->priv->pending)
365     {
366       g_simple_async_report_error_in_idle (G_OBJECT (enumerator),
367                                            callback,
368                                            user_data,
369                                            G_IO_ERROR, G_IO_ERROR_PENDING,
370                                            _("File enumerator has outstanding operation"));
371       return;
372     }
373
374   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
375   
376   enumerator->priv->pending = TRUE;
377   enumerator->priv->outstanding_callback = callback;
378   g_object_ref (enumerator);
379   (* class->next_files_async) (enumerator, num_files, io_priority, cancellable, 
380                                next_async_callback_wrapper, user_data);
381 }
382
383 /**
384  * g_file_enumerator_next_files_finish:
385  * @enumerator: a #GFileEnumerator.
386  * @result: a #GAsyncResult.
387  * @error: a #GError location to store the error occuring, or %NULL to 
388  * ignore.
389  * 
390  * Finishes the asynchronous operation started with g_file_enumerator_next_files_async().
391  * 
392  * Returns: a #GList of #GFileInfo<!---->s. You must free the list with 
393  *     g_list_free() and unref the infos with g_object_unref when you're 
394  *     done with them.
395  **/
396 GList *
397 g_file_enumerator_next_files_finish (GFileEnumerator  *enumerator,
398                                      GAsyncResult     *result,
399                                      GError          **error)
400 {
401   GFileEnumeratorClass *class;
402   GSimpleAsyncResult *simple;
403   
404   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
405   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
406   
407   if (G_IS_SIMPLE_ASYNC_RESULT (result))
408     {
409       simple = G_SIMPLE_ASYNC_RESULT (result);
410       if (g_simple_async_result_propagate_error (simple, error))
411         return NULL;
412       
413       /* Special case read of 0 files */
414       if (g_simple_async_result_get_source_tag (simple) == g_file_enumerator_next_files_async)
415         return NULL;
416     }
417   
418   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
419   return class->next_files_finish (enumerator, result, error);
420 }
421
422 static void
423 close_async_callback_wrapper (GObject      *source_object,
424                               GAsyncResult *res,
425                               gpointer      user_data)
426 {
427   GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object);
428   
429   enumerator->priv->pending = FALSE;
430   enumerator->priv->closed = TRUE;
431   if (enumerator->priv->outstanding_callback)
432     (*enumerator->priv->outstanding_callback) (source_object, res, user_data);
433   g_object_unref (enumerator);
434 }
435
436 /**
437  * g_file_enumerator_close_async:
438  * @enumerator: a #GFileEnumerator.
439  * @io_priority: the <link linkend="io-priority">I/O priority</link> 
440  *     of the request.
441  * @cancellable: optional #GCancellable object, %NULL to ignore. 
442  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
443  * @user_data: the data to pass to callback function
444  *
445  * Asynchronously closes the file enumerator. 
446  *
447  * If @cancellable is not %NULL, then the operation can be cancelled by
448  * triggering the cancellable object from another thread. If the operation
449  * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned in 
450  * g_file_enumerator_close_finish(). 
451  **/
452 void
453 g_file_enumerator_close_async (GFileEnumerator     *enumerator,
454                                int                  io_priority,
455                                GCancellable        *cancellable,
456                                GAsyncReadyCallback  callback,
457                                gpointer             user_data)
458 {
459   GFileEnumeratorClass *class;
460
461   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
462
463   if (enumerator->priv->closed)
464     {
465       g_simple_async_report_error_in_idle (G_OBJECT (enumerator),
466                                            callback,
467                                            user_data,
468                                            G_IO_ERROR, G_IO_ERROR_CLOSED,
469                                            _("File enumerator is already closed"));
470       return;
471     }
472   
473   if (enumerator->priv->pending)
474     {
475       g_simple_async_report_error_in_idle (G_OBJECT (enumerator),
476                                            callback,
477                                            user_data,
478                                            G_IO_ERROR, G_IO_ERROR_PENDING,
479                                            _("File enumerator has outstanding operation"));
480       return;
481     }
482
483   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
484   
485   enumerator->priv->pending = TRUE;
486   enumerator->priv->outstanding_callback = callback;
487   g_object_ref (enumerator);
488   (* class->close_async) (enumerator, io_priority, cancellable,
489                           close_async_callback_wrapper, user_data);
490 }
491
492 /**
493  * g_file_enumerator_close_finish:
494  * @enumerator: a #GFileEnumerator.
495  * @result: a #GAsyncResult.
496  * @error: a #GError location to store the error occuring, or %NULL to 
497  * ignore.
498  * 
499  * Finishes closing a file enumerator, started from g_file_enumerator_close_async().
500  * 
501  * If the file enumerator was already closed when g_file_enumerator_close_async() 
502  * was called, then this function will report %G_IO_ERROR_CLOSED in @error, and 
503  * return %FALSE. If the file enumerator had pending operation when the close 
504  * operation was started, then this function will report %G_IO_ERROR_PENDING, and
505  * return %FALSE.  If @cancellable was not %NULL, then the operation may have been 
506  * cancelled by triggering the cancellable object from another thread. If the operation
507  * was cancelled, the error %G_IO_ERROR_CANCELLED will be set, and %FALSE will be 
508  * returned. 
509  * 
510  * Returns: %TRUE if the close operation has finished successfully.
511  **/
512 gboolean
513 g_file_enumerator_close_finish (GFileEnumerator  *enumerator,
514                                 GAsyncResult     *result,
515                                 GError          **error)
516 {
517   GSimpleAsyncResult *simple;
518   GFileEnumeratorClass *class;
519
520   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
521   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
522   
523   if (G_IS_SIMPLE_ASYNC_RESULT (result))
524     {
525       simple = G_SIMPLE_ASYNC_RESULT (result);
526       if (g_simple_async_result_propagate_error (simple, error))
527         return FALSE;
528     }
529   
530   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
531   return class->close_finish (enumerator, result, error);
532 }
533
534 /**
535  * g_file_enumerator_is_closed:
536  * @enumerator: a #GFileEnumerator.
537  *
538  * Checks if the file enumerator has been closed.
539  * 
540  * Returns: %TRUE if the @enumerator is closed.
541  **/
542 gboolean
543 g_file_enumerator_is_closed (GFileEnumerator *enumerator)
544 {
545   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
546   
547   return enumerator->priv->closed;
548 }
549
550 /**
551  * g_file_enumerator_has_pending:
552  * @enumerator: a #GFileEnumerator.
553  * 
554  * Checks if the file enumerator has pending operations.
555  *
556  * Returns: %TRUE if the @enumerator has pending operations.
557  **/
558 gboolean
559 g_file_enumerator_has_pending (GFileEnumerator *enumerator)
560 {
561   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
562   
563   return enumerator->priv->pending;
564 }
565
566 /**
567  * g_file_enumerator_set_pending:
568  * @enumerator: a #GFileEnumerator.
569  * @pending: a boolean value.
570  * 
571  * Sets the file enumerator as having pending operations.
572  **/
573 void
574 g_file_enumerator_set_pending (GFileEnumerator *enumerator,
575                                gboolean         pending)
576 {
577   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
578   
579   enumerator->priv->pending = pending;
580 }
581
582 /**
583  * g_file_enumerator_get_container:
584  * @enumerator: a #GFileEnumerator
585  *
586  * Get the #GFile container which is being enumerated.
587  *
588  * Returns: the #GFile which is being enumerated.
589  *
590  * Since: 2.18.
591  */
592 GFile *
593 g_file_enumerator_get_container (GFileEnumerator *enumerator)
594 {
595   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
596
597   return enumerator->priv->container;
598 }
599
600 typedef struct {
601   int                num_files;
602   GList             *files;
603 } NextAsyncOp;
604
605 static void
606 next_async_op_free (NextAsyncOp *op)
607 {
608   /* Free the list, if finish wasn't called */
609   g_list_foreach (op->files, (GFunc)g_object_unref, NULL);
610   g_list_free (op->files);
611   
612   g_free (op);
613 }
614                     
615
616
617 static void
618 next_files_thread (GSimpleAsyncResult *res,
619                    GObject            *object,
620                    GCancellable       *cancellable)
621 {
622   NextAsyncOp *op;
623   GFileEnumeratorClass *class;
624   GError *error = NULL;
625   GFileInfo *info;
626   GFileEnumerator *enumerator;
627   int i;
628
629   enumerator = G_FILE_ENUMERATOR (object);
630   op = g_simple_async_result_get_op_res_gpointer (res);
631
632   class = G_FILE_ENUMERATOR_GET_CLASS (object);
633
634   for (i = 0; i < op->num_files; i++)
635     {
636       if (g_cancellable_set_error_if_cancelled (cancellable, &error))
637         info = NULL;
638       else
639         info = class->next_file (enumerator, cancellable, &error);
640       
641       if (info == NULL)
642         {
643           /* If we get an error after first file, return that on next operation */
644           if (error != NULL && i > 0)
645             {
646               if (error->domain == G_IO_ERROR &&
647                   error->code == G_IO_ERROR_CANCELLED)
648                 g_error_free (error); /* Never propagate cancel errors to other call */
649               else
650                 enumerator->priv->outstanding_error = error;
651               error = NULL;
652             }
653               
654           break;
655         }
656       else
657         op->files = g_list_prepend (op->files, info);
658     }
659 }
660
661 static void
662 g_file_enumerator_real_next_files_async (GFileEnumerator     *enumerator,
663                                          int                  num_files,
664                                          int                  io_priority,
665                                          GCancellable        *cancellable,
666                                          GAsyncReadyCallback  callback,
667                                          gpointer             user_data)
668 {
669   GSimpleAsyncResult *res;
670   NextAsyncOp *op;
671
672   op = g_new0 (NextAsyncOp, 1);
673
674   op->num_files = num_files;
675   op->files = NULL;
676
677   res = g_simple_async_result_new (G_OBJECT (enumerator), callback, user_data, g_file_enumerator_real_next_files_async);
678   g_simple_async_result_set_op_res_gpointer (res, op, (GDestroyNotify) next_async_op_free);
679   
680   g_simple_async_result_run_in_thread (res, next_files_thread, io_priority, cancellable);
681   g_object_unref (res);
682 }
683
684 static GList *
685 g_file_enumerator_real_next_files_finish (GFileEnumerator                *enumerator,
686                                           GAsyncResult                   *result,
687                                           GError                        **error)
688 {
689   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
690   NextAsyncOp *op;
691   GList *res;
692
693   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == 
694             g_file_enumerator_real_next_files_async);
695
696   op = g_simple_async_result_get_op_res_gpointer (simple);
697
698   res = op->files;
699   op->files = NULL;
700   return res;
701 }
702
703 static void
704 close_async_thread (GSimpleAsyncResult *res,
705                     GObject            *object,
706                     GCancellable       *cancellable)
707 {
708   GFileEnumeratorClass *class;
709   GError *error = NULL;
710   gboolean result;
711
712   /* Auto handling of cancelation disabled, and ignore
713      cancellation, since we want to close things anyway, although
714      possibly in a quick-n-dirty way. At least we never want to leak
715      open handles */
716   
717   class = G_FILE_ENUMERATOR_GET_CLASS (object);
718   result = class->close_fn (G_FILE_ENUMERATOR (object), cancellable, &error);
719   if (!result)
720     {
721       g_simple_async_result_set_from_error (res, error);
722       g_error_free (error);
723     }
724 }
725
726
727 static void
728 g_file_enumerator_real_close_async (GFileEnumerator     *enumerator,
729                                     int                  io_priority,
730                                     GCancellable        *cancellable,
731                                     GAsyncReadyCallback  callback,
732                                     gpointer             user_data)
733 {
734   GSimpleAsyncResult *res;
735   
736   res = g_simple_async_result_new (G_OBJECT (enumerator),
737                                    callback,
738                                    user_data,
739                                    g_file_enumerator_real_close_async);
740
741   g_simple_async_result_set_handle_cancellation (res, FALSE);
742   
743   g_simple_async_result_run_in_thread (res,
744                                        close_async_thread,
745                                        io_priority,
746                                        cancellable);
747   g_object_unref (res);
748 }
749
750 static gboolean
751 g_file_enumerator_real_close_finish (GFileEnumerator  *enumerator,
752                                      GAsyncResult     *result,
753                                      GError          **error)
754 {
755   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
756   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == 
757             g_file_enumerator_real_close_async);
758   return TRUE;
759 }
760
761 #define __G_FILE_ENUMERATOR_C__
762 #include "gioaliasdef.c"