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 : 2121 : 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 : 223 : g_file_enumerator_set_property (GObject *object,
100 : : guint property_id,
101 : : const GValue *value,
102 : : GParamSpec *pspec)
103 : : {
104 : : GFileEnumerator *enumerator;
105 : :
106 : 223 : enumerator = G_FILE_ENUMERATOR (object);
107 : :
108 : 223 : switch (property_id) {
109 : 223 : case PROP_CONTAINER:
110 : 223 : enumerator->priv->container = g_value_dup_object (value);
111 : 223 : break;
112 : 0 : default:
113 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
114 : 0 : break;
115 : : }
116 : 223 : }
117 : :
118 : : static void
119 : 223 : g_file_enumerator_dispose (GObject *object)
120 : : {
121 : : GFileEnumerator *enumerator;
122 : :
123 : 223 : enumerator = G_FILE_ENUMERATOR (object);
124 : :
125 : 223 : if (enumerator->priv->container) {
126 : 223 : g_object_unref (enumerator->priv->container);
127 : 223 : enumerator->priv->container = NULL;
128 : : }
129 : :
130 : 223 : G_OBJECT_CLASS (g_file_enumerator_parent_class)->dispose (object);
131 : 223 : }
132 : :
133 : : static void
134 : 223 : g_file_enumerator_finalize (GObject *object)
135 : : {
136 : : GFileEnumerator *enumerator;
137 : :
138 : 223 : enumerator = G_FILE_ENUMERATOR (object);
139 : :
140 : 223 : if (!enumerator->priv->closed)
141 : 199 : g_file_enumerator_close (enumerator, NULL, NULL);
142 : :
143 : 223 : G_OBJECT_CLASS (g_file_enumerator_parent_class)->finalize (object);
144 : 223 : }
145 : :
146 : : static void
147 : 5 : g_file_enumerator_class_init (GFileEnumeratorClass *klass)
148 : : {
149 : 5 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
150 : :
151 : 5 : gobject_class->set_property = g_file_enumerator_set_property;
152 : 5 : gobject_class->dispose = g_file_enumerator_dispose;
153 : 5 : gobject_class->finalize = g_file_enumerator_finalize;
154 : :
155 : 5 : klass->next_files_async = g_file_enumerator_real_next_files_async;
156 : 5 : klass->next_files_finish = g_file_enumerator_real_next_files_finish;
157 : 5 : klass->close_async = g_file_enumerator_real_close_async;
158 : 5 : klass->close_finish = g_file_enumerator_real_close_finish;
159 : :
160 : : /**
161 : : * GFileEnumerator:container:
162 : : *
163 : : * The container that is being enumerated.
164 : : */
165 : 5 : 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 : 5 : }
173 : :
174 : : static void
175 : 223 : g_file_enumerator_init (GFileEnumerator *enumerator)
176 : : {
177 : 223 : enumerator->priv = g_file_enumerator_get_instance_private (enumerator);
178 : 223 : }
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 : 576 : g_file_enumerator_next_file (GFileEnumerator *enumerator,
204 : : GCancellable *cancellable,
205 : : GError **error)
206 : : {
207 : : GFileEnumeratorClass *class;
208 : : GFileInfo *info;
209 : :
210 : 576 : g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
211 : 576 : g_return_val_if_fail (enumerator != NULL, NULL);
212 : :
213 : 576 : if (enumerator->priv->closed)
214 : : {
215 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
216 : : _("Enumerator is closed"));
217 : 0 : return NULL;
218 : : }
219 : :
220 : 576 : if (enumerator->priv->pending)
221 : : {
222 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING,
223 : : _("File enumerator has outstanding operation"));
224 : 0 : return NULL;
225 : : }
226 : :
227 : 576 : if (enumerator->priv->outstanding_error)
228 : : {
229 : 0 : g_propagate_error (error, enumerator->priv->outstanding_error);
230 : 0 : enumerator->priv->outstanding_error = NULL;
231 : 0 : return NULL;
232 : : }
233 : :
234 : 576 : class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
235 : :
236 : 576 : if (cancellable)
237 : 1 : g_cancellable_push_current (cancellable);
238 : :
239 : 576 : enumerator->priv->pending = TRUE;
240 : 576 : info = (* class->next_file) (enumerator, cancellable, error);
241 : 576 : enumerator->priv->pending = FALSE;
242 : :
243 : 576 : if (cancellable)
244 : 1 : g_cancellable_pop_current (cancellable);
245 : :
246 : 576 : 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 : 223 : g_file_enumerator_close (GFileEnumerator *enumerator,
266 : : GCancellable *cancellable,
267 : : GError **error)
268 : : {
269 : : GFileEnumeratorClass *class;
270 : :
271 : 223 : g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
272 : 223 : g_return_val_if_fail (enumerator != NULL, FALSE);
273 : :
274 : 223 : class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
275 : :
276 : 223 : if (enumerator->priv->closed)
277 : 0 : return TRUE;
278 : :
279 : 223 : if (enumerator->priv->pending)
280 : : {
281 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING,
282 : : _("File enumerator has outstanding operation"));
283 : 0 : return FALSE;
284 : : }
285 : :
286 : 223 : if (cancellable)
287 : 0 : g_cancellable_push_current (cancellable);
288 : :
289 : 223 : enumerator->priv->pending = TRUE;
290 : 223 : (* class->close_fn) (enumerator, cancellable, error);
291 : 223 : enumerator->priv->pending = FALSE;
292 : 223 : enumerator->priv->closed = TRUE;
293 : :
294 : 223 : if (cancellable)
295 : 0 : g_cancellable_pop_current (cancellable);
296 : :
297 : 223 : return TRUE;
298 : : }
299 : :
300 : : static void
301 : 0 : next_async_callback_wrapper (GObject *source_object,
302 : : GAsyncResult *res,
303 : : gpointer user_data)
304 : : {
305 : 0 : GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object);
306 : :
307 : 0 : enumerator->priv->pending = FALSE;
308 : 0 : if (enumerator->priv->outstanding_callback)
309 : 0 : (*enumerator->priv->outstanding_callback) (source_object, res, user_data);
310 : 0 : g_object_unref (enumerator);
311 : 0 : }
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](iface.AsyncResult.html#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 : 0 : 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 : 0 : g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
399 : 0 : g_return_if_fail (enumerator != NULL);
400 : 0 : g_return_if_fail (num_files >= 0);
401 : :
402 : 0 : if (num_files == 0)
403 : : {
404 : : GTask *task;
405 : :
406 : 0 : task = g_task_new (enumerator, cancellable, callback, user_data);
407 : 0 : g_task_set_source_tag (task, g_file_enumerator_next_files_async);
408 : 0 : g_task_return_pointer (task, NULL, NULL);
409 : 0 : g_object_unref (task);
410 : 0 : return;
411 : : }
412 : :
413 : 0 : if (enumerator->priv->closed)
414 : : {
415 : 0 : 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 : 0 : _("File enumerator is already closed"));
419 : 0 : return;
420 : : }
421 : :
422 : 0 : if (enumerator->priv->pending)
423 : : {
424 : 0 : 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 : 0 : _("File enumerator has outstanding operation"));
428 : 0 : return;
429 : : }
430 : :
431 : 0 : class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
432 : :
433 : 0 : enumerator->priv->pending = TRUE;
434 : 0 : enumerator->priv->outstanding_callback = callback;
435 : 0 : g_object_ref (enumerator);
436 : 0 : (* 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 : 0 : g_file_enumerator_next_files_finish (GFileEnumerator *enumerator,
455 : : GAsyncResult *result,
456 : : GError **error)
457 : : {
458 : : GFileEnumeratorClass *class;
459 : :
460 : 0 : g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
461 : 0 : g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
462 : :
463 : 0 : if (g_async_result_legacy_propagate_error (result, error))
464 : 0 : return NULL;
465 : 0 : else if (g_async_result_is_tagged (result, g_file_enumerator_next_files_async))
466 : 0 : return g_task_propagate_pointer (G_TASK (result), error);
467 : :
468 : 0 : class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
469 : 0 : return class->next_files_finish (enumerator, result, error);
470 : : }
471 : :
472 : : static void
473 : 0 : close_async_callback_wrapper (GObject *source_object,
474 : : GAsyncResult *res,
475 : : gpointer user_data)
476 : : {
477 : 0 : GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object);
478 : :
479 : 0 : enumerator->priv->pending = FALSE;
480 : 0 : enumerator->priv->closed = TRUE;
481 : 0 : if (enumerator->priv->outstanding_callback)
482 : 0 : (*enumerator->priv->outstanding_callback) (source_object, res, user_data);
483 : 0 : g_object_unref (enumerator);
484 : 0 : }
485 : :
486 : : /**
487 : : * g_file_enumerator_close_async:
488 : : * @enumerator: a #GFileEnumerator.
489 : : * @io_priority: the [I/O priority](iface.AsyncResult.html#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 : 0 : 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 : 0 : g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
512 : :
513 : 0 : if (enumerator->priv->closed)
514 : : {
515 : 0 : g_task_report_new_error (enumerator, callback, user_data,
516 : : g_file_enumerator_close_async,
517 : : G_IO_ERROR, G_IO_ERROR_CLOSED,
518 : 0 : _("File enumerator is already closed"));
519 : 0 : return;
520 : : }
521 : :
522 : 0 : if (enumerator->priv->pending)
523 : : {
524 : 0 : g_task_report_new_error (enumerator, callback, user_data,
525 : : g_file_enumerator_close_async,
526 : : G_IO_ERROR, G_IO_ERROR_PENDING,
527 : 0 : _("File enumerator has outstanding operation"));
528 : 0 : return;
529 : : }
530 : :
531 : 0 : class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
532 : :
533 : 0 : enumerator->priv->pending = TRUE;
534 : 0 : enumerator->priv->outstanding_callback = callback;
535 : 0 : g_object_ref (enumerator);
536 : 0 : (* 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 : 0 : g_file_enumerator_close_finish (GFileEnumerator *enumerator,
562 : : GAsyncResult *result,
563 : : GError **error)
564 : : {
565 : : GFileEnumeratorClass *class;
566 : :
567 : 0 : g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
568 : 0 : g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
569 : :
570 : 0 : if (g_async_result_legacy_propagate_error (result, error))
571 : 0 : return FALSE;
572 : 0 : else if (g_async_result_is_tagged (result, g_file_enumerator_close_async))
573 : 0 : return g_task_propagate_boolean (G_TASK (result), error);
574 : :
575 : 0 : class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
576 : 0 : 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 : 9 : g_file_enumerator_is_closed (GFileEnumerator *enumerator)
589 : : {
590 : 9 : g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
591 : :
592 : 9 : 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 : 0 : g_file_enumerator_has_pending (GFileEnumerator *enumerator)
605 : : {
606 : 0 : g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
607 : :
608 : 0 : 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 : 0 : g_file_enumerator_set_pending (GFileEnumerator *enumerator,
620 : : gboolean pending)
621 : : {
622 : 0 : g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
623 : :
624 : 0 : 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 : 298 : g_file_enumerator_iterate (GFileEnumerator *direnum,
679 : : GFileInfo **out_info,
680 : : GFile **out_child,
681 : : GCancellable *cancellable,
682 : : GError **error)
683 : : {
684 : 298 : gboolean ret = FALSE;
685 : 298 : GError *temp_error = NULL;
686 : 298 : GFileInfo *ret_info = NULL;
687 : :
688 : : static GQuark cached_info_quark;
689 : : static GQuark cached_child_quark;
690 : : static gsize quarks_initialized;
691 : :
692 : 298 : g_return_val_if_fail (direnum != NULL, FALSE);
693 : 298 : g_return_val_if_fail (out_info != NULL || out_child != NULL, FALSE);
694 : :
695 : 298 : if (g_once_init_enter (&quarks_initialized))
696 : : {
697 : 1 : cached_info_quark = g_quark_from_static_string ("g-cached-info");
698 : 1 : cached_child_quark = g_quark_from_static_string ("g-cached-child");
699 : 1 : g_once_init_leave (&quarks_initialized, 1);
700 : : }
701 : :
702 : 298 : ret_info = g_file_enumerator_next_file (direnum, cancellable, &temp_error);
703 : 298 : if (temp_error != NULL)
704 : : {
705 : 0 : g_propagate_error (error, temp_error);
706 : 0 : goto out;
707 : : }
708 : :
709 : 298 : if (ret_info)
710 : : {
711 : 198 : if (out_child != NULL)
712 : : {
713 : 2 : const char *name = g_file_info_get_name (ret_info);
714 : :
715 : 2 : if (G_UNLIKELY (name == NULL))
716 : : {
717 : 0 : g_critical ("g_file_enumerator_iterate() created without standard::name");
718 : : g_return_val_if_reached (FALSE);
719 : : }
720 : : else
721 : : {
722 : 2 : *out_child = g_file_get_child (g_file_enumerator_get_container (direnum), name);
723 : 2 : g_object_set_qdata_full ((GObject*)direnum, cached_child_quark, *out_child, (GDestroyNotify)g_object_unref);
724 : : }
725 : : }
726 : 198 : if (out_info != NULL)
727 : : {
728 : 196 : g_object_set_qdata_full ((GObject*)direnum, cached_info_quark, ret_info, (GDestroyNotify)g_object_unref);
729 : 196 : *out_info = ret_info;
730 : : }
731 : : else
732 : 2 : g_object_unref (ret_info);
733 : : }
734 : : else
735 : : {
736 : 100 : if (out_info)
737 : 99 : *out_info = NULL;
738 : 100 : if (out_child)
739 : 1 : *out_child = NULL;
740 : : }
741 : :
742 : 298 : ret = TRUE;
743 : 298 : out:
744 : 298 : 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 : 11 : g_file_enumerator_get_container (GFileEnumerator *enumerator)
759 : : {
760 : 11 : g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
761 : :
762 : 11 : 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 : 55 : g_file_enumerator_get_child (GFileEnumerator *enumerator,
791 : : GFileInfo *info)
792 : : {
793 : : const gchar *name;
794 : :
795 : 55 : g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
796 : 55 : g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
797 : :
798 : 55 : name = g_file_info_get_name (info);
799 : :
800 : 55 : if (G_UNLIKELY (name == NULL))
801 : : {
802 : 0 : g_critical ("GFileEnumerator created without standard::name");
803 : : g_return_val_if_reached (NULL);
804 : : }
805 : :
806 : 55 : return g_file_get_child (enumerator->priv->container, name);
807 : : }
808 : :
809 : : static void
810 : 0 : next_async_op_free (GList *files)
811 : : {
812 : 0 : g_list_free_full (files, g_object_unref);
813 : 0 : }
814 : :
815 : : static void
816 : 0 : next_files_thread (GTask *task,
817 : : gpointer source_object,
818 : : gpointer task_data,
819 : : GCancellable *cancellable)
820 : : {
821 : 0 : GFileEnumerator *enumerator = source_object;
822 : 0 : int num_files = GPOINTER_TO_INT (task_data);
823 : : GFileEnumeratorClass *class;
824 : 0 : GList *files = NULL;
825 : 0 : GError *error = NULL;
826 : : GFileInfo *info;
827 : : int i;
828 : :
829 : 0 : class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
830 : :
831 : 0 : for (i = 0; i < num_files; i++)
832 : : {
833 : 0 : if (g_cancellable_set_error_if_cancelled (cancellable, &error))
834 : 0 : info = NULL;
835 : : else
836 : 0 : info = class->next_file (enumerator, cancellable, &error);
837 : :
838 : 0 : if (info == NULL)
839 : : {
840 : : /* If we get an error after first file, return that on next operation */
841 : 0 : if (error != NULL && i > 0)
842 : : {
843 : 0 : if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
844 : 0 : g_error_free (error); /* Never propagate cancel errors to other call */
845 : : else
846 : 0 : enumerator->priv->outstanding_error = error;
847 : 0 : error = NULL;
848 : : }
849 : :
850 : 0 : break;
851 : : }
852 : : else
853 : 0 : files = g_list_prepend (files, info);
854 : : }
855 : :
856 : 0 : if (error)
857 : : {
858 : 0 : g_list_free_full (files, g_object_unref);
859 : 0 : g_task_return_error (task, error);
860 : : }
861 : : else
862 : 0 : g_task_return_pointer (task, files, (GDestroyNotify)next_async_op_free);
863 : 0 : }
864 : :
865 : : static void
866 : 0 : 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 : 0 : task = g_task_new (enumerator, cancellable, callback, user_data);
876 : 0 : g_task_set_source_tag (task, g_file_enumerator_real_next_files_async);
877 : 0 : g_task_set_task_data (task, GINT_TO_POINTER (num_files), NULL);
878 : 0 : g_task_set_priority (task, io_priority);
879 : :
880 : 0 : g_task_run_in_thread (task, next_files_thread);
881 : 0 : g_object_unref (task);
882 : 0 : }
883 : :
884 : : static GList *
885 : 0 : g_file_enumerator_real_next_files_finish (GFileEnumerator *enumerator,
886 : : GAsyncResult *result,
887 : : GError **error)
888 : : {
889 : 0 : g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
890 : :
891 : 0 : return g_task_propagate_pointer (G_TASK (result), error);
892 : : }
893 : :
894 : : static void
895 : 0 : close_async_thread (GTask *task,
896 : : gpointer source_object,
897 : : gpointer task_data,
898 : : GCancellable *cancellable)
899 : : {
900 : 0 : GFileEnumerator *enumerator = source_object;
901 : : GFileEnumeratorClass *class;
902 : 0 : GError *error = NULL;
903 : : gboolean result;
904 : :
905 : 0 : class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
906 : 0 : result = class->close_fn (enumerator, cancellable, &error);
907 : 0 : if (result)
908 : 0 : g_task_return_boolean (task, TRUE);
909 : : else
910 : 0 : g_task_return_error (task, error);
911 : 0 : }
912 : :
913 : : static void
914 : 0 : 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 : 0 : task = g_task_new (enumerator, cancellable, callback, user_data);
923 : 0 : g_task_set_source_tag (task, g_file_enumerator_real_close_async);
924 : 0 : g_task_set_priority (task, io_priority);
925 : :
926 : 0 : g_task_run_in_thread (task, close_async_thread);
927 : 0 : g_object_unref (task);
928 : 0 : }
929 : :
930 : : static gboolean
931 : 0 : g_file_enumerator_real_close_finish (GFileEnumerator *enumerator,
932 : : GAsyncResult *result,
933 : : GError **error)
934 : : {
935 : 0 : g_return_val_if_fail (g_task_is_valid (result, enumerator), FALSE);
936 : :
937 : 0 : return g_task_propagate_boolean (G_TASK (result), error);
938 : : }
|