Esempio n. 1
0
static void
xs_destroy   (XMLSource* xs)
{
  GError* error = NULL;
  
  g_return_if_fail(xs != NULL);

  /* do this first in case we're in a "fast cleanup just before exit"
     situation */
  if (xs->lock != NULL && !gconf_release_lock(xs->lock, &error))
    {
      gconf_log (GCL_ERR, _("Failed to give up lock on XML directory \"%s\": %s"),
                 xs->root_dir, error->message);
      g_error_free(error);
      error = NULL;
    }
  
  if (!g_source_remove(xs->timeout_id))
    {
      /* should not happen, don't translate */
      gconf_log(GCL_ERR, "timeout not found to remove?");
    }
  
  cache_unref(xs->cache);
  g_free(xs->root_dir);
  g_free(xs);
}
Esempio n. 2
0
gboolean
gconfd_dbus_init (void)
{
  DBusError error;
  gint      ret;

  dbus_error_init (&error);

  bus_conn = dbus_bus_get (DBUS_BUS_SESSION, &error);

  if (!bus_conn) 
   {
     gconf_log (GCL_ERR, _("Daemon failed to connect to the D-BUS daemon:\n%s"),
		error.message);
     dbus_error_free (&error);
     return FALSE;
   }

  /* We handle exiting ourselves on disconnect. */
  dbus_connection_set_exit_on_disconnect (bus_conn, FALSE);

  /* Add message filter to handle Disconnected. */
  dbus_connection_add_filter (bus_conn,
			      (DBusHandleMessageFunction) server_filter_func,
			      NULL, NULL);
  
  ret = dbus_bus_request_name (bus_conn,
			       GCONF_DBUS_SERVICE,
			       0,
			       &error);

  if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
    {
      gconf_log (GCL_ERR, "Daemon could not become primary owner");
      return FALSE;
    }
  
  if (dbus_error_is_set (&error)) 
    {
      gconf_log (GCL_ERR, _("Daemon failed to acquire gconf service:\n%s"),
		 error.message);
      dbus_error_free (&error);
      return FALSE;
    }

  if (!dbus_connection_register_object_path (bus_conn,
					     server_path,
					     &server_vtable,
					     NULL))
    {
      gconf_log (GCL_ERR, _("Failed to register server object with the D-BUS bus daemon"));
      return FALSE;
    }
  
  
  nr_of_connections = 1;
  dbus_connection_setup_with_g_main (bus_conn, NULL);
  
  return TRUE;
}
Esempio n. 3
0
GConfValue*
entry_get_value(Entry* e, const gchar** locales, GError** err)
{
  const gchar* sl;
  
  g_return_val_if_fail(e != NULL, NULL);
  
  if (e->cached_value == NULL)
    return NULL;

  /* only schemas have locales for now anyway */
  if (e->cached_value->type != GCONF_VALUE_SCHEMA)
    return e->cached_value;

  g_assert(e->cached_value->type == GCONF_VALUE_SCHEMA);

  sl = gconf_schema_get_locale(gconf_value_get_schema(e->cached_value));

  gconf_log (GCL_DEBUG, "Cached schema value has locale \"%s\", looking for %s",
             sl ? sl : "null",
             locales && locales [0] ? locales[0] : "null");
  
  /* optimize most common cases first */
  if (sl == NULL && (locales == NULL ||
                     *locales == NULL))
    return e->cached_value;
  else if (sl && locales && *locales &&
           strcmp(sl, *locales) == 0)
    return e->cached_value;
  else
    {
      /* We want a locale other than the currently-loaded one */
      GConfValue* newval;
      GError* error = NULL;

      entry_sync_if_needed(e);
      
      newval = node_extract_value(e->node, locales, &error);
      if (newval != NULL)
        {
          /* We found a schema with an acceptable locale */
          gconf_value_free(e->cached_value);
          e->cached_value = newval;
          g_return_val_if_fail(error == NULL, e->cached_value);
        }
      else if (error != NULL)
        {
          /* There was an error */
          gconf_log(GCL_WARNING, _("Ignoring XML node with name `%s': %s"),
                    e->name, error->message);
          g_error_free(error);

          /* Fall back to currently-loaded thing if any */
        }
      /* else fall back to the currently-loaded schema */
    }

  return e->cached_value;
}
Esempio n. 4
0
static GConfValue* 
query_value (GConfSource* source,
             const gchar* key,
             const gchar** locales,
             gchar** schema_name,
             GError** err)
{
  XMLSource* xs = (XMLSource*)source;
  gchar* parent;
  Dir* dir;
  GError* error = NULL;

  parent = gconf_key_directory(key);
  
  g_assert(parent != NULL);
  
  dir = cache_lookup(xs->cache, parent, FALSE, &error);

  /* We DO NOT want to return an error unless it represents a general
     problem with the backend; since we don't want to report stuff
     like "this key doesn't exist yet" - however this is a maintenance
     problem, since some errors may be added that need reporting. */
  if (error != NULL)
    {
      gconf_log(GCL_WARNING, "%s", error->message);
      g_error_free(error);
      error = NULL;
    }
  
  g_free(parent);
  parent = NULL;
  
  if (dir != NULL)
    {
      const gchar* relative_key;
      GConfValue* retval;
      
      relative_key = gconf_key_key(key);

      retval = dir_get_value(dir, relative_key, locales, schema_name, &error);

      /* perhaps we should be reporting this error... */
      if (error != NULL)
        {
          gconf_log(GCL_WARNING, "%s", error->message);
          g_error_free(error);
          error = NULL;
        }
      
      return retval;
    }
  else
    return NULL;
}
Esempio n. 5
0
gchar*       
gconf_backend_file(const gchar* address)
{
  gchar* back;
  gchar* file;
  gchar* retval;
  const gchar* backenddir;

  g_return_val_if_fail(address != NULL, NULL);

  back = gconf_address_backend(address);

  if (back == NULL)
    return NULL;

  backenddir = g_getenv("GCONF_BACKEND_DIR");
  if (backenddir == NULL)
    backenddir = GCONF_BACKEND_DIR;

  file = g_strconcat("gconfbackend-", back, NULL);
  
  retval = g_module_build_path(backenddir, file);

  g_free(back);

  if (g_file_test(retval, G_FILE_TEST_EXISTS))
    {
      g_free(file);

      return retval;
    }
  else
    {
      /* -- debug only */
#ifdef GCONF_ENABLE_DEBUG      
      gchar* dir;

      g_free(retval);
      dir = g_strconcat(GCONF_SRCDIR, "/gconf/",
                        GCONF_BUILDDIR, "/backends/.libs", NULL);

      retval = g_module_build_path(dir, file);

      g_free(dir);
      
      if (g_file_test(retval, G_FILE_TEST_EXISTS))
        {
          g_free(file);
          return retval;
        }
#endif
      /* -- end debug only */

      gconf_log(GCL_ERR, _("No such file `%s'\n"), retval);

      g_free(file);
      g_free(retval);
      return NULL;
    }
}
Esempio n. 6
0
static GConfSource *
resolve_address (const char  *address,
		 GError     **err)
{
  EvoSource *esource;
  char      *conf_file;

  if ((conf_file = gconf_address_resource (address)) == NULL)
    {
      g_set_error (err, GCONF_ERROR,
		   GCONF_ERROR_BAD_ADDRESS,
		   _("Failed to get configuration file path from '%s'"),
		   address);
      return NULL;
    }

  esource = g_new0 (EvoSource, 1);

  esource->conf_file    = conf_file;
  esource->source.flags = GCONF_SOURCE_ALL_READABLE | GCONF_SOURCE_NEVER_WRITEABLE;

  gconf_log (GCL_DEBUG,
	     _("Created Evolution/LDAP source using configuration file '%s'"),
	     esource->conf_file);

  return (GConfSource *) esource;
}
Esempio n. 7
0
static void          
unset_value     (GConfSource* source,
                 const gchar* key,
                 const gchar* locale,
                 GError** err)
{
  XMLSource* xs = (XMLSource*)source;
  Dir* dir;
  gchar* parent;

  gconf_log(GCL_DEBUG, "XML backend: unset value `%s'", key);
  
  parent = gconf_key_directory(key);
  
  dir = cache_lookup(xs->cache, parent, FALSE, err);

  g_free(parent);
  
  if (dir == NULL)
    return;
  else
    {
      const gchar* relative_key;
  
      relative_key = gconf_key_key(key);

      dir_unset_value(dir, relative_key, locale, err);
    }
}
Esempio n. 8
0
static GSList*
all_subdirs     (GConfSource* source,
                 const gchar* key,
                 GError** err)
{
  Dir* dir;
  XMLSource* xs = (XMLSource*)source;
  GError *sync_err;
  
  /* We have to sync before we can do this, to see which
   * subdirs have gone away.
   */
  sync_err = NULL;
  cache_sync (xs->cache, &sync_err);
  if (sync_err)
    {
      gconf_log (GCL_WARNING, _("Error syncing the XML backend directory cache: %s"),
                 sync_err->message);
      g_error_free (sync_err);
      sync_err = NULL;
      /* continue, may as well try our best. */
    }
  
  dir = cache_lookup (xs->cache, key, FALSE, err);
  
  if (dir == NULL)
    return NULL;
  else
    return dir_all_subdirs (dir, err);
}
Esempio n. 9
0
static gboolean
cache_clean_foreach(const gchar* key,
                    Dir* dir, CleanData* cd)
{
  GTime last_access;

  last_access = dir_get_last_access(dir);

  if ((cd->now - last_access) >= cd->length)
    {
      if (!dir_sync_pending(dir))
        {
          dir_destroy(dir);
          return TRUE;
        }
      else
        {
          gconf_log(GCL_WARNING, _("Unable to remove directory `%s' from the XML backend cache, because it has not been successfully synced to disk"),
                    dir_get_name(dir));
          return FALSE;
        }
    }
  else
    return FALSE;
}
Esempio n. 10
0
static void
cache_insert (Cache* cache,
              Dir* d)
{
  g_return_if_fail(d != NULL);

  gconf_log(GCL_DEBUG, "Caching dir %s", dir_get_name(d));
  
  safe_g_hash_table_insert(cache->cache, (gchar*)dir_get_name(d), d);
}
Esempio n. 11
0
static void
cache_destroy_foreach(const gchar* key,
                      Dir* dir, gpointer data)
{
#ifdef GCONF_ENABLE_DEBUG
  if (dir_sync_pending (dir))
    gconf_log(GCL_DEBUG, "Destroying a directory (%s) with sync still pending",
              dir_get_name (dir));
#endif
  dir_destroy (dir);
}
Esempio n. 12
0
/* If we use G_MODULE_EXPORT, *only* thusly marked functions will be
 * exported, and xml-test uses other ones, too.
 */
