1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
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 struct _GFileEnumeratorPrivate {
33 /* TODO: Should be public for subclasses? */
34 GFile *container;
35 guint closed : 1;
36 guint pending : 1;
37 GAsyncReadyCallback outstanding_callback;
38 GError *outstanding_error;
39 };
40
41 /**
42 * GFileEnumerator:
43 *
44 * `GFileEnumerator` allows you to operate on a set of [iface@Gio.File] objects,
45 * returning a [class@Gio.FileInfo] structure for each file enumerated (e.g.
46 * [method@Gio.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 * [method@Gio.FileEnumerator.next_file] or its asynchronous version,
51 * [method@Gio.FileEnumerator.next_files_async]. Note that the asynchronous
52 * version will return a list of [class@Gio.FileInfo] objects, 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 [method@GLib.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 [method@Gio.FileEnumerator.close], or
67 * its asynchronous version, [method@Gio.FileEnumerator.close_async]. Once
68 * a `GFileEnumerator` is closed, no further actions may be performed
69 * on it, and it should be freed with [method@GObject.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
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
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
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
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 /**
161 * GFileEnumerator:container:
162 *
163 * The container that is being enumerated.
164 */
165 g_object_class_install_property
166 (gobject_class, PROP_CONTAINER,
167 g_param_spec_object ("container", NULL, NULL,
168 G_TYPE_FILE,
169 G_PARAM_WRITABLE |
170 G_PARAM_CONSTRUCT_ONLY |
171 G_PARAM_STATIC_STRINGS));
172 }
173
174 static void
175 g_file_enumerator_init (GFileEnumerator *enumerator)
176 {
177 enumerator->priv = g_file_enumerator_get_instance_private (enumerator);
178 }
179
180 /**
181 * g_file_enumerator_next_file:
182 * @enumerator: a #GFileEnumerator.
183 * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
184 * @error: location to store the error occurring, or %NULL to ignore
185 *
186 * Returns information for the next file in the enumerated object.
187 * Will block until the information is available. The #GFileInfo
188 * returned from this function will contain attributes that match the
189 * attribute string that was passed when the #GFileEnumerator was created.
190 *
191 * See the documentation of #GFileEnumerator for information about the
192 * order of returned files.
193 *
194 * On error, returns %NULL and sets @error to the error. If the
195 * enumerator is at the end, %NULL will be returned and @error will
196 * be unset.
197 *
198 * Returns: (nullable) (transfer full): A #GFileInfo or %NULL on error
199 * or end of enumerator. Free the returned object with
200 * g_object_unref() when no longer needed.
201 **/
202 GFileInfo *
203 g_file_enumerator_next_file (GFileEnumerator *enumerator,
204 GCancellable *cancellable,
205 GError **error)
206 {
207 GFileEnumeratorClass *class;
208 GFileInfo *info;
209
210 g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
211 g_return_val_if_fail (enumerator != NULL, NULL);
212
213 if (enumerator->priv->closed)
214 {
215 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
216 _("Enumerator is closed"));
217 return NULL;
218 }
219
220 if (enumerator->priv->pending)
221 {
222 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING,
223 _("File enumerator has outstanding operation"));
224 return NULL;
225 }
226
227 if (enumerator->priv->outstanding_error)
228 {
229 g_propagate_error (error, enumerator->priv->outstanding_error);
230 enumerator->priv->outstanding_error = NULL;
231 return NULL;
232 }
233
234 class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
235
236 if (cancellable)
237 g_cancellable_push_current (cancellable);
238
239 enumerator->priv->pending = TRUE;
240 info = (* class->next_file) (enumerator, cancellable, error);
241 enumerator->priv->pending = FALSE;
242
243 if (cancellable)
244 g_cancellable_pop_current (cancellable);
245
246 return info;
247 }
248
249 /**
250 * g_file_enumerator_close:
251 * @enumerator: a #GFileEnumerator.
252 * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
253 * @error: location to store the error occurring, or %NULL to ignore
254 *
255 * Releases all resources used by this enumerator, making the
256 * enumerator return %G_IO_ERROR_CLOSED on all calls.
257 *
258 * This will be automatically called when the last reference
259 * is dropped, but you might want to call this function to make
260 * sure resources are released as early as possible.
261 *
262 * Returns: #TRUE on success or #FALSE on error.
263 **/
264 gboolean
265 g_file_enumerator_close (GFileEnumerator *enumerator,
266 GCancellable *cancellable,
267 GError **error)
268 {
269 GFileEnumeratorClass *class;
270
271 g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
272 g_return_val_if_fail (enumerator != NULL, FALSE);
273
274 class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
275
276 if (enumerator->priv->closed)
277 return TRUE;
278
279 if (enumerator->priv->pending)
280 {
281 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING,
282 _("File enumerator has outstanding operation"));
283 return FALSE;
284 }
285
286 if (cancellable)
287 g_cancellable_push_current (cancellable);
288
289 enumerator->priv->pending = TRUE;
290 (* class->close_fn) (enumerator, cancellable, error);
291 enumerator->priv->pending = FALSE;
292 enumerator->priv->closed = TRUE;
293
294 if (cancellable)
295 g_cancellable_pop_current (cancellable);
296
297 return TRUE;
298 }
299
300 static void
301 next_async_callback_wrapper (GObject *source_object,
302 GAsyncResult *res,
303 gpointer user_data)
304 {
305 GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object);
306
307 enumerator->priv->pending = FALSE;
308 if (enumerator->priv->outstanding_callback)
309 (*enumerator->priv->outstanding_callback) (source_object, res, user_data);
310 g_object_unref (enumerator);
311 }
312
313 /**
314 * g_file_enumerator_next_files_async:
315 * @enumerator: a #GFileEnumerator.
316 * @num_files: the number of file info objects to request
317 * @io_priority: the [I/O priority][io-priority] of the request
318 * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
319 * @callback: (scope async) (closure user_data): a #GAsyncReadyCallback
320 * to call when the request is satisfied
321 * @user_data: the data to pass to callback function
322 *
323 * Request information for a number of files from the enumerator asynchronously.
324 * When all I/O for the operation is finished the @callback will be called with
325 * the requested information.
326 *
327 * See the documentation of #GFileEnumerator for information about the
328 * order of returned files.
329 *
330 * Once the end of the enumerator is reached, or if an error occurs, the
331 * @callback will be called with an empty list. In this case, the previous call
332 * to g_file_enumerator_next_files_async() will typically have returned fewer
333 * than @num_files items.
334 *
335 * If a request is cancelled the callback will be called with
336 * %G_IO_ERROR_CANCELLED.
337 *
338 * This leads to the following pseudo-code usage:
339 * |[
340 * g_autoptr(GFile) dir = get_directory ();
341 * g_autoptr(GFileEnumerator) enumerator = NULL;
342 * g_autolist(GFileInfo) files = NULL;
343 * g_autoptr(GError) local_error = NULL;
344 *
345 * enumerator = yield g_file_enumerate_children_async (dir,
346 * G_FILE_ATTRIBUTE_STANDARD_NAME ","
347 * G_FILE_ATTRIBUTE_STANDARD_TYPE,
348 * G_FILE_QUERY_INFO_NONE,
349 * G_PRIORITY_DEFAULT,
350 * cancellable,
351 * …,
352 * &local_error);
353 * if (enumerator == NULL)
354 * g_error ("Error enumerating: %s", local_error->message);
355 *
356 * // Loop until no files are returned, either because the end of the enumerator
357 * // has been reached, or an error was returned.
358 * do
359 * {
360 * files = yield g_file_enumerator_next_files_async (enumerator,
361 * 5, // number of files to request
362 * G_PRIORITY_DEFAULT,
363 * cancellable,
364 * …,
365 * &local_error);
366 *
367 * // Process the returned files, but don’t assume that exactly 5 were returned.
368 * for (GList *l = files; l != NULL; l = l->next)
369 * {
370 * GFileInfo *info = l->data;
371 * handle_file_info (info);
372 * }
373 * }
374 * while (files != NULL);
375 *
376 * if (local_error != NULL &&
377 * !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
378 * g_error ("Error while enumerating: %s", local_error->message);
379 * ]|
380 *
381 * During an async request no other sync and async calls are allowed, and will
382 * result in %G_IO_ERROR_PENDING errors.
383 *
384 * Any outstanding I/O request with higher priority (lower numerical value) will
385 * be executed before an outstanding request with lower priority. Default
386 * priority is %G_PRIORITY_DEFAULT.
387 **/
388 void
389 g_file_enumerator_next_files_async (GFileEnumerator *enumerator,
390 int num_files,
391 int io_priority,
392 GCancellable *cancellable,
393 GAsyncReadyCallback callback,
394 gpointer user_data)
395 {
396 GFileEnumeratorClass *class;
397
398 g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
399 g_return_if_fail (enumerator != NULL);
400 g_return_if_fail (num_files >= 0);
401
402 if (num_files == 0)
403 {
404 GTask *task;
405
406 task = g_task_new (enumerator, cancellable, callback, user_data);
407 g_task_set_source_tag (task, g_file_enumerator_next_files_async);
408 g_task_return_pointer (task, NULL, NULL);
409 g_object_unref (task);
410 return;
411 }
412
413 if (enumerator->priv->closed)
414 {
415 g_task_report_new_error (enumerator, callback, user_data,
416 g_file_enumerator_next_files_async,
417 G_IO_ERROR, G_IO_ERROR_CLOSED,
418 _("File enumerator is already closed"));
419 return;
420 }
421
422 if (enumerator->priv->pending)
423 {
424 g_task_report_new_error (enumerator, callback, user_data,
425 g_file_enumerator_next_files_async,
426 G_IO_ERROR, G_IO_ERROR_PENDING,
427 _("File enumerator has outstanding operation"));
428 return;
429 }
430
431 class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
432
433 enumerator->priv->pending = TRUE;
434 enumerator->priv->outstanding_callback = callback;
435 g_object_ref (enumerator);
436 (* class->next_files_async) (enumerator, num_files, io_priority, cancellable,
437 next_async_callback_wrapper, user_data);
438 }
439
440 /**
441 * g_file_enumerator_next_files_finish:
442 * @enumerator: a #GFileEnumerator.
443 * @result: a #GAsyncResult.
444 * @error: a #GError location to store the error occurring, or %NULL to
445 * ignore.
446 *
447 * Finishes the asynchronous operation started with g_file_enumerator_next_files_async().
448 *
449 * Returns: (transfer full) (element-type Gio.FileInfo): a #GList of #GFileInfos. You must free the list with
450 * g_list_free() and unref the infos with g_object_unref() when you're
451 * done with them.
452 **/
453 GList *
454 g_file_enumerator_next_files_finish (GFileEnumerator *enumerator,
455 GAsyncResult *result,
456 GError **error)
457 {
458 GFileEnumeratorClass *class;
459
460 g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
461 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
462
463 if (g_async_result_legacy_propagate_error (result, error))
464 return NULL;
465 else if (g_async_result_is_tagged (result, g_file_enumerator_next_files_async))
466 return g_task_propagate_pointer (G_TASK (result), error);
467
468 class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
469 return class->next_files_finish (enumerator, result, error);
470 }
471
472 static void
473 close_async_callback_wrapper (GObject *source_object,
474 GAsyncResult *res,
475 gpointer user_data)
476 {
477 GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object);
478
479 enumerator->priv->pending = FALSE;
480 enumerator->priv->closed = TRUE;
481 if (enumerator->priv->outstanding_callback)
482 (*enumerator->priv->outstanding_callback) (source_object, res, user_data);
483 g_object_unref (enumerator);
484 }
485
486 /**
487 * g_file_enumerator_close_async:
488 * @enumerator: a #GFileEnumerator.
489 * @io_priority: the [I/O priority][io-priority] of the request
490 * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
491 * @callback: (scope async) (closure user_data): a #GAsyncReadyCallback
492 * to call when the request is satisfied
493 * @user_data: the data to pass to callback function
494 *
495 * Asynchronously closes the file enumerator.
496 *
497 * If @cancellable is not %NULL, then the operation can be cancelled by
498 * triggering the cancellable object from another thread. If the operation
499 * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned in
500 * g_file_enumerator_close_finish().
501 **/
502 void
503 g_file_enumerator_close_async (GFileEnumerator *enumerator,
504 int io_priority,
505 GCancellable *cancellable,
506 GAsyncReadyCallback callback,
507 gpointer user_data)
508 {
509 GFileEnumeratorClass *class;
510
511 g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
512
513 if (enumerator->priv->closed)
514 {
515 g_task_report_new_error (enumerator, callback, user_data,
516 g_file_enumerator_close_async,
517 G_IO_ERROR, G_IO_ERROR_CLOSED,
518 _("File enumerator is already closed"));
519 return;
520 }
521
522 if (enumerator->priv->pending)
523 {
524 g_task_report_new_error (enumerator, callback, user_data,
525 g_file_enumerator_close_async,
526 G_IO_ERROR, G_IO_ERROR_PENDING,
527 _("File enumerator has outstanding operation"));
528 return;
529 }
530
531 class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
532
533 enumerator->priv->pending = TRUE;
534 enumerator->priv->outstanding_callback = callback;
535 g_object_ref (enumerator);
536 (* class->close_async) (enumerator, io_priority, cancellable,
537 close_async_callback_wrapper, user_data);
538 }
539
540 /**
541 * g_file_enumerator_close_finish:
542 * @enumerator: a #GFileEnumerator.
543 * @result: a #GAsyncResult.
544 * @error: a #GError location to store the error occurring, or %NULL to
545 * ignore.
546 *
547 * Finishes closing a file enumerator, started from g_file_enumerator_close_async().
548 *
549 * If the file enumerator was already closed when g_file_enumerator_close_async()
550 * was called, then this function will report %G_IO_ERROR_CLOSED in @error, and
551 * return %FALSE. If the file enumerator had pending operation when the close
552 * operation was started, then this function will report %G_IO_ERROR_PENDING, and
553 * return %FALSE. If @cancellable was not %NULL, then the operation may have been
554 * cancelled by triggering the cancellable object from another thread. If the operation
555 * was cancelled, the error %G_IO_ERROR_CANCELLED will be set, and %FALSE will be
556 * returned.
557 *
558 * Returns: %TRUE if the close operation has finished successfully.
559 **/
560 gboolean
561 g_file_enumerator_close_finish (GFileEnumerator *enumerator,
562 GAsyncResult *result,
563 GError **error)
564 {
565 GFileEnumeratorClass *class;
566
567 g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
568 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
569
570 if (g_async_result_legacy_propagate_error (result, error))
571 return FALSE;
572 else if (g_async_result_is_tagged (result, g_file_enumerator_close_async))
573 return g_task_propagate_boolean (G_TASK (result), error);
574
575 class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
576 return class->close_finish (enumerator, result, error);
577 }
578
579 /**
580 * g_file_enumerator_is_closed:
581 * @enumerator: a #GFileEnumerator.
582 *
583 * Checks if the file enumerator has been closed.
584 *
585 * Returns: %TRUE if the @enumerator is closed.
586 **/
587 gboolean
588 g_file_enumerator_is_closed (GFileEnumerator *enumerator)
589 {
590 g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
591
592 return enumerator->priv->closed;
593 }
594
595 /**
596 * g_file_enumerator_has_pending:
597 * @enumerator: a #GFileEnumerator.
598 *
599 * Checks if the file enumerator has pending operations.
600 *
601 * Returns: %TRUE if the @enumerator has pending operations.
602 **/
603 gboolean
604 g_file_enumerator_has_pending (GFileEnumerator *enumerator)
605 {
606 g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
607
608 return enumerator->priv->pending;
609 }
610
611 /**
612 * g_file_enumerator_set_pending:
613 * @enumerator: a #GFileEnumerator.
614 * @pending: a boolean value.
615 *
616 * Sets the file enumerator as having pending operations.
617 **/
618 void
619 g_file_enumerator_set_pending (GFileEnumerator *enumerator,
620 gboolean pending)
621 {
622 g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
623
624 enumerator->priv->pending = pending;
625 }
626
627 /**
628 * g_file_enumerator_iterate:
629 * @direnum: an open #GFileEnumerator
630 * @out_info: (out) (transfer none) (optional): Output location for the next #GFileInfo, or %NULL
631 * @out_child: (out) (transfer none) (optional): Output location for the next #GFile, or %NULL
632 * @cancellable: a #GCancellable
633 * @error: a #GError
634 *
635 * This is a version of g_file_enumerator_next_file() that's easier to
636 * use correctly from C programs. With g_file_enumerator_next_file(),
637 * the gboolean return value signifies "end of iteration or error", which
638 * requires allocation of a temporary #GError.
639 *
640 * In contrast, with this function, a %FALSE return from
641 * g_file_enumerator_iterate() *always* means
642 * "error". End of iteration is signaled by @out_info or @out_child being %NULL.
643 *
644 * Another crucial difference is that the references for @out_info and
645 * @out_child are owned by @direnum (they are cached as hidden
646 * properties). You must not unref them in your own code. This makes
647 * memory management significantly easier for C code in combination
648 * with loops.
649 *
650 * Finally, this function optionally allows retrieving a #GFile as
651 * well.
652 *
653 * You must specify at least one of @out_info or @out_child.
654 *
655 * The code pattern for correctly using g_file_enumerator_iterate() from C
656 * is:
657 *
658 * |[
659 * direnum = g_file_enumerate_children (file, ...);
660 * while (TRUE)
661 * {
662 * GFileInfo *info;
663 * if (!g_file_enumerator_iterate (direnum, &info, NULL, cancellable, error))
664 * goto out;
665 * if (!info)
666 * break;
667 * ... do stuff with "info"; do not unref it! ...
668 * }
669 *
670 * out:
671 * g_object_unref (direnum); // Note: frees the last @info
672 * ]|
673 *
674 *
675 * Since: 2.44
676 */
677 gboolean
678 g_file_enumerator_iterate (GFileEnumerator *direnum,
679 GFileInfo **out_info,
680 GFile **out_child,
681 GCancellable *cancellable,
682 GError **error)
683 {
684 gboolean ret = FALSE;
685 GError *temp_error = NULL;
686 GFileInfo *ret_info = NULL;
687
688 static GQuark cached_info_quark;
689 static GQuark cached_child_quark;
690 static gsize quarks_initialized;
691
692 g_return_val_if_fail (direnum != NULL, FALSE);
693 g_return_val_if_fail (out_info != NULL || out_child != NULL, FALSE);
694
695 if (g_once_init_enter (&quarks_initialized))
696 {
697 cached_info_quark = g_quark_from_static_string ("g-cached-info");
698 cached_child_quark = g_quark_from_static_string ("g-cached-child");
699 g_once_init_leave (&quarks_initialized, 1);
700 }
701
702 ret_info = g_file_enumerator_next_file (direnum, cancellable, &temp_error);
703 if (temp_error != NULL)
704 {
705 g_propagate_error (error, temp_error);
706 goto out;
707 }
708
709 if (ret_info)
710 {
711 if (out_child != NULL)
712 {
713 const char *name = g_file_info_get_name (ret_info);
714
715 if (G_UNLIKELY (name == NULL))
716 {
717 g_critical ("g_file_enumerator_iterate() created without standard::name");
718 g_return_val_if_reached (FALSE);
719 }
720 else
721 {
722 *out_child = g_file_get_child (g_file_enumerator_get_container (direnum), name);
723 g_object_set_qdata_full ((GObject*)direnum, cached_child_quark, *out_child, (GDestroyNotify)g_object_unref);
724 }
725 }
726 if (out_info != NULL)
727 {
728 g_object_set_qdata_full ((GObject*)direnum, cached_info_quark, ret_info, (GDestroyNotify)g_object_unref);
729 *out_info = ret_info;
730 }
731 else
732 g_object_unref (ret_info);
733 }
734 else
735 {
736 if (out_info)
737 *out_info = NULL;
738 if (out_child)
739 *out_child = NULL;
740 }
741
742 ret = TRUE;
743 out:
744 return ret;
745 }
746
747 /**
748 * g_file_enumerator_get_container:
749 * @enumerator: a #GFileEnumerator
750 *
751 * Get the #GFile container which is being enumerated.
752 *
753 * Returns: (transfer none): the #GFile which is being enumerated.
754 *
755 * Since: 2.18
756 */
757 GFile *
758 g_file_enumerator_get_container (GFileEnumerator *enumerator)
759 {
760 g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
761
762 return enumerator->priv->container;
763 }
764
765 /**
766 * g_file_enumerator_get_child:
767 * @enumerator: a #GFileEnumerator
768 * @info: a #GFileInfo gotten from g_file_enumerator_next_file()
769 * or the async equivalents.
770 *
771 * Return a new #GFile which refers to the file named by @info in the source
772 * directory of @enumerator. This function is primarily intended to be used
773 * inside loops with g_file_enumerator_next_file().
774 *
775 * To use this, %G_FILE_ATTRIBUTE_STANDARD_NAME must have been listed in the
776 * attributes list used when creating the #GFileEnumerator.
777 *
778 * This is a convenience method that's equivalent to:
779 * |[<!-- language="C" -->
780 * gchar *name = g_file_info_get_name (info);
781 * GFile *child = g_file_get_child (g_file_enumerator_get_container (enumr),
782 * name);
783 * ]|
784 *
785 * Returns: (transfer full): a #GFile for the #GFileInfo passed it.
786 *
787 * Since: 2.36
788 */
789 GFile *
790 g_file_enumerator_get_child (GFileEnumerator *enumerator,
791 GFileInfo *info)
792 {
793 const gchar *name;
794
795 g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
796 g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
797
798 name = g_file_info_get_name (info);
799
800 if (G_UNLIKELY (name == NULL))
801 {
802 g_critical ("GFileEnumerator created without standard::name");
803 g_return_val_if_reached (NULL);
804 }
805
806 return g_file_get_child (enumerator->priv->container, name);
807 }
808
809 static void
810 next_async_op_free (GList *files)
811 {
812 g_list_free_full (files, g_object_unref);
813 }
814
815 static void
816 next_files_thread (GTask *task,
817 gpointer source_object,
818 gpointer task_data,
819 GCancellable *cancellable)
820 {
821 GFileEnumerator *enumerator = source_object;
822 int num_files = GPOINTER_TO_INT (task_data);
823 GFileEnumeratorClass *class;
824 GList *files = NULL;
825 GError *error = NULL;
826 GFileInfo *info;
827 int i;
828
829 class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
830
831 for (i = 0; i < num_files; i++)
832 {
833 if (g_cancellable_set_error_if_cancelled (cancellable, &error))
834 info = NULL;
835 else
836 info = class->next_file (enumerator, cancellable, &error);
837
838 if (info == NULL)
839 {
840 /* If we get an error after first file, return that on next operation */
841 if (error != NULL && i > 0)
842 {
843 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
844 g_error_free (error); /* Never propagate cancel errors to other call */
845 else
846 enumerator->priv->outstanding_error = error;
847 error = NULL;
848 }
849
850 break;
851 }
852 else
853 files = g_list_prepend (files, info);
854 }
855
856 if (error)
857 {
858 g_list_free_full (files, g_object_unref);
859 g_task_return_error (task, error);
860 }
861 else
862 g_task_return_pointer (task, files, (GDestroyNotify)next_async_op_free);
863 }
864
865 static void
866 g_file_enumerator_real_next_files_async (GFileEnumerator *enumerator,
867 int num_files,
868 int io_priority,
869 GCancellable *cancellable,
870 GAsyncReadyCallback callback,
871 gpointer user_data)
872 {
873 GTask *task;
874
875 task = g_task_new (enumerator, cancellable, callback, user_data);
876 g_task_set_source_tag (task, g_file_enumerator_real_next_files_async);
877 g_task_set_task_data (task, GINT_TO_POINTER (num_files), NULL);
878 g_task_set_priority (task, io_priority);
879
880 g_task_run_in_thread (task, next_files_thread);
881 g_object_unref (task);
882 }
883
884 static GList *
885 g_file_enumerator_real_next_files_finish (GFileEnumerator *enumerator,
886 GAsyncResult *result,
887 GError **error)
888 {
889 g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
890
891 return g_task_propagate_pointer (G_TASK (result), error);
892 }
893
894 static void
895 close_async_thread (GTask *task,
896 gpointer source_object,
897 gpointer task_data,
898 GCancellable *cancellable)
899 {
900 GFileEnumerator *enumerator = source_object;
901 GFileEnumeratorClass *class;
902 GError *error = NULL;
903 gboolean result;
904
905 class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
906 result = class->close_fn (enumerator, cancellable, &error);
907 if (result)
908 g_task_return_boolean (task, TRUE);
909 else
910 g_task_return_error (task, error);
911 }
912
913 static void
914 g_file_enumerator_real_close_async (GFileEnumerator *enumerator,
915 int io_priority,
916 GCancellable *cancellable,
917 GAsyncReadyCallback callback,
918 gpointer user_data)
919 {
920 GTask *task;
921
922 task = g_task_new (enumerator, cancellable, callback, user_data);
923 g_task_set_source_tag (task, g_file_enumerator_real_close_async);
924 g_task_set_priority (task, io_priority);
925
926 g_task_run_in_thread (task, close_async_thread);
927 g_object_unref (task);
928 }
929
930 static gboolean
931 g_file_enumerator_real_close_finish (GFileEnumerator *enumerator,
932 GAsyncResult *result,
933 GError **error)
934 {
935 g_return_val_if_fail (g_task_is_valid (result, enumerator), FALSE);
936
937 return g_task_propagate_boolean (G_TASK (result), error);
938 }