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