G_MODULE_EXPORT
#endif
const gchar*
g_module_check_init (GModule *module)
{
  gconf_log(GCL_DEBUG, _("Initializing XML backend module"));

  LIBXML_TEST_VERSION;
  xmlKeepBlanksDefault(1);

  return NULL;
}
Esempio n. 13
0
gboolean
entry_unset_value     (Entry        *e,
                       const gchar  *locale)
{
  g_return_val_if_fail(e != NULL, FALSE);

  if (e->cached_value != NULL)
    {
      if (locale && e->cached_value->type == GCONF_VALUE_SCHEMA)
        {
          GError* error = NULL;
          
          /* Remove the localized node from the XML tree */
          g_assert(e->node != NULL);
          node_unset_by_locale(e->node, locale);

          /* e->cached_value is always non-NULL if some value is
             available; in the schema case there may be leftover
             values */
          gconf_value_free(e->cached_value);
          e->cached_value = node_extract_value(e->node, NULL, &error);

          if (error != NULL)
            {
              gconf_log(GCL_WARNING, "%s", error->message);
              g_error_free(error);
              error = NULL;
            }
        }
      else if (e->cached_value->type == GCONF_VALUE_SCHEMA)
        {
          /* if locale == NULL nuke all the locales */
          if (e->cached_value)
            gconf_value_free(e->cached_value);
          e->cached_value = NULL;
        }
      else
        {
          gconf_value_free(e->cached_value);
          e->cached_value = NULL;
        }

      e->dirty = TRUE;
      
      return TRUE;
    }
  else
    return FALSE;
}
Esempio n. 14
0
static void
safe_g_hash_table_insert(GHashTable* ht, gpointer key, gpointer value)
{
  gpointer oldkey = NULL, oldval = NULL;

  if (g_hash_table_lookup_extended(ht, key, &oldkey, &oldval))
    {
      gconf_log(GCL_WARNING, "Hash key `%s' is already in the table!",
                (gchar*)key);
      return;
    }
  else
    {
      g_hash_table_insert(ht, key, value);
    }
}
Esempio n. 15
0
gboolean
cache_sync (Cache    *cache,
            GError  **err)
{
  SyncData sd = { FALSE, NULL, FALSE };
  GSList *list;
  
  sd.dc = cache;

  gconf_log (GCL_DEBUG, "Syncing the dir cache");

 redo:
  sd.failed = FALSE;
  sd.deleted_some = FALSE;
  
  /* get a list of everything; we can't filter by
   * whether a sync is pending since we may make parents
   * of removed directories dirty when we sync their child
   * dir.
   */
  list = NULL;
  g_hash_table_foreach (cache->cache, (GHFunc)listify_foreach, &list);

  /* sort subdirs before parents */
  list = g_slist_sort (list, dircmp);

  /* sync it all */
  g_slist_foreach (list, (GFunc) cache_sync_foreach, &sd);
  g_slist_free (list);

  /* If we deleted some subdirs, we may now be able to delete
   * more parent dirs. So go ahead and do the sync again.
   * Yeah this could be more efficient.
   */
  if (!sd.failed && sd.deleted_some)
    goto redo;
  
  if (sd.failed && err && *err == NULL)
    {
      gconf_set_error (err, GCONF_ERROR_FAILED,
		       _("Failed to sync XML cache contents to disk"));
    }
  
  return !sd.failed;  
}
Esempio n. 16
0
static void
server_handle_shutdown (DBusConnection *connection, DBusMessage *message)
{
  DBusMessage *reply;

  if (gconfd_dbus_check_in_shutdown (connection, message))
    return;

  gconf_log(GCL_DEBUG, _("Shutdown request received"));

  reply = dbus_message_new_method_return (message);
  dbus_connection_send (connection, reply, NULL);
  dbus_message_unref (reply);
  
  dbus_connection_unregister_object_path (connection, server_path);

  gconfd_main_quit();
}
Esempio n. 17
0
static void
database_handle_remove_notify (DBusConnection    *conn,
			       DBusMessage       *message,
			       GConfDatabase *db)
{
  gchar *namespace_section;
  DBusMessage *reply;
  const char *sender;
  NotificationData *notification;
  ListeningClientData *client;
  
  if (!gconfd_dbus_get_message_args (conn, message,
				     DBUS_TYPE_STRING, &namespace_section,
				     DBUS_TYPE_INVALID)) 
    return;

  sender = dbus_message_get_sender (message);
  
  notification = g_hash_table_lookup (db->notifications, namespace_section);

  client = g_hash_table_lookup (db->listening_clients, sender);
  if (client) {
    client->nr_of_notifications--;
    
    if (client->nr_of_notifications == 0) {
      database_remove_listening_client (db, client);
    }
  }
    
  /* Notification can be NULL if the client and server get out of sync. */
  if (notification == NULL || !database_remove_notification_data (db, notification, sender))
    {
      gconf_log (GCL_DEBUG, _("Notification on %s doesn't exist"),
                 namespace_section);
    }
  
  reply = dbus_message_new_method_return (message);
  dbus_connection_send (conn, reply, NULL);
  dbus_message_unref (reply);
}
Esempio n. 18
0
void
cache_clean      (Cache        *cache,
                  GTime         older_than)
{
  CleanData cd = { 0, NULL, 0 };
  cd.cache = cache;
  cd.length = older_than;
  
  cd.now = time(NULL); /* ha ha, it's an online store! */
  
  g_hash_table_foreach_remove(cache->cache, (GHRFunc)cache_clean_foreach,
                              &cd);

#if 0
  size = g_hash_table_size(cache->cache);

  if (size != 0)
    gconf_log (GCL_DEBUG,
               "%u items remain in the cache after cleaning already-synced items older than %u seconds",
               size,
               older_than);
#endif
}
Esempio n. 19
0
static void
cache_sync_foreach (Dir      *dir,
                    SyncData *sd)
{
  GError* error = NULL;
  gboolean deleted;
  
  deleted = FALSE;
  
  /* log errors but don't report the specific ones */
  if (!dir_sync (dir, &deleted, &error))
    {
      sd->failed = TRUE;
      g_return_if_fail (error != NULL);
      gconf_log (GCL_ERR, "%s", error->message);
      g_error_free (error);
      g_return_if_fail (dir_sync_pending (dir));
    }
  else
    {
      g_return_if_fail (error == NULL);
      g_return_if_fail (!dir_sync_pending (dir));

      if (deleted)
        {
          /* Get rid of this directory */
          cache_remove_from_parent (sd->dc, dir);
          g_hash_table_remove (sd->dc->cache,
                               dir_get_name (dir));
          cache_set_nonexistent (sd->dc, dir_get_name (dir),
                                 TRUE);
          dir_destroy (dir);

          sd->deleted_some = TRUE;
        }
    }
}
Esempio n. 20
0
static Dir*
dir_blank(const gchar* key)
{
  Dir* d;
  
  d = g_new0(Dir, 1);

#ifdef GCONF_ENABLE_DEBUG
  {
    gchar* why;
    if (!gconf_valid_key(key, &why)) {
      gconf_log(GCL_DEBUG, "key `%s' invalid: %s",
                key, why);
    }
    g_assert(gconf_valid_key(key, NULL));
  }
#endif
  
  d->key = g_strdup (key);
  d->parent_key = gconf_key_directory (key);
  
  d->last_access = time(NULL);
  d->doc = NULL;

  d->entry_cache = g_hash_table_new (g_str_hash, g_str_equal);
  
  d->dirty = FALSE;
  d->need_rescan_subdirs = TRUE;

  d->subdir_names = NULL;
  
  d->dir_mode = 0700;
  d->file_mode = 0600;
  
  return d;
}
Esempio n. 21
0
Dir*
cache_lookup     (Cache        *cache,
                  const gchar  *key,
                  gboolean create_if_missing,
                  GError  **err)
{
  Dir* dir;
  
  g_assert(key != NULL);
  g_return_val_if_fail(cache != NULL, NULL);
  
  /* Check cache */
  dir = g_hash_table_lookup(cache->cache, key);
  
  if (dir != NULL)
    {
      gconf_log(GCL_DEBUG, "Using dir %s from cache", key);
      return dir;
    }
  else
    {
      /* Not in cache, check whether we already failed
         to load it */
      if (cache_is_nonexistent(cache, key))
        {
          if (!create_if_missing)
            return NULL;
        }
      else
        {
          /* Didn't already fail to load, try to load */
          dir = dir_load (key, cache->root_dir, err);
          
          if (dir != NULL)
            {
              g_assert(err == NULL || *err == NULL);
              
              /* Cache it and add to parent */
              cache_insert (cache, dir);
              cache_add_to_parent (cache, dir);
              
              return dir;
            }
          else
            {
              /* Remember that we failed to load it */
              if (!create_if_missing)
                {
                  cache_set_nonexistent(cache, key, TRUE);
              
                  return NULL;
                }
              else
                {
                  if (err && *err)
                    {
                      g_error_free(*err);
                      *err = NULL;
                    }
                }
            }
        }
    }
  
  g_assert(dir == NULL);
  g_assert(create_if_missing);
  g_assert(err == NULL || *err == NULL);
  
  if (dir == NULL)
    {
      gconf_log(GCL_DEBUG, "Creating new dir %s", key);
      
      dir = dir_new(key, cache->root_dir, cache->dir_mode, cache->file_mode);

      if (!dir_ensure_exists(dir, err))
        {
          dir_destroy(dir);
          
          g_return_val_if_fail((err == NULL) ||
                               (*err != NULL) ,
                               NULL);
          return NULL;
        }
      else
        {
          cache_insert (cache, dir);
          cache_add_to_parent (cache, dir);
          cache_unset_nonexistent (cache, dir_get_name (dir));
        }
    }

  return dir;
}
Esempio n. 22
0
gboolean 
gconfd_dbus_set_exception (DBusConnection  *connection,
			   DBusMessage     *message,
			   GError         **error)
{
  GConfError en;
  const char *name = NULL;
  DBusMessage *reply;
                                                                                
  if (error == NULL || *error == NULL)
    return FALSE;
                                                                                
  en = (*error)->code;
                                                                                
  /* success is not supposed to get set */
  g_return_val_if_fail(en != GCONF_ERROR_SUCCESS, FALSE);

  switch (en)
    {
    case GCONF_ERROR_FAILED:
      name = GCONF_DBUS_ERROR_FAILED;
      break;
    case GCONF_ERROR_NO_PERMISSION:
      name = GCONF_DBUS_ERROR_NO_PERMISSION;
      break;
    case GCONF_ERROR_BAD_ADDRESS:
      name = GCONF_DBUS_ERROR_BAD_ADDRESS;
      break;
    case GCONF_ERROR_BAD_KEY:
      name = GCONF_DBUS_ERROR_BAD_KEY;
      break;
    case GCONF_ERROR_PARSE_ERROR:
      name = GCONF_DBUS_ERROR_PARSE_ERROR;
      break;
    case GCONF_ERROR_CORRUPT:
      name = GCONF_DBUS_ERROR_CORRUPT;
      break;
    case GCONF_ERROR_TYPE_MISMATCH:
      name = GCONF_DBUS_ERROR_TYPE_MISMATCH;
      break;
    case GCONF_ERROR_IS_DIR:
      name = GCONF_DBUS_ERROR_IS_DIR;
      break;
    case GCONF_ERROR_IS_KEY:
      name = GCONF_DBUS_ERROR_IS_KEY;
      break;
    case GCONF_ERROR_NO_WRITABLE_DATABASE:
      name = GCONF_DBUS_ERROR_NO_WRITABLE_DATABASE;
      break;
    case GCONF_ERROR_IN_SHUTDOWN:
      name = GCONF_DBUS_ERROR_IN_SHUTDOWN;
      break;
    case GCONF_ERROR_OVERRIDDEN:
      name = GCONF_DBUS_ERROR_OVERRIDDEN;
      break;
    case GCONF_ERROR_LOCK_FAILED:
      name = GCONF_DBUS_ERROR_LOCK_FAILED;
      break;
    case GCONF_ERROR_OAF_ERROR:
    case GCONF_ERROR_LOCAL_ENGINE:
    case GCONF_ERROR_NO_SERVER:
    case GCONF_ERROR_SUCCESS:
    default:
      gconf_log (GCL_ERR, "Unhandled error code %d", en);
      g_assert_not_reached();
      break;
    }
                                                                                
  reply = dbus_message_new_error (message, name, (*error)->message);
  dbus_connection_send (connection, reply, NULL);
  dbus_message_unref (reply);
                                                                                
  return TRUE;
}
Esempio n. 23
0
gboolean
dir_sync (Dir      *d,
          gboolean *deleted,
          GError  **err)
{
  gboolean retval = TRUE;

  if (deleted)
    *deleted = FALSE;  

  if (!d->dirty)
    return TRUE; 

  gconf_log (GCL_DEBUG, "Syncing dir \"%s\"", d->key);
  
  d->last_access = time (NULL);
  
  if (dir_useless (d))
    {
      gconf_log (GCL_DEBUG, "Deleting useless dir \"%s\"",
                 d->key);
      
      if (g_unlink (d->xml_filename) != 0)
        {
          gconf_set_error (err, GCONF_ERROR_FAILED, _("Failed to delete \"%s\": %s"),
                           d->xml_filename, g_strerror (errno));
          return FALSE;
        }

      if (strcmp (d->key, "/") != 0) /* don't delete root dir */
        {
          if (g_rmdir (d->fs_dirname) != 0)
            {
              gconf_set_error (err, GCONF_ERROR_FAILED, _("Failed to delete \"%s\": %s"),
                               d->fs_dirname, g_strerror (errno));
              return FALSE;
            }
        }

      if (deleted)
        *deleted = TRUE;
    }
  else
    {
      gboolean old_existed = FALSE;
      gchar* tmp_filename;
      gchar* old_filename;
      FILE* outfile;

      /* We should have a doc if deleted is FALSE */
      g_assert(d->doc != NULL);
      
      /* First make sure entry values are synced to their
         XML nodes */
      g_hash_table_foreach(d->entry_cache, (GHFunc)entry_sync_foreach, NULL);
      
      tmp_filename = g_strconcat(d->fs_dirname, "/%gconf.xml.tmp", NULL);
      old_filename = g_strconcat(d->fs_dirname, "/%gconf.xml.old", NULL);

      outfile = g_fopen (tmp_filename, "w");

      if (outfile == NULL)
        {
          /* Try to solve the problem by creating the FS dir */
          if (!g_file_test (d->fs_dirname, G_FILE_TEST_EXISTS))
            {
              if (create_fs_dir(d->fs_dirname, d->xml_filename,
                                d->root_dir_len,
                                d->dir_mode, d->file_mode,
                                err))
                outfile = g_fopen (tmp_filename, "w");
            }

          if (outfile == NULL)
            {
              /* Don't set error if it's already set by some
               * earlier failure.
               */
              if (err && *err == NULL)
                gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to write file `%s': %s"), 
                                tmp_filename, g_strerror(errno));
              
              retval = FALSE;
              
              goto failed_end_of_sync;
            }
        }

#ifdef HAVE_FCHMOD
      /* Set permissions on the new file */
      if (fchmod (fileno (outfile), d->file_mode) != 0)
        {
          gconf_set_error(err, GCONF_ERROR_FAILED, 
                          _("Failed to set mode on `%s': %s"),
                          tmp_filename, g_strerror(errno));
          
          retval = FALSE;
          goto failed_end_of_sync;
        }
#endif

      if (gconf_xml_doc_dump (outfile, d->doc) < 0)
        {
          gconf_set_error (err, GCONF_ERROR_FAILED, 
                           _("Failed to write XML data to `%s': %s"),
                           tmp_filename, g_strerror (errno));
          
          retval = FALSE;
          goto failed_end_of_sync;
        }

      if (fclose (outfile) < 0)
        {
          gconf_set_error (err, GCONF_ERROR_FAILED, 
                           _("Failed to close file `%s': %s"),
                           tmp_filename, g_strerror (errno));
          
          retval = FALSE;
          outfile = NULL;
          goto failed_end_of_sync;
        }

      outfile = NULL;
      
#ifndef HAVE_FCHMOD
      /* Set permissions on the new file */
      if (chmod (tmp_filename, d->file_mode) != 0)
        {
          gconf_set_error(err, GCONF_ERROR_FAILED, 
                          _("Failed to set mode on `%s': %s"),
                          tmp_filename, g_strerror(errno));
          
          retval = FALSE;
          goto failed_end_of_sync;
        }
#endif

      old_existed = g_file_test (d->xml_filename, G_FILE_TEST_EXISTS);

      if (old_existed)
        {
          if (g_rename(d->xml_filename, old_filename) < 0)
            {
              gconf_set_error(err, GCONF_ERROR_FAILED, 
                              _("Failed to rename `%s' to `%s': %s"),
                              d->xml_filename, old_filename, g_strerror(errno));

              retval = FALSE;
              goto failed_end_of_sync;
            }
        }

      if (g_rename(tmp_filename, d->xml_filename) < 0)
        {
          gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to rename `%s' to `%s': %s"),
                          tmp_filename, d->xml_filename, g_strerror(errno));

          /* Put the original file back, so this isn't a total disaster. */
          if (g_rename(old_filename, d->xml_filename) < 0)
            {
              gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to restore `%s' from `%s': %s"),
                              d->xml_filename, old_filename, g_strerror(errno));
            }

          retval = FALSE;
          goto failed_end_of_sync;
        }

      if (old_existed)
        {
          if (g_unlink(old_filename) < 0)
            {
              gconf_log(GCL_WARNING, _("Failed to delete old file `%s': %s"),
                         old_filename, g_strerror(errno));
              /* Not a failure, just leaves cruft around. */
            }
        }

    failed_end_of_sync:
      
      g_free(old_filename);
      g_free(tmp_filename);
      if (outfile)
        fclose (outfile);
    }

  if (retval)
    d->dirty = FALSE;

  return retval;
}
Esempio n. 24
0
static void
dir_load_doc(Dir* d, GError** err)
{
  gboolean xml_already_exists = TRUE;
  gboolean need_backup = FALSE;
  struct stat statbuf;
  
  g_return_if_fail(d->doc == NULL);

  if (stat(d->xml_filename, &statbuf) < 0)
    {
      switch (errno)
        {
        case ENOENT:
          xml_already_exists = FALSE;
          break;
        case ENOTDIR:
#ifdef ELOOP
        case ELOOP:
#endif
        case EFAULT:
        case EACCES:
        case ENOMEM:
        case ENAMETOOLONG:
        default:
          /* These are all fatal errors */
          gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to stat `%s': %s"),
                          d->xml_filename, g_strerror(errno));
          return;
          break;
        }
    }

  if (statbuf.st_size == 0)
    {
      xml_already_exists = FALSE;
    }

  if (xml_already_exists)
    {
      GError *tmp_err;
      gboolean error_was_fatal;

      error_was_fatal = FALSE;
      tmp_err = NULL;
      d->doc = my_xml_parse_file (d->xml_filename, &tmp_err);

      if (tmp_err != NULL)
        {
          gconf_log (GCL_WARNING,
                     "%s", tmp_err->message);

          /* file errors are assumed to be some kind of
           * blowup, like out of file descriptors, so
           * we play it safe and don't touch anything
           */
          if (tmp_err->domain == G_FILE_ERROR)
            error_was_fatal = TRUE;
          
          g_error_free (tmp_err);
        }

      if (error_was_fatal)
        return;
    }
  
  /* We recover from parse errors instead of passing them up */

  /* This has the potential to just blow away an entire corrupted
   * config file; but I think that is better than the alternatives
   * (disabling config for a directory because the document is mangled).
   *
   * Parse errors really should not happen from an XML file we created
   * ourselves anyway...
   */  

  /* Also we create empty %gconf.xml files when we create a new dir,
   * and those return a parse error, though they should be trapped
   * by the statbuf.st_size == 0 check above.
   */
  
  if (d->doc == NULL)
    {
      if (xml_already_exists)
        need_backup = TRUE; /* rather uselessly save whatever broken stuff was in the file */
          
      /* Create a new doc */
      
      d->doc = xmlNewDoc((xmlChar *)"1.0");
    }
  
  if (d->doc->xmlRootNode == NULL)
    {
      /* fill it in */
      d->doc->xmlRootNode = xmlNewDocNode(d->doc, NULL, "gconf", NULL);
    }
  else if (strcmp((char*)d->doc->xmlRootNode->name, "gconf") != 0)
    {
      xmlFreeDoc(d->doc);
      d->doc = xmlNewDoc((xmlChar*)"1.0");
      d->doc->xmlRootNode = xmlNewDocNode(d->doc, NULL, (xmlChar *)"gconf", NULL);
      need_backup = TRUE; /* save broken stuff */
    }
  else
    {
      /* We had an initial doc with a valid root */
      /* Fill child_cache from entries */
      dir_fill_cache_from_doc(d);
    }

  if (need_backup)
    {
      /* Back up the file we failed to parse, if it exists,
         we aren't going to be able to do anything if this call
         fails
      */
      
      gchar* backup = g_strconcat(d->xml_filename, ".bak", NULL);
      int fd;
      
      g_rename(d->xml_filename, backup);
      
      /* Recreate %gconf.xml to maintain our integrity and be sure
         all_subdirs works */
      /* If we failed to rename, we just give up and truncate the file */
      fd = g_open(d->xml_filename, O_CREAT | O_WRONLY | O_TRUNC, d->file_mode);
      if (fd >= 0)
        close(fd);
      
      g_free(backup);
    }
  
  g_assert(d->doc != NULL);
  g_assert(d->doc->xmlRootNode != NULL);
}
Esempio n. 25
0
static void
dir_fill_cache_from_doc(Dir* d)
{
  xmlNodePtr node;
  
  if (d->doc == NULL ||
      d->doc->xmlRootNode == NULL ||
      d->doc->xmlRootNode->xmlChildrenNode == NULL)
    {
      /* Empty document - just return. */
      return;
    }

  node = d->doc->xmlRootNode->xmlChildrenNode;

  while (node != NULL)
    {
      if (node->type == XML_ELEMENT_NODE && 
          (strcmp((xmlChar *)node->name, "entry") == 0))
        {
          gchar* attr = my_xmlGetProp(node, "name");

          if (attr != NULL)
            {
              if (g_hash_table_lookup(d->entry_cache, attr) != NULL)
                {
                  gconf_log(GCL_WARNING,
                             _("Duplicate entry `%s' in `%s', ignoring"),
                             attr, d->xml_filename);
                }
              else
                {
                  Entry* e;
                  
                  e = entry_new(attr);

                  entry_set_node(e, node);
                  
                  entry_fill_from_node(e);
                  
                  safe_g_hash_table_insert(d->entry_cache,
                                           (gchar*)entry_get_name(e), e);
                }

              free(attr);
            }
          else
            {
              gconf_log(GCL_WARNING,
                         _("Entry with no name in XML file `%s', ignoring"),
                         d->xml_filename);
            }
        }
      else
        {
          if (node->type == XML_ELEMENT_NODE)
            gconf_log(GCL_WARNING,
                      _("A toplevel node in XML file `%s' is <%s> rather than <entry>, ignoring"),
                      d->xml_filename,
                      node->name ? (char*) node->name : "unknown");
        }
      
      node = node->next;
    }
}
Esempio n. 26
0
static void          
x_shutdown (GError** err)
{
  gconf_log(GCL_DEBUG, _("Unloading XML backend module."));
}
Esempio n. 27
0
static GConfSource*  
resolve_address (const gchar* address, GError** err)
{
  struct stat statbuf;
  gchar* root_dir;
  XMLSource* xsource;
  GConfSource* source;
  gint flags = 0;
  GConfLock* lock = NULL;
  guint dir_mode = 0700;
  guint file_mode = 0600;
  gchar** address_flags;
  gchar** iter;
  gboolean force_readonly;
  
  root_dir = get_dir_from_address (address, err);
  if (root_dir == NULL)
    return NULL;

  if (g_stat (root_dir, &statbuf) == 0)
    {
      /* Already exists, base our dir_mode on it */
      dir_mode = _gconf_mode_t_to_mode (statbuf.st_mode);

      /* dir_mode without search bits */
      file_mode = dir_mode & (~0111); 
    }
  else if (g_mkdir (root_dir, dir_mode) < 0)
    {
      /* Error out even on EEXIST - shouldn't happen anyway */
      gconf_set_error (err, GCONF_ERROR_FAILED,
		       _("Could not make directory `%s': %s"),
		      (gchar *)root_dir, g_strerror (errno));
      g_free (root_dir);
      return NULL;
    }

  force_readonly = FALSE;
  
  address_flags = gconf_address_flags (address);  
  if (address_flags)
    {
      iter = address_flags;
      while (*iter)
        {
          if (strcmp (*iter, "readonly") == 0)
            {
              force_readonly = TRUE;
              break;
            }

          ++iter;
        }
    }

  g_strfreev (address_flags);

  {
    /* See if we're writable */
    gboolean writable;
    int fd;
    gchar* testfile;

    writable = FALSE;
    
    if (!force_readonly)
      {
        testfile = g_strconcat(root_dir, "/.testing.writeability", NULL);    
        
        fd = g_open(testfile, O_CREAT|O_WRONLY, S_IRWXU);
        
        if (fd >= 0)
          {
            writable = TRUE;
            close(fd);
          }
        
        g_unlink(testfile);
        
        g_free(testfile);
      }
    
    if (writable)
      flags |= GCONF_SOURCE_ALL_WRITEABLE;

    /* We only do locking if it's writable,
     * and if not using local locks,
     * which is sort of broken but close enough
     */
    if (writable && !gconf_use_local_locks ())
      {
        gchar* lockdir;

        lockdir = get_lock_dir_from_root_dir (root_dir);
        
        lock = gconf_get_lock(lockdir, err);

        if (lock != NULL)
          gconf_log(GCL_DEBUG, "Acquired lock directory `%s'", lockdir);
        
        g_free(lockdir);
        
        if (lock == NULL)
          {
            g_free(root_dir);
            return NULL;
          }
      }
  }

  {
    /* see if we're readable */
    gboolean readable = FALSE;
    GDir* d;

    d = g_dir_open(root_dir, 0, NULL);

    if (d != NULL)
      {
        readable = TRUE;
        g_dir_close(d);
      }
    
    if (readable)
      flags |= GCONF_SOURCE_ALL_READABLE;
  }

  if (!(flags & GCONF_SOURCE_ALL_READABLE) &&
      !(flags & GCONF_SOURCE_ALL_WRITEABLE))
    {
      gconf_set_error(err, GCONF_ERROR_BAD_ADDRESS, _("Can't read from or write to the XML root directory in the address \"%s\""), address);
      g_free(root_dir);
      return NULL;
    }  
  
  /* Create the new source */

  xsource = xs_new(root_dir, dir_mode, file_mode, lock);

  gconf_log(GCL_DEBUG,
            _("Directory/file permissions for XML source at root %s are: %o/%o"),
            root_dir, dir_mode, file_mode);
  
  source = (GConfSource*)xsource;

  source->flags = flags;
  
  g_free(root_dir);
  
  return source;
}
Esempio n. 28
0
static gboolean
create_fs_dir(const gchar* dir, const gchar* xml_filename,
              guint root_dir_len, guint dir_mode, guint file_mode,
              GError** err)
{
  g_return_val_if_fail(xml_filename != NULL, FALSE);
  
  gconf_log(GCL_DEBUG, "Enter create_fs_dir: %s", dir);

  if (g_file_test(xml_filename, G_FILE_TEST_IS_REGULAR))
    {
      gconf_log(GCL_DEBUG, "XML backend file %s already exists", xml_filename);
      return TRUE;
    }
      
  /* Don't create anything above the root directory */
  if (strlen(dir) > root_dir_len)
    {
      gchar* parent;
      
      parent = _gconf_parent_dir (dir);

      gconf_log (GCL_DEBUG, "Parent dir is %s", parent);
      
      if (parent != NULL)
        {
          gchar* parent_xml = NULL;
          gboolean success = FALSE;
          
          if (xml_filename)
            parent_xml = g_strconcat(parent, "/%gconf.xml", NULL);
          
          success = create_fs_dir(parent, parent_xml, root_dir_len,
                                  dir_mode, file_mode, err);

          if (success)
            gconf_log(GCL_DEBUG, "created parent: %s", parent);
          else
            gconf_log(GCL_DEBUG, "failed parent: %s", parent);
          
          g_free(parent);
          g_free(parent_xml);
          
          if (!success)
            return FALSE;
        }
      else
        {
          gconf_log(GCL_DEBUG, "%s has no parent", dir);
        }
    }

  gconf_log(GCL_DEBUG, "Making directory %s", dir);
  
  if (g_mkdir(dir, dir_mode) < 0)
    {
      if (errno != EEXIST)
        {
          gconf_set_error(err, GCONF_ERROR_FAILED,
                          _("Could not make directory \"%s\": %s"),
                          (gchar*)dir, g_strerror(errno));
          return FALSE;
        }
    }

  if (xml_filename != NULL)
    {
      int fd;
      /* don't truncate the file, it may well already exist */
      fd = g_open(xml_filename, O_CREAT | O_WRONLY, file_mode);

      gconf_log(GCL_DEBUG, "Creating XML file %s", xml_filename);
      
      if (fd < 0)
        {
          gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to create file `%s': %s"),
                          xml_filename, g_strerror(errno));
          
          return FALSE;
        }
      
      if (close(fd) < 0)
        {
          gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to close file `%s': %s"),
                          xml_filename, g_strerror(errno));
          
          return FALSE;
        }
    }
  else
    {
      gconf_log(GCL_DEBUG, "No XML filename passed to create_fs_dir() for %s", dir);
    }
  
  return TRUE;
}
Esempio n. 29
0
/* this actually works on any node,
   not just <entry>, such as the <car>
   and <cdr> nodes and the <li> nodes and the
   <default> node
*/
static GConfValue*
node_extract_value(xmlNodePtr node, const gchar** locales, GError** err)
{
  GConfValue* value = NULL;
  gchar* type_str;
  GConfValueType type = GCONF_VALUE_INVALID;
  const gchar* default_locales[] = { "C", NULL };
  
  if (locales == NULL)
    locales = default_locales;
  
  type_str = my_xmlGetProp(node, "type");

  if (type_str == NULL)
    {
      gconf_set_error(err, GCONF_ERROR_PARSE_ERROR,
                      _("No \"type\" attribute for <%s> node"),
                      (node->name ? (char*)node->name : "(nil)"));
      return NULL;
    }
      
  type = gconf_value_type_from_string(type_str);

  xmlFree(type_str);
  
  switch (type)
    {
    case GCONF_VALUE_INVALID:
      {
        gconf_set_error(err, GCONF_ERROR_PARSE_ERROR,
                        _("A node has unknown \"type\" attribute `%s', ignoring"), type_str);
        return NULL;
      }
      break;
    case GCONF_VALUE_INT:
    case GCONF_VALUE_BOOL:
    case GCONF_VALUE_FLOAT:
      {
        gchar* value_str;
        
        value_str = my_xmlGetProp(node, "value");
        
        if (value_str == NULL)
          {
            gconf_set_error(err, GCONF_ERROR_PARSE_ERROR,
                            _("No \"value\" attribute for node"));
            return NULL;
          }
            
        value = gconf_value_new_from_string(type, value_str, err);

        xmlFree(value_str);

        g_return_val_if_fail( (value != NULL) ||
                              (err == NULL) ||
                              (*err != NULL),
                              NULL );
        
        return value;
      }
      break;
    case GCONF_VALUE_STRING:
      {
        xmlNodePtr iter;
        
        iter = node->xmlChildrenNode;

        while (iter != NULL)
          {
            if (iter->type == XML_ELEMENT_NODE)
              {
                GConfValue* v = NULL;

                if (strcmp((char *)iter->name, "stringvalue") == 0)
                  {
                    gchar* s;

                    s = (gchar *)xmlNodeGetContent(iter);

                    v = gconf_value_new(GCONF_VALUE_STRING);

                    /* strdup() caused purely by g_free()/free()
                       difference */
                    gconf_value_set_string(v, s ? s : "");
                    if (s)
                      xmlFree(s);
                        
                    return v;
                  }
                else
                  {
                    /* What the hell is this? */
                    gconf_log(GCL_WARNING,
                              _("Didn't understand XML node <%s> inside an XML list node"),
                              iter->name ? iter->name : (guchar*)"???");
                  }
              }
            iter = iter->next;
          }
        return NULL;
      }
      break;      
    case GCONF_VALUE_SCHEMA:
      return schema_node_extract_value(node, locales);
      break;
    case GCONF_VALUE_LIST:
      {
        xmlNodePtr iter;
        GSList* values = NULL;
        GConfValueType list_type = GCONF_VALUE_INVALID;

        {
          gchar* s;
          s = my_xmlGetProp(node, "ltype");
          if (s != NULL)
            {
              list_type = gconf_value_type_from_string(s);
              xmlFree(s);
            }
        }

        switch (list_type)
          {
          case GCONF_VALUE_INVALID:
          case GCONF_VALUE_LIST:
          case GCONF_VALUE_PAIR:
            gconf_set_error(err, GCONF_ERROR_PARSE_ERROR,
                            _("Invalid type (list, pair, or unknown) in a list node"));
              
            return NULL;
          default:
            break;
          }
        
        iter = node->xmlChildrenNode;

        while (iter != NULL)
          {
            if (iter->type == XML_ELEMENT_NODE)
              {
                GConfValue* v = NULL;
                if (strcmp((char*)iter->name, "li") == 0)
                  {
                    
                    v = node_extract_value(iter, locales, err);
                    if (v == NULL)
                      {
                        if (err && *err)
                          {
                            gconf_log(GCL_WARNING,
                                      _("Bad XML node: %s"),
                                      (*err)->message);
                            /* avoid pile-ups */
                            g_clear_error(err);
                          }
                      }
                    else if (v->type != list_type)
                      {
                        gconf_log(GCL_WARNING, _("List contains a badly-typed node (%s, should be %s)"),
                                  gconf_value_type_to_string(v->type),
                                  gconf_value_type_to_string(list_type));
                        gconf_value_free(v);
                        v = NULL;
                      }
                  }
                else
                  {
                    /* What the hell is this? */
                    gconf_log(GCL_WARNING,
                              _("Didn't understand XML node <%s> inside an XML list node"),
                              iter->name ? iter->name : (guchar*)"???");
                  }

                if (v != NULL)
                  values = g_slist_prepend(values, v);
              }
            iter = iter->next;
          }
        
        /* put them in order, set the value */
        values = g_slist_reverse(values);

        value = gconf_value_new(GCONF_VALUE_LIST);

        gconf_value_set_list_type(value, list_type);
        gconf_value_set_list_nocopy(value, values);

        return value;
      }
      break;
    case GCONF_VALUE_PAIR:
      {
        GConfValue* car = NULL;
        GConfValue* cdr = NULL;
        xmlNodePtr iter;
        
        iter = node->xmlChildrenNode;

        while (iter != NULL)
          {
            if (iter->type == XML_ELEMENT_NODE)
              {
                if (car == NULL && strcmp((char *)iter->name, "car") == 0)
                  {
                    car = node_extract_value(iter, locales, err);
                    if (car == NULL)
                      {
                        if (err && *err)
                          {
                            gconf_log(GCL_WARNING,
                                      _("Ignoring bad car from XML pair: %s"),
                                      (*err)->message);
                            /* prevent pile-ups */
                            g_clear_error(err);
                          }
                      }
                    else if (car->type == GCONF_VALUE_LIST ||
                             car->type == GCONF_VALUE_PAIR)
                      {
                        gconf_log(GCL_WARNING, _("parsing XML file: lists and pairs may not be placed inside a pair"));
                        gconf_value_free(car);
                        car = NULL;
                      }
                  }
                else if (cdr == NULL && strcmp((char *)iter->name, "cdr") == 0)
                  {
                    cdr = node_extract_value(iter, locales, err);
                    if (cdr == NULL)
                      {
                        if (err && *err)
                          {
                            gconf_log(GCL_WARNING,
                                      _("Ignoring bad cdr from XML pair: %s"),
                                      (*err)->message);
                            /* avoid pile-ups */
                            g_clear_error(err);
                          }
                      }
                    else if (cdr->type == GCONF_VALUE_LIST ||
                             cdr->type == GCONF_VALUE_PAIR)
                      {
                        gconf_log(GCL_WARNING,
                                  _("parsing XML file: lists and pairs may not be placed inside a pair"));
                        gconf_value_free(cdr);
                        cdr = NULL;
                      }
                  }
                else
                  {
                    /* What the hell is this? */
                    gconf_log(GCL_WARNING,
                              _("Didn't understand XML node <%s> inside an XML pair node"),
                              iter->name ? (gchar*)iter->name : "???");                    
                  }
              }
            iter = iter->next;
          }

        /* Return the pair if we got both halves */
        if (car && cdr)
          {
            value = gconf_value_new(GCONF_VALUE_PAIR);
            gconf_value_set_car_nocopy(value, car);
            gconf_value_set_cdr_nocopy(value, cdr);

            return value;
          }
        else
          {
            gconf_log(GCL_WARNING, _("Didn't find car and cdr for XML pair node"));
            if (car)
              {
                g_assert(cdr == NULL);
                gconf_value_free(car);
                gconf_set_error(err, GCONF_ERROR_PARSE_ERROR,
                                _("Missing cdr from pair of values in XML file"));
              }
            else if (cdr)
              {
                g_assert(car == NULL);
                gconf_value_free(cdr);
                gconf_set_error(err, GCONF_ERROR_PARSE_ERROR,
                                _("Missing car from pair of values in XML file"));
              }
            else
              {
                gconf_set_error(err, GCONF_ERROR_PARSE_ERROR,
                                _("Missing both car and cdr values from pair in XML file"));
              }

            return NULL;
          }
      }
      break;
    default:
      g_assert_not_reached();
      return NULL;
      break;
    }
}
Esempio n. 30
0
Dir*
dir_load (const gchar* key, const gchar* xml_root_dir, GError** err)
{
  Dir* d;
  gchar* fs_dirname;
  gchar* xml_filename;
  guint dir_mode = 0700;
  guint file_mode = 0600;
  
  g_return_val_if_fail(gconf_valid_key(key, NULL), NULL);
  
  fs_dirname = gconf_concat_dir_and_key(xml_root_dir, key);
  xml_filename = g_strconcat(fs_dirname, "/%gconf.xml", NULL);

  {
    struct stat s;
    gboolean notfound = FALSE;
    
    if (g_stat(xml_filename, &s) != 0)
      {
        if (errno != ENOENT)
          {
            gconf_set_error (err, GCONF_ERROR_FAILED,
                             _("Could not stat `%s': %s"),
                             xml_filename, g_strerror(errno));

          }
        
        notfound = TRUE;
      }
    else if (S_ISDIR(s.st_mode))
      {
        gconf_set_error (err, GCONF_ERROR_FAILED,
                         _("XML filename `%s' is a directory"),
                         xml_filename);
        notfound = TRUE;
      }

    if (notfound)
      {
        gconf_log(GCL_DEBUG, "dir file %s not found", xml_filename);
        g_free(fs_dirname);
        g_free(xml_filename);
        return NULL;
      }
    else
      {
        /* Take directory mode from the xml_root_dir, if possible */
        if (g_stat (xml_root_dir, &s) == 0)
          {
            dir_mode = _gconf_mode_t_to_mode (s.st_mode);
          }
        
        file_mode = dir_mode & ~0111; /* turn off search bits */
      }
  }

  d = dir_blank(key);

  /* sync with dir_new() */
  d->fs_dirname = fs_dirname;
  d->xml_filename = xml_filename;
  d->root_dir_len = strlen(xml_root_dir);

  d->dir_mode = dir_mode;
  d->file_mode = file_mode;
  
  gconf_log (GCL_DEBUG, "loaded dir %s", fs_dirname);
  
  return d;
}