Coding style fixups
[platform/upstream/glib.git] / gio / gfileenumerator.c
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 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, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include <config.h>
24 #include "gfileenumerator.h"
25 #include "gioscheduler.h"
26 #include "gasynchelper.h"
27 #include "gsimpleasyncresult.h"
28 #include "glibintl.h"
29
30 #include "gioalias.h"
31
32 /**
33  * SECTION:gfileenumerator
34  * @short_description: Enumerated Files Routines
35  * 
36  * 
37  **/ 
38
39 G_DEFINE_TYPE (GFileEnumerator, g_file_enumerator, G_TYPE_OBJECT);
40
41 struct _GFileEnumeratorPrivate {
42   /* TODO: Should be public for subclasses? */
43   guint closed : 1;
44   guint pending : 1;
45   GAsyncReadyCallback outstanding_callback;
46   GError *outstanding_error;
47 };
48
49 static void     g_file_enumerator_real_next_files_async  (GFileEnumerator      *enumerator,
50                                                           int                   num_files,
51                                                           int                   io_priority,
52                                                           GCancellable         *cancellable,
53                                                           GAsyncReadyCallback   callback,
54                                                           gpointer              user_data);
55 static GList *  g_file_enumerator_real_next_files_finish (GFileEnumerator      *enumerator,
56                                                           GAsyncResult         *res,
57                                                           GError              **error);
58 static void     g_file_enumerator_real_close_async       (GFileEnumerator      *enumerator,
59                                                           int                   io_priority,
60                                                           GCancellable         *cancellable,
61                                                           GAsyncReadyCallback   callback,
62                                                           gpointer              user_data);
63 static gboolean g_file_enumerator_real_close_finish      (GFileEnumerator      *enumerator,
64                                                           GAsyncResult         *res,
65                                                           GError              **error);
66
67 static void
68 g_file_enumerator_finalize (GObject *object)
69 {
70   GFileEnumerator *enumerator;
71
72   enumerator = G_FILE_ENUMERATOR (object);
73   
74   if (!enumerator->priv->closed)
75     g_file_enumerator_close (enumerator, NULL, NULL);
76
77   if (G_OBJECT_CLASS (g_file_enumerator_parent_class)->finalize)
78     (*G_OBJECT_CLASS (g_file_enumerator_parent_class)->finalize) (object);
79 }
80
81 static void
82 g_file_enumerator_class_init (GFileEnumeratorClass *klass)
83 {
84   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
85   
86   g_type_class_add_private (klass, sizeof (GFileEnumeratorPrivate));
87   
88   gobject_class->finalize = g_file_enumerator_finalize;
89
90   klass->next_files_async = g_file_enumerator_real_next_files_async;
91   klass->next_files_finish = g_file_enumerator_real_next_files_finish;
92   klass->close_async = g_file_enumerator_real_close_async;
93   klass->close_finish = g_file_enumerator_real_close_finish;
94 }
95
96 static void
97 g_file_enumerator_init (GFileEnumerator *enumerator)
98 {
99   enumerator->priv = G_TYPE_INSTANCE_GET_PRIVATE (enumerator,
100                                                   G_TYPE_FILE_ENUMERATOR,
101                                                   GFileEnumeratorPrivate);
102 }
103
104 /**
105  * g_file_enumerator_next_file:
106  * @enumerator: a #GFileEnumerator.
107  * @cancellable: optional #GCancellable object, %NULL to ignore.
108  * @error: location to store the error occuring, or %NULL to ignore
109  *
110  * Returns information for the next file in the enumerated object.
111  * Will block until the information is available.
112  *
113  * On error, returns %NULL and sets @error to the error. If the
114  * enumerator is at the end, %NULL will be returned and @error will
115  * be unset.
116  *
117  * Return value: A #GFileInfo or %NULL on error or end of enumerator
118  **/
119 GFileInfo *
120 g_file_enumerator_next_file (GFileEnumerator *enumerator,
121                              GCancellable *cancellable,
122                              GError **error)
123 {
124   GFileEnumeratorClass *class;
125   GFileInfo *info;
126   
127   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
128   g_return_val_if_fail (enumerator != NULL, NULL);
129   
130   if (enumerator->priv->closed)
131     {
132       g_set_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
133                    _("Enumerator is closed"));
134       return NULL;
135     }
136
137   if (enumerator->priv->pending)
138     {
139       g_set_error (error, G_IO_ERROR, G_IO_ERROR_PENDING,
140                    _("File enumerator has outstanding operation"));
141       return NULL;
142     }
143
144   if (enumerator->priv->outstanding_error)
145     {
146       g_propagate_error (error, enumerator->priv->outstanding_error);
147       enumerator->priv->outstanding_error = NULL;
148       return NULL;
149     }
150   
151   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
152
153   if (cancellable)
154     g_push_current_cancellable (cancellable);
155   
156   enumerator->priv->pending = TRUE;
157   info = (* class->next_file) (enumerator, cancellable, error);
158   enumerator->priv->pending = FALSE;
159
160   if (cancellable)
161     g_pop_current_cancellable (cancellable);
162   
163   return info;
164 }
165   
166 /**
167  * g_file_enumerator_close:
168  * @enumerator: a #GFileEnumerator.
169  * @cancellable: optional #GCancellable object, %NULL to ignore. 
170  * @error: location to store the error occuring, or %NULL to ignore
171  *
172  * Releases all resources used by this enumerator, making the
173  * enumerator return %G_IO_ERROR_CLOSED on all calls.
174  *
175  * This will be automatically called when the last reference
176  * is dropped, but you might want to call make sure resources
177  * are released as early as possible.
178  *
179  * Return value: #TRUE on success or #FALSE on error.
180  **/
181 gboolean
182 g_file_enumerator_close (GFileEnumerator  *enumerator,
183                          GCancellable     *cancellable,
184                          GError          **error)
185 {
186   GFileEnumeratorClass *class;
187
188   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
189   g_return_val_if_fail (enumerator != NULL, FALSE);
190   
191   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
192
193   if (enumerator->priv->closed)
194     return TRUE;
195   
196   if (enumerator->priv->pending)
197     {
198       g_set_error (error, G_IO_ERROR, G_IO_ERROR_PENDING,
199                    _("File enumerator has outstanding operation"));
200       return FALSE;
201     }
202
203   if (cancellable)
204     g_push_current_cancellable (cancellable);
205   
206   enumerator->priv->pending = TRUE;
207   (* class->close) (enumerator, cancellable, error);
208   enumerator->priv->pending = FALSE;
209   enumerator->priv->closed = TRUE;
210
211   if (cancellable)
212     g_pop_current_cancellable (cancellable);
213   
214   return TRUE;
215 }
216
217 static void
218 next_async_callback_wrapper (GObject      *source_object,
219                              GAsyncResult *res,
220                              gpointer      user_data)
221 {
222   GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object);
223
224   enumerator->priv->pending = FALSE;
225   if (enumerator->priv->outstanding_callback)
226     (*enumerator->priv->outstanding_callback) (source_object, res, user_data);
227   g_object_unref (enumerator);
228 }
229
230 /**
231  * g_file_enumerator_next_files_async:
232  * @enumerator: a #GFileEnumerator.
233  * @num_files: the number of file info objects to request
234  * @io_priority: the io priority of the request. the io priority of the request
235  * @cancellable: optional #GCancellable object, %NULL to ignore.
236  * @callback: callback to call when the request is satisfied
237  * @user_data: the user_data to pass to callback function 
238  *
239  * Request information for a number of files from the enumerator asynchronously.
240  * When all i/o for the operation is finished the @callback will be called with
241  * the requested information.
242  *
243  * The callback can be called with less than @num_files files in case of error
244  * or at the end of the enumerator. In case of a partial error the callback will
245  * be called with any succeeding items and no error, and on the next request the
246  * error will be reported. If a request is cancelled the callback will be called
247  * with %G_IO_ERROR_CANCELLED.
248  *
249  * During an async request no other sync and async calls are allowed, and will
250  * result in %G_IO_ERROR_PENDING errors. 
251  *
252  * Any outstanding i/o request with higher priority (lower numerical value) will
253  * be executed before an outstanding request with lower priority. Default
254  * priority is %G_PRIORITY_DEFAULT.
255  **/
256 void
257 g_file_enumerator_next_files_async (GFileEnumerator     *enumerator,
258                                     int                  num_files,
259                                     int                  io_priority,
260                                     GCancellable        *cancellable,
261                                     GAsyncReadyCallback  callback,
262                                     gpointer             user_data)
263 {
264   GFileEnumeratorClass *class;
265   GSimpleAsyncResult *simple;
266
267   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
268   g_return_if_fail (enumerator != NULL);
269   g_return_if_fail (num_files >= 0);
270
271   if (num_files == 0)
272     {
273       simple = g_simple_async_result_new (G_OBJECT (enumerator),
274                                           callback,
275                                           user_data,
276                                           g_file_enumerator_next_files_async);
277       g_simple_async_result_complete_in_idle (simple);
278       g_object_unref (simple);
279       return;
280     }
281   
282   if (enumerator->priv->closed)
283     {
284       g_simple_async_report_error_in_idle (G_OBJECT (enumerator),
285                                            callback,
286                                            user_data,
287                                            G_IO_ERROR, G_IO_ERROR_CLOSED,
288                                            _("File enumerator is already closed"));
289       return;
290     }
291   
292   if (enumerator->priv->pending)
293     {
294       g_simple_async_report_error_in_idle (G_OBJECT (enumerator),
295                                            callback,
296                                            user_data,
297                                            G_IO_ERROR, G_IO_ERROR_PENDING,
298                                            _("File enumerator has outstanding operation"));
299       return;
300     }
301
302   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
303   
304   enumerator->priv->pending = TRUE;
305   enumerator->priv->outstanding_callback = callback;
306   g_object_ref (enumerator);
307   (* class->next_files_async) (enumerator, num_files, io_priority, cancellable, 
308                                next_async_callback_wrapper, user_data);
309 }
310
311 /**
312  * g_file_enumerator_next_files_finish:
313  * @enumerator: a #GFileEnumerator.
314  * @result: a #GAsyncResult.
315  * @error: a #GError location to store the error occuring, or %NULL to 
316  * ignore.
317  * 
318  * 
319  * 
320  * Returns: 
321  **/
322 GList *
323 g_file_enumerator_next_files_finish (GFileEnumerator  *enumerator,
324                                      GAsyncResult     *result,
325                                      GError          **error)
326 {
327   GFileEnumeratorClass *class;
328   GSimpleAsyncResult *simple;
329   
330   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
331   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
332   
333   if (G_IS_SIMPLE_ASYNC_RESULT (result))
334     {
335       simple = G_SIMPLE_ASYNC_RESULT (result);
336       if (g_simple_async_result_propagate_error (simple, error))
337         return NULL;
338       
339       /* Special case read of 0 files */
340       if (g_simple_async_result_get_source_tag (simple) == g_file_enumerator_next_files_async)
341         return NULL;
342     }
343   
344   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
345   return class->next_files_finish (enumerator, result, error);
346 }
347
348 static void
349 close_async_callback_wrapper (GObject      *source_object,
350                               GAsyncResult *res,
351                               gpointer      user_data)
352 {
353   GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object);
354   
355   enumerator->priv->pending = FALSE;
356   enumerator->priv->closed = TRUE;
357   if (enumerator->priv->outstanding_callback)
358     (*enumerator->priv->outstanding_callback) (source_object, res, user_data);
359   g_object_unref (enumerator);
360 }
361
362 /**
363  * g_file_enumerator_close_async:
364  * @enumerator: a #GFileEnumerator.
365  * @io_priority: the io priority of the request.
366  * @cancellable: optional #GCancellable object, %NULL to ignore. 
367  * @callback: callback to call when the request is satisfied
368  * @user_data: the user_data to pass to callback function 
369  * 
370  **/
371 void
372 g_file_enumerator_close_async (GFileEnumerator     *enumerator,
373                                int                  io_priority,
374                                GCancellable        *cancellable,
375                                GAsyncReadyCallback  callback,
376                                gpointer             user_data)
377 {
378   GFileEnumeratorClass *class;
379
380   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
381
382   if (enumerator->priv->closed)
383     {
384       g_simple_async_report_error_in_idle (G_OBJECT (enumerator),
385                                            callback,
386                                            user_data,
387                                            G_IO_ERROR, G_IO_ERROR_CLOSED,
388                                            _("File enumerator is already closed"));
389       return;
390     }
391   
392   if (enumerator->priv->pending)
393     {
394       g_simple_async_report_error_in_idle (G_OBJECT (enumerator),
395                                            callback,
396                                            user_data,
397                                            G_IO_ERROR, G_IO_ERROR_PENDING,
398                                            _("File enumerator has outstanding operation"));
399       return;
400     }
401
402   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
403   
404   enumerator->priv->pending = TRUE;
405   enumerator->priv->outstanding_callback = callback;
406   g_object_ref (enumerator);
407   (* class->close_async) (enumerator, io_priority, cancellable,
408                           close_async_callback_wrapper, user_data);
409 }
410
411 /**
412  * g_file_enumerator_close_finish:
413  * @enumerator: a #GFileEnumerator.
414  * @result: a #GAsyncResult.
415  * @error: a #GError location to store the error occuring, or %NULL to 
416  * ignore.
417  * 
418  * 
419  * 
420  * Returns: %TRUE if the close operation has finished successfully.
421  **/
422 gboolean
423 g_file_enumerator_close_finish (GFileEnumerator  *enumerator,
424                                 GAsyncResult     *result,
425                                 GError          **error)
426 {
427   GSimpleAsyncResult *simple;
428   GFileEnumeratorClass *class;
429
430   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), FALSE);
431   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
432   
433   if (G_IS_SIMPLE_ASYNC_RESULT (result))
434     {
435       simple = G_SIMPLE_ASYNC_RESULT (result);
436       if (g_simple_async_result_propagate_error (simple, error))
437         return FALSE;
438     }
439   
440   class = G_FILE_ENUMERATOR_GET_CLASS (enumerator);
441   return class->close_finish (enumerator, result, error);
442 }
443
444 /**
445  * g_file_enumerator_is_closed:
446  * @enumerator: a #GFileEnumerator.
447  * 
448  * Returns: %TRUE if the @enumerator is closed.
449  **/
450 gboolean
451 g_file_enumerator_is_closed (GFileEnumerator *enumerator)
452 {
453   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
454   
455   return enumerator->priv->closed;
456 }
457
458 /**
459  * g_file_enumerator_has_pending:
460  * @enumerator: a #GFileEnumerator.
461  * 
462  * Returns: %TRUE if the @enumerator has pending operations.
463  **/
464 gboolean
465 g_file_enumerator_has_pending (GFileEnumerator *enumerator)
466 {
467   g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), TRUE);
468   
469   return enumerator->priv->pending;
470 }
471
472 /**
473  * g_file_enumerator_set_pending:
474  * @enumerator: a #GFileEnumerator.
475  * @pending: a boolean value.
476  * 
477  **/
478 void
479 g_file_enumerator_set_pending (GFileEnumerator *enumerator,
480                                gboolean         pending)
481 {
482   g_return_if_fail (G_IS_FILE_ENUMERATOR (enumerator));
483   
484   enumerator->priv->pending = pending;
485 }
486
487 typedef struct {
488   int                num_files;
489   GList             *files;
490 } NextAsyncOp;
491
492 static void
493 next_files_thread (GSimpleAsyncResult *res,
494                    GObject            *object,
495                    GCancellable       *cancellable)
496 {
497   NextAsyncOp *op;
498   GFileEnumeratorClass *class;
499   GError *error = NULL;
500   GFileInfo *info;
501   GFileEnumerator *enumerator;
502   int i;
503
504   enumerator = G_FILE_ENUMERATOR (object);
505   op = g_simple_async_result_get_op_res_gpointer (res);
506
507   class = G_FILE_ENUMERATOR_GET_CLASS (object);
508
509   for (i = 0; i < op->num_files; i++)
510     {
511       if (g_cancellable_set_error_if_cancelled (cancellable, &error))
512         info = NULL;
513       else
514         info = class->next_file (enumerator, cancellable, &error);
515       
516       if (info == NULL)
517         {
518           /* If we get an error after first file, return that on next operation */
519           if (error != NULL && i > 0)
520             {
521               if (error->domain == G_IO_ERROR &&
522                   error->code == G_IO_ERROR_CANCELLED)
523                 g_error_free (error); /* Never propagate cancel errors to other call */
524               else
525                 enumerator->priv->outstanding_error = error;
526               error = NULL;
527             }
528               
529           break;
530         }
531       else
532         op->files = g_list_prepend (op->files, info);
533     }
534 }
535
536
537 static void
538 g_file_enumerator_real_next_files_async (GFileEnumerator     *enumerator,
539                                          int                  num_files,
540                                          int                  io_priority,
541                                          GCancellable        *cancellable,
542                                          GAsyncReadyCallback  callback,
543                                          gpointer             user_data)
544 {
545   GSimpleAsyncResult *res;
546   NextAsyncOp *op;
547
548   op = g_new0 (NextAsyncOp, 1);
549
550   op->num_files = num_files;
551   op->files = NULL;
552
553   res = g_simple_async_result_new (G_OBJECT (enumerator), callback, user_data, g_file_enumerator_real_next_files_async);
554   g_simple_async_result_set_op_res_gpointer (res, op, g_free);
555   
556   g_simple_async_result_run_in_thread (res, next_files_thread, io_priority, cancellable);
557   g_object_unref (res);
558 }
559
560 static GList *
561 g_file_enumerator_real_next_files_finish (GFileEnumerator                *enumerator,
562                                           GAsyncResult                   *result,
563                                           GError                        **error)
564 {
565   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
566   NextAsyncOp *op;
567
568   g_assert (g_simple_async_result_get_source_tag (simple) == 
569             g_file_enumerator_real_next_files_async);
570
571   op = g_simple_async_result_get_op_res_gpointer (simple);
572
573   return op->files;
574 }
575
576 static void
577 close_async_thread (GSimpleAsyncResult *res,
578                     GObject            *object,
579                     GCancellable       *cancellable)
580 {
581   GFileEnumeratorClass *class;
582   GError *error = NULL;
583   gboolean result;
584
585   /* Auto handling of cancelation disabled, and ignore
586      cancellation, since we want to close things anyway, although
587      possibly in a quick-n-dirty way. At least we never want to leak
588      open handles */
589   
590   class = G_FILE_ENUMERATOR_GET_CLASS (object);
591   result = class->close (G_FILE_ENUMERATOR (object), cancellable, &error);
592   if (!result)
593     {
594       g_simple_async_result_set_from_error (res, error);
595       g_error_free (error);
596     }
597 }
598
599
600 static void
601 g_file_enumerator_real_close_async (GFileEnumerator     *enumerator,
602                                     int                  io_priority,
603                                     GCancellable        *cancellable,
604                                     GAsyncReadyCallback  callback,
605                                     gpointer             user_data)
606 {
607   GSimpleAsyncResult *res;
608   
609   res = g_simple_async_result_new (G_OBJECT (enumerator),
610                                    callback,
611                                    user_data,
612                                    g_file_enumerator_real_close_async);
613
614   g_simple_async_result_set_handle_cancellation (res, FALSE);
615   
616   g_simple_async_result_run_in_thread (res,
617                                        close_async_thread,
618                                        io_priority,
619                                        cancellable);
620   g_object_unref (res);
621 }
622
623 static gboolean
624 g_file_enumerator_real_close_finish (GFileEnumerator  *enumerator,
625                                      GAsyncResult     *result,
626                                      GError          **error)
627 {
628   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
629   g_assert (g_simple_async_result_get_source_tag (simple) == 
630             g_file_enumerator_real_close_async);
631   return TRUE;
632 }
633
634 #define __G_FILE_ENUMERATOR_C__
635 #include "gioaliasdef.c"