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