1 | /* GLIB - Library of useful routines for C programming |
2 | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
3 | * |
4 | * gdir.c: Simplified wrapper around the DIRENT functions. |
5 | * |
6 | * Copyright 2001 Hans Breuer |
7 | * Copyright 2004 Tor Lillqvist |
8 | * |
9 | * This library is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU Lesser General Public |
11 | * License as published by the Free Software Foundation; either |
12 | * version 2.1 of the License, or (at your option) any later version. |
13 | * |
14 | * This library is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * Lesser General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU Lesser General Public |
20 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
21 | */ |
22 | |
23 | #include "config.h" |
24 | |
25 | #include <errno.h> |
26 | #include <string.h> |
27 | #include <stdio.h> |
28 | #include <sys/stat.h> |
29 | |
30 | #ifdef HAVE_DIRENT_H |
31 | #include <sys/types.h> |
32 | #include <dirent.h> |
33 | #endif |
34 | |
35 | #include "gdir.h" |
36 | |
37 | #include "gconvert.h" |
38 | #include "gfileutils.h" |
39 | #include "gstrfuncs.h" |
40 | #include "gtestutils.h" |
41 | #include "glibintl.h" |
42 | |
43 | #if defined (_MSC_VER) && !defined (HAVE_DIRENT_H) |
44 | #include "dirent/dirent.h" |
45 | #endif |
46 | |
47 | #include "glib-private.h" /* g_dir_open_with_errno, g_dir_new_from_dirp */ |
48 | |
49 | /** |
50 | * GDir: |
51 | * |
52 | * An opaque structure representing an opened directory. |
53 | */ |
54 | |
55 | struct _GDir |
56 | { |
57 | #ifdef G_OS_WIN32 |
58 | _WDIR *wdirp; |
59 | #else |
60 | DIR *dirp; |
61 | #endif |
62 | #ifdef G_OS_WIN32 |
63 | gchar utf8_buf[FILENAME_MAX*4]; |
64 | #endif |
65 | }; |
66 | |
67 | /*< private > |
68 | * g_dir_open_with_errno: |
69 | * @path: the path to the directory you are interested in. |
70 | * @flags: Currently must be set to 0. Reserved for future use. |
71 | * |
72 | * Opens a directory for reading. |
73 | * |
74 | * This function is equivalent to g_dir_open() except in the error case, |
75 | * errno will be set accordingly. |
76 | * |
77 | * This is useful if you want to construct your own error message. |
78 | * |
79 | * Returns: a newly allocated #GDir on success, or %NULL on failure, |
80 | * with errno set accordingly. |
81 | * |
82 | * Since: 2.38 |
83 | */ |
84 | GDir * |
85 | g_dir_open_with_errno (const gchar *path, |
86 | guint flags) |
87 | { |
88 | GDir dir; |
89 | #ifdef G_OS_WIN32 |
90 | gint saved_errno; |
91 | wchar_t *wpath; |
92 | #endif |
93 | |
94 | g_return_val_if_fail (path != NULL, NULL); |
95 | |
96 | #ifdef G_OS_WIN32 |
97 | wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL); |
98 | |
99 | g_return_val_if_fail (wpath != NULL, NULL); |
100 | |
101 | dir.wdirp = _wopendir (wpath); |
102 | saved_errno = errno; |
103 | g_free (wpath); |
104 | errno = saved_errno; |
105 | |
106 | if (dir.wdirp == NULL) |
107 | return NULL; |
108 | #else |
109 | dir.dirp = opendir (name: path); |
110 | |
111 | if (dir.dirp == NULL) |
112 | return NULL; |
113 | #endif |
114 | |
115 | return g_memdup2 (mem: &dir, byte_size: sizeof dir); |
116 | } |
117 | |
118 | /** |
119 | * g_dir_open: |
120 | * @path: the path to the directory you are interested in. On Unix |
121 | * in the on-disk encoding. On Windows in UTF-8 |
122 | * @flags: Currently must be set to 0. Reserved for future use. |
123 | * @error: return location for a #GError, or %NULL. |
124 | * If non-%NULL, an error will be set if and only if |
125 | * g_dir_open() fails. |
126 | * |
127 | * Opens a directory for reading. The names of the files in the |
128 | * directory can then be retrieved using g_dir_read_name(). Note |
129 | * that the ordering is not defined. |
130 | * |
131 | * Returns: a newly allocated #GDir on success, %NULL on failure. |
132 | * If non-%NULL, you must free the result with g_dir_close() |
133 | * when you are finished with it. |
134 | **/ |
135 | GDir * |
136 | g_dir_open (const gchar *path, |
137 | guint flags, |
138 | GError **error) |
139 | { |
140 | gint saved_errno; |
141 | GDir *dir; |
142 | |
143 | dir = g_dir_open_with_errno (path, flags); |
144 | |
145 | if (dir == NULL) |
146 | { |
147 | gchar *utf8_path; |
148 | |
149 | saved_errno = errno; |
150 | |
151 | utf8_path = g_filename_to_utf8 (opsysstring: path, len: -1, NULL, NULL, NULL); |
152 | |
153 | g_set_error (err: error, G_FILE_ERROR, code: g_file_error_from_errno (err_no: saved_errno), |
154 | _("Error opening directory ā%sā: %s" ), utf8_path, g_strerror (errnum: saved_errno)); |
155 | g_free (mem: utf8_path); |
156 | } |
157 | |
158 | return dir; |
159 | } |
160 | |
161 | /*< private > |
162 | * g_dir_new_from_dirp: |
163 | * @dirp: a #DIR* created by opendir() or fdopendir() |
164 | * |
165 | * Creates a #GDir object from the DIR object that is created using |
166 | * opendir() or fdopendir(). The created #GDir assumes ownership of the |
167 | * passed-in #DIR pointer. |
168 | * |
169 | * @dirp must not be %NULL. |
170 | * |
171 | * This function never fails. |
172 | * |
173 | * Returns: a newly allocated #GDir, which should be closed using |
174 | * g_dir_close(). |
175 | * |
176 | * Since: 2.38 |
177 | **/ |
178 | GDir * |
179 | g_dir_new_from_dirp (gpointer dirp) |
180 | { |
181 | #ifdef G_OS_UNIX |
182 | GDir *dir; |
183 | |
184 | g_return_val_if_fail (dirp != NULL, NULL); |
185 | |
186 | dir = g_new (GDir, 1); |
187 | dir->dirp = dirp; |
188 | |
189 | return dir; |
190 | #else |
191 | g_assert_not_reached (); |
192 | |
193 | return NULL; |
194 | #endif |
195 | } |
196 | |
197 | /** |
198 | * g_dir_read_name: |
199 | * @dir: a #GDir* created by g_dir_open() |
200 | * |
201 | * Retrieves the name of another entry in the directory, or %NULL. |
202 | * The order of entries returned from this function is not defined, |
203 | * and may vary by file system or other operating-system dependent |
204 | * factors. |
205 | * |
206 | * %NULL may also be returned in case of errors. On Unix, you can |
207 | * check `errno` to find out if %NULL was returned because of an error. |
208 | * |
209 | * On Unix, the '.' and '..' entries are omitted, and the returned |
210 | * name is in the on-disk encoding. |
211 | * |
212 | * On Windows, as is true of all GLib functions which operate on |
213 | * filenames, the returned name is in UTF-8. |
214 | * |
215 | * Returns: (type filename): The entry's name or %NULL if there are no |
216 | * more entries. The return value is owned by GLib and |
217 | * must not be modified or freed. |
218 | **/ |
219 | const gchar * |
220 | g_dir_read_name (GDir *dir) |
221 | { |
222 | #ifdef G_OS_WIN32 |
223 | gchar *utf8_name; |
224 | struct _wdirent *wentry; |
225 | #else |
226 | struct dirent *entry; |
227 | #endif |
228 | |
229 | g_return_val_if_fail (dir != NULL, NULL); |
230 | |
231 | #ifdef G_OS_WIN32 |
232 | while (1) |
233 | { |
234 | wentry = _wreaddir (dir->wdirp); |
235 | while (wentry |
236 | && (0 == wcscmp (wentry->d_name, L"." ) || |
237 | 0 == wcscmp (wentry->d_name, L".." ))) |
238 | wentry = _wreaddir (dir->wdirp); |
239 | |
240 | if (wentry == NULL) |
241 | return NULL; |
242 | |
243 | utf8_name = g_utf16_to_utf8 (wentry->d_name, -1, NULL, NULL, NULL); |
244 | |
245 | if (utf8_name == NULL) |
246 | continue; /* Huh, impossible? Skip it anyway */ |
247 | |
248 | strcpy (dir->utf8_buf, utf8_name); |
249 | g_free (utf8_name); |
250 | |
251 | return dir->utf8_buf; |
252 | } |
253 | #else |
254 | entry = readdir (dirp: dir->dirp); |
255 | while (entry |
256 | && (0 == strcmp (s1: entry->d_name, s2: "." ) || |
257 | 0 == strcmp (s1: entry->d_name, s2: ".." ))) |
258 | entry = readdir (dirp: dir->dirp); |
259 | |
260 | if (entry) |
261 | return entry->d_name; |
262 | else |
263 | return NULL; |
264 | #endif |
265 | } |
266 | |
267 | /** |
268 | * g_dir_rewind: |
269 | * @dir: a #GDir* created by g_dir_open() |
270 | * |
271 | * Resets the given directory. The next call to g_dir_read_name() |
272 | * will return the first entry again. |
273 | **/ |
274 | void |
275 | g_dir_rewind (GDir *dir) |
276 | { |
277 | g_return_if_fail (dir != NULL); |
278 | |
279 | #ifdef G_OS_WIN32 |
280 | _wrewinddir (dir->wdirp); |
281 | #else |
282 | rewinddir (dirp: dir->dirp); |
283 | #endif |
284 | } |
285 | |
286 | /** |
287 | * g_dir_close: |
288 | * @dir: a #GDir* created by g_dir_open() |
289 | * |
290 | * Closes the directory and deallocates all related resources. |
291 | **/ |
292 | void |
293 | g_dir_close (GDir *dir) |
294 | { |
295 | g_return_if_fail (dir != NULL); |
296 | |
297 | #ifdef G_OS_WIN32 |
298 | _wclosedir (dir->wdirp); |
299 | #else |
300 | closedir (dirp: dir->dirp); |
301 | #endif |
302 | g_free (mem: dir); |
303 | } |
304 | |
305 | #ifdef G_OS_WIN32 |
306 | |
307 | /* Binary compatibility versions. Not for newly compiled code. */ |
308 | |
309 | _GLIB_EXTERN GDir *g_dir_open_utf8 (const gchar *path, |
310 | guint flags, |
311 | GError **error); |
312 | _GLIB_EXTERN const gchar *g_dir_read_name_utf8 (GDir *dir); |
313 | |
314 | GDir * |
315 | g_dir_open_utf8 (const gchar *path, |
316 | guint flags, |
317 | GError **error) |
318 | { |
319 | return g_dir_open (path, flags, error); |
320 | } |
321 | |
322 | const gchar * |
323 | g_dir_read_name_utf8 (GDir *dir) |
324 | { |
325 | return g_dir_read_name (dir); |
326 | } |
327 | |
328 | #endif |
329 | |