diff options
Diffstat (limited to 'src/analysis/db/cdb.c')
-rw-r--r-- | src/analysis/db/cdb.c | 391 |
1 files changed, 201 insertions, 190 deletions
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c index ca39a58..e03b875 100644 --- a/src/analysis/db/cdb.c +++ b/src/analysis/db/cdb.c @@ -44,6 +44,7 @@ #include "collection.h" #include "protocol.h" +#include "snapshot.h" #include "../../common/compression.h" #include "../../common/cpp.h" #include "../../common/extstr.h" @@ -54,6 +55,9 @@ +/* ------------------------- COEUR DE LA GESTION D'ARCHIVES ------------------------- */ + + /* Informations relatives à un client */ typedef struct _cdb_client { @@ -73,17 +77,14 @@ struct _GCdbArchive rle_string hash; /* Empreinte cryptographique */ char *filename; /* Chemin d'accès à l'archive */ - + char *tmpdir; /* Répertoire de travail */ char *xml_desc; /* Fichier de description */ - char *sql_db; /* Base de données SQLite */ - xmlDocPtr xdoc; /* Document XML à créer */ - xmlXPathContextPtr context; /* Contexte pour les recherches*/ + GList *collections; /* Ensemble de modifications */ + GDbSnapshot *snapshot; /* Instantanés de bases SQL */ sqlite3 *db; /* Base de données à manipuler */ - GList *collections; /* Ensemble de modifications */ - cdb_client *clients; /* Connexions en place */ size_t count; /* Quantité de clients */ GMutex clients_access; /* Verrou pour l'accès */ @@ -116,7 +117,7 @@ static void g_cdb_archive_dispose(GCdbArchive *); static void g_cdb_archive_finalize(GCdbArchive *); /* Ouvre une archive avec tous les éléments à conserver. */ -static bool g_cdb_archive_read(GCdbArchive *); +static DBError g_cdb_archive_read(GCdbArchive *); @@ -124,27 +125,22 @@ static bool g_cdb_archive_read(GCdbArchive *); /* Crée la description XML correspondant à l'archive. */ -static bool g_cdb_archive_create_xml_desc(GCdbArchive *); +static bool g_cdb_archive_create_xml_desc(const GCdbArchive *, xmlDocPtr *, xmlXPathContextPtr *); /* Vérifie la conformité d'une description XML avec le serveur. */ -static bool g_cdb_archive_check_xml_version(const GCdbArchive *); - - - -/* ------------------------- ACCES A LA BASE DE DONNEES SQL ------------------------- */ +static bool g_cdb_archive_check_xml_version(const GCdbArchive *, xmlXPathContextPtr); -/* Crée la base de données correspondant à l'archive. */ -static bool g_cdb_archive_create_db(const GCdbArchive *); - - -/////////////////////////: +/* -------------------------- ACTUALISATION DE COLLECTIONS -------------------------- */ /* Crée et remplit les collections à partir de leurs bases. */ static bool g_cdb_archive_load_collections(GCdbArchive *); +/* Enregistre les signaux associés au suivi des collections. */ +static void g_cdb_archive_register_signals(GCdbArchive *); + /* Réagit à une modification au sein d'une collection donnée. */ static void on_collection_extended(GDbCollection *, GDbItem *, GCdbArchive *); @@ -156,6 +152,9 @@ static void g_cdb_archive_remove_client(GCdbArchive *, size_t); +/* ---------------------------------------------------------------------------------- */ +/* COEUR DE LA GESTION D'ARCHIVES */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour une une archive d'éléments utilisateur. */ @@ -200,8 +199,12 @@ static void g_cdb_archive_class_init(GCdbArchiveClass *klass) static void g_cdb_archive_init(GCdbArchive *archive) { + archive->tmpdir = NULL; + archive->collections = create_collections_list(); + archive->snapshot = NULL; + g_mutex_init(&archive->clients_access); g_mutex_init(&archive->id_access); @@ -224,6 +227,8 @@ static void g_cdb_archive_init(GCdbArchive *archive) static void g_cdb_archive_dispose(GCdbArchive *archive) { + g_clear_object(&archive->snapshot); + g_cond_clear(&archive->id_cond); g_mutex_clear(&archive->id_access); @@ -256,29 +261,14 @@ static void g_cdb_archive_finalize(GCdbArchive *archive) assert(ret == SQLITE_OK); } - if (archive->xdoc != NULL) - close_xml_file(archive->xdoc, archive->context); - if (archive->xml_desc != NULL) - { - ret = unlink(archive->xml_desc); - if (ret != 0) LOG_ERROR_N("unlink"); - free(archive->xml_desc); - } - - if (archive->sql_db != NULL) - { - ret = unlink(archive->sql_db); - if (ret != 0) LOG_ERROR_N("unlink"); - - free(archive->sql_db); - - } - free(archive->filename); + if (archive->tmpdir != NULL) + free(archive->tmpdir); + exit_rle_string(&archive->hash); G_OBJECT_CLASS(g_cdb_archive_parent_class)->finalize(G_OBJECT(archive)); @@ -307,11 +297,14 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl GCdbArchive *result; /* Adresse à retourner */ int ret; /* Retour d'un appel */ struct stat finfo; /* Information sur l'archive */ + const char *id; /* Identifiant d'instantané */ result = g_object_new(G_TYPE_CDB_ARCHIVE, NULL); dup_into_rle_string(&result->hash, get_rle_string(hash)); + *error = DBE_SYS_ERROR; + /* Chemin de l'archive */ result->filename = strdup(basedir); @@ -319,21 +312,20 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl result->filename = stradd(result->filename, ".cdb.tar.xz"); if (!mkpath(result->filename)) - goto gcan_error; + goto error; /* Chemin des enregistrements temporaires */ + result->tmpdir = strdup(tmpdir); + if (!mkpath(tmpdir)) - goto gcan_error; + goto error; - ret = asprintf(&result->xml_desc, "%s" G_DIR_SEPARATOR_S "%s_desc.xml", tmpdir, result->hash.data); - if (ret == -1) goto gcan_no_tmp; + ret = asprintf(&result->xml_desc, "%s" G_DIR_SEPARATOR_S "%s_desc.xml", tmpdir, get_rle_string(hash)); + if (ret == -1) goto no_tmp; ret = ensure_path_exists(result->xml_desc); - if (ret == -1) goto gcan_no_tmp; - - ret = asprintf(&result->sql_db, "%s" G_DIR_SEPARATOR_S "%s_db.sql", tmpdir, result->hash.data); - if (ret == -1) goto gcan_no_tmp; + if (ret == -1) goto no_tmp; /* Création de l'archive si elle n'existe pas */ @@ -342,44 +334,74 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl if (ret != 0) { /* Le soucis ne vient pas de l'absence du fichier... */ - if (errno != ENOENT) goto gcan_error; + if (errno != ENOENT) goto error; - g_cdb_archive_create_xml_desc(result); - g_cdb_archive_create_db(result); + result->snapshot = g_db_snapshot_new_empty(tmpdir, get_rle_string(hash), result->collections); - *error = g_cdb_archive_write(result); + if (result->snapshot == NULL) + goto error; - if (*error != DBE_NONE) - goto gcan_error; + /* Récupération de la base courante */ - } - else if (!S_ISREG(finfo.st_mode)) - goto gcan_error; + id = g_db_snapshot_get_current_id(result->snapshot); + assert(id != NULL); + + result->db = g_db_snapshot_get_database(result->snapshot, id); - /* Ouverture de l'archive */ + if (result->db == NULL) + { + *error = DBE_XML_ERROR; + goto error; + } - if (!g_cdb_archive_read(result)) - goto gcan_error; + *error = DBE_NONE; - if (!g_cdb_archive_check_xml_version(result)) - { - *error = DBE_XML_VERSION_ERROR; - goto gcan_error; } - /* Chargement des éléments sauvegardés */ + else if (!S_ISREG(finfo.st_mode)) + goto error; - if (!g_cdb_archive_load_collections(result)) + else { - *error = DBE_DB_LOADING_ERROR; - goto gcan_error; + /* Ouverture de l'archive */ + + *error = g_cdb_archive_read(result); + + if (*error != DBE_NONE) + goto error; + + /* Récupération de la base courante */ + + id = g_db_snapshot_get_current_id(result->snapshot); + assert(id != NULL); + + result->db = g_db_snapshot_get_database(result->snapshot, id); + + if (result->db == NULL) + { + *error = DBE_XML_ERROR; + goto error; + } + + /* Chargement des éléments sauvegardés */ + + if (!g_cdb_archive_load_collections(result)) + { + *error = DBE_DB_LOADING_ERROR; + goto error; + } + } + /* Ultimes connexions */ + + g_cdb_archive_register_signals(result); + return result; - gcan_no_tmp: + no_tmp: - gcan_error: + error: g_object_unref(G_OBJECT(result)); @@ -400,22 +422,25 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl * * ******************************************************************************/ -static bool g_cdb_archive_read(GCdbArchive *archive) +static DBError g_cdb_archive_read(GCdbArchive *archive) { - bool result; /* Conclusion à retourner */ + DBError result; /* Conclusion à retourner */ struct archive *in; /* Archive à consulter */ int ret; /* Bilan d'un appel */ struct archive_entry *entry; /* Elément de l'archive */ const char *path; /* Désignation d'un fichier */ + xmlDocPtr xdoc; /* Document XML à créer */ + xmlXPathContextPtr context; /* Contexte pour les recherches*/ + bool status; /* Bilan d'un chargement */ - result = false; + result = DBE_ARCHIVE_ERROR; in = archive_read_new(); archive_read_support_filter_all(in); archive_read_support_format_all(in); ret = archive_read_open_filename(in, archive->filename, 10240 /* ?! */); - if (ret != ARCHIVE_OK) goto gcar_bad_archive; + if (ret != ARCHIVE_OK) goto bad_archive; for (ret = archive_read_next_header(in, &entry); ret == ARCHIVE_OK; @@ -426,33 +451,53 @@ static bool g_cdb_archive_read(GCdbArchive *archive) if (strcmp(path, "desc.xml") == 0) { if (!dump_archive_entry_into_file(in, entry, archive->xml_desc)) - goto gcar_exit; + goto load_error; - if (!open_xml_file(archive->xml_desc, &archive->xdoc, &archive->context)) - goto gcar_exit; + if (!open_xml_file(archive->xml_desc, &xdoc, &context)) + goto load_error; - } - else if (strcmp(path, "sql.db") == 0) - { - if (!dump_archive_entry_into_file(in, entry, archive->sql_db)) - goto gcar_exit; + if (!g_cdb_archive_check_xml_version(archive, context)) + { + result = DBE_XML_VERSION_ERROR; + goto load_error; + } + + archive->snapshot = g_db_snapshot_new_from_xml(archive->tmpdir, get_rle_string(&archive->hash), + xdoc, context); + + close_xml_file(xdoc, context); + + ret = unlink(archive->xml_desc); + if (ret != 0) LOG_ERROR_N("unlink"); + + if (archive->snapshot == NULL) + goto load_error; + + break; - ret = sqlite3_open(archive->sql_db, &archive->db); - if (ret != SQLITE_OK) - goto gcar_exit; } } - if (ret != ARCHIVE_EOF) - goto gcar_exit; + archive_read_close(in); + archive_read_free(in); + + in = archive_read_new(); + archive_read_support_filter_all(in); + archive_read_support_format_all(in); + + ret = archive_read_open_filename(in, archive->filename, 10240 /* ?! */); + if (ret != ARCHIVE_OK) goto bad_archive; + + status = g_db_snapshot_fill(archive->snapshot, in); + if (!status) goto load_error; - result = true; + result = DBE_NONE; - gcar_exit: + load_error: - gcar_bad_archive: + bad_archive: archive_read_close(in); archive_read_free(in); @@ -479,23 +524,54 @@ DBError g_cdb_archive_write(const GCdbArchive *archive) DBError result; /* Conclusion à retourner */ struct archive *out; /* Archive à constituer */ int ret; /* Bilan d'un appel */ - CPError status; /* Bilan d'une compression */ - - result = DBE_ARCHIVE_ERROR; + xmlDocPtr xdoc; /* Document XML à créer */ + xmlXPathContextPtr context; /* Contexte pour les recherches*/ + bool status; /* Bilan d'un appel */ + CPError error; /* Bilan d'une compression */ out = archive_write_new(); archive_write_add_filter_xz(out); archive_write_set_format_gnutar(out); ret = archive_write_open_filename(out, archive->filename); - if (ret != ARCHIVE_OK) goto gcaw_bad_archive; + if (ret != ARCHIVE_OK) + { + result = DBE_ARCHIVE_ERROR; + goto bad_archive; + } - status = add_file_into_archive(out, archive->xml_desc, "desc.xml"); + status = g_cdb_archive_create_xml_desc(archive, &xdoc, &context); - switch (status) + if (!status) + { + result = DBE_XML_ERROR; + goto bad_archive; + } + + /* Enregistrement des bases */ + + result = g_db_snapshot_save(archive->snapshot, xdoc, context, out); + + if (result != DBE_NONE) + goto bad_archive; + + /* Enregistrement du document XML */ + + status = save_xml_file(xdoc, archive->xml_desc); + + close_xml_file(xdoc, context); + + if (!status) + { + result = DBE_SYS_ERROR; + goto bad_xml; + } + + error = add_file_into_archive(out, archive->xml_desc, "desc.xml"); + + switch (error) { case CPE_NO_ERROR: - result = DBE_NONE; break; case CPE_SYSTEM_ERROR: @@ -508,29 +584,12 @@ DBError g_cdb_archive_write(const GCdbArchive *archive) } - if (result == DBE_NONE) - { - status = add_file_into_archive(out, archive->sql_db, "sql.db"); + bad_xml: - switch (status) - { - case CPE_NO_ERROR: - result = DBE_NONE; - break; + ret = unlink(archive->xml_desc); + if (ret != 0) LOG_ERROR_N("unlink"); - case CPE_SYSTEM_ERROR: - result = DBE_SYS_ERROR; - break; - - case CPE_ARCHIVE_ERROR: - result = DBE_ARCHIVE_ERROR; - break; - - } - - } - - gcaw_bad_archive: + bad_archive: archive_write_close(out); archive_write_free(out); @@ -569,6 +628,8 @@ int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *has /****************************************************************************** * * * Paramètres : archive = archive à constituer. * +* xdoc = document XML à compléter. [OUT] * +* context = contexte pour les recherches. [OUT] * * * * Description : Crée la description XML correspondant à l'archive. * * * @@ -578,38 +639,20 @@ int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *has * * ******************************************************************************/ -static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive) +static bool g_cdb_archive_create_xml_desc(const GCdbArchive *archive, xmlDocPtr *xdoc, xmlXPathContextPtr *context) { bool result; /* Bilan à retourner */ - timestamp_t timestamp; /* Date de création */ - char tmp[sizeof(XSTR(UINT64_MAX))]; /* Stockage temporaire */ - - result = create_new_xml_file(&archive->xdoc, &archive->context); - if (result) - result = add_content_to_node(archive->xdoc, archive->context, - "/ChrysalideBinary/Version", PACKAGE_VERSION); - - if (result) - result = add_content_to_node(archive->xdoc, archive->context, - "/ChrysalideBinary/Protocol", XSTR(CDB_PROTOCOL_VERSION)); + result = create_new_xml_file(xdoc, context); if (result) - result = add_content_to_node(archive->xdoc, archive->context, - "/ChrysalideBinary/Hash", archive->hash.data); + result = add_content_to_node(*xdoc, *context, "/ChrysalideBinary/Version", PACKAGE_VERSION); if (result) - { - init_timestamp(×tamp); - snprintf(tmp, sizeof(tmp), "%" PRIu64, timestamp); - - result = add_content_to_node(archive->xdoc, archive->context, - "/ChrysalideBinary/CreationDate", tmp); - - } + result = add_content_to_node(*xdoc, *context, "/ChrysalideBinary/Protocol", XSTR(CDB_PROTOCOL_VERSION)); if (result) - result = save_xml_file(archive->xdoc, archive->xml_desc); + result = add_content_to_node(*xdoc, *context, "/ChrysalideBinary/Hash", archive->hash.data); return result; @@ -619,6 +662,7 @@ static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive) /****************************************************************************** * * * Paramètres : archive = archive à consulter. * +* context = contexte pour les recherches. * * * * Description : Vérifie la conformité d'une description XML avec le serveur. * * * @@ -628,7 +672,7 @@ static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive) * * ******************************************************************************/ -static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive) +static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive, xmlXPathContextPtr context) { bool result; /* Bilan à retourner */ char *version; /* Version protocolaire */ @@ -636,7 +680,7 @@ static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive) result = NULL; - version = get_node_text_value(archive->context, "/ChrysalideBinary/Protocol"); + version = get_node_text_value(context, "/ChrysalideBinary/Protocol"); if (version == NULL) return false; used = strtoul(version, NULL, 16); @@ -650,16 +694,17 @@ static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive) } + /* ---------------------------------------------------------------------------------- */ -/* ACCES A LA BASE DE DONNEES SQL */ +/* ACTUALISATION DE COLLECTIONS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : archive = archive à constituer. * +* Paramètres : archive = archive dont les collections sont à initialiser. * * * -* Description : Crée la base de données correspondant à l'archive. * +* Description : Crée et remplit les collections à partir de leurs bases. * * * * Retour : Bilan de l'opération. * * * @@ -667,72 +712,40 @@ static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive) * * ******************************************************************************/ -static bool g_cdb_archive_create_db(const GCdbArchive *archive) +static bool g_cdb_archive_load_collections(GCdbArchive *archive) { - bool result; /* Bilan à retourner */ - sqlite3 *db; /* Base de données à constituer*/ - int ret; /* Bilan de la création */ GList *iter; /* Boucle de parcours */ GDbCollection *collec; /* Collection visée manipulée */ - ret = sqlite3_open(archive->sql_db, &db); - - if (ret != SQLITE_OK) - { - fprintf(stderr, "sqlite3_open(): %s\n", sqlite3_errmsg(db)); - return false; - } - - result = true; - for (iter = g_list_first(archive->collections); - iter != NULL && result; + iter != NULL; iter = g_list_next(iter)) { collec = G_DB_COLLECTION(iter->data); - result = g_db_collection_create_db_table(collec, db); - } - - sqlite3_close(db); - - return result; - -} - - - - - - - - - - - - -/* ---------------------------------------------------------------------------------- */ -/* ACCES A LA BASE DE DONNEES SQL */ -/* ACCES A LA BASE DE DONNEES SQL */ -/* ---------------------------------------------------------------------------------- */ + if (!g_db_collection_load_all_items(collec, archive->db)) + return false; + } + return true; +} /****************************************************************************** * * -* Paramètres : archive = archive dont les collections sont à initialiser. * +* Paramètres : archive = archive dont les collections sont à suivre. * * * -* Description : Crée et remplit les collections à partir de leurs bases. * +* Description : Enregistre les signaux associés au suivi des collections. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool g_cdb_archive_load_collections(GCdbArchive *archive) +static void g_cdb_archive_register_signals(GCdbArchive *archive) { GList *iter; /* Boucle de parcours */ GDbCollection *collec; /* Collection visée manipulée */ @@ -742,15 +755,11 @@ static bool g_cdb_archive_load_collections(GCdbArchive *archive) iter = g_list_next(iter)) { collec = G_DB_COLLECTION(iter->data); - g_signal_connect(collec, "content-extended", G_CALLBACK(on_collection_extended), archive); - if (!g_db_collection_load_all_items(collec, archive->db)) - return false; + g_signal_connect(collec, "content-extended", G_CALLBACK(on_collection_extended), archive); } - return true; - } @@ -1001,6 +1010,8 @@ static void *g_cdb_archive_process(GCdbArchive *archive) LOG_ERROR(LMT_ERROR, _("Bad exchange")); + assert(0); + exit_packed_buffer(&in_pbuf); closed_exchange: |