Coverage Report

Created: 2025-06-13 06:55

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