Coverage Report

Created: 2025-11-09 06:50

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