Below is the file 'sqlite-backend.c' from this revision. You can also download the file.
/* GConf sqlite backend * Copyright (C) 1999, 2000, 2002 Red Hat Inc. * Copyright (C) 2005 Grahame Bowland. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * designed for correctness, speed. uses sqlite3 for local storage. */ #include <gconf/gconf-backend.h> #include <gconf/gconf-internals.h> #include <gconf/gconf.h> #include <glib.h> #include <sys/types.h> #include <sys/stat.h> #include <sqlite3.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <pwd.h> #define ROOT_DIRECTORY_PARENT -1 #define ROOT_DIRECTORY_NAME "" /* used for columns, they indicate which gconf type we're actually storing */ #define T_STRING "s" #define T_INT "i" #define T_FLOAT "f" #define T_BOOL "b" #define T_SCHEMA "c" #define T_LIST "l" #define T_PAIR "p" /* * VTable functions */ /* shutdown() is a BSD libc function */ static void x_shutdown (GError **err); static GConfSource* resolve_address (const char *address, GError **err); static void lock (GConfSource *source, GError **err); static void unlock (GConfSource *source, GError **err); static gboolean readable (GConfSource *source, const char *key, GError **err); static gboolean writable (GConfSource *source, const char *key, GError **err); static GConfValue* query_value (GConfSource *source, const char *key, const char **locales, char **schema_name, GError **err); static GConfMetaInfo* query_metainfo (GConfSource *source, const char *key, GError **err); static void set_value (GConfSource *source, const char *key, const GConfValue *value, GError **err); static GSList* all_entries (GConfSource *source, const char *dir, const char **locales, GError **err); static GSList* all_subdirs (GConfSource *source, const char *dir, GError **err); static void unset_value (GConfSource *source, const char *key, const char *locale, GError **err); static gboolean dir_exists (GConfSource *source, const char *dir, GError **err); static void remove_dir (GConfSource *source, const char *dir, GError **err); static void set_schema (GConfSource *source, const char *key, const char *schema_key, GError **err); static gboolean sync_all (GConfSource *source, GError **err); static void destroy_source (GConfSource *source); static void clear_cache (GConfSource *source); static void blow_away_locks (const char *address); typedef struct { long long int id; } SqliteDirectory; typedef struct { GConfSource source; /* inherit from GConfSource */ gchar *dbfile; GConfLock* lock; sqlite3 *db; SqliteDirectory root_dir; } SqliteSource; /* to be used whenever appropriate (stock error message) */ static void update_failure (GError **err) { return; // TODO: don't leave this commented out! g_set_error (err, GCONF_ERROR, GCONF_ERROR_FAILED, _("Failed to write some configuration data to disk\n")); } /* returns TRUE if the directory exists; in this case dir will be filled in with the * details of the directory. * * returns FALSE otherwise */ static gboolean get_directory (SqliteSource *ss, SqliteDirectory *parent, const char *name, SqliteDirectory *dir) { long long int id; char *query, *tail; gboolean rv; long long int nrow; int res; sqlite3_stmt *statement; /* normal sub-directory case */ g_return_val_if_fail (parent != NULL, FALSE); g_return_val_if_fail (name != NULL, FALSE); /* NB: there should only be one row in the result (especially with the table constraints set */ query = sqlite3_mprintf ("SELECT id FROM directories WHERE parent_id=%lld AND name='%s'", dir->id, name); if (sqlite3_prepare (ss->db, query, strlen(query), &statement, (const char **)&tail) != SQLITE_OK) { gconf_log (GCL_ERR, "(get_directory) Unable to compile query: %s", query); sqlite3_free (query); return FALSE; } nrow = 0; rv = TRUE; for (;;) { res = sqlite3_step (statement); if (res == SQLITE_ROW) { nrow++; id = sqlite3_column_int64(statement, 0); } else if (res == SQLITE_DONE) { break; } else { /* ought to be one of: SQLITE_BUSY || res == SQLITE_ERROR || res == SQLITE_MISUSE */ gconf_log (GCL_ERR, "(get_directory) query error\n"); rv = FALSE; break; } } if (nrow != 1) rv = FALSE; if (rv) dir->id = id; sqlite3_finalize (statement); sqlite3_free (query); return rv; } static gboolean create_directory (SqliteSource *ss, SqliteDirectory *parent, const char *name, SqliteDirectory *dir) { char *query, *err_mesg; gboolean rv; /* normal subdirectory */ g_return_val_if_fail (parent != NULL, FALSE); g_return_val_if_fail (name != NULL, FALSE); query = sqlite3_mprintf ("INSERT INTO directories (name,parent_id) VALUES ('%s',%d)", name, parent->id); if (sqlite3_exec (ss->db, query, NULL, NULL, &err_mesg) != SQLITE_OK) { gconf_log (GCL_ERR, "(create_directory) SQL error: %s", err_mesg); sqlite3_free (err_mesg); rv = FALSE; } else { dir->id = sqlite3_last_insert_rowid (ss->db); rv = TRUE; } sqlite3_free (query); return rv; } /* make sure we have a root directory in the directories table */ static gboolean ensure_has_root_directory (SqliteSource *ss) { gboolean rv; ss->root_dir.id = -1; if (!get_directory (ss, &ss->root_dir, ROOT_DIRECTORY_NAME, &ss->root_dir)) { gconf_log (GCL_DEBUG, "(ensure_has_root_directory) no root directory\n"); /* okay then, better create it */ rv = create_directory (ss, &ss->root_dir, ROOT_DIRECTORY_NAME, &ss->root_dir); } else { rv = TRUE; } return rv; } static SqliteDirectory * traverse_to_directory (SqliteSource *ss, const char *path, gboolean do_create, GError **error) { SqliteDirectory *rv; char **components; int i; g_assert (ss != NULL); g_assert (path != NULL); g_return_val_if_fail (*path == '/', NULL); rv = g_new0 (SqliteDirectory, 1); components = g_strsplit (path + 1, "/", -1); /* we know that we have a root directory entry, so start there */ rv->id = ss->root_dir.id; if (!components) { /* they are just after the root directory */ return rv; } /* loop, finding and then creating directories as needed */ i = 0; while (rv && components[i]) { if (!get_directory (ss, rv, components[i], rv)) { /* not there, so create it.. */ if (!do_create || !create_directory (ss, rv, components[i], rv)) { g_free (rv); rv = NULL; break; } } i++; } g_strfreev (components); return rv; } static char * get_username (void) { uid_t uid; struct passwd *pw; uid = getuid(); if (uid < 0) return NULL; pw = getpwuid(uid); if (!pw) return NULL; return g_strdup(pw->pw_name); } static gboolean start_transaction (SqliteSource *ss) { gboolean rv; char *query, *err_mesg; rv = TRUE; query = "BEGIN"; if (sqlite3_exec (ss->db, query, NULL, NULL, &err_mesg) != SQLITE_OK) { gconf_log (GCL_ERR, "(start_transaction) SQL error: %s", err_mesg); sqlite3_free (err_mesg); rv = FALSE; } return rv; } static gboolean abort_transaction (SqliteSource *ss) { gboolean rv; char *query, *err_mesg; rv = TRUE; query = "ROLLBACK"; if (sqlite3_exec (ss->db, query, NULL, NULL, &err_mesg) != SQLITE_OK) { gconf_log (GCL_ERR, "(abort_transaction) SQL error: %s", err_mesg); sqlite3_free (err_mesg); rv = FALSE; } return rv; } static gboolean commit_transaction (SqliteSource *ss) { gboolean rv; char *query, *err_mesg; rv = TRUE; query = "COMMIT"; if (sqlite3_exec (ss->db, query, NULL, NULL, &err_mesg) != SQLITE_OK) { gconf_log (GCL_ERR, "(commit_transaction) SQL error: %s", err_mesg); sqlite3_free (err_mesg); rv = FALSE; } return rv; } static gboolean get_value_id_in_directory (SqliteSource *ss, SqliteDirectory *dir, const char *name, long long int *id) { long long int possible_id, nrow; char *query, *tail; gboolean rv; int res; sqlite3_stmt *statement; g_return_val_if_fail (ss != NULL, FALSE); g_return_val_if_fail (dir != NULL, FALSE); g_return_val_if_fail (name != NULL, FALSE); query = sqlite3_mprintf ("SELECT id FROM keys WHERE directory_id=%lld AND name='%q'", dir->id, name); if (sqlite3_prepare (ss->db, query, strlen(query), &statement, (const char **)&tail) != SQLITE_OK) { gconf_log (GCL_ERR, "(get_value_id_in_directory) Unable to compile query: %s", query); sqlite3_free (query); return FALSE; } nrow = 0; rv = TRUE; for (;;) { res = sqlite3_step (statement); if (res == SQLITE_ROW) { nrow++; possible_id = sqlite3_column_int64 (statement, 0); } else if (res == SQLITE_DONE) { break; } else { /* ought to be one of: SQLITE_BUSY || res == SQLITE_ERROR || res == SQLITE_MISUSE */ gconf_log (GCL_ERR, "(get_directory) query error\n"); break; } } if (nrow != 1) rv = FALSE; if (rv) *id = possible_id; sqlite3_free (query); sqlite3_finalize (statement); return rv; } static gboolean delete_old_list (SqliteSource *ss, long long int id) { gboolean rv; char *query, *err_mesg; rv = TRUE; query = sqlite3_mprintf ("DELETE FROM lists WHERE key_id=%lld", id); if (sqlite3_exec (ss->db, query, NULL, NULL, &err_mesg) != SQLITE_OK) { gconf_log (GCL_ERR, "(delete_old_list) SQL error: %s", err_mesg); sqlite3_free (err_mesg); rv = FALSE; } sqlite3_free (query); return rv; } static gboolean delete_old_pair (SqliteSource *ss, long long int id) { gboolean rv; char *query, *err_mesg; rv = TRUE; query = sqlite3_mprintf ("DELETE FROM pairs WHERE key_id=%lld", id); if (sqlite3_exec (ss->db, query, NULL, NULL, &err_mesg) != SQLITE_OK) { gconf_log (GCL_ERR, "(delete_old_pair) SQL error: %s", err_mesg); sqlite3_free (err_mesg); rv = FALSE; } sqlite3_free (query); return rv; } static const char * get_type_for_column (GConfValueType t) { const char *lt; if (t == GCONF_VALUE_STRING) { lt = T_STRING; } else if (t == GCONF_VALUE_INT) { lt = T_INT; } else if (t == GCONF_VALUE_FLOAT) { lt = T_FLOAT; } else if (t == GCONF_VALUE_BOOL) { lt = T_BOOL; } else { lt = NULL; } return lt; } static gboolean insert_or_update_value (SqliteSource *ss, SqliteDirectory *dir, const char *name, const GConfValue *value) { gchar *mod_user; GTime mod_time; gboolean rv; GConfValueType list_type; char *query, *err_mesg; const char *lt; g_return_val_if_fail (ss != NULL, FALSE); g_return_val_if_fail (dir != NULL, FALSE); g_return_val_if_fail (name != NULL, FALSE); /* we want to update these at the same time */ mod_user = get_username (); mod_time = time (NULL); #define BASIC_INSERT "INSERT OR REPLACE INTO keys (name, directory_id, mod_user, mod_time, value_type, value) VALUES " rv = TRUE; query = NULL; switch (value->type) { case GCONF_VALUE_STRING: query = sqlite3_mprintf (BASIC_INSERT "('%q', %lld, '%q', %d, '%q', '%q')", name, dir->id, mod_user, mod_time, T_STRING, gconf_value_get_string (value)); break; case GCONF_VALUE_INT: query = sqlite3_mprintf (BASIC_INSERT "('%q', %lld, '%q', %d, '%q', %d)", name, dir->id, mod_user, mod_time, T_INT, gconf_value_get_int (value)); break; case GCONF_VALUE_FLOAT: query = sqlite3_mprintf (BASIC_INSERT "('%q', %lld, '%q', %d, '%q', %f)", name, dir->id, mod_user, mod_time, T_FLOAT, gconf_value_get_float (value)); break; case GCONF_VALUE_BOOL: query = sqlite3_mprintf (BASIC_INSERT "('%q', %lld, '%q', %d, '%q', %d)", name, dir->id, mod_user, mod_time, T_BOOL, gconf_value_get_bool (value)); break; case GCONF_VALUE_SCHEMA: query = sqlite3_mprintf (BASIC_INSERT "('%q', %lld, '%q', %d, '%q', NULL)", name, dir->id, mod_user, mod_time, T_SCHEMA); break; case GCONF_VALUE_LIST: list_type = gconf_value_get_list_type (value); lt = get_type_for_column (list_type); if (!lt) { gconf_log (GCL_ERR, "(insert_or_update_value) List is of invalid type."); rv = FALSE; break; } query = sqlite3_mprintf (BASIC_INSERT "('%q', %lld, '%q', %d, '%q', '%q')", name, dir->id, mod_user, mod_time, T_LIST, lt); break; case GCONF_VALUE_PAIR: query = sqlite3_mprintf (BASIC_INSERT "('%q', %lld, '%q', %d, '%q', NULL)", name, dir->id, mod_user, mod_time, T_PAIR); break; case GCONF_VALUE_INVALID: default: gconf_log (GCL_ERR, "(insert_or_update_value) Attempt to insert item with invalid type."); rv = FALSE; break; } if (!rv) { if (query) sqlite3_free (query); return rv; } /* okay, so we have a query that does what we want. execute it. */ if (sqlite3_exec (ss->db, query, NULL, NULL, &err_mesg) != SQLITE_OK) { gconf_log (GCL_ERR, "(insert_or_update_value) SQL error: %s", err_mesg); sqlite3_free (err_mesg); rv = FALSE; } sqlite3_free (query); return rv; } #define BASIC_LIST_INSERT "INSERT INTO lists (key_id, list_idx, value) " static inline char * list_sql_string (long long int key, long long int idx, const void *v) { return sqlite3_mprintf (BASIC_LIST_INSERT "VALUES (%lld, %lld, '%q')", key, idx, *(const char *)v); } static inline char * list_sql_int (long long int key, long long int idx, const void *v) { return sqlite3_mprintf (BASIC_LIST_INSERT "VALUES (%lld, %lld, %d)", key, idx, *(const int *)v); } static inline char * list_sql_float (long long int key, long long int idx, const void *v) { return sqlite3_mprintf (BASIC_LIST_INSERT "VALUES (%lld, %lld, %f)", key, idx, *(const double *)v); } static inline char * list_sql_bool (long long int key, long long int idx, const void *v) { return sqlite3_mprintf (BASIC_LIST_INSERT "VALUES (%lld, %lld, %d)", key, idx, *(const gboolean *)v); } static gboolean insert_list_for_key (SqliteSource *ss, const GConfValue *value, long long int key) { GConfValueType list_type; long long int idx; GSList *list; gboolean rv; char *query; char *err_mesg; char *(*list_sql_func)(long long int, long long int, const void *); g_return_val_if_fail (ss != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); list_type = gconf_value_get_list_type (value); /* overly paranoid perhaps? */ g_return_val_if_fail (get_type_for_column (list_type) != NULL, FALSE); switch (list_type) { case GCONF_VALUE_STRING: list_sql_func = list_sql_string; break; case GCONF_VALUE_INT: list_sql_func = list_sql_int; break; case GCONF_VALUE_FLOAT: list_sql_func = list_sql_float; break; case GCONF_VALUE_BOOL: list_sql_func = list_sql_bool; break; default: list_sql_func= NULL; } g_return_val_if_fail (list_sql_func != NULL, FALSE); rv = TRUE; idx = 0; list = gconf_value_get_list (value); while (list) { query = list_sql_func (key, idx, list->data); if (sqlite3_exec (ss->db, query, NULL, NULL, &err_mesg) != SQLITE_OK) { gconf_log (GCL_ERR, "(insert_list_for_key) SQL error: %s", err_mesg); sqlite3_free (query); sqlite3_free (err_mesg); rv = FALSE; break; } sqlite3_free (query); list = g_slist_next (list); idx++; } return rv; } static gboolean insert_pair_for_key (SqliteSource *ss, const GConfValue *value, long long int key) { g_return_val_if_fail (ss != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); return FALSE; } static gboolean insert_schema_for_key (SqliteSource *ss, const GConfValue *value, long long int key) { g_return_val_if_fail (ss != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); return FALSE; } static gboolean set_value_in_directory (SqliteSource *ss, SqliteDirectory *dir, const char *name, const GConfValue *value, GError **error) { char *query = NULL; gboolean rv; long long int existing_id; g_return_val_if_fail (ss != NULL, FALSE); g_return_val_if_fail (dir != NULL, FALSE); g_return_val_if_fail (name != NULL, FALSE); /* * we need to handle several things here * * first consideration; this might be a new key, or it might be an update to an existing key * if we're updating, we need to handle non-scalar types correctly. this basically means removing * the old list / pair and then adding a new one in. * * second consideration; need to do clean insert of non-scalar types. * * third consideration; make sure we do it all in a transaction block, and abort the transaction * appropriately if something goes wrong. */ rv = TRUE; do { if (!start_transaction (ss)) { rv = FALSE; break; } /* if there was a value in the past, clean up any possible * lists or pair. This could be more elegant, but this way is * the best; it's slower (eg. might do a pair of DELETEs we don't need) * but it does mean that there's no chance of us leaving a * pair or list dangling by mistake * * Note: old schema values are fine * (they are in the key_to_schema_name table) */ if (get_value_id_in_directory (ss, dir, name, &existing_id)) { if (!delete_old_list (ss, existing_id)) { rv = FALSE; break; } if (!delete_old_pair (ss, existing_id)) { rv = FALSE; break; } } /* whatever type we're inserting, we need to have a row in the keys * table. if we're inserting a GCONF_VALUE_LIST, GCONF_VALUE_PAIR, * or GCONF_VALUE_SCHEMA another row in a seperate table will be * needed. this row will reference the row in keys. */ if (!insert_or_update_value (ss, dir, name, value)) { rv = FALSE; break; } if (value->type == GCONF_VALUE_LIST) { long long int last_rowid; last_rowid = sqlite3_last_insert_rowid (ss->db); if (!insert_list_for_key (ss, value, last_rowid)) { rv = FALSE; break; } } else if (value->type == GCONF_VALUE_PAIR) { long long int last_rowid; last_rowid = sqlite3_last_insert_rowid (ss->db); if (!insert_pair_for_key (ss, value, last_rowid)) { rv = FALSE; break; } } else if (value->type == GCONF_VALUE_SCHEMA) { long long int last_rowid; last_rowid = sqlite3_last_insert_rowid (ss->db); if (!insert_schema_for_key (ss, value, last_rowid)) { rv = FALSE; break; } } } while (0); if (rv) { commit_transaction (ss); } else { abort_transaction (ss); } if (!query) return FALSE; printf("query is: %s\n", query); sqlite3_free (query); return FALSE; } /* check that the database looks about right */ static gboolean verify_database (SqliteSource *ss) { char *query, *tail; gboolean rv; long long int nrow; int res; sqlite3_stmt *statement; g_return_val_if_fail (ss != NULL, FALSE); query = sqlite3_mprintf ("SELECT * FROM gconf"); if (sqlite3_prepare (ss->db, query, strlen(query), &statement, (const char **)&tail) != SQLITE_OK) { gconf_log (GCL_ERR, "(verify_database) Unable to compile query: %s", query); sqlite3_free (query); return FALSE; } nrow = 0; rv = TRUE; for (;;) { res = sqlite3_step (statement); if (res == SQLITE_ROW) { nrow++; if (sqlite3_column_int64(statement, 0) != 1) rv = FALSE; } else if (res == SQLITE_DONE) { break; } else { /* ought to be one of: SQLITE_BUSY || res == SQLITE_ERROR || res == SQLITE_MISUSE */ gconf_log (GCL_ERR, "(verify_database) query error\n"); break; } } if (nrow != 1) rv = FALSE; sqlite3_finalize (statement); sqlite3_free (query); return rv; } /* create a new SqliteSource, if possible. * otherwise, return NULL */ static SqliteSource * ss_new (const char *dbfile, GConfLock *lock) { SqliteSource *ss; mode_t m; int rv; g_return_val_if_fail (dbfile != NULL, NULL); ss = g_new0 (SqliteSource, 1); ss->dbfile = g_strdup (dbfile); ss->lock = lock; /* if the database does not exist, sqlite will create it. we must make sure * it is created in with secure permissions */ m = umask(077); rv = sqlite3_open (ss->dbfile, &ss->db); umask(m); if (rv) { gconf_log (GCL_ERR, _("Couldn't open database \"%s\": %s\n"), ss->dbfile, sqlite3_errmsg(ss->db)); sqlite3_close (ss->db); g_free (ss->dbfile); g_free (ss); return NULL; } if (!verify_database(ss)) { return NULL; } if (!ensure_has_root_directory (ss)) { return NULL; } return ss; } static void ss_destroy (SqliteSource *ss) { GError* error = NULL; g_return_if_fail (ss != NULL); if (ss->lock != NULL && !gconf_release_lock (ss->lock, &error)) { gconf_log (GCL_ERR, _("Failed to give up lock on database \"%s\" : %s"), ss->dbfile, error->message); g_error_free (error); error = NULL; } sqlite3_close (ss->db); g_free (ss->dbfile); g_free (ss); } /* public methods are all below this line */ static GConfBackendVTable markup_vtable = { sizeof (GConfBackendVTable), x_shutdown, resolve_address, lock, unlock, readable, writable, query_value, query_metainfo, set_value, all_entries, all_subdirs, unset_value, dir_exists, remove_dir, set_schema, sync_all, destroy_source, clear_cache, blow_away_locks, NULL, /* set_notify_func */ NULL, /* add_listener */ NULL /* remove_listener */ }; static void x_shutdown (GError **err) { gconf_log (GCL_DEBUG, _("Unloading sqlite backend module.")); } /* possible problem here; according to the SQLite documentation, * the library is threadsafe (except for sqlite3_global_recover) * but it is a bug to use a sqlite3* in a thread other than that * in which it was created * * not sure if that's going to be a problem - I doubt it though. */ static void lock (GConfSource *source, GError **err) { } static void unlock (GConfSource *source, GError **err) { } static gboolean readable (GConfSource *source, const char *key, GError **err) { return TRUE; } static gboolean writable (GConfSource *source, const char *key, GError **err) { return TRUE; } static GConfValue* query_value (GConfSource *source, const char *key, const char **locales, char **schema_name, GError **err) { gconf_log (GCL_DEBUG, "query_value: %s", key); return NULL; } static GConfMetaInfo* query_metainfo (GConfSource *source, const char *key, GError **err) { gconf_log (GCL_DEBUG, "query_metainfo: %s", key); return NULL; } static void set_value (GConfSource *source, const char *key, const GConfValue *value, GError **err) { const char *relative_key; char *parent; SqliteDirectory *dir; gconf_log (GCL_DEBUG, "set_value: %s", key); parent = gconf_key_directory (key); relative_key = gconf_key_key (key); dir = traverse_to_directory ((SqliteSource *)source, parent, TRUE, err); do { if (!dir) { update_failure (err); break; } if (!set_value_in_directory ((SqliteSource *)source, dir, relative_key, value, err)) { update_failure (err); break; } } while (0); g_free (parent); g_free (dir); g_assert (parent != NULL); } /* all entries in the directory pointed to by key */ static GSList* all_entries (GConfSource *source, const char *key, const char **locales, GError **err) { gconf_log (GCL_DEBUG, "all_entries: %s", key); return NULL; } /* all subdirectories of the directory pointed to by key */ static GSList* all_subdirs (GConfSource *source, const char *key, GError **err) { gconf_log (GCL_DEBUG, "all_subdirs: %s", key); return NULL; } static void unset_value (GConfSource *source, const char *key, const char *locale, GError **err) { gconf_log (GCL_DEBUG, "unset_value: %s", key); } static gboolean dir_exists (GConfSource *source, const char *key, GError **err) { gconf_log (GCL_DEBUG, "dir_exists: %s", key); return FALSE; } static void remove_dir (GConfSource *source, const char *key, GError **err) { gconf_log (GCL_DEBUG, "remove_dir: %s", key); } static void set_schema (GConfSource *source, const char *key, const char *schema_name, GError **err) { gconf_log (GCL_DEBUG, "set_schema: %s", key); } static gboolean sync_all (GConfSource *source, GError **err) { return FALSE; } static void destroy_source (GConfSource *source) { ss_destroy ((SqliteSource *)source); } static void clear_cache (GConfSource *source) { } static void blow_away_locks (const char *address) { } static GConfSource* resolve_address (const char *address, GError **err) { SqliteSource *new_source; GConfLock *lock; char *dbfile; gconf_log (GCL_DEBUG, "sqlite module initialising, address=%s", address); dbfile = gconf_address_resource (address); if (!dbfile) return NULL; /* for now, let's ignore locking; sqlite does it anyway * and probably better than we'd manage */ lock = NULL; new_source = ss_new (dbfile, lock); if (!new_source) { return NULL; } ((GConfSource *)new_source)->flags = 0; gconf_log (GCL_ERR, "sqlite dbfile at: %s\n", dbfile); g_free (dbfile); return (GConfSource *)new_source; } /**************** EXPORT *********************/ /* Initializer */ G_MODULE_EXPORT const char* g_module_check_init (GModule *module) { gconf_log (GCL_DEBUG, _("Initializing Markup backend module")); return NULL; } G_MODULE_EXPORT GConfBackendVTable* gconf_backend_get_vtable (void) { return &markup_vtable; }