• 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.1 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, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: Alexander Larsson <alexl@redhat.com>
19  */
20 
21 #include "config.h"
22 #include "gfileenumerator.h"
23 #include "gfile.h"
24 #include "gioscheduler.h"
25 #include "gasyncresult.h"
26 #include "gasynchelper.h"
27 #include "gioerror.h"
28 #include "glibintl.h"
29 
30 struct _GFileEnumeratorPrivate {
31   /* TODO: Should be public for subclasses? */
32   GFile *container;
33   guint closed : 1;
34   guint pending : 1;
35   GAsyncReadyCallback outstanding_callback;
36   GError *outstanding_error;
37 };
38 
39 /**
40  * SECTION:gfileenumerator
41  * @short_description: Enumerated Files Routines
42  * @include: gio/gio.h
43  *
44  * #GFileEnumerator allows you to operate on a set of #GFiles,
45  * returning a #GFileInfo structure for each file enumerated (e.g.
46  * g_file_enumerate_children() will return a #GFileEnumerator for each
47  * of the children within a directory).
48  *
49  * To get the next file's information from a #GFileEnumerator, use
50  * g_file_enumerator_next_file() or its asynchronous version,
51  * g_file_enumerator_next_files_async(). Note that the asynchronous
52  * version will return a list of #GFileInfos, whereas the
53  * synchronous will only return the next file in the enumerator.
54  *
55  * The ordering of returned files is unspecified for non-Unix
56  * platforms; for more information, see g_dir_read_name().  On Unix,
57  * when operating on local files, returned files will be sorted by
58  * inode number.  Effectively you can assume that the ordering of
59  * returned files will be stable between successive calls (and
60  * applications) assuming the directory is unchanged.
61  *
62  * If your application needs a specific ordering, such as by name or
63  * modification time, you will have to implement that in your
64  * application code.
65  *
66  * To close a #GFileEnumerator, use g_file_enumerator_close(), or
67  * its asynchronous version, g_file_enumerator_close_async(). Once
68  * a #GFileEnumerator is closed, no further actions may be performed
69  * on it, and it should be freed with g_object_unref().
70  *
71  **/
72 
73 G_DEFINE_TYPE_WITH_PRIVATE (GFileEnumerator, g_file_enumerator, G_TYPE_OBJECT)
74 
75 enum {
76   PROP_0,
77   PROP_CONTAINER
78 };
79 
80 static void     g_file_enumerator_real_next_files_async  (GFileEnumerator      *enumerator,
81 							  int                   num_files,
82 							  int                   io_priority,
83 							  GCancellable         *cancellable,
84 							  GAsyncReadyCallback   callback,
85 							  gpointer              user_data);
86 static GList *  g_file_enumerator_real_next_files_finish (GFileEnumerator      *enumerator,
87 							  GAsyncResult         *res,
88 							  GError              **error);
89 static void     g_file_enumerator_real_close_async       (GFileEnumerator      *enumerator,
90 							  int                   io_priority,
91 							  GCancellable         *cancellable,
92 							  GAsyncReadyCallback   callback,
93 							  gpointer              user_data);
94 static gboolean g_file_enumerator_real_close_finish      (GFileEnumerator      *enumerator,
95 							  GAsyncResult         *res,
96 							  GError              **error);
97 
98 static void
g_file_enumerator_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)99 g_file_enumerator_set_property (GObject      *object,
100                                 guint         property_id,
101                                 const GValue *value,
102                                 GParamSpec   *pspec)
103 {
104   GFileEnumerator *enumerator;
105 
106   enumerator = G_FILE_ENUMERATOR (object);
107 
108   switch (property_id) {
109   case PROP_CONTAINER:
110     enumerator->priv->container = g_value_dup_object (value);
111     break;
112   default:
113     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
114     break;
115   }
116 }
117 
118 static void
g_file_enumerator_dispose(GObject * object)119 g_file_enumerator_dispose (GObject *object)
120 {
121   GFileEnumerator *enumerator;
122 
123   enumerator = G_FILE_ENUMERATOR (object);
124 
125   if (enumerator->priv->container) {
126     g_object_unref (enumerator->priv->container);
127     enumerator->priv->container = NULL;
128   }
129 
130   G_OBJECT_CLASS (g_file_enumerator_parent_class)->dispose (object);
131 }
132 
133 static void
g_file_enumerator_finalize(GObject * object)134 g_file_enumerator_finalize (GObject *object)
135 {
136   GFileEnumerator *enumerator;
137 
138   enumerator = G_FILE_ENUMERATOR (object);
139 
140   if (!enumerator->priv->closed)
141     g_file_enumerator_close (enumerator, NULL, NULL);
142 
143   G_OBJECT_CLASS (g_file_enumerator_parent_class)->finalize (object);
144 }
145 
146 static void
g_file_enumerator_class_init(GFileEnumeratorClass * klass)147 g_file_enumerator_class_init (GFileEnumeratorClass *klass)
148 {
149   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
150 
151   gobject_class->set_property = g_file_enumerator_set_property;
152   gobject_class->dispose = g_file_enumerator_dispose;
153   gobject_class->finalize = g_file_enumerator_finalize;
154 
155   klass->next_files_async = g_file_enumerator_real_next_files_async;
156   klass->next_files_finish = g_file_enumerator_real_next_files_finish;
157   klass->close_async = g_file_enumerator_real_close_async;
158   klass->close_finish = g_file_enumerator_real_close_finish;
159 
160   g_object_class_install_property
161     (gobject_class, PROP_CONTAINER,
162      g_param_spec_object ("container", P_("Container"),
163                           P_("The container that is being enumerated"),
164                           G_TYPE_FILE,
165                           G_PARAM_WRITABLE |
166                           G_PARAM_CONSTRUCT_ONLY |
167                           G_PARAM_STATIC_STRINGS));
168 }
169 
170 static void
g_file_enumerator_init(GFileEnumerator * enumerator)171 g_file_enumerator_init (GFileEnumerator *enumerator)
172 {
173   enumerator->priv = g_file_enumerator_get_instance_private (enumerator);
174 }
175 
176 /**
177  * g_file_enumerator_next_file:
178  * @enumerator: a #GFileEnumerator.
179  * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
180  * @error: location to store the error occurring, or %NULL to ignore
181  *
182  * Returns information for the next file in the enumerated object.
183  * Will block until the information is available. The #GFileInfo
184  * returned from this function will contain attributes that match the
185  * attribute string that was passed when the #GFileEnumerator was created.
186  *
187  * See the documentation of #GFileEnumerator for information about the
188  * order of returned files.
189  *
190  * On error, returns %NULL and sets @error to the error. If the
191  * enumerator is at the end, %NULL will be returned and @error will
192  * be unset.
193  *
194  * Returns: (nullable) (transfer full): A #GFileInfo or %NULL on error
195  *    or end of enumerator.  Free the returned object with
196  *    g_object_unref() when no longer needed.
197  **/
198 GFileInfo *
g_file_enumerator_next_file(GFileEnumerator * enumerator,GCancellable * cancellable,GError ** error)199 g_file_enumerator_next_file (GFileEnumerator *enumerator,
200 			     GCancellable *cancellable,
201 			     GError **error)
202 {
203   GFileEnumeratorClass *class;
204   GFileInfo *info;
205 
206   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
207   g_return_val_if_fail (enumerator != NULL, NULL);
208 
209   if (enumerator->priv->closed)
210     {
211       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
212                            _("Enumerator is closed"));
213       return NULL;
214     }
215 
216   if (enumerator->priv->pending)
217     {
218       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING,
219                            _("File enumerator has outstanding operation"));
220       return NULL;
221     }
222 
223   if (enumerator->priv->outstanding_error)
224     {
225       g_propagate_error (error, enumerator->priv->outstanding_error);
226       enumerator->priv->outstanding_error = NULL;
227       return NULL;
228     }
229 
230   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
231 
232   if (cancellable)
233     g_cancellable_push_current (cancellable);
234 
235   enumerator->priv->pending = TRUE;
236   info = (* class->next_file) (enumerator, cancellable, error);
237   enumerator->priv->pending = FALSE;
238 
239   if (cancellable)
240     g_cancellable_pop_current (cancellable);
241 
242   return info;
243 }
244 
245 /**
246  * g_file_enumerator_close:
247  * @enumerator: a #GFileEnumerator.
248  * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
249  * @error: location to store the error occurring, or %NULL to ignore
250  *
251  * Releases all resources used by this enumerator, making the
252  * enumerator return %G_IO_ERROR_CLOSED on all calls.
253  *
254  * This will be automatically called when the last reference
255  * is dropped, but you might want to call this function to make
256  * sure resources are released as early as possible.
257  *
258  * Returns: #TRUE on success or #FALSE on error.
259  **/
260 gboolean
g_file_enumerator_close(GFileEnumerator * enumerator,GCancellable * cancellable,GError ** error)261 g_file_enumerator_close (GFileEnumerator  *enumerator,
262 			 GCancellable     *cancellable,
263 			 GError          **error)
264 {
265   GFileEnumeratorClass *class;
266 
267   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
268   g_return_val_if_fail (enumerator != NULL, FALSE);
269 
270   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
271 
272   if (enumerator->priv->closed)
273     return TRUE;
274 
275   if (enumerator->priv->pending)
276     {
277       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING,
278                            _("File enumerator has outstanding operation"));
279       return FALSE;
280     }
281 
282   if (cancellable)
283     g_cancellable_push_current (cancellable);
284 
285   enumerator->priv->pending = TRUE;
286   (* class->close_fn) (enumerator, cancellable, error);
287   enumerator->priv->pending = FALSE;
288   enumerator->priv->closed = TRUE;
289 
290   if (cancellable)
291     g_cancellable_pop_current (cancellable);
292 
293   return TRUE;
294 }
295 
296 static void
next_async_callback_wrapper(GObject * source_object,GAsyncResult * res,gpointer user_data)297 next_async_callback_wrapper (GObject      *source_object,
298 			     GAsyncResult *res,
299 			     gpointer      user_data)
300 {
301   GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object);
302 
303   enumerator->priv->pending = FALSE;
304   if (enumerator->priv->outstanding_callback)
305     (*enumerator->priv->outstanding_callback) (source_object, res, user_data);
306   g_object_unref (enumerator);
307 }
308 
309 /**
310  * g_file_enumerator_next_files_async:
311  * @enumerator: a #GFileEnumerator.
312  * @num_files: the number of file info objects to request
313  * @io_priority: the [I/O priority][io-priority] of the request
314  * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
315  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
316  * @user_data: (closure): the data to pass to callback function
317  *
318  * Request information for a number of files from the enumerator asynchronously.
319  * When all i/o for the operation is finished the @callback will be called with
320  * the requested information.
321  *
322  * See the documentation of #GFileEnumerator for information about the
323  * order of returned files.
324  *
325  * The callback can be called with less than @num_files files in case of error
326  * or at the end of the enumerator. In case of a partial error the callback will
327  * be called with any succeeding items and no error, and on the next request the
328  * error will be reported. If a request is cancelled the callback will be called
329  * with %G_IO_ERROR_CANCELLED.
330  *
331  * During an async request no other sync and async calls are allowed, and will
332  * result in %G_IO_ERROR_PENDING errors.
333  *
334  * Any outstanding i/o request with higher priority (lower numerical value) will
335  * be executed before an outstanding request with lower priority. Default
336  * priority is %G_PRIORITY_DEFAULT.
337  **/
338 void
g_file_enumerator_next_files_async(GFileEnumerator * enumerator,int num_files,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)339 g_file_enumerator_next_files_async (GFileEnumerator     *enumerator,
340 				    int                  num_files,
341 				    int                  io_priority,
342 				    GCancellable        *cancellable,
343 				    GAsyncReadyCallback  callback,
344 				    gpointer             user_data)
345 {
346   GFileEnumeratorClass *class;
347 
348   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
349   g_return_if_fail (enumerator != NULL);
350   g_return_if_fail (num_files >= 0);
351 
352   if (num_files == 0)
353     {
354       GTask *task;
355 
356       task = g_task_new (enumerator, cancellable, callback, user_data);
357       g_task_set_source_tag (task, g_file_enumerator_next_files_async);
358       g_task_return_pointer (task, NULL, NULL);
359       g_object_unref (task);
360       return;
361     }
362 
363   if (enumerator->priv->closed)
364     {
365       g_task_report_new_error (enumerator, callback, user_data,
366                                g_file_enumerator_next_files_async,
367                                G_IO_ERROR, G_IO_ERROR_CLOSED,
368                                _("File enumerator is already closed"));
369       return;
370     }
371 
372   if (enumerator->priv->pending)
373     {
374       g_task_report_new_error (enumerator, callback, user_data,
375                                g_file_enumerator_next_files_async,
376                                G_IO_ERROR, G_IO_ERROR_PENDING,
377                                _("File enumerator has outstanding operation"));
378       return;
379     }
380 
381   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
382 
383   enumerator->priv->pending = TRUE;
384   enumerator->priv->outstanding_callback = callback;
385   g_object_ref (enumerator);
386   (* class->next_files_async) (enumerator, num_files, io_priority, cancellable,
387 			       next_async_callback_wrapper, user_data);
388 }
389 
390 /**
391  * g_file_enumerator_next_files_finish:
392  * @enumerator: a #GFileEnumerator.
393  * @result: a #GAsyncResult.
394  * @error: a #GError location to store the error occurring, or %NULL to
395  * ignore.
396  *
397  * Finishes the asynchronous operation started with g_file_enumerator_next_files_async().
398  *
399  * Returns: (transfer full) (element-type Gio.FileInfo): a #GList of #GFileInfos. You must free the list with
400  *     g_list_free() and unref the infos with g_object_unref() when you're
401  *     done with them.
402  **/
403 GList *
g_file_enumerator_next_files_finish(GFileEnumerator * enumerator,GAsyncResult * result,GError ** error)404 g_file_enumerator_next_files_finish (GFileEnumerator  *enumerator,
405 				     GAsyncResult     *result,
406 				     GError          **error)
407 {
408   GFileEnumeratorClass *class;
409 
410   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
411   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
412 
413   if (g_async_result_legacy_propagate_error (result, error))
414     return NULL;
415   else if (g_async_result_is_tagged (result, g_file_enumerator_next_files_async))
416     return g_task_propagate_pointer (G_TASK (result), error);
417 
418   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
419   return class->next_files_finish (enumerator, result, error);
420 }
421 
422 static void
close_async_callback_wrapper(GObject * source_object,GAsyncResult * res,gpointer user_data)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 [I/O priority][io-priority] of the request
440  * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
441  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
442  * @user_data: (closure): the data to pass to callback function
443  *
444  * Asynchronously closes the file enumerator.
445  *
446  * If @cancellable is not %NULL, then the operation can be cancelled by
447  * triggering the cancellable object from another thread. If the operation
448  * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned in
449  * g_file_enumerator_close_finish().
450  **/
451 void
g_file_enumerator_close_async(GFileEnumerator * enumerator,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)452 g_file_enumerator_close_async (GFileEnumerator     *enumerator,
453 			       int                  io_priority,
454 			       GCancellable        *cancellable,
455 			       GAsyncReadyCallback  callback,
456 			       gpointer             user_data)
457 {
458   GFileEnumeratorClass *class;
459 
460   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
461 
462   if (enumerator->priv->closed)
463     {
464       g_task_report_new_error (enumerator, callback, user_data,
465                                g_file_enumerator_close_async,
466                                G_IO_ERROR, G_IO_ERROR_CLOSED,
467                                _("File enumerator is already closed"));
468       return;
469     }
470 
471   if (enumerator->priv->pending)
472     {
473       g_task_report_new_error (enumerator, callback, user_data,
474                                g_file_enumerator_close_async,
475                                G_IO_ERROR, G_IO_ERROR_PENDING,
476                                _("File enumerator has outstanding operation"));
477       return;
478     }
479 
480   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
481 
482   enumerator->priv->pending = TRUE;
483   enumerator->priv->outstanding_callback = callback;
484   g_object_ref (enumerator);
485   (* class->close_async) (enumerator, io_priority, cancellable,
486 			  close_async_callback_wrapper, user_data);
487 }
488 
489 /**
490  * g_file_enumerator_close_finish:
491  * @enumerator: a #GFileEnumerator.
492  * @result: a #GAsyncResult.
493  * @error: a #GError location to store the error occurring, or %NULL to
494  * ignore.
495  *
496  * Finishes closing a file enumerator, started from g_file_enumerator_close_async().
497  *
498  * If the file enumerator was already closed when g_file_enumerator_close_async()
499  * was called, then this function will report %G_IO_ERROR_CLOSED in @error, and
500  * return %FALSE. If the file enumerator had pending operation when the close
501  * operation was started, then this function will report %G_IO_ERROR_PENDING, and
502  * return %FALSE.  If @cancellable was not %NULL, then the operation may have been
503  * cancelled by triggering the cancellable object from another thread. If the operation
504  * was cancelled, the error %G_IO_ERROR_CANCELLED will be set, and %FALSE will be
505  * returned.
506  *
507  * Returns: %TRUE if the close operation has finished successfully.
508  **/
509 gboolean
g_file_enumerator_close_finish(GFileEnumerator * enumerator,GAsyncResult * result,GError ** error)510 g_file_enumerator_close_finish (GFileEnumerator  *enumerator,
511 				GAsyncResult     *result,
512 				GError          **error)
513 {
514   GFileEnumeratorClass *class;
515 
516   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
517   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
518 
519   if (g_async_result_legacy_propagate_error (result, error))
520     return FALSE;
521   else if (g_async_result_is_tagged (result, g_file_enumerator_close_async))
522     return g_task_propagate_boolean (G_TASK (result), error);
523 
524   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
525   return class->close_finish (enumerator, result, error);
526 }
527 
528 /**
529  * g_file_enumerator_is_closed:
530  * @enumerator: a #GFileEnumerator.
531  *
532  * Checks if the file enumerator has been closed.
533  *
534  * Returns: %TRUE if the @enumerator is closed.
535  **/
536 gboolean
g_file_enumerator_is_closed(GFileEnumerator * enumerator)537 g_file_enumerator_is_closed (GFileEnumerator *enumerator)
538 {
539   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
540 
541   return enumerator->priv->closed;
542 }
543 
544 /**
545  * g_file_enumerator_has_pending:
546  * @enumerator: a #GFileEnumerator.
547  *
548  * Checks if the file enumerator has pending operations.
549  *
550  * Returns: %TRUE if the @enumerator has pending operations.
551  **/
552 gboolean
g_file_enumerator_has_pending(GFileEnumerator * enumerator)553 g_file_enumerator_has_pending (GFileEnumerator *enumerator)
554 {
555   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
556 
557   return enumerator->priv->pending;
558 }
559 
560 /**
561  * g_file_enumerator_set_pending:
562  * @enumerator: a #GFileEnumerator.
563  * @pending: a boolean value.
564  *
565  * Sets the file enumerator as having pending operations.
566  **/
567 void
g_file_enumerator_set_pending(GFileEnumerator * enumerator,gboolean pending)568 g_file_enumerator_set_pending (GFileEnumerator *enumerator,
569 			       gboolean         pending)
570 {
571   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
572 
573   enumerator->priv->pending = pending;
574 }
575 
576 /**
577  * g_file_enumerator_iterate:
578  * @direnum: an open #GFileEnumerator
579  * @out_info: (out) (transfer none) (optional): Output location for the next #GFileInfo, or %NULL
580  * @out_child: (out) (transfer none) (optional): Output location for the next #GFile, or %NULL
581  * @cancellable: a #GCancellable
582  * @error: a #GError
583  *
584  * This is a version of g_file_enumerator_next_file() that's easier to
585  * use correctly from C programs.  With g_file_enumerator_next_file(),
586  * the gboolean return value signifies "end of iteration or error", which
587  * requires allocation of a temporary #GError.
588  *
589  * In contrast, with this function, a %FALSE return from
590  * g_file_enumerator_iterate() *always* means
591  * "error".  End of iteration is signaled by @out_info or @out_child being %NULL.
592  *
593  * Another crucial difference is that the references for @out_info and
594  * @out_child are owned by @direnum (they are cached as hidden
595  * properties).  You must not unref them in your own code.  This makes
596  * memory management significantly easier for C code in combination
597  * with loops.
598  *
599  * Finally, this function optionally allows retrieving a #GFile as
600  * well.
601  *
602  * You must specify at least one of @out_info or @out_child.
603  *
604  * The code pattern for correctly using g_file_enumerator_iterate() from C
605  * is:
606  *
607  * |[
608  * direnum = g_file_enumerate_children (file, ...);
609  * while (TRUE)
610  *   {
611  *     GFileInfo *info;
612  *     if (!g_file_enumerator_iterate (direnum, &info, NULL, cancellable, error))
613  *       goto out;
614  *     if (!info)
615  *       break;
616  *     ... do stuff with "info"; do not unref it! ...
617  *   }
618  *
619  * out:
620  *   g_object_unref (direnum); // Note: frees the last @info
621  * ]|
622  *
623  *
624  * Since: 2.44
625  */
626 gboolean
g_file_enumerator_iterate(GFileEnumerator * direnum,GFileInfo ** out_info,GFile ** out_child,GCancellable * cancellable,GError ** error)627 g_file_enumerator_iterate (GFileEnumerator  *direnum,
628                            GFileInfo       **out_info,
629                            GFile           **out_child,
630                            GCancellable     *cancellable,
631                            GError          **error)
632 {
633   gboolean ret = FALSE;
634   GError *temp_error = NULL;
635   GFileInfo *ret_info = NULL;
636 
637   static GQuark cached_info_quark;
638   static GQuark cached_child_quark;
639   static gsize quarks_initialized;
640 
641   g_return_val_if_fail (direnum != NULL, FALSE);
642   g_return_val_if_fail (out_info != NULL || out_child != NULL, FALSE);
643 
644   if (g_once_init_enter (&quarks_initialized))
645     {
646       cached_info_quark = g_quark_from_static_string ("g-cached-info");
647       cached_child_quark = g_quark_from_static_string ("g-cached-child");
648       g_once_init_leave (&quarks_initialized, 1);
649     }
650 
651   ret_info = g_file_enumerator_next_file (direnum, cancellable, &temp_error);
652   if (temp_error != NULL)
653     {
654       g_propagate_error (error, temp_error);
655       goto out;
656     }
657 
658   if (ret_info)
659     {
660       if (out_child != NULL)
661         {
662           const char *name = g_file_info_get_name (ret_info);
663 
664           if (G_UNLIKELY (name == NULL))
665             g_warning ("g_file_enumerator_iterate() created without standard::name");
666           else
667             {
668               *out_child = g_file_get_child (g_file_enumerator_get_container (direnum), name);
669               g_object_set_qdata_full ((GObject*)direnum, cached_child_quark, *out_child, (GDestroyNotify)g_object_unref);
670             }
671         }
672       if (out_info != NULL)
673         {
674           g_object_set_qdata_full ((GObject*)direnum, cached_info_quark, ret_info, (GDestroyNotify)g_object_unref);
675           *out_info = ret_info;
676         }
677       else
678         g_object_unref (ret_info);
679     }
680   else
681     {
682       if (out_info)
683         *out_info = NULL;
684       if (out_child)
685         *out_child = NULL;
686     }
687 
688   ret = TRUE;
689  out:
690   return ret;
691 }
692 
693 /**
694  * g_file_enumerator_get_container:
695  * @enumerator: a #GFileEnumerator
696  *
697  * Get the #GFile container which is being enumerated.
698  *
699  * Returns: (transfer none): the #GFile which is being enumerated.
700  *
701  * Since: 2.18
702  */
703 GFile *
g_file_enumerator_get_container(GFileEnumerator * enumerator)704 g_file_enumerator_get_container (GFileEnumerator *enumerator)
705 {
706   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
707 
708   return enumerator->priv->container;
709 }
710 
711 /**
712  * g_file_enumerator_get_child:
713  * @enumerator: a #GFileEnumerator
714  * @info: a #GFileInfo gotten from g_file_enumerator_next_file()
715  *   or the async equivalents.
716  *
717  * Return a new #GFile which refers to the file named by @info in the source
718  * directory of @enumerator.  This function is primarily intended to be used
719  * inside loops with g_file_enumerator_next_file().
720  *
721  * This is a convenience method that's equivalent to:
722  * |[<!-- language="C" -->
723  *   gchar *name = g_file_info_get_name (info);
724  *   GFile *child = g_file_get_child (g_file_enumerator_get_container (enumr),
725  *                                    name);
726  * ]|
727  *
728  * Returns: (transfer full): a #GFile for the #GFileInfo passed it.
729  *
730  * Since: 2.36
731  */
732 GFile *
g_file_enumerator_get_child(GFileEnumerator * enumerator,GFileInfo * info)733 g_file_enumerator_get_child (GFileEnumerator *enumerator,
734                              GFileInfo       *info)
735 {
736   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
737 
738   return g_file_get_child (enumerator->priv->container,
739                            g_file_info_get_name (info));
740 }
741 
742 static void
next_async_op_free(GList * files)743 next_async_op_free (GList *files)
744 {
745   g_list_free_full (files, g_object_unref);
746 }
747 
748 static void
next_files_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)749 next_files_thread (GTask        *task,
750                    gpointer      source_object,
751                    gpointer      task_data,
752                    GCancellable *cancellable)
753 {
754   GFileEnumerator *enumerator = source_object;
755   int num_files = GPOINTER_TO_INT (task_data);
756   GFileEnumeratorClass *class;
757   GList *files = NULL;
758   GError *error = NULL;
759   GFileInfo *info;
760   int i;
761 
762   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
763 
764   for (i = 0; i < num_files; i++)
765     {
766       if (g_cancellable_set_error_if_cancelled (cancellable, &error))
767 	info = NULL;
768       else
769 	info = class->next_file (enumerator, cancellable, &error);
770 
771       if (info == NULL)
772 	{
773 	  /* If we get an error after first file, return that on next operation */
774 	  if (error != NULL && i > 0)
775 	    {
776 	      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
777 		g_error_free (error); /* Never propagate cancel errors to other call */
778 	      else
779 		enumerator->priv->outstanding_error = error;
780 	      error = NULL;
781 	    }
782 
783 	  break;
784 	}
785       else
786 	files = g_list_prepend (files, info);
787     }
788 
789   if (error)
790     g_task_return_error (task, error);
791   else
792     g_task_return_pointer (task, files, (GDestroyNotify)next_async_op_free);
793 }
794 
795 static void
g_file_enumerator_real_next_files_async(GFileEnumerator * enumerator,int num_files,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)796 g_file_enumerator_real_next_files_async (GFileEnumerator     *enumerator,
797 					 int                  num_files,
798 					 int                  io_priority,
799 					 GCancellable        *cancellable,
800 					 GAsyncReadyCallback  callback,
801 					 gpointer             user_data)
802 {
803   GTask *task;
804 
805   task = g_task_new (enumerator, cancellable, callback, user_data);
806   g_task_set_source_tag (task, g_file_enumerator_real_next_files_async);
807   g_task_set_task_data (task, GINT_TO_POINTER (num_files), NULL);
808   g_task_set_priority (task, io_priority);
809 
810   g_task_run_in_thread (task, next_files_thread);
811   g_object_unref (task);
812 }
813 
814 static GList *
g_file_enumerator_real_next_files_finish(GFileEnumerator * enumerator,GAsyncResult * result,GError ** error)815 g_file_enumerator_real_next_files_finish (GFileEnumerator                *enumerator,
816 					  GAsyncResult                   *result,
817 					  GError                        **error)
818 {
819   g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
820 
821   return g_task_propagate_pointer (G_TASK (result), error);
822 }
823 
824 static void
close_async_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)825 close_async_thread (GTask        *task,
826                     gpointer      source_object,
827                     gpointer      task_data,
828                     GCancellable *cancellable)
829 {
830   GFileEnumerator *enumerator = source_object;
831   GFileEnumeratorClass *class;
832   GError *error = NULL;
833   gboolean result;
834 
835   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
836   result = class->close_fn (enumerator, cancellable, &error);
837   if (result)
838     g_task_return_boolean (task, TRUE);
839   else
840     g_task_return_error (task, error);
841 }
842 
843 static void
g_file_enumerator_real_close_async(GFileEnumerator * enumerator,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)844 g_file_enumerator_real_close_async (GFileEnumerator     *enumerator,
845 				    int                  io_priority,
846 				    GCancellable        *cancellable,
847 				    GAsyncReadyCallback  callback,
848 				    gpointer             user_data)
849 {
850   GTask *task;
851 
852   task = g_task_new (enumerator, cancellable, callback, user_data);
853   g_task_set_source_tag (task, g_file_enumerator_real_close_async);
854   g_task_set_priority (task, io_priority);
855 
856   g_task_run_in_thread (task, close_async_thread);
857   g_object_unref (task);
858 }
859 
860 static gboolean
g_file_enumerator_real_close_finish(GFileEnumerator * enumerator,GAsyncResult * result,GError ** error)861 g_file_enumerator_real_close_finish (GFileEnumerator  *enumerator,
862                                      GAsyncResult     *result,
863                                      GError          **error)
864 {
865   g_return_val_if_fail (g_task_is_valid (result, enumerator), FALSE);
866 
867   return g_task_propagate_boolean (G_TASK (result), error);
868 }
869