1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2006-2007 Red Hat, Inc.
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.
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.
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.
20 * Author: Alexander Larsson <alexl@redhat.com>
26 #include <glocalfileenumerator.h>
27 #include <glocalfileinfo.h>
28 #include <glocalfile.h>
35 #define CHUNK_SIZE 1000
38 * It would be nice to use the dirent->d_type to check file type without
39 * needing to stat each files on linux and other systems that support it.
40 * (question: does that following symlink or not?)
49 #include <sys/types.h>
60 struct _GLocalFileEnumerator
62 GFileEnumerator parent
;
64 GFileAttributeMatcher
*matcher
;
67 GFileQueryInfoFlags flags
;
69 gboolean got_parent_info
;
70 GLocalParentFileInfo parent_info
;
81 gboolean follow_symlinks
;
84 #define g_local_file_enumerator_get_type _g_local_file_enumerator_get_type
85 G_DEFINE_TYPE (GLocalFileEnumerator
, g_local_file_enumerator
, G_TYPE_FILE_ENUMERATOR
);
87 static GFileInfo
*g_local_file_enumerator_next_file (GFileEnumerator
*enumerator
,
88 GCancellable
*cancellable
,
90 static gboolean
g_local_file_enumerator_close (GFileEnumerator
*enumerator
,
91 GCancellable
*cancellable
,
96 free_entries (GLocalFileEnumerator
*local
)
101 if (local
->entries
!= NULL
)
103 for (i
= 0; local
->entries
[i
].name
!= NULL
; i
++)
104 g_free (local
->entries
[i
].name
);
106 g_free (local
->entries
);
112 g_local_file_enumerator_finalize (GObject
*object
)
114 GLocalFileEnumerator
*local
;
116 local
= G_LOCAL_FILE_ENUMERATOR (object
);
118 if (local
->got_parent_info
)
119 _g_local_file_info_free_parent_info (&local
->parent_info
);
120 g_free (local
->filename
);
121 g_file_attribute_matcher_unref (local
->matcher
);
125 g_dir_close (local
->dir
);
127 closedir (local
->dir
);
132 free_entries (local
);
134 G_OBJECT_CLASS (g_local_file_enumerator_parent_class
)->finalize (object
);
139 g_local_file_enumerator_class_init (GLocalFileEnumeratorClass
*klass
)
141 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
142 GFileEnumeratorClass
*enumerator_class
= G_FILE_ENUMERATOR_CLASS (klass
);
144 gobject_class
->finalize
= g_local_file_enumerator_finalize
;
146 enumerator_class
->next_file
= g_local_file_enumerator_next_file
;
147 enumerator_class
->close_fn
= g_local_file_enumerator_close
;
151 g_local_file_enumerator_init (GLocalFileEnumerator
*local
)
157 convert_file_to_io_error (GError
**error
,
162 if (file_error
== NULL
)
165 new_code
= G_IO_ERROR_FAILED
;
167 if (file_error
->domain
== G_FILE_ERROR
)
169 switch (file_error
->code
)
171 case G_FILE_ERROR_NOENT
:
172 new_code
= G_IO_ERROR_NOT_FOUND
;
174 case G_FILE_ERROR_ACCES
:
175 new_code
= G_IO_ERROR_PERMISSION_DENIED
;
177 case G_FILE_ERROR_NOTDIR
:
178 new_code
= G_IO_ERROR_NOT_DIRECTORY
;
180 case G_FILE_ERROR_MFILE
:
181 new_code
= G_IO_ERROR_TOO_MANY_OPEN_FILES
;
188 g_set_error_literal (error
, G_IO_ERROR
,
190 file_error
->message
);
195 _g_local_file_enumerator_new (GLocalFile
*file
,
196 const char *attributes
,
197 GFileQueryInfoFlags flags
,
198 GCancellable
*cancellable
,
201 GLocalFileEnumerator
*local
;
202 char *filename
= g_file_get_path (G_FILE (file
));
209 dir
= g_dir_open (filename
, 0, error
!= NULL
? &dir_error
: NULL
);
214 convert_file_to_io_error (error
, dir_error
);
215 g_error_free (dir_error
);
224 dir
= opendir (filename
);
229 g_set_error_literal (error
, G_IO_ERROR
,
230 g_io_error_from_errno (errsv
),
238 local
= g_object_new (G_TYPE_LOCAL_FILE_ENUMERATOR
,
243 local
->filename
= filename
;
244 local
->matcher
= g_file_attribute_matcher_new (attributes
);
245 local
->flags
= flags
;
247 return G_FILE_ENUMERATOR (local
);
252 sort_by_inode (const void *_a
, const void *_b
)
254 const DirEntry
*a
, *b
;
258 return a
->inode
- b
->inode
;
262 next_file_helper (GLocalFileEnumerator
*local
)
264 struct dirent
*entry
;
265 const char *filename
;
271 if (local
->entries
== NULL
||
272 (local
->entries
[local
->entries_pos
].name
== NULL
))
274 if (local
->entries
== NULL
)
275 local
->entries
= g_new (DirEntry
, CHUNK_SIZE
+ 1);
278 /* Restart by clearing old names */
279 for (i
= 0; local
->entries
[i
].name
!= NULL
; i
++)
280 g_free (local
->entries
[i
].name
);
283 for (i
= 0; i
< CHUNK_SIZE
; i
++)
285 entry
= readdir (local
->dir
);
287 && (0 == strcmp (entry
->d_name
, ".") ||
288 0 == strcmp (entry
->d_name
, "..")))
289 entry
= readdir (local
->dir
);
293 local
->entries
[i
].name
= g_strdup (entry
->d_name
);
294 local
->entries
[i
].inode
= entry
->d_ino
;
299 local
->entries
[i
].name
= NULL
;
300 local
->entries_pos
= 0;
302 qsort (local
->entries
, i
, sizeof (DirEntry
), sort_by_inode
);
305 filename
= local
->entries
[local
->entries_pos
++].name
;
306 if (filename
== NULL
)
307 local
->at_end
= TRUE
;
315 g_local_file_enumerator_next_file (GFileEnumerator
*enumerator
,
316 GCancellable
*cancellable
,
319 GLocalFileEnumerator
*local
= G_LOCAL_FILE_ENUMERATOR (enumerator
);
320 const char *filename
;
325 if (!local
->got_parent_info
)
327 _g_local_file_info_get_parent_info (local
->filename
, local
->matcher
, &local
->parent_info
);
328 local
->got_parent_info
= TRUE
;
334 filename
= g_dir_read_name (local
->dir
);
336 filename
= next_file_helper (local
);
339 if (filename
== NULL
)
343 path
= g_build_filename (local
->filename
, filename
, NULL
);
344 info
= _g_local_file_info_get (filename
, path
,
353 /* Failed to get info */
354 /* If the file does not exist there might have been a race where
355 * the file was removed between the readdir and the stat, so we
356 * ignore the file. */
357 if (g_error_matches (my_error
, G_IO_ERROR
, G_IO_ERROR_NOT_FOUND
))
359 g_error_free (my_error
);
363 g_propagate_error (error
, my_error
);
370 g_local_file_enumerator_close (GFileEnumerator
*enumerator
,
371 GCancellable
*cancellable
,
374 GLocalFileEnumerator
*local
= G_LOCAL_FILE_ENUMERATOR (enumerator
);
379 g_dir_close (local
->dir
);
381 closedir (local
->dir
);