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 <fanchunwei@src.gnome.org> for portions of this
patch and for reviews.

https://bugzilla.gnome.org/show_bug.cgi?id=707787
This commit is contained in:
Ryan Lortie 2013-09-12 17:00:29 +08:00
parent 0e71110d17
commit 725125aba3
4 changed files with 115 additions and 55 deletions

View File

@ -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()

View File

@ -30,6 +30,10 @@
#include <glib/gerror.h>
#ifdef G_OS_UNIX
#include <dirent.h>
#endif
G_BEGIN_DECLS
typedef struct _GDir GDir;

View File

@ -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;

View File

@ -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;