glib/gio/gio-querymodules.c
Philip Withnall 5cddde1fb2 Consistently save errno immediately after the operation setting it
Prevent the situation where errno is set by function A, then function B
is called (which is typically _(), but could be anything else) and it
overwrites errno, then errno is checked by the caller.

errno is a horrific API, and we need to be careful to save its value as
soon as a function call (which might set it) returns. i.e. Follow the
pattern:
  int errsv, ret;
  ret = some_call_which_might_set_errno ();
  errsv = errno;

  if (ret < 0)
    puts (strerror (errsv));

This patch implements that pattern throughout GLib. There might be a few
places in the test code which still use errno directly. They should be
ported as necessary. It doesn’t modify all the call sites like this:
  if (some_call_which_might_set_errno () && errno == ESOMETHING)
since the refactoring involved is probably more harmful than beneficial
there. It does, however, refactor other call sites regardless of whether
they were originally buggy.

https://bugzilla.gnome.org/show_bug.cgi?id=785577
2017-08-03 10:21:13 +01:00

152 lines
3.4 KiB
C

/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2007 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Alexander Larsson <alexl@redhat.com>
*/
#include "config.h"
#include "giomodule.h"
#include <gstdio.h>
#include <errno.h>
#include <locale.h>
static gboolean
is_valid_module_name (const gchar *basename)
{
#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
return
g_str_has_prefix (basename, "lib") &&
g_str_has_suffix (basename, ".so");
#else
return g_str_has_suffix (basename, ".dll");
#endif
}
static void
query_dir (const char *dirname)
{
GString *data;
GDir *dir;
const char *name;
char *cachename;
char **(* query) (void);
GError *error;
int i;
if (!g_module_supported ())
return;
error = NULL;
dir = g_dir_open (dirname, 0, &error);
if (!dir)
{
g_printerr ("Unable to open directory %s: %s\n", dirname, error->message);
g_error_free (error);
return;
}
data = g_string_new ("");
while ((name = g_dir_read_name (dir)))
{
GModule *module;
gchar *path;
char **extension_points;
if (!is_valid_module_name (name))
continue;
path = g_build_filename (dirname, name, NULL);
module = g_module_open (path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
g_free (path);
if (module)
{
g_module_symbol (module, "g_io_module_query", (gpointer) &query);
if (query)
{
extension_points = query ();
if (extension_points)
{
g_string_append_printf (data, "%s: ", name);
for (i = 0; extension_points[i] != NULL; i++)
g_string_append_printf (data, "%s%s", i == 0 ? "" : ",", extension_points[i]);
g_string_append (data, "\n");
g_strfreev (extension_points);
}
}
g_module_close (module);
}
}
g_dir_close (dir);
cachename = g_build_filename (dirname, "giomodule.cache", NULL);
if (data->len > 0)
{
error = NULL;
if (!g_file_set_contents (cachename, data->str, data->len, &error))
{
g_printerr ("Unable to create %s: %s\n", cachename, error->message);
g_error_free (error);
}
}
else
{
if (g_unlink (cachename) != 0 && errno != ENOENT)
{
int errsv = errno;
g_printerr ("Unable to unlink %s: %s\n", cachename, g_strerror (errsv));
}
}
g_free (cachename);
g_string_free (data, TRUE);
}
int
main (gint argc,
gchar *argv[])
{
int i;
if (argc == 1)
{
g_print ("Usage: gio-querymodules <directory1> [<directory2> ...]\n");
g_print ("Will update giomodule.cache in the listed directories\n");
return 1;
}
setlocale (LC_ALL, "");
/* Be defensive and ensure we're linked to GObject */
g_type_ensure (G_TYPE_OBJECT);
for (i = 1; i < argc; i++)
query_dir (argv[i]);
return 0;
}