From 725125aba3875ccd86dc51b8e4f301fe3c8de3a4 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Thu, 12 Sep 2013 17:00:29 +0800 Subject: [PATCH] GDir: add some glib-private APIs Add a simple UNIX-only API that is used to create a GDir object from a DIR* that is aquired using opendir() or fdopendir(). This makes it possible to use GDir with openat(), which in turn will allow use of GDir in the existing GLocalFile implementation of g_file_measure_disk_usage(), avoiding the current MSVC compatibility problems there. Also add an API similar to g_dir_open(), but without the GError handling (since we want to create a better error message from inside of glocalfile.c). Thanks to Chun-wei Fan for portions of this patch and for reviews. https://bugzilla.gnome.org/show_bug.cgi?id=707787 --- glib/gdir.c | 153 ++++++++++++++++++++++++++++---------------- glib/gdir.h | 4 ++ glib/glib-private.c | 5 +- glib/glib-private.h | 8 +++ 4 files changed, 115 insertions(+), 55 deletions(-) diff --git a/glib/gdir.c b/glib/gdir.c index 0c304f6be..4f1798158 100644 --- a/glib/gdir.c +++ b/glib/gdir.c @@ -47,6 +47,8 @@ #include "../build/win32/dirent/wdirent.c" #endif +#include "glib-private.h" /* g_dir_open_with_errno, g_dir_new_from_dirp */ + /** * GDir: * @@ -65,6 +67,57 @@ struct _GDir #endif }; +/*< private > + * g_dir_open_with_errno: + * @path: the path to the directory you are interested in. + * @flags: Currently must be set to 0. Reserved for future use. + * + * Opens a directory for reading. + * + * This function is equivalent to g_dir_open() except in the error case, + * errno will be set accordingly. + * + * This is useful if you want to construct your own error message. + * + * Returns: a newly allocated #GDir on success, or %NULL on failure, + * with errno set accordingly. + * + * Since: 2.38 + */ +GDir * +g_dir_open_with_errno (const gchar *path, + guint flags) +{ + GDir dir; +#ifdef G_OS_WIN32 + gint saved_errno; + wchar_t *wpath; +#endif + + g_return_val_if_fail (path != NULL, NULL); + +#ifdef G_OS_WIN32 + wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL); + + g_return_val_if_fail (wpath != NULL, NULL); + + dir.wdirp = _wopendir (wpath); + saved_errno = errno; + g_free (wpath); + errno = saved_errno; + + if (dir.wdirp == NULL) + return NULL; +#else + dir.dirp = opendir (path); + + if (dir.dirp == NULL) + return NULL; +#endif + + return g_memdup (&dir, sizeof dir); +} + /** * g_dir_open: * @path: the path to the directory you are interested in. On Unix @@ -87,67 +140,25 @@ g_dir_open (const gchar *path, guint flags, GError **error) { + gint saved_errno; GDir *dir; - int errsv; -#ifdef G_OS_WIN32 - wchar_t *wpath; -#else - gchar *utf8_path; -#endif - g_return_val_if_fail (path != NULL, NULL); + dir = g_dir_open_with_errno (path, flags); -#ifdef G_OS_WIN32 - wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, error); + if (dir == NULL) + { + gchar *utf8_path; - if (wpath == NULL) - return NULL; + saved_errno = errno; - dir = g_new (GDir, 1); + utf8_path = g_filename_to_utf8 (path, -1, NULL, NULL, NULL); - dir->wdirp = _wopendir (wpath); - g_free (wpath); + g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno), + _("Error opening directory '%s': %s"), utf8_path, g_strerror (saved_errno)); + g_free (utf8_path); + } - if (dir->wdirp) - return dir; - - /* error case */ - errsv = errno; - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - _("Error opening directory '%s': %s"), - path, g_strerror (errsv)); - - g_free (dir); - - return NULL; -#else - dir = g_new (GDir, 1); - - dir->dirp = opendir (path); - - if (dir->dirp) - return dir; - - /* error case */ - errsv = errno; - - utf8_path = g_filename_to_utf8 (path, -1, - NULL, NULL, NULL); - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - _("Error opening directory '%s': %s"), - utf8_path, g_strerror (errsv)); - - g_free (utf8_path); - g_free (dir); - - return NULL; -#endif + return dir; } #if defined (G_OS_WIN32) && !defined (_WIN64) @@ -180,6 +191,40 @@ g_dir_open (const gchar *path, } #endif +/*< private > + * g_dir_new_from_dirp: + * @dirp: a #DIR* created by opendir() or fdopendir() + * + * Creates a #GDir object from the DIR object that is created using + * opendir() or fdopendir(). The created #GDir assumes ownership of the + * passed-in #DIR pointer. + * + * @dirp must not be %NULL. + * + * This function never fails. + * + * Returns: a newly allocated #GDir, which should be closed using + * g_dir_close(). + * + * Since: 2.38 + **/ +GDir * +g_dir_new_from_dirp (gpointer dirp) +{ +#ifdef G_OS_UNIX + GDir *dir; + + g_return_val_if_fail (dirp != NULL, NULL); + + dir = g_new (GDir, 1); + dir->dirp = dirp; + + return dir; +#else + g_assert_not_reached (); +#endif +} + /** * g_dir_read_name: * @dir: a #GDir* created by g_dir_open() diff --git a/glib/gdir.h b/glib/gdir.h index 0b7c4afce..7b6ec1b51 100644 --- a/glib/gdir.h +++ b/glib/gdir.h @@ -30,6 +30,10 @@ #include +#ifdef G_OS_UNIX +#include +#endif + G_BEGIN_DECLS typedef struct _GDir GDir; diff --git a/glib/glib-private.c b/glib/glib-private.c index d2da2cd47..c357502b2 100644 --- a/glib/glib-private.c +++ b/glib/glib-private.c @@ -43,7 +43,10 @@ glib__private__ (void) g_get_worker_context, g_check_setuid, - g_main_context_new_with_next_id + g_main_context_new_with_next_id, + + g_dir_open_with_errno, + g_dir_new_from_dirp }; return &table; diff --git a/glib/glib-private.h b/glib/glib-private.h index 7e2e61efc..44cbf3d94 100644 --- a/glib/glib-private.h +++ b/glib/glib-private.h @@ -33,6 +33,9 @@ GLIB_AVAILABLE_IN_ALL gchar *_glib_get_locale_dir (void); #endif +GDir * g_dir_open_with_errno (const gchar *path, guint flags); +GDir * g_dir_new_from_dirp (gpointer dirp); + #define GLIB_PRIVATE_CALL(symbol) (glib__private__()->symbol) typedef struct { @@ -49,6 +52,11 @@ typedef struct { gboolean (* g_check_setuid) (void); GMainContext * (* g_main_context_new_with_next_id) (guint next_id); + + GDir * (* g_dir_open_with_errno) (const gchar *path, + guint flags); + GDir * (* g_dir_new_from_dirp) (gpointer dirp); + /* Add other private functions here, initialize them in glib-private.c */ } GLibPrivateVTable;