Coverage Report

Created: 2026-02-26 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/irssi/subprojects/glib-2.74.7/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
 * The callback can be called with less than @num_files files in case of error
328
 * or at the end of the enumerator. In case of a partial error the callback will
329
 * be called with any succeeding items and no error, and on the next request the
330
 * error will be reported. If a request is cancelled the callback will be called
331
 * with %G_IO_ERROR_CANCELLED.
332
 *
333
 * During an async request no other sync and async calls are allowed, and will
334
 * result in %G_IO_ERROR_PENDING errors. 
335
 *
336
 * Any outstanding i/o request with higher priority (lower numerical value) will
337
 * be executed before an outstanding request with lower priority. Default
338
 * priority is %G_PRIORITY_DEFAULT.
339
 **/
340
void
341
g_file_enumerator_next_files_async (GFileEnumerator     *enumerator,
342
            int                  num_files,
343
            int                  io_priority,
344
            GCancellable        *cancellable,
345
            GAsyncReadyCallback  callback,
346
            gpointer             user_data)
347
0
{
348
0
  GFileEnumeratorClass *class;
349
350
0
  g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
351
0
  g_return_if_fail (enumerator != NULL);
352
0
  g_return_if_fail (num_files >= 0);
353
354
0
  if (num_files == 0)
355
0
    {
356
0
      GTask *task;
357
358
0
      task = g_task_new (enumerator, cancellable, callback, user_data);
359
0
      g_task_set_source_tag (task, g_file_enumerator_next_files_async);
360
0
      g_task_return_pointer (task, NULL, NULL);
361
0
      g_object_unref (task);
362
0
      return;
363
0
    }
364
  
365
0
  if (enumerator->priv->closed)
366
0
    {
367
0
      g_task_report_new_error (enumerator, callback, user_data,
368
0
                               g_file_enumerator_next_files_async,
369
0
                               G_IO_ERROR, G_IO_ERROR_CLOSED,
370
0
                               _("File enumerator is already closed"));
371
0
      return;
372
0
    }
373
  
374
0
  if (enumerator->priv->pending)
375
0
    {
376
0
      g_task_report_new_error (enumerator, callback, user_data,
377
0
                               g_file_enumerator_next_files_async,
378
0
                               G_IO_ERROR, G_IO_ERROR_PENDING,
379
0
                               _("File enumerator has outstanding operation"));
380
0
      return;
381
0
    }
382
383
0
  class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
384
  
385
0
  enumerator->priv->pending = TRUE;
386
0
  enumerator->priv->outstanding_callback = callback;
387
0
  g_object_ref (enumerator);
388
0
  (* class->next_files_async) (enumerator, num_files, io_priority, cancellable, 
389
0
             next_async_callback_wrapper, user_data);
390
0
}
391
392
/**
393
 * g_file_enumerator_next_files_finish:
394
 * @enumerator: a #GFileEnumerator.
395
 * @result: a #GAsyncResult.
396
 * @error: a #GError location to store the error occurring, or %NULL to 
397
 * ignore.
398
 * 
399
 * Finishes the asynchronous operation started with g_file_enumerator_next_files_async().
400
 * 
401
 * Returns: (transfer full) (element-type Gio.FileInfo): a #GList of #GFileInfos. You must free the list with 
402
 *     g_list_free() and unref the infos with g_object_unref() when you're 
403
 *     done with them.
404
 **/
405
GList *
406
g_file_enumerator_next_files_finish (GFileEnumerator  *enumerator,
407
             GAsyncResult     *result,
408
             GError          **error)
409
0
{
410
0
  GFileEnumeratorClass *class;
411
  
412
0
  g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
413
0
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
414
  
415
0
  if (g_async_result_legacy_propagate_error (result, error))
416
0
    return NULL;
417
0
  else if (g_async_result_is_tagged (result, g_file_enumerator_next_files_async))
418
0
    return g_task_propagate_pointer (G_TASK (result), error);
419
  
420
0
  class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
421
0
  return class->next_files_finish (enumerator, result, error);
422
0
}
423
424
static void
425
close_async_callback_wrapper (GObject      *source_object,
426
            GAsyncResult *res,
427
            gpointer      user_data)
428
0
{
429
0
  GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object);
