Exemplo n.º 1
0
static gboolean
gconf_backend_verify_vtable (GConfBackendVTable  *vtable,
			     GConfBackendVTable  *vtable_copy,
			     const char          *backend_name,			    
			     GError             **err)
{
  int i;
  struct
  {
    char  *name;
    gsize  offset;
  } required_vtable_functions[] = {
    { "shutdown",        G_STRUCT_OFFSET(GConfBackendVTable, shutdown)        },
    { "resolve_address", G_STRUCT_OFFSET(GConfBackendVTable, resolve_address) },
    { "query_value",     G_STRUCT_OFFSET(GConfBackendVTable, query_value)     },
    { "query_metainfo",  G_STRUCT_OFFSET(GConfBackendVTable, query_metainfo)  },
    { "set_value",       G_STRUCT_OFFSET(GConfBackendVTable, set_value)       },
    { "all_entries",     G_STRUCT_OFFSET(GConfBackendVTable, all_entries)     },
    { "all_subdirs",     G_STRUCT_OFFSET(GConfBackendVTable, all_subdirs)     },
    { "unset_value",     G_STRUCT_OFFSET(GConfBackendVTable, unset_value)     },
    { "dir_exists",      G_STRUCT_OFFSET(GConfBackendVTable, dir_exists)      },
    { "remove_dir",      G_STRUCT_OFFSET(GConfBackendVTable, remove_dir)      },
    { "set_schema",      G_STRUCT_OFFSET(GConfBackendVTable, set_schema)      },
    { "sync_all",        G_STRUCT_OFFSET(GConfBackendVTable, sync_all)        },
    { "destroy_source",  G_STRUCT_OFFSET(GConfBackendVTable, destroy_source)  },
    { "blow_away_locks", G_STRUCT_OFFSET(GConfBackendVTable, blow_away_locks) }
  };

  if (!vtable)
    {
      gconf_set_error(err,
		      GCONF_ERROR_FAILED, _("Backend `%s' failed to return a vtable\n"),
		      backend_name);
      return FALSE;
    }

  /* Create a copy in case vtable size doesn't match */
  memcpy(vtable_copy, vtable, MIN(vtable->vtable_size, sizeof(GConfBackendVTable)));

  vtable_copy->vtable_size = sizeof(GConfBackendVTable);

  for (i = 0; i < G_N_ELEMENTS(required_vtable_functions); i++)
    {
      if (G_STRUCT_MEMBER_P(vtable_copy, required_vtable_functions[i].offset) == NULL)
	{
	  gconf_set_error(err,
			  GCONF_ERROR_FAILED, _("Backend `%s' missing required vtable member `%s'\n"),
			  backend_name,
			  required_vtable_functions[i].name);
	  return FALSE;
	}
    }

  return TRUE;
}
Exemplo n.º 2
0
static char*
get_dir_from_address (const char *address,
                      GError    **err)
{
  char *root_dir;
  int len;
  
  root_dir = gconf_address_resource (address);

  if (root_dir == NULL)
    {
      gconf_set_error (err, GCONF_ERROR_BAD_ADDRESS,
                       _("Couldn't find the XML root directory in the address `%s'"),
                       address);
      return NULL;
    }

  /* Chop trailing '/' to canonicalize */
  len = strlen (root_dir);

  if (root_dir[len-1] == '/')
    root_dir[len-1] = '\0';

  return root_dir;
}
Exemplo n.º 3
0
/** Type checking helper */
static
gboolean
gconf_require_type(const char *key, const GConfValue *value,
                   GConfValueType type, GError **err)
{
  if( value->type == type )
  {
    return TRUE;
  }

  gconf_set_error(err, GCONF_ERROR_TYPE_MISMATCH, "%s: is %s, not %s",
                  key, gconf_type_repr(value->type), gconf_type_repr(type));
  return FALSE;
}
Exemplo n.º 4
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;  
}
Exemplo n.º 5
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;
}
Exemplo n.º 6
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);
}
Exemplo n.º 7
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;
}
Exemplo n.º 8
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;
}
Exemplo n.º 9
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;
}
Exemplo n.º 10
0
GConfBackend* 
gconf_get_backend(const gchar* address, GError** err)
{
  GConfBackend* backend;
  gchar* name;
  gchar* why_invalid;

  if (loaded_backends == NULL)
    {
      loaded_backends = g_hash_table_new(g_str_hash, g_str_equal);
    }

  why_invalid = NULL;
  if (!gconf_address_valid (address, &why_invalid))
    {
      g_assert (why_invalid != NULL);
      gconf_set_error (err, GCONF_ERROR_BAD_ADDRESS, _("Bad address `%s': %s"),
		       address, why_invalid);
      g_free (why_invalid);
      return NULL;
    }

  name = gconf_address_backend(address);
      
  if (name == NULL)
    {
      gconf_set_error(err, GCONF_ERROR_BAD_ADDRESS, _("Bad address `%s'"), address);
      return NULL;
    }

  backend = g_hash_table_lookup(loaded_backends, name);

  if (backend != NULL)
    {
      /* Returning a "copy" */
      gconf_backend_ref(backend);
      g_free(name);
      return backend;
    }
  else
    {
      gchar* file;
          
      file = gconf_backend_file(address);
          
      if (file != NULL)
        {
          GModule* module;
          GConfBackendVTable* (*get_vtable)(void);

          if (!g_module_supported())
            g_error(_("GConf won't work without dynamic module support (gmodule)"));
              
          module = g_module_open(file, G_MODULE_BIND_LAZY);
              
          g_free(file);
          
          if (module == NULL)
            {
              gconf_set_error(err,
                              GCONF_ERROR_FAILED, _("Error opening module `%s': %s\n"),
                              name, g_module_error());
              g_free(name);
              return NULL;
            }

          if (!g_module_symbol(module, 
                               "gconf_backend_get_vtable", 
                               (gpointer*)&get_vtable))
            {
              gconf_set_error(err,
                              GCONF_ERROR_FAILED, _("Error initializing module `%s': %s\n"),
                              name, g_module_error());
              g_module_close(module);
              g_free(name);
              return NULL;
            }
          
          backend = g_new0(GConfBackend, 1);

          backend->module = module;

	  if (!gconf_backend_verify_vtable((*get_vtable)(), &backend->vtable, name, err))
	    {
	      g_module_close(module);
	      g_free(name);
	      g_free(backend);
	      return NULL;
	    }
              
          backend->name = name;

          g_hash_table_insert(loaded_backends, (gchar*)backend->name, backend);
          
          /* Returning a "copy" */
          gconf_backend_ref(backend);

          return backend;
        }
      else
        {
          gconf_set_error(err, GCONF_ERROR_FAILED,
                          _("Couldn't locate backend module for `%s'"), address);
          return NULL;
        }
    }
}
Exemplo n.º 11
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;
    }
}