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>
36 #define CHUNK_SIZE 1000
39 * It would be nice to use the dirent->d_type to check file type without
40 * needing to stat each files on linux and other systems that support it.
41 * (question: does that following symlink or not?)
50 #include <sys/types.h>
61 struct _GLocalFileEnumerator
63 GFileEnumerator parent
;
65 GFileAttributeMatcher
*matcher
;
68 GFileQueryInfoFlags flags
;
70 gboolean got_parent_info
;
71 GLocalParentFileInfo parent_info
;
82 gboolean follow_symlinks
;
85 #define g_local_file_enumerator_get_type _g_local_file_enumerator_get_type
86 G_DEFINE_TYPE (GLocalFileEnumerator
, g_local_file_enumerator
, G_TYPE_FILE_ENUMERATOR
);
88 static GFileInfo
*g_local_file_enumerator_next_file (GFileEnumerator
*enumerator
,
89 GCancellable
*cancellable
,
91 static gboolean
g_local_file_enumerator_close (GFileEnumerator
*enumerator
,
92 GCancellable
*cancellable
,
97 free_entries (GLocalFileEnumerator
*local
)
102 if (local
->entries
!= NULL
)
104 for (i
= 0; local
->entries
[i
].name
!= NULL
; i
++)
105 g_free (local
->entries
[i
].name
);
107 g_free (local
->entries
);
113 g_local_file_enumerator_finalize (GObject
*object
)
115 GLocalFileEnumerator
*local
;
117 local
= G_LOCAL_FILE_ENUMERATOR (object
);
119 g_free (local
->filename
);
120 g_file_attribute_matcher_unref (local
->matcher
);
124 g_dir_close (local
->dir
);
126 closedir (local
->dir
);
131 free_entries (local
);
133 G_OBJECT_CLASS (g_local_file_enumerator_parent_class
)->finalize (object
);
138 g_local_file_enumerator_class_init (GLocalFileEnumeratorClass
*klass
)
140 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
141 GFileEnumeratorClass
*enumerator_class
= G_FILE_ENUMERATOR_CLASS (klass
);
143 gobject_class
->finalize
= g_local_file_enumerator_finalize
;
145 enumerator_class
->next_file
= g_local_file_enumerator_next_file
;
146 enumerator_class
->close_fn
= g_local_file_enumerator_close
;
150 g_local_file_enumerator_init (GLocalFileEnumerator
*local
)
156 convert_file_to_io_error (GError
**error
,
161 if (file_error
== NULL
)
164 new_code
= G_IO_ERROR_FAILED
;
166 if (file_error
->domain
== G_FILE_ERROR
)
168 switch (file_error
->code
)
170 case G_FILE_ERROR_NOENT
:
171 new_code
= G_IO_ERROR_NOT_FOUND
;
173 case G_FILE_ERROR_ACCES
:
174 new_code
= G_IO_ERROR_PERMISSION_DENIED
;
176 case G_FILE_ERROR_NOTDIR
:
177 new_code
= G_IO_ERROR_NOT_DIRECTORY
;
184 g_set_error_literal (error
, G_IO_ERROR
,
186 file_error
->message
);
191 _g_local_file_enumerator_new (GLocalFile
*file
,
192 const char *attributes
,
193 GFileQueryInfoFlags flags
,
194 GCancellable
*cancellable
,
197 GLocalFileEnumerator
*local
;
198 char *filename
= g_file_get_path (G_FILE (file
));
205 dir
= g_dir_open (filename
, 0, error
!= NULL
? &dir_error
: NULL
);
210 convert_file_to_io_error (error
, dir_error
);
211 g_error_free (dir_error
);
220 dir
= opendir (filename
);
225 g_set_error_literal (error
, G_IO_ERROR
,
226 g_io_error_from_errno (errsv
),
234 local
= g_object_new (G_TYPE_LOCAL_FILE_ENUMERATOR
,
239 local
->filename
= filename
;
240 local
->matcher
= g_file_attribute_matcher_new (attributes
);
241 local
->flags
= flags
;
243 return G_FILE_ENUMERATOR (local
);
248 sort_by_inode (const void *_a
, const void *_b
)
250 const DirEntry
*a
, *b
;
254 return a
->inode
- b
->inode
;
258 next_file_helper (GLocalFileEnumerator
*local
)
260 struct dirent
*entry
;
261 const char *filename
;
267 if (local
->entries
== NULL
||
268 (local
->entries
[local
->entries_pos
].name
== NULL
))
270 if (local
->entries
== NULL
)
271 local
->entries
= g_new (DirEntry
, CHUNK_SIZE
+ 1);
274 /* Restart by clearing old names */
275 for (i
= 0; local
->entries
[i
].name
!= NULL
; i
++)
276 g_free (local
->entries
[i
].name
);
279 for (i
= 0; i
< CHUNK_SIZE
; i
++)
281 entry
= readdir (local
->dir
);
283 && (0 == strcmp (entry
->d_name
, ".") ||
284 0 == strcmp (entry
->d_name
, "..")))
285 entry
= readdir (local
->dir
);
289 local
->entries
[i
].name
= g_strdup (entry
->d_name
);
290 local
->entries
[i
].inode
= entry
->d_ino
;
295 local
->entries
[i
].name
= NULL
;
296 local
->entries_pos
= 0;
298 qsort (local
->entries
, i
, sizeof (DirEntry
), sort_by_inode
);
301 filename
= local
->entries
[local
->entries_pos
++].name
;
302 if (filename
== NULL
)
303 local
->at_end
= TRUE
;
311 g_local_file_enumerator_next_file (GFileEnumerator
*enumerator
,
312 GCancellable
*cancellable
,
315 GLocalFileEnumerator
*local
= G_LOCAL_FILE_ENUMERATOR (enumerator
);
316 const char *filename
;
321 if (!local
->got_parent_info
)
323 _g_local_file_info_get_parent_info (local
->filename
, local
->matcher
, &local
->parent_info
);
324 local
->got_parent_info
= TRUE
;
330 filename
= g_dir_read_name (local
->dir
);
332 filename
= next_file_helper (local
);
335 if (filename
== NULL
)
339 path
= g_build_filename (local
->filename
, filename
, NULL
);
340 info
= _g_local_file_info_get (filename
, path
,
349 /* Failed to get info */
350 /* If the file does not exist there might have been a race where
351 * the file was removed between the readdir and the stat, so we
352 * ignore the file. */
353 if (my_error
->domain
== G_IO_ERROR
&&
354 my_error
->code
== G_IO_ERROR_NOT_FOUND
)
356 g_error_free (my_error
);
360 g_propagate_error (error
, my_error
);
367 g_local_file_enumerator_close (GFileEnumerator
*enumerator
,
368 GCancellable
*cancellable
,
371 GLocalFileEnumerator
*local
= G_LOCAL_FILE_ENUMERATOR (enumerator
);
376 g_dir_close (local
->dir
);
378 closedir (local
->dir
);