/src/tinysparql/subprojects/glib-2.80.3/glib/gdir.c
Line | Count | Source (jump to first uncovered line) |
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 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
10 | | * |
11 | | * This library is free software; you can redistribute it and/or |
12 | | * modify it under the terms of the GNU Lesser General Public |
13 | | * License as published by the Free Software Foundation; either |
14 | | * version 2.1 of the License, or (at your option) any later version. |
15 | | * |
16 | | * This library is distributed in the hope that it will be useful, |
17 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
19 | | * Lesser General Public License for more details. |
20 | | * |
21 | | * You should have received a copy of the GNU Lesser General Public |
22 | | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
23 | | */ |
24 | | |
25 | | #include "config.h" |
26 | | |
27 | | #include <errno.h> |
28 | | #include <string.h> |
29 | | #include <stdio.h> |
30 | | #include <sys/stat.h> |
31 | | |
32 | | #ifdef HAVE_DIRENT_H |
33 | | #include <sys/types.h> |
34 | | #include <dirent.h> |
35 | | #endif |
36 | | |
37 | | #include "gdir.h" |
38 | | |
39 | | #include "gconvert.h" |
40 | | #include "gfileutils.h" |
41 | | #include "gstrfuncs.h" |
42 | | #include "gtestutils.h" |
43 | | #include "glibintl.h" |
44 | | |
45 | | #if defined (_MSC_VER) && !defined (HAVE_DIRENT_H) |
46 | | #include "dirent/dirent.h" |
47 | | #endif |
48 | | |
49 | | #include "glib-private.h" /* g_dir_open_with_errno, g_dir_new_from_dirp */ |
50 | | |
51 | | /** |
52 | | * GDir: |
53 | | * |
54 | | * An opaque structure representing an opened directory. |
55 | | */ |
56 | | |
57 | | struct _GDir |
58 | | { |
59 | | gatomicrefcount ref_count; |
60 | | #ifdef G_OS_WIN32 |
61 | | _WDIR *wdirp; |
62 | | #else |
63 | | DIR *dirp; |
64 | | #endif |
65 | | #ifdef G_OS_WIN32 |
66 | | /* maximum encoding of FILENAME_MAX UTF-8 characters, plus a nul terminator |
67 | | * (FILENAME_MAX is not guaranteed to include one) */ |
68 | | gchar utf8_buf[FILENAME_MAX*4 + 1]; |
69 | | #endif |
70 | | }; |
71 | | |
72 | | /*< private > |
73 | | * g_dir_open_with_errno: |
74 | | * @path: the path to the directory you are interested in. |
75 | | * @flags: Currently must be set to 0. Reserved for future use. |
76 | | * |
77 | | * Opens a directory for reading. |
78 | | * |
79 | | * This function is equivalent to g_dir_open() except in the error case, |
80 | | * errno will be set accordingly. |
81 | | * |
82 | | * This is useful if you want to construct your own error message. |
83 | | * |
84 | | * Returns: a newly allocated #GDir on success, or %NULL on failure, |
85 | | * with errno set accordingly. |
86 | | * |
87 | | * Since: 2.38 |
88 | | */ |
89 | | GDir * |
90 | | g_dir_open_with_errno (const gchar *path, |
91 | | guint flags) |
92 | 4 | { |
93 | | #ifdef G_OS_WIN32 |
94 | | GDir *dir; |
95 | | _WDIR *wdirp; |
96 | | gint saved_errno; |
97 | | wchar_t *wpath; |
98 | | #else |
99 | 4 | DIR *dirp; |
100 | 4 | #endif |
101 | | |
102 | 4 | g_return_val_if_fail (path != NULL, NULL); |
103 | | |
104 | | #ifdef G_OS_WIN32 |
105 | | wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL); |
106 | | |
107 | | g_return_val_if_fail (wpath != NULL, NULL); |
108 | | |
109 | | wdirp = _wopendir (wpath); |
110 | | saved_errno = errno; |
111 | | g_free (wpath); |
112 | | errno = saved_errno; |
113 | | |
114 | | if (wdirp == NULL) |
115 | | return NULL; |
116 | | |
117 | | dir = g_new0 (GDir, 1); |
118 | | g_atomic_ref_count_init (&dir->ref_count); |
119 | | dir->wdirp = wdirp; |
120 | | |
121 | | return g_steal_pointer (&dir); |
122 | | #else |
123 | 4 | dirp = opendir (path); |
124 | | |
125 | 4 | if (dirp == NULL) |
126 | 4 | return NULL; |
127 | | |
128 | 0 | return g_dir_new_from_dirp (dirp); |
129 | 4 | #endif |
130 | 4 | } |
131 | | |
132 | | /** |
133 | | * g_dir_open: (constructor) |
134 | | * @path: the path to the directory you are interested in. On Unix |
135 | | * in the on-disk encoding. On Windows in UTF-8 |
136 | | * @flags: Currently must be set to 0. Reserved for future use. |
137 | | * @error: return location for a #GError, or %NULL. |
138 | | * If non-%NULL, an error will be set if and only if |
139 | | * g_dir_open() fails. |
140 | | * |
141 | | * Opens a directory for reading. The names of the files in the |
142 | | * directory can then be retrieved using g_dir_read_name(). Note |
143 | | * that the ordering is not defined. |
144 | | * |
145 | | * Returns: (transfer full): a newly allocated #GDir on success, %NULL on failure. |
146 | | * If non-%NULL, you must free the result with g_dir_close() |
147 | | * when you are finished with it. |
148 | | **/ |
149 | | GDir * |
150 | | g_dir_open (const gchar *path, |
151 | | guint flags, |
152 | | GError **error) |
153 | 4 | { |
154 | 4 | gint saved_errno; |
155 | 4 | GDir *dir; |
156 | | |
157 | 4 | dir = g_dir_open_with_errno (path, flags); |
158 | | |
159 | 4 | if (dir == NULL) |
160 | 4 | { |
161 | 4 | gchar *utf8_path; |
162 | | |
163 | 4 | saved_errno = errno; |
164 | | |
165 | 4 | utf8_path = g_filename_to_utf8 (path, -1, NULL, NULL, NULL); |
166 | | |
167 | 4 | g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno), |
168 | 4 | _("Error opening directory ā%sā: %s"), utf8_path, g_strerror (saved_errno)); |
169 | 4 | g_free (utf8_path); |
170 | 4 | } |
171 | | |
172 | 4 | return dir; |
173 | 4 | } |
174 | | |
175 | | /*< private > |
176 | | * g_dir_new_from_dirp: |
177 | | * @dirp: a #DIR* created by opendir() or fdopendir() |
178 | | * |
179 | | * Creates a #GDir object from the DIR object that is created using |
180 | | * opendir() or fdopendir(). The created #GDir assumes ownership of the |
181 | | * passed-in #DIR pointer. |
182 | | * |
183 | | * @dirp must not be %NULL. |
184 | | * |
185 | | * This function never fails. |
186 | | * |
187 | | * Returns: a newly allocated #GDir, which should be closed using |
188 | | * g_dir_close(). |
189 | | * |
190 | | * Since: 2.38 |
191 | | **/ |
192 | | GDir * |
193 | | g_dir_new_from_dirp (gpointer dirp) |
194 | 0 | { |
195 | 0 | #ifdef G_OS_UNIX |
196 | 0 | GDir *dir; |
197 | |
|
198 | 0 | g_return_val_if_fail (dirp != NULL, NULL); |
199 | | |
200 | 0 | dir = g_new0 (GDir, 1); |
201 | 0 | g_atomic_ref_count_init (&dir->ref_count); |
202 | 0 | dir->dirp = dirp; |
203 | |
|
204 | 0 | return dir; |
205 | | #else |
206 | | g_assert_not_reached (); |
207 | | |
208 | | return NULL; |
209 | | #endif |
210 | 0 | } |
211 | | |
212 | | /** |
213 | | * g_dir_read_name: |
214 | | * @dir: a #GDir* created by g_dir_open() |
215 | | * |
216 | | * Retrieves the name of another entry in the directory, or %NULL. |
217 | | * The order of entries returned from this function is not defined, |
218 | | * and may vary by file system or other operating-system dependent |
219 | | * factors. |
220 | | * |
221 | | * %NULL may also be returned in case of errors. On Unix, you can |
222 | | * check `errno` to find out if %NULL was returned because of an error. |
223 | | * |
224 | | * On Unix, the '.' and '..' entries are omitted, and the returned |
225 | | * name is in the on-disk encoding. |
226 | | * |
227 | | * On Windows, as is true of all GLib functions which operate on |
228 | | * filenames, the returned name is in UTF-8. |
229 | | * |
230 | | * Returns: (type filename): The entry's name or %NULL if there are no |
231 | | * more entries. The return value is owned by GLib and |
232 | | * must not be modified or freed. |
233 | | **/ |
234 | | const gchar * |
235 | | g_dir_read_name (GDir *dir) |
236 | 0 | { |
237 | | #ifdef G_OS_WIN32 |
238 | | gchar *utf8_name; |
239 | | struct _wdirent *wentry; |
240 | | #else |
241 | 0 | struct dirent *entry; |
242 | 0 | #endif |
243 | |
|
244 | 0 | g_return_val_if_fail (dir != NULL, NULL); |
245 | | |
246 | | #ifdef G_OS_WIN32 |
247 | | while (1) |
248 | | { |
249 | | wentry = _wreaddir (dir->wdirp); |
250 | | while (wentry |
251 | | && (0 == wcscmp (wentry->d_name, L".") || |
252 | | 0 == wcscmp (wentry->d_name, L".."))) |
253 | | wentry = _wreaddir (dir->wdirp); |
254 | | |
255 | | if (wentry == NULL) |
256 | | return NULL; |
257 | | |
258 | | utf8_name = g_utf16_to_utf8 (wentry->d_name, -1, NULL, NULL, NULL); |
259 | | |
260 | | if (utf8_name == NULL) |
261 | | continue; /* Huh, impossible? Skip it anyway */ |
262 | | |
263 | | strcpy (dir->utf8_buf, utf8_name); |
264 | | g_free (utf8_name); |
265 | | |
266 | | return dir->utf8_buf; |
267 | | } |
268 | | #else |
269 | 0 | entry = readdir (dir->dirp); |
270 | 0 | while (entry |
271 | 0 | && (0 == strcmp (entry->d_name, ".") || |
272 | 0 | 0 == strcmp (entry->d_name, ".."))) |
273 | 0 | entry = readdir (dir->dirp); |
274 | |
|
275 | 0 | if (entry) |
276 | 0 | return entry->d_name; |
277 | 0 | else |
278 | 0 | return NULL; |
279 | 0 | #endif |
280 | 0 | } |
281 | | |
282 | | /** |
283 | | * g_dir_rewind: |
284 | | * @dir: a #GDir* created by g_dir_open() |
285 | | * |
286 | | * Resets the given directory. The next call to g_dir_read_name() |
287 | | * will return the first entry again. |
288 | | **/ |
289 | | void |
290 | | g_dir_rewind (GDir *dir) |
291 | 0 | { |
292 | 0 | g_return_if_fail (dir != NULL); |
293 | | |
294 | | #ifdef G_OS_WIN32 |
295 | | _wrewinddir (dir->wdirp); |
296 | | #else |
297 | 0 | rewinddir (dir->dirp); |
298 | 0 | #endif |
299 | 0 | } |
300 | | |
301 | | static void |
302 | | g_dir_actually_close (GDir *dir) |
303 | 0 | { |
304 | | #ifdef G_OS_WIN32 |
305 | | g_clear_pointer (&dir->wdirp, _wclosedir); |
306 | | #else |
307 | 0 | g_clear_pointer (&dir->dirp, closedir); |
308 | 0 | #endif |
309 | 0 | } |
310 | | |
311 | | /** |
312 | | * g_dir_close: |
313 | | * @dir: (transfer full): a #GDir* created by g_dir_open() |
314 | | * |
315 | | * Closes the directory immediately and decrements the reference count. |
316 | | * |
317 | | * Once the reference count reaches zero, the `GDir` structure itself will be |
318 | | * freed. Prior to GLib 2.80, `GDir` was not reference counted. |
319 | | * |
320 | | * It is an error to call any of the `GDir` methods other than |
321 | | * [method@GLib.Dir.ref] and [method@GLib.Dir.unref] on a `GDir` after calling |
322 | | * [method@GLib.Dir.close] on it. |
323 | | **/ |
324 | | void |
325 | | g_dir_close (GDir *dir) |
326 | 0 | { |
327 | 0 | g_return_if_fail (dir != NULL); |
328 | | |
329 | 0 | g_dir_actually_close (dir); |
330 | 0 | g_dir_unref (dir); |
331 | 0 | } |
332 | | |
333 | | /** |
334 | | * g_dir_ref: |
335 | | * @dir: (transfer none): a `GDir` |
336 | | * |
337 | | * Increment the reference count of `dir`. |
338 | | * |
339 | | * Returns: (transfer full): the same pointer as `dir` |
340 | | * Since: 2.80 |
341 | | */ |
342 | | GDir * |
343 | | g_dir_ref (GDir *dir) |
344 | 0 | { |
345 | 0 | g_return_val_if_fail (dir != NULL, NULL); |
346 | | |
347 | 0 | g_atomic_ref_count_inc (&dir->ref_count); |
348 | 0 | return dir; |
349 | 0 | } |
350 | | |
351 | | /** |
352 | | * g_dir_unref: |
353 | | * @dir: (transfer full): a `GDir` |
354 | | * |
355 | | * Decrements the reference count of `dir`. |
356 | | * |
357 | | * Once the reference count reaches zero, the directory will be closed and all |
358 | | * resources associated with it will be freed. If [method@GLib.Dir.close] is |
359 | | * called when the reference count is greater than zero, the directory is closed |
360 | | * but the `GDir` structure will not be freed until its reference count reaches |
361 | | * zero. |
362 | | * |
363 | | * It is an error to call any of the `GDir` methods other than |
364 | | * [method@GLib.Dir.ref] and [method@GLib.Dir.unref] on a `GDir` after calling |
365 | | * [method@GLib.Dir.close] on it. |
366 | | * |
367 | | * Since: 2.80 |
368 | | */ |
369 | | void |
370 | | g_dir_unref (GDir *dir) |
371 | 0 | { |
372 | 0 | g_return_if_fail (dir != NULL); |
373 | | |
374 | 0 | if (g_atomic_ref_count_dec (&dir->ref_count)) |
375 | 0 | { |
376 | 0 | g_dir_actually_close (dir); |
377 | 0 | g_free (dir); |
378 | 0 | } |
379 | 0 | } |
380 | | |
381 | | #ifdef G_OS_WIN32 |
382 | | |
383 | | /* Binary compatibility versions. Not for newly compiled code. */ |
384 | | |
385 | | _GLIB_EXTERN GDir *g_dir_open_utf8 (const gchar *path, |
386 | | guint flags, |
387 | | GError **error); |
388 | | _GLIB_EXTERN const gchar *g_dir_read_name_utf8 (GDir *dir); |
389 | | |
390 | | GDir * |
391 | | g_dir_open_utf8 (const gchar *path, |
392 | | guint flags, |
393 | | GError **error) |
394 | | { |
395 | | return g_dir_open (path, flags, error); |
396 | | } |
397 | | |
398 | | const gchar * |
399 | | g_dir_read_name_utf8 (GDir *dir) |
400 | | { |
401 | | return g_dir_read_name (dir); |
402 | | } |
403 | | |
404 | | #endif |