Coverage Report

Created: 2025-07-01 07:09

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