430
  
431
0
  enumerator->priv->pending = FALSE;
432
0
  enumerator->priv->closed = TRUE;
433
0
  if (enumerator->priv->outstanding_callback)
434
0
    (*enumerator->priv->outstanding_callback) (source_object, res, user_data);
435
0
  g_object_unref (enumerator);
436
0
}
437
438
/**
439
 * g_file_enumerator_close_async:
440
 * @enumerator: a #GFileEnumerator.
441
 * @io_priority: the [I/O priority][io-priority] of the request
442
 * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
443
 * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
444
 * @user_data: (closure): the data to pass to callback function
445
 *
446
 * Asynchronously closes the file enumerator. 
447
 *
448
 * If @cancellable is not %NULL, then the operation can be cancelled by
449
 * triggering the cancellable object from another thread. If the operation
450
 * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned in 
451
 * g_file_enumerator_close_finish(). 
452
 **/
453
void
454
g_file_enumerator_close_async (GFileEnumerator     *enumerator,
455
             int                  io_priority,
456
             GCancellable        *cancellable,
457
             GAsyncReadyCallback  callback,
458
             gpointer             user_data)
459
0
{
460
0
  GFileEnumeratorClass *class;
461
462
0
  g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
463
464
0
  if (enumerator->priv->closed)
465
0
    {
466
0
      g_task_report_new_error (enumerator, callback, user_data,
467
0
                               g_file_enumerator_close_async,
468
0
                               G_IO_ERROR, G_IO_ERROR_CLOSED,
469
0
                               _("File enumerator is already closed"));
470
0
      return;
471
0
    }
472
  
473
0
  if (enumerator->priv->pending)
474
0
    {
475
0
      g_task_report_new_error (enumerator, callback, user_data,
476
0
                               g_file_enumerator_close_async,
477
0
                               G_IO_ERROR, G_IO_ERROR_PENDING,
478
0
                               _("File enumerator has outstanding operation"));
479
0
      return;
480
0
    }
481
482
0
  class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
483
  
484
0
  enumerator->priv->pending = TRUE;
485
0
  enumerator->priv->outstanding_callback = callback;
486
0
  g_object_ref (enumerator);
487
0
  (* class->close_async) (enumerator, io_priority, cancellable,
488
0
        close_async_callback_wrapper, user_data);
489
0
}
490
491
/**
492
 * g_file_enumerator_close_finish:
493
 * @enumerator: a #GFileEnumerator.
494
 * @result: a #GAsyncResult.
495
 * @error: a #GError location to store the error occurring, or %NULL to 
496
 * ignore.
497
 * 
498
 * Finishes closing a file enumerator, started from g_file_enumerator_close_async().
499
 * 
500
 * If the file enumerator was already closed when g_file_enumerator_close_async() 
501
 * was called, then this function will report %G_IO_ERROR_CLOSED in @error, and 
502
 * return %FALSE. If the file enumerator had pending operation when the close 
503
 * operation was started, then this function will report %G_IO_ERROR_PENDING, and
504
 * return %FALSE.  If @cancellable was not %NULL, then the operation may have been 
505
 * cancelled by triggering the cancellable object from another thread. If the operation
506
 * was cancelled, the error %G_IO_ERROR_CANCELLED will be set, and %FALSE will be 
507
 * returned. 
508
 * 
509
 * Returns: %TRUE if the close operation has finished successfully.
510
 **/
511
gboolean
512
g_file_enumerator_close_finish (GFileEnumerator  *enumerator,
513
        GAsyncResult     *result,
514
        GError          **error)
515
0
{
516
0
  GFileEnumeratorClass *class;
517
518
0
  g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
519
0
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
520
  
521
0
  if (g_async_result_legacy_propagate_error (result, error))
522
0
    return FALSE;
523
0
  else if (g_async_result_is_tagged (result, g_file_enumerator_close_async))
524
0
    return g_task_propagate_boolean (G_TASK (result), error);
525
526
0
  class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
527
0
  return class->close_finish (enumerator, result, error);
528
0
}
529
530
/**
531
 * g_file_enumerator_is_closed:
532
 * @enumerator: a #GFileEnumerator.
533
 *
534
 * Checks if the file enumerator has been closed.
535
 * 
536
 * Returns: %TRUE if the @enumerator is closed.
537
 **/
538
gboolean
539
g_file_enumerator_is_closed (GFileEnumerator *enumerator)
540
0
{
541
0
  g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
542
  
543
0
  return enumerator->priv->closed;
544
0
}
545
546
/**
547
 * g_file_enumerator_has_pending:
548
 * @enumerator: a #GFileEnumerator.
549
 * 
550
 * Checks if the file enumerator has pending operations.
551
 *
552
 * Returns: %TRUE if the @enumerator has pending operations.
553
 **/
554
gboolean
555
g_file_enumerator_has_pending (GFileEnumerator *enumerator)
556
0
{
557
0
  g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
558
  
559
0
  return enumerator->priv->pending;
560
0
}
561
562
/**
563
 * g_file_enumerator_set_pending:
564
 * @enumerator: a #GFileEnumerator.
565
 * @pending: a boolean value.
566
 * 
567
 * Sets the file enumerator as having pending operations.
568
 **/
569
void
570
g_file_enumerator_set_pending (GFileEnumerator *enumerator,
571
             gboolean         pending)
572
0
{
573
0
  g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
574
  
575
0
  enumerator->priv->pending = pending;
576
0
}
577
578
/**
579
 * g_file_enumerator_iterate:
580
 * @direnum: an open #GFileEnumerator
581
 * @out_info: (out) (transfer none) (optional): Output location for the next #GFileInfo, or %NULL
582
 * @out_child: (out) (transfer none) (optional): Output location for the next #GFile, or %NULL
583
 * @cancellable: a #GCancellable
584
 * @error: a #GError
585
 *
586
 * This is a version of g_file_enumerator_next_file() that's easier to
587
 * use correctly from C programs.  With g_file_enumerator_next_file(),
588
 * the gboolean return value signifies "end of iteration or error", which
589
 * requires allocation of a temporary #GError.
590
 *
591
 * In contrast, with this function, a %FALSE return from
592
 * g_file_enumerator_iterate() *always* means
593
 * "error".  End of iteration is signaled by @out_info or @out_child being %NULL.
594
 *
595
 * Another crucial difference is that the references for @out_info and
596
 * @out_child are owned by @direnum (they are cached as hidden
597
 * properties).  You must not unref them in your own code.  This makes
598
 * memory management significantly easier for C code in combination
599
 * with loops.
600
 *
601
 * Finally, this function optionally allows retrieving a #GFile as
602
 * well.
603
 *
604
 * You must specify at least one of @out_info or @out_child.
605
 *
606
 * The code pattern for correctly using g_file_enumerator_iterate() from C
607
 * is:
608
 *
609
 * |[
610
 * direnum = g_file_enumerate_children (file, ...);
611
 * while (TRUE)
612
 *   {
613
 *     GFileInfo *info;
614
 *     if (!g_file_enumerator_iterate (direnum, &info, NULL, cancellable, error))
615
 *       goto out;
616
 *     if (!info)
617
 *       break;
618
 *     ... do stuff with "info"; do not unref it! ...
619
 *   }
620
 * 
621
 * out:
622
 *   g_object_unref (direnum); // Note: frees the last @info
623
 * ]|
624
 *
625
 *
626
 * Since: 2.44
627
 */
628
gboolean
629
g_file_enumerator_iterate (GFileEnumerator  *direnum,
630
                           GFileInfo       **out_info,
631
                           GFile           **out_child,
632
                           GCancellable     *cancellable,
633
                           GError          **error)
634
0
{
635
0
  gboolean ret = FALSE;
636
0
  GError *temp_error = NULL;
637
0
  GFileInfo *ret_info = NULL;
638
639
0
  static GQuark cached_info_quark;
640
0
  static GQuark cached_child_quark;
641
0
  static gsize quarks_initialized;
642
643
0
  g_return_val_if_fail (direnum != NULL, FALSE);
644
0
  g_return_val_if_fail (out_info != NULL || out_child != NULL, FALSE);
645
646
0
  if (g_once_init_enter (&quarks_initialized))
647
0
    {
648
0
      cached_info_quark = g_quark_from_static_string ("g-cached-info");
649
0
      cached_child_quark = g_quark_from_static_string ("g-cached-child");
650
0
      g_once_init_leave (&quarks_initialized, 1);
651
0
    }
652
653
0
  ret_info = g_file_enumerator_next_file (direnum, cancellable, &temp_error);
654
0
  if (temp_error != NULL)
655
0
    {
656
0
      g_propagate_error (error, temp_error);
657
0
      goto out;
658
0
    }
659
660
0
  if (ret_info)
661
0
    { 
662
0
      if (out_child != NULL)
663
0
        {
664
0
          const char *name = g_file_info_get_name (ret_info);
665
666
0
          if (G_UNLIKELY (name == NULL))
667
0
            {
668
0
              g_critical ("g_file_enumerator_iterate() created without standard::name");
669
0
              g_return_val_if_reached (FALSE);
670
0
            }
671
0
          else
672
0
            {
673
0
              *out_child = g_file_get_child (g_file_enumerator_get_container (direnum), name);
674
0
              g_object_set_qdata_full ((GObject*)direnum, cached_child_quark, *out_child, (GDestroyNotify)g_object_unref);
675
0
            }
676
0
        }
677
0
      if (out_info != NULL)
678
0
        {
679
0
          g_object_set_qdata_full ((GObject*)direnum, cached_info_quark, ret_info, (GDestroyNotify)g_object_unref);
680
0
          *out_info = ret_info;
681
0
        }
682
0
      else
683
0
        g_object_unref (ret_info);
684
0
    }
685
0
  else
686
0
    {
687
0
      if (out_info)
688
0
        *out_info = NULL;
689
0
      if (out_child)
690
0
        *out_child = NULL;
691
0
    }
692
693
0
  ret = TRUE;
694
0
 out:
695
0
  return ret;
696
0
}
697
698
/**
699
 * g_file_enumerator_get_container:
700
 * @enumerator: a #GFileEnumerator
701
 *
702
 * Get the #GFile container which is being enumerated.
703
 *
704
 * Returns: (transfer none): the #GFile which is being enumerated.
705
 *
706
 * Since: 2.18
707
 */
708
GFile *
709
g_file_enumerator_get_container (GFileEnumerator *enumerator)
710
0
{
711
0
  g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
712
713
0
  return enumerator->priv->container;
714
0
}
715
716
/**
717
 * g_file_enumerator_get_child:
718
 * @enumerator: a #GFileEnumerator
719
 * @info: a #GFileInfo gotten from g_file_enumerator_next_file()
720
 *   or the async equivalents.
721
 *
722
 * Return a new #GFile which refers to the file named by @info in the source
723
 * directory of @enumerator.  This function is primarily intended to be used
724
 * inside loops with g_file_enumerator_next_file().
725
 *
726
 * To use this, %G_FILE_ATTRIBUTE_STANDARD_NAME must have been listed in the
727
 * attributes list used when creating the #GFileEnumerator.
728
 *
729
 * This is a convenience method that's equivalent to:
730
 * |[<!-- language="C" -->
731
 *   gchar *name = g_file_info_get_name (info);
732
 *   GFile *child = g_file_get_child (g_file_enumerator_get_container (enumr),
733
 *                                    name);
734
 * ]|
735
 *
736
 * Returns: (transfer full): a #GFile for the #GFileInfo passed it.
737
 *
738
 * Since: 2.36
739
 */
740
GFile *
741
g_file_enumerator_get_child (GFileEnumerator *enumerator,
742
                             GFileInfo       *info)
743
0
{
744
0
  const gchar *name;
745
746
0
  g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
747
0
  g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
748
749
0
  name = g_file_info_get_name (info);
750
751
0
  if (G_UNLIKELY (name == NULL))
752
0
    {
753
0
      g_critical ("GFileEnumerator created without standard::name");
754
0
      g_return_val_if_reached (NULL);
755
0
    }
756
757
0
  return g_file_get_child (enumerator->priv->container, name);
758
0
}
759
760
static void
761
next_async_op_free (GList *files)
762
0
{
763
0
  g_list_free_full (files, g_object_unref);
764
0
}
765
766
static void
767
next_files_thread (GTask        *task,
768
                   gpointer      source_object,
769
                   gpointer      task_data,
770
                   GCancellable *cancellable)
771
0
{
772
0
  GFileEnumerator *enumerator = source_object;
773
0
  int num_files = GPOINTER_TO_INT (task_data);
774
0
  GFileEnumeratorClass *class;
775
0
  GList *files = NULL;
776
0
  GError *error = NULL;
777
0
  GFileInfo *info;
778
0
  int i;
779
780
0
  class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
781
782
0
  for (i = 0; i < num_files; i++)
783
0
    {
784
0
      if (g_cancellable_set_error_if_cancelled (cancellable, &error))
785
0
  info = NULL;
786
0
      else
787
0
  info = class->next_file (enumerator, cancellable, &error);
788
      
789
0
      if (info == NULL)
790
0
  {
791
    /* If we get an error after first file, return that on next operation */
792
0
    if (error != NULL && i > 0)
793
0
      {
794
0
        if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
795
0
    g_error_free (error); /* Never propagate cancel errors to other call */
796
0
        else
797
0
    enumerator->priv->outstanding_error = error;
798
0
        error = NULL;
799
0
      }
800
        
801
0
    break;
802
0
  }
803
0
      else
804
0
  files = g_list_prepend (files, info);
805
0
    }
806
807
0
  if (error)
808
0
    {
809
0
      g_list_free_full (files, g_object_unref);
810
0
      g_task_return_error (task, error);
811
0
    }
812
0
  else
813
0
    g_task_return_pointer (task, files, (GDestroyNotify)next_async_op_free);
814
0
}
815
816
static void
817
g_file_enumerator_real_next_files_async (GFileEnumerator     *enumerator,
818
           int                  num_files,
819
           int                  io_priority,
820
           GCancellable        *cancellable,
821
           GAsyncReadyCallback  callback,
822
           gpointer             user_data)
823
0
{
824
0
  GTask *task;
825
826
0
  task = g_task_new (enumerator, cancellable, callback, user_data);
827
0
  g_task_set_source_tag (task, g_file_enumerator_real_next_files_async);
828
0
  g_task_set_task_data (task, GINT_TO_POINTER (num_files), NULL);
829
0
  g_task_set_priority (task, io_priority);
830
831
0
  g_task_run_in_thread (task, next_files_thread);
832
0
  g_object_unref (task);
833
0
}
834
835
static GList *
836
g_file_enumerator_real_next_files_finish (GFileEnumerator                *enumerator,
837
            GAsyncResult                   *result,
838
            GError                        **error)
839
0
{
840
0
  g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
841
842
0
  return g_task_propagate_pointer (G_TASK (result), error);
843
0
}
844
845
static void
846
close_async_thread (GTask        *task,
847
                    gpointer      source_object,
848
                    gpointer      task_data,
849
                    GCancellable *cancellable)
850
0
{
851
0
  GFileEnumerator *enumerator = source_object;
852
0
  GFileEnumeratorClass *class;
853
0
  GError *error = NULL;
854
0
  gboolean result;
855
856
0
  class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
857
0
  result = class->close_fn (enumerator, cancellable, &error);
858
0
  if (result)
859
0
    g_task_return_boolean (task, TRUE);
860
0
  else
861
0
    g_task_return_error (task, error);
862
0
}
863
864
static void
865
g_file_enumerator_real_close_async (GFileEnumerator     *enumerator,
866
            int                  io_priority,
867
            GCancellable        *cancellable,
868
            GAsyncReadyCallback  callback,
869
            gpointer             user_data)
870
0
{
871
0
  GTask *task;
872
873
0
  task = g_task_new (enumerator, cancellable, callback, user_data);
874
0
  g_task_set_source_tag (task, g_file_enumerator_real_close_async);
875
0
  g_task_set_priority (task, io_priority);
876
  
877
0
  g_task_run_in_thread (task, close_async_thread);
878
0
  g_object_unref (task);
879
0
}
880
881
static gboolean
882
g_file_enumerator_real_close_finish (GFileEnumerator  *enumerator,
883
                                     GAsyncResult     *result,
884
                                     GError          **error)
885
0
{
886
0
  g_return_val_if_fail (g_task_is_valid (result, enumerator), FALSE);
887
888
0
  return g_task_propagate_boolean (G_TASK (result), error);
889
0
}