/src/tinysparql/subprojects/glib-2.80.3/gio/gfileenumerator.c
Line | Count | Source (jump to first uncovered line) |
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 | 32.8k | { |
104 | 32.8k | GFileEnumerator *enumerator; |
105 | | |
106 | 32.8k | enumerator = G_FILE_ENUMERATOR (object); |
107 | | |
108 | 32.8k | switch (property_id) { |
109 | 32.8k | case PROP_CONTAINER: |
110 | 32.8k | enumerator->priv->container = g_value_dup_object (value); |
111 | 32.8k | break; |
112 | 0 | default: |
113 | 0 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
114 | 0 | break; |
115 | 32.8k | } |
116 | 32.8k | } |
117 | | |
118 | | static void |
119 | | g_file_enumerator_dispose (GObject *object) |
120 | 32.8k | { |
121 | 32.8k | GFileEnumerator *enumerator; |
122 | | |
123 | 32.8k | enumerator = G_FILE_ENUMERATOR (object); |
124 | | |
125 | 32.8k | if (enumerator->priv->container) { |
126 | 32.8k | g_object_unref (enumerator->priv->container); |
127 | 32.8k | enumerator->priv->container = NULL; |
128 | 32.8k | } |
129 | | |
130 | 32.8k | G_OBJECT_CLASS (g_file_enumerator_parent_class)->dispose (object); |
131 | 32.8k | } |
132 | | |
133 | | static void |
134 | | g_file_enumerator_finalize (GObject *object) |
135 | 32.8k | { |
136 | 32.8k | GFileEnumerator *enumerator; |
137 | | |
138 | 32.8k | enumerator = G_FILE_ENUMERATOR (object); |
139 | | |
140 | 32.8k | if (!enumerator->priv->closed) |
141 | 32.8k | g_file_enumerator_close (enumerator, NULL, NULL); |
142 | | |
143 | 32.8k | G_OBJECT_CLASS (g_file_enumerator_parent_class)->finalize (object); |
144 | 32.8k | } |
145 | | |
146 | | static void |
147 | | g_file_enumerator_class_init (GFileEnumeratorClass *klass) |
148 | 4 | { |
149 | 4 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
150 | | |
151 | 4 | gobject_class->set_property = g_file_enumerator_set_property; |
152 | 4 | gobject_class->dispose = g_file_enumerator_dispose; |
153 | 4 | gobject_class->finalize = g_file_enumerator_finalize; |
154 | | |
155 | 4 | klass->next_files_async = g_file_enumerator_real_next_files_async; |
156 | 4 | klass->next_files_finish = g_file_enumerator_real_next_files_finish; |
157 | 4 | klass->close_async = g_file_enumerator_real_close_async; |
158 | 4 | klass->close_finish = g_file_enumerator_real_close_finish; |
159 | | |
160 | | /** |
161 | | * GFileEnumerator:container: |
162 | | * |
163 | | * The container that is being enumerated. |
164 | | */ |
165 | 4 | g_object_class_install_property |
166 | 4 | (gobject_class, PROP_CONTAINER, |
167 | 4 | g_param_spec_object ("container", NULL, NULL, |
168 | 4 | G_TYPE_FILE, |
169 | 4 | G_PARAM_WRITABLE | |
170 | 4 | G_PARAM_CONSTRUCT_ONLY | |
171 | 4 | G_PARAM_STATIC_STRINGS)); |
172 | 4 | } |
173 | | |
174 | | static void |
175 | | g_file_enumerator_init (GFileEnumerator *enumerator) |
176 | 32.8k | { |
177 | 32.8k | enumerator->priv = g_file_enumerator_get_instance_private (enumerator); |
178 | 32.8k | } |
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 | 114k | { |
207 | 114k | GFileEnumeratorClass *class; |
208 | 114k | GFileInfo *info; |
209 | | |
210 | 114k | g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL); |
211 | 114k | g_return_val_if_fail (enumerator != NULL, NULL); |
212 | | |
213 | 114k | if (enumerator->priv->closed) |
214 | 0 | { |
215 | 0 | g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED, |
216 | 0 | _("Enumerator is closed")); |
217 | 0 | return NULL; |
218 | 0 | } |
219 | | |
220 | 114k | if (enumerator->priv->pending) |
221 | 0 | { |
222 | 0 | g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING, |
223 | 0 | _("File enumerator has outstanding operation")); |
224 | 0 | return NULL; |
225 | 0 | } |
226 | | |
227 | 114k | if (enumerator->priv->outstanding_error) |
228 | 0 | { |
229 | 0 | g_propagate_error (error, enumerator->priv->outstanding_error); |
230 | 0 | enumerator->priv->outstanding_error = NULL; |
231 | 0 | return NULL; |
232 | 0 | } |
233 | | |
234 | 114k | class = G_FILE_ENUMERATOR_GET_CLASS (enumerator); |
235 | | |
236 | 114k | if (cancellable) |
237 | 0 | g_cancellable_push_current (cancellable); |
238 | | |
239 | 114k | enumerator->priv->pending = TRUE; |
240 | 114k | info = (* class->next_file) (enumerator, cancellable, error); |
241 | 114k | enumerator->priv->pending = FALSE; |
242 | | |
243 | 114k | if (cancellable) |
244 | 0 | g_cancellable_pop_current (cancellable); |
245 | | |
246 | 114k | return info; |
247 | 114k | } |
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 | 32.8k | { |
269 | 32.8k | GFileEnumeratorClass *class; |
270 | | |
271 | 32.8k | g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE); |
272 | 32.8k | g_return_val_if_fail (enumerator != NULL, FALSE); |
273 | | |
274 | 32.8k | class = G_FILE_ENUMERATOR_GET_CLASS (enumerator); |
275 | | |
276 | 32.8k | if (enumerator->priv->closed) |
277 | 0 | return TRUE; |
278 | | |
279 | 32.8k | if (enumerator->priv->pending) |
280 | 0 | { |
281 | 0 | g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING, |
282 | 0 | _("File enumerator has outstanding operation")); |
283 | 0 | return FALSE; |
284 | 0 | } |
285 | | |
286 | 32.8k | if (cancellable) |
287 | 0 | g_cancellable_push_current (cancellable); |
288 | | |
289 | 32.8k | enumerator->priv->pending = TRUE; |
290 | 32.8k | (* class->close_fn) (enumerator, cancellable, error); |
291 | 32.8k | enumerator->priv->pending = FALSE; |
292 | 32.8k | enumerator->priv->closed = TRUE; |
293 | | |
294 | 32.8k | if (cancellable) |
295 | 0 | g_cancellable_pop_current (cancellable); |
296 | | |
297 | 32.8k | return TRUE; |
298 | 32.8k | } |
299 | | |
300 | | static void |
301 | | next_async_callback_wrapper (GObject *source_object, |
302 | | GAsyncResult *res, |
303 | | gpointer user_data) |
304 | 0 | { |
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][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 | 0 | { |
396 | 0 | 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 | 0 | { |
404 | 0 | 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 | 0 | } |
412 | | |
413 | 0 | if (enumerator->priv->closed) |
414 | 0 | { |
415 | 0 | g_task_report_new_error (enumerator, callback, user_data, |
416 | 0 | g_file_enumerator_next_files_async, |
417 | 0 | G_IO_ERROR, G_IO_ERROR_CLOSED, |
418 | 0 | _("File enumerator is already closed")); |
419 | 0 | return; |
420 | 0 | } |
421 | | |
422 | 0 | if (enumerator->priv->pending) |
423 | 0 | { |
424 | 0 | g_task_report_new_error (enumerator, callback, user_data, |
425 | 0 | g_file_enumerator_next_files_async, |
426 | 0 | G_IO_ERROR, G_IO_ERROR_PENDING, |
427 | 0 | _("File enumerator has outstanding operation")); |
428 | 0 | return; |
429 | 0 | } |
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 | 0 | next_async_callback_wrapper, user_data); |
438 | 0 | } |
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 | 0 | { |
458 | 0 | 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 | 0 | } |
471 | | |
472 | | static void |
473 | | close_async_callback_wrapper (GObject *source_object, |
474 | | GAsyncResult *res, |
475 | | gpointer user_data) |
476 | 0 | { |
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][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 | 0 | { |
509 | 0 | GFileEnumeratorClass *class; |
510 | |
|
511 | 0 | g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator)); |
512 | | |
513 | 0 | if (enumerator->priv->closed) |
514 | 0 | { |
515 | 0 | g_task_report_new_error (enumerator, callback, user_data, |
516 | 0 | g_file_enumerator_close_async, |
517 | 0 | G_IO_ERROR, G_IO_ERROR_CLOSED, |
518 | 0 | _("File enumerator is already closed")); |
519 | 0 | return; |
520 | 0 | } |
521 | | |
522 | 0 | if (enumerator->priv->pending) |
523 | 0 | { |
524 | 0 | g_task_report_new_error (enumerator, callback, user_data, |
525 | 0 | g_file_enumerator_close_async, |
526 | 0 | G_IO_ERROR, G_IO_ERROR_PENDING, |
527 | 0 | _("File enumerator has outstanding operation")); |
528 | 0 | return; |
529 | 0 | } |
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 | 0 | close_async_callback_wrapper, user_data); |
538 | 0 | } |
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 | 0 | { |
565 | 0 | 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 | 0 | } |
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 | 0 | { |
590 | 0 | g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE); |
591 | | |
592 | 0 | return enumerator->priv->closed; |
593 | 0 | } |
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 | 0 | { |
606 | 0 | g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE); |
607 | | |
608 | 0 | return enumerator->priv->pending; |
609 | 0 | } |
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 | 0 | { |
622 | 0 | g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator)); |
623 | | |
624 | 0 | enumerator->priv->pending = pending; |
625 | 0 | } |
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 | 114k | { |
684 | 114k | gboolean ret = FALSE; |
685 | 114k | GError *temp_error = NULL; |
686 | 114k | GFileInfo *ret_info = NULL; |
687 | | |
688 | 114k | static GQuark cached_info_quark; |
689 | 114k | static GQuark cached_child_quark; |
690 | 114k | static gsize quarks_initialized; |
691 | | |
692 | 114k | g_return_val_if_fail (direnum != NULL, FALSE); |
693 | 114k | g_return_val_if_fail (out_info != NULL || out_child != NULL, FALSE); |
694 | | |
695 | 114k | if (g_once_init_enter (&quarks_initialized)) |
696 | 4 | { |
697 | 4 | cached_info_quark = g_quark_from_static_string ("g-cached-info"); |
698 | 4 | cached_child_quark = g_quark_from_static_string ("g-cached-child"); |
699 | 4 | g_once_init_leave (&quarks_initialized, 1); |
700 | 4 | } |
701 | | |
702 | 114k | ret_info = g_file_enumerator_next_file (direnum, cancellable, &temp_error); |
703 | 114k | if (temp_error != NULL) |
704 | 0 | { |
705 | 0 | g_propagate_error (error, temp_error); |
706 | 0 | goto out; |
707 | 0 | } |
708 | | |
709 | 114k | if (ret_info) |
710 | 82.0k | { |
711 | 82.0k | if (out_child != NULL) |
712 | 82.0k | { |
713 | 82.0k | const char *name = g_file_info_get_name (ret_info); |
714 | | |
715 | 82.0k | if (G_UNLIKELY (name == NULL)) |
716 | 0 | { |
717 | 0 | g_critical ("g_file_enumerator_iterate() created without standard::name"); |
718 | 0 | g_return_val_if_reached (FALSE); |
719 | 0 | } |
720 | 82.0k | else |
721 | 82.0k | { |
722 | 82.0k | *out_child = g_file_get_child (g_file_enumerator_get_container (direnum), name); |
723 | 82.0k | g_object_set_qdata_full ((GObject*)direnum, cached_child_quark, *out_child, (GDestroyNotify)g_object_unref); |
724 | 82.0k | } |
725 | 82.0k | } |
726 | 82.0k | if (out_info != NULL) |
727 | 82.0k | { |
728 | 82.0k | g_object_set_qdata_full ((GObject*)direnum, cached_info_quark, ret_info, (GDestroyNotify)g_object_unref); |
729 | 82.0k | *out_info = ret_info; |
730 | 82.0k | } |
731 | 0 | else |
732 | 0 | g_object_unref (ret_info); |
733 | 82.0k | } |
734 | 32.8k | else |
735 | 32.8k | { |
736 | 32.8k | if (out_info) |
737 | 32.8k | *out_info = NULL; |
738 | 32.8k | if (out_child) |
739 | 32.8k | *out_child = NULL; |
740 | 32.8k | } |
741 | | |
742 | 114k | ret = TRUE; |
743 | 114k | out: |
744 | 114k | return ret; |
745 | 114k | } |
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 | 82.0k | { |
760 | 82.0k | g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL); |
761 | | |
762 | 82.0k | return enumerator->priv->container; |
763 | 82.0k | } |
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 | 0 | { |
793 | 0 | const gchar *name; |
794 | |
|
795 | 0 | g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL); |
796 | 0 | g_return_val_if_fail (G_IS_FILE_INFO (info), NULL); |
797 | | |
798 | 0 | name = g_file_info_get_name (info); |
799 | |
|
800 | 0 | if (G_UNLIKELY (name == NULL)) |
801 | 0 | { |
802 | 0 | g_critical ("GFileEnumerator created without standard::name"); |
803 | 0 | g_return_val_if_reached (NULL); |
804 | 0 | } |
805 | | |
806 | 0 | return g_file_get_child (enumerator->priv->container, name); |
807 | 0 | } |
808 | | |
809 | | static void |
810 | | next_async_op_free (GList *files) |
811 | 0 | { |
812 | 0 | g_list_free_full (files, g_object_unref); |
813 | 0 | } |
814 | | |
815 | | static void |
816 | | next_files_thread (GTask *task, |
817 | | gpointer source_object, |
818 | | gpointer task_data, |
819 | | GCancellable *cancellable) |
820 | 0 | { |
821 | 0 | GFileEnumerator *enumerator = source_object; |
822 | 0 | int num_files = GPOINTER_TO_INT (task_data); |
823 | 0 | GFileEnumeratorClass *class; |
824 | 0 | GList *files = NULL; |
825 | 0 | GError *error = NULL; |
826 | 0 | GFileInfo *info; |
827 | 0 | int i; |
828 | |
|
829 | 0 | class = G_FILE_ENUMERATOR_GET_CLASS (enumerator); |
830 | |
|
831 | 0 | for (i = 0; i < num_files; i++) |
832 | 0 | { |
833 | 0 | if (g_cancellable_set_error_if_cancelled (cancellable, &error)) |
834 | 0 | info = NULL; |
835 | 0 | else |
836 | 0 | info = class->next_file (enumerator, cancellable, &error); |
837 | | |
838 | 0 | if (info == NULL) |
839 | 0 | { |
840 | | /* If we get an error after first file, return that on next operation */ |
841 | 0 | if (error != NULL && i > 0) |
842 | 0 | { |
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 | 0 | else |
846 | 0 | enumerator->priv->outstanding_error = error; |
847 | 0 | error = NULL; |
848 | 0 | } |
849 | | |
850 | 0 | break; |
851 | 0 | } |
852 | 0 | else |
853 | 0 | files = g_list_prepend (files, info); |
854 | 0 | } |
855 | |
|
856 | 0 | if (error) |
857 | 0 | { |
858 | 0 | g_list_free_full (files, g_object_unref); |
859 | 0 | g_task_return_error (task, error); |
860 | 0 | } |
861 | 0 | else |
862 | 0 | g_task_return_pointer (task, files, (GDestroyNotify)next_async_op_free); |
863 | 0 | } |
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 | 0 | { |
873 | 0 | 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 | | g_file_enumerator_real_next_files_finish (GFileEnumerator *enumerator, |
886 | | GAsyncResult *result, |
887 | | GError **error) |
888 | 0 | { |
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 | 0 | } |
893 | | |
894 | | static void |
895 | | close_async_thread (GTask *task, |
896 | | gpointer source_object, |
897 | | gpointer task_data, |
898 | | GCancellable *cancellable) |
899 | 0 | { |
900 | 0 | GFileEnumerator *enumerator = source_object; |
901 | 0 | GFileEnumeratorClass *class; |
902 | 0 | GError *error = NULL; |
903 | 0 | 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 | 0 | else |
910 | 0 | g_task_return_error (task, error); |
911 | 0 | } |
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 | 0 | { |
920 | 0 | 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 | | g_file_enumerator_real_close_finish (GFileEnumerator *enumerator, |
932 | | GAsyncResult *result, |
933 | | GError **error) |
934 | 0 | { |
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 | 0 | } |