From 6d34dbbb00da0c276261d0e1ce4bf862f22fd8e0 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 16 Oct 2014 22:04:29 +0000 Subject: Stored a bookmark into the data base and saved the archive. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@414 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 39 +++++++++ src/analysis/binary.c | 6 +- src/analysis/db/cdb.c | 47 ++++++++--- src/analysis/db/cdb.h | 2 +- src/analysis/db/client.c | 43 +++++++++- src/analysis/db/client.h | 3 + src/analysis/db/collection.c | 162 +++++++++++++++++++++++++++++++++++++- src/analysis/db/collection.h | 6 +- src/analysis/db/item-int.h | 10 +++ src/analysis/db/item.c | 93 ++++++++++++++++++++++ src/analysis/db/item.h | 18 +++++ src/analysis/db/items/bookmark.c | 61 +++++++++++--- src/analysis/db/items/bookmark.h | 2 +- src/analysis/db/protocol.h | 27 +++++++ src/arch/vmpa.c | 56 +++++++++++++ src/arch/vmpa.h | 9 +++ src/common/Makefile.am | 1 + src/common/sqlite.h | 56 +++++++++++++ src/core/collections.c | 2 +- src/gui/panels/bookmarks.c | 166 ++++++++++++++++++++------------------- 20 files changed, 694 insertions(+), 115 deletions(-) create mode 100644 src/common/sqlite.h diff --git a/ChangeLog b/ChangeLog index d621c81..fef9d17 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,42 @@ +14-10-16 Cyrille Bagard + + * src/analysis/binary.c: + Update test code for bookmarks. + + * src/analysis/db/cdb.c: + * src/analysis/db/cdb.h: + Write an archive on demand, and provide a final status. + + * src/analysis/db/client.c: + * src/analysis/db/client.h: + Ask the server for saving its archive. + + * src/analysis/db/collection.c: + * src/analysis/db/collection.h: + * src/analysis/db/item.c: + * src/analysis/db/item.h: + * src/analysis/db/item-int.h: + * src/analysis/db/items/bookmark.c: + * src/analysis/db/items/bookmark.h: + Store an item into the data base. + + * src/analysis/db/protocol.h: + Define a 'save' command. + + * src/arch/vmpa.c: + * src/arch/vmpa.h: + Provide a function to save the new 'vmpa_t' types into a SQLite DB. + + * src/common/Makefile.am: + Add the 'sqlite.h' file to libcommon_la_SOURCES. + + * src/common/sqlite.h: + New entry: extend SQLite with some internal definitions. + + * src/core/collections.c: + * src/gui/panels/bookmarks.c: + Update code. + 14-10-12 Cyrille Bagard * src/arch/arm/v7/arm.c: diff --git a/src/analysis/binary.c b/src/analysis/binary.c index 5577bb8..0fcbe0d 100644 --- a/src/analysis/binary.c +++ b/src/analysis/binary.c @@ -309,7 +309,7 @@ GLoadedBinary *g_loaded_binary_new_from_xml(xmlXPathContextPtr context, const ch bool status; - init_vmpa(&addr, 123, 0x200); + init_vmpa(&addr, 0xaeb4, VMPA_NO_VIRTUAL); bm = g_db_bookmark_new(&addr, "Premier commentaire"); @@ -323,6 +323,10 @@ GLoadedBinary *g_loaded_binary_new_from_xml(xmlXPathContextPtr context, const ch printf("send nok\n"); + g_db_client_save(result->local); + + + /* safe_send(client->fd, (uint32_t []) { htobe32(DBC_COLLECTION) }, sizeof(uint32_t), MSG_MORE); safe_send(client->fd, (uint32_t []) { htobe32(DBF_BOOKMARKS) }, sizeof(uint32_t), MSG_MORE); diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c index 563aa40..55d1b2d 100644 --- a/src/analysis/db/cdb.c +++ b/src/analysis/db/cdb.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -283,6 +282,8 @@ GCdbArchive *g_cdb_archive_new(const char *owner, const rle_string *hash, const result->filename = get_xdg_config_dir(suffix); + printf("dealing with '%s'...\n", result->filename); + free(suffix); if (!mkpath(result->filename)) @@ -318,7 +319,7 @@ GCdbArchive *g_cdb_archive_new(const char *owner, const rle_string *hash, const g_cdb_archive_create_xml_desc(result, user); g_cdb_archive_create_db(result, NULL); - if (!g_cdb_archive_write(result)) + if (g_cdb_archive_write(result) != DBE_NONE) goto gcan_error; } @@ -473,13 +474,13 @@ static bool g_cdb_archive_read(GCdbArchive *archive) * * ******************************************************************************/ -bool g_cdb_archive_write(const GCdbArchive *archive) +DBError g_cdb_archive_write(const GCdbArchive *archive) { - bool result; /* Conclusion à retourner */ + DBError result; /* Conclusion à retourner */ struct archive *out; /* Archive à constituer */ int ret; /* Bilan d'un appel */ - result = false; + result = DBE_ARCHIVE_ERROR; out = archive_write_new(); archive_write_add_filter_xz(out); @@ -488,16 +489,19 @@ bool g_cdb_archive_write(const GCdbArchive *archive) ret = archive_write_open_filename(out, archive->filename); if (ret != ARCHIVE_OK) goto gcaw_exit; - bool add_file_to_archive(struct archive *out, const char *src, const char *path) + DBError add_file_to_archive(struct archive *out, const char *src, const char *path) { + DBError status; /* Bilan à renvoyer */ struct stat info; /* Informations d'origine */ struct archive_entry *entry; /* Elément de l'archive */ int fd; /* Flux ouvert en lecture */ char buffer[ARCHIVE_RBUF_SIZE]; /* Tampon pour les transferts */ ssize_t len; /* Quantité de données lues */ + status = DBE_ARCHIVE_ERROR; + ret = stat(src, &info); - if (ret != 0) return false; + if (ret != 0) return DBE_SYS_ERROR; entry = archive_entry_new(); @@ -508,7 +512,11 @@ bool g_cdb_archive_write(const GCdbArchive *archive) if (ret != 0) goto afta_error; fd = open(src, O_RDONLY); - if (fd == -1) goto afta_error; + if (fd == -1) + { + status = DBE_SYS_ERROR; + goto afta_error; + } for (len = safe_read(fd, buffer, ARCHIVE_RBUF_SIZE); len > 0; @@ -522,18 +530,20 @@ bool g_cdb_archive_write(const GCdbArchive *archive) archive_entry_free(entry); - return true; + return DBE_NONE; afta_error: archive_entry_free(entry); - return false; + return status; } result = add_file_to_archive(out, archive->xml_desc, "desc.xml"); - result &= add_file_to_archive(out, archive->sql_db, "sql.db"); + + if (result == DBE_NONE) + result = add_file_to_archive(out, archive->sql_db, "sql.db"); gcaw_exit: @@ -781,6 +791,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive) uint32_t val32; /* Valeur sur 32 bits */ bool status; /* Bilan de lecture initiale */ uint32_t command; /* Commande de la requête */ + DBError error; /* Bilan d'une opération */ GDbCollection *collec; /* Collection visée au final */ void interrupt_poll_with_sigusr1(int sig) { }; @@ -843,6 +854,18 @@ static void *g_cdb_archive_process(GCdbArchive *archive) switch (command) { + case DBC_SAVE: + + error = g_cdb_archive_write(archive); + + if (!safe_send(fds[i].fd, (uint32_t []) { htobe32(DBC_SAVE) }, sizeof(uint32_t), 0)) + goto gcap_bad_exchange; + + if (!safe_send(fds[i].fd, (uint32_t []) { htobe32(error) }, sizeof(uint32_t), 0)) + goto gcap_bad_exchange; + + break; + case DBC_COLLECTION: status = safe_recv(fds[i].fd, &val32, sizeof(uint32_t), 0); @@ -851,7 +874,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive) collec = find_collection_in_list(archive->collections, be32toh(val32)); if (collec == NULL) goto gcap_bad_exchange; - status = g_db_collection_recv(collec, fds[i].fd); + status = g_db_collection_recv(collec, fds[i].fd, archive->db); if (!status) goto gcap_bad_exchange; printf("## CDB ## Got something for collection %p...\n", collec); diff --git a/src/analysis/db/cdb.h b/src/analysis/db/cdb.h index 17327f5..e9abb02 100644 --- a/src/analysis/db/cdb.h +++ b/src/analysis/db/cdb.h @@ -60,7 +60,7 @@ GType g_cdb_archive_get_type(void); GCdbArchive *g_cdb_archive_new(const char *, const rle_string *, const rle_string *, DBError *); /* Enregistre une archive avec tous les éléments à conserver. */ -bool g_cdb_archive_write(const GCdbArchive *); +DBError g_cdb_archive_write(const GCdbArchive *); /* Détermine si une empreinte correspond à celle d'une archive. */ int g_cdb_archive_compare_hash(const GCdbArchive *, const rle_string *); diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c index 4b807ae..71df99c 100644 --- a/src/analysis/db/client.c +++ b/src/analysis/db/client.c @@ -328,6 +328,7 @@ static void *g_db_client_update(GDbClient *client) uint32_t val32; /* Valeur sur 32 bits */ bool status; /* Bilan d'une opération */ uint32_t command; /* Commande de la requête */ + DBError error; /* Bilan d'une commande passée */ GDbCollection *collec; /* Collection visée au final */ fds.fd = client->fd; @@ -353,6 +354,19 @@ static void *g_db_client_update(GDbClient *client) switch (command) { + case DBC_SAVE: + + status = safe_recv(fds.fd, &val32, sizeof(uint32_t), 0); + if (!status) goto gdcu_bad_exchange; + + error = be32toh(val32); + + printf("## CLIENT ## Saved ? %d\n", error); + + + + break; + case DBC_COLLECTION: status = safe_recv(fds.fd, &val32, sizeof(uint32_t), 0); @@ -361,7 +375,7 @@ static void *g_db_client_update(GDbClient *client) collec = find_collection_in_list(client->collections, be32toh(val32)); if (collec == NULL) goto gdcu_bad_exchange; - status = g_db_collection_recv(collec, fds.fd); + status = g_db_collection_recv(collec, fds.fd, NULL); if (!status) goto gdcu_bad_exchange; @@ -459,3 +473,30 @@ void g_db_client_put_fd(GDbClient *client) g_mutex_unlock(&client->sending_lock); } + + +/****************************************************************************** +* * +* Paramètres : client = client pour les accès distants à manipuler. * +* * +* Description : Effectue une demande de sauvegarde de l'état courant. * +* * +* Retour : true si la commande a bien été envoyée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_db_client_save(GDbClient *client) +{ + bool result; /* Bilan partiel à remonter */ + + g_db_client_get_fd(client); + + result = safe_send(client->fd, (uint32_t []) { htobe32(DBC_SAVE) }, sizeof(uint32_t), 0); + + g_db_client_put_fd(client); + + return result; + +} diff --git a/src/analysis/db/client.h b/src/analysis/db/client.h index a1a9f8e..963744b 100644 --- a/src/analysis/db/client.h +++ b/src/analysis/db/client.h @@ -65,6 +65,9 @@ int g_db_client_get_fd(GDbClient *); /* Marque le canal de communication comme disponible. */ void g_db_client_put_fd(GDbClient *); +/* Effectue une demande de sauvegarde de l'état courant. */ +bool g_db_client_save(GDbClient *); + #endif /* _ANALYSIS_DB_CLIENT_H */ diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c index 20b1ff3..5c25720 100644 --- a/src/analysis/db/collection.c +++ b/src/analysis/db/collection.c @@ -24,6 +24,11 @@ #include "collection.h" +#include +#include + + +#include "../../common/extstr.h" #include "../../common/io.h" #include "../../glibext/chrysamarshal.h" @@ -36,6 +41,7 @@ struct _GDbCollection uint32_t featuring; /* Fonctionnalité représentée */ GType type; /* Identifiant GLib équivalent */ + const char *name; /* Nom en base de données */ GList *items; /* Eléments rassemblés */ GList *sorted; /* Eléments triés */ @@ -71,6 +77,15 @@ static void g_db_collection_finalize(GDbCollection *); +/* --------------------- MANIPULATIONS AVEC UNE BASE DE DONNEES --------------------- */ + + +/* Enregistre un élément de collection dans une base de données. */ +static bool g_db_collection_store_item(const GDbCollection *, const GDbItem *, sqlite3 *); + + + + /* Indique le type défini pour une collection générique d'éléments. */ G_DEFINE_TYPE(GDbCollection, g_db_collection, G_TYPE_OBJECT); @@ -170,7 +185,8 @@ static void g_db_collection_finalize(GDbCollection *collec) /****************************************************************************** * * * Paramètres : id = identifiant réseau des éléments à traiter. * -* type = type GLib des éléments à intégrer dans la collection. * +* type = type GLib des éléments à placer dans la collection. * +* name = indique le nom désignant la table associée. * * * * Description : Prépare la mise en place d'une nouvelle collection. * * * @@ -180,7 +196,7 @@ static void g_db_collection_finalize(GDbCollection *collec) * * ******************************************************************************/ -GDbCollection *g_db_collection_new(uint32_t id, GType type) +GDbCollection *g_db_collection_new(uint32_t id, GType type, const char *name) { GDbCollection *result; /* Adresse à retourner */ @@ -188,6 +204,7 @@ GDbCollection *g_db_collection_new(uint32_t id, GType type) result->featuring = id; result->type = type; + result->name = name; return result; @@ -233,6 +250,7 @@ uint32_t g_db_collection_get_feature(const GDbCollection *collec) * * * Paramètres : collec = ensemble d'éléments à considérer. * * fd = flux ouvert en lecture pour la réception de données.* +* db = base de données à mettre à jour. * * * * Description : Réceptionne et traite une requête réseau pour collection. * * * @@ -244,7 +262,7 @@ uint32_t g_db_collection_get_feature(const GDbCollection *collec) * * ******************************************************************************/ -bool g_db_collection_recv(GDbCollection *collec, int fd) +bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db) { bool result; /* Bilan à faire remonter */ uint32_t val32; /* Valeur sur 32 bits */ @@ -269,6 +287,8 @@ bool g_db_collection_recv(GDbCollection *collec, int fd) { case DBA_ADD_ITEM: result = g_db_collection_add_item(collec, item); + if (result && db != NULL) + result = g_db_collection_store_item(collec, item, db); break; case DBA_REM_ITEM: @@ -430,6 +450,10 @@ bool g_db_collection_add_item(GDbCollection *collec, GDbItem *item) g_signal_emit_by_name(collec, "content-changed", DBA_ADD_ITEM, item); + + printf(" ==== CONTENT CHANGED !!!\n"); + + result = true; } @@ -478,6 +502,138 @@ bool g_db_collection_modify_item(GDbCollection *collec, GDbItem *item) /* ---------------------------------------------------------------------------------- */ /* CREATION DE L'ABSTRACTION POUR COLLECTIONS */ +/* MANIPULATIONS AVEC UNE BASE DE DONNEES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : collec = ensemble d'éléments à considérer. * +* item = élément de collection à enregistrer. * +* db = base de données à mettre à jour. * +* * +* Description : Enregistre un élément de collection dans une base de données.* +* * +* Retour : Bilan de l'exécution de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_db_collection_store_item(const GDbCollection *collec, const GDbItem *item, sqlite3 *db) +{ + bool result; /* Conclusion à faire remonter */ + bound_value *values; /* Champs de table à inclure */ + size_t count; /* Nombre de ces champs */ + char *sql; /* Requête SQL à construire */ + size_t i; /* Boucle de parcours */ + sqlite3_stmt *stmt; /* Déclaration mise en place */ + int ret; /* Bilan d'un appel à SQLite */ + int index; /* Indice de valeur attachée */ + + if (!g_db_item_prepare_db_statement(item, true, &values, &count)) + return false; + + result = false; + + /* Préparation de la requête */ + + sql = strdup("INSERT INTO "); + sql = stradd(sql, collec->name); + sql = stradd(sql, " ("); + + for (i = 0; i < count; i++) + { + if (i > 0) sql = stradd(sql, ", "); + + sql = stradd(sql, values[i].name); + + } + + sql = stradd(sql, ") VALUES ("); + + for (i = 0; i < count; i++) + { + if (i > 0) sql = stradd(sql, ", "); + + if (values[i].type == SQLITE_RAW) + sql = stradd(sql, values[i].cstring); + else + sql = stradd(sql, "?"); + + } + + sql = stradd(sql, ");"); + + ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); + if (ret != SQLITE_OK) + { + fprintf(stderr, "Can't prepare INSERT statment '%s' (ret=%d): %s\n", sql, ret, sqlite3_errmsg(db)); + goto gdcsi_exit; + } + + /* Attribution des valeurs */ + + index = 1; + + for (i = 0; i < count; i++) + { + switch (values[i].type) + { + case SQLITE_INT64: + ret = sqlite3_bind_int64(stmt, index, values[i].integer64); + index++; + break; + + case SQLITE_TEXT: + ret = sqlite3_bind_text(stmt, index, values[i].string, -1, values[i].delete); + index++; + break; + + default: + ret = SQLITE_OK; + break; + + } + + if (ret != SQLITE_OK) + { + fprintf(stderr, "Can't bind value for parameter nb %d in '%s' (ret=%d): %s\n", + index - 1, sql, ret, sqlite3_errmsg(db)); + goto gdcsi_exit; + } + + } + + /* Exécution finale */ + + ret = sqlite3_step(stmt); + + if (ret != SQLITE_DONE) + { + fprintf(stderr, "INSERT statement '%s' didn't return DONE (ret=%d): %s\n", sql, ret, sqlite3_errmsg(db)); + goto gdcsi_exit; + } + + sqlite3_finalize(stmt); + + result = true; + + gdcsi_exit: + + free(sql); + + printf("INSERT ? %d\n", result); + + return result; + +} + + + + +/* ---------------------------------------------------------------------------------- */ +/* CREATION DE L'ABSTRACTION POUR COLLECTIONS */ /* ---------------------------------------------------------------------------------- */ diff --git a/src/analysis/db/collection.h b/src/analysis/db/collection.h index 75ee7df..b400820 100644 --- a/src/analysis/db/collection.h +++ b/src/analysis/db/collection.h @@ -26,6 +26,8 @@ #include +#include +#include #include @@ -52,7 +54,7 @@ typedef struct _GDbCollectionClass GDbCollectionClass; GType g_db_collection_get_type(void); /* Prépare la mise en place d'une nouvelle collection. */ -GDbCollection *g_db_collection_new(uint32_t, GType); +GDbCollection *g_db_collection_new(uint32_t, GType, const char *); @@ -63,7 +65,7 @@ uint32_t g_db_collection_get_feature(const GDbCollection *); /* Réceptionne et traite une requête réseau pour collection. */ -bool g_db_collection_recv(GDbCollection *, int); +bool g_db_collection_recv(GDbCollection *, int, sqlite3 *); /* Envoie pour traitement une requête réseau pour collection. */ bool g_db_collection_send(GDbCollection *, int, DBAction, GDbItem *); diff --git a/src/analysis/db/item-int.h b/src/analysis/db/item-int.h index b6d8f9c..0f75ed4 100644 --- a/src/analysis/db/item-int.h +++ b/src/analysis/db/item-int.h @@ -32,12 +32,20 @@ + + + + + /* Importe la définition d'une base d'éléments pour collection. */ typedef bool (* recv_db_item_fc) (GDbItem *, int, int); /* Exporte la définition d'une base d'éléments pour collection. */ typedef bool (* send_db_item_fc) (const GDbItem *, int, int); +/* Constitue les champs destinés à une insertion / modification. */ +typedef bool (* prepare_db_statement) (const GDbItem *, bool, bound_value **, size_t *); + /* Base d'un élément pour collection générique (instance) */ struct _GDbItem @@ -61,6 +69,8 @@ struct _GDbItemClass recv_db_item_fc recv; /* Réception depuis le réseau */ send_db_item_fc send; /* Emission depuis le réseau */ + prepare_db_statement prepare_stmt; /* Préparation d'une requête */ + }; diff --git a/src/analysis/db/item.c b/src/analysis/db/item.c index e2fd7f3..7fa1a52 100644 --- a/src/analysis/db/item.c +++ b/src/analysis/db/item.c @@ -24,8 +24,13 @@ #include "item.h" +#include +#include + + #include "item-int.h" #include "../../common/io.h" +#include "../../core/params.h" @@ -52,6 +57,13 @@ static bool g_db_item_send_to_fd(const GDbItem *, int, int); +/* --------------------- MANIPULATIONS AVEC UNE BASE DE DONNEES --------------------- */ + + +/* Constitue les champs destinés à une insertion / modification. */ +static bool _g_db_item_prepare_db_statement(const GDbItem *, bool, bound_value **, size_t *); + + /* Indique le type défini pour une base d'élément de collection générique. */ G_DEFINE_TYPE(GDbItem, g_db_item, G_TYPE_OBJECT); @@ -83,6 +95,8 @@ static void g_db_item_class_init(GDbItemClass *klass) klass->recv = (recv_db_item_fc)g_db_item_recv_from_fd; klass->send = (send_db_item_fc)g_db_item_send_to_fd; + klass->prepare_stmt = (prepare_db_statement)_g_db_item_prepare_db_statement; + } @@ -354,3 +368,82 @@ bool g_db_item_is_volatile(const GDbItem *item) return item->is_volatile; } + + + +/* ---------------------------------------------------------------------------------- */ +/* MANIPULATIONS AVEC UNE BASE DE DONNEES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = base d'éléments sur laquelle s'appuyer. * +* create = indique si la préparation vise une création ou non. * +* values = couples de champs et de valeurs à lier. [OUT] * +* count = nombre de ces couples. [OUT] * +* * +* Description : Constitue les champs destinés à une insertion / modification.* +* * +* Retour : Bilan de l'opération : succès ou non. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool _g_db_item_prepare_db_statement(const GDbItem *item, bool create, bound_value **values, size_t *count) +{ + char *author; /* Identification à diffuser */ + bound_value *value; /* Valeur à éditer / définir */ + + if (!g_generic_config_get_value(get_main_configuration(), MPK_AUTHOR_NAME, &author)) + return false; + + *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value)); + value = &(*values)[*count - 1]; + + value->name = "user"; + value->type = SQLITE_TEXT; + value->string = author; + value->delete = free; + + if (!create) + { + *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value)); + value = &(*values)[*count - 1]; + + value->name = "modified"; + value->type = SQLITE_RAW; + value->string = "CURRENT_TIMESTAMP"; + value->delete = SQLITE_STATIC; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : item = base d'éléments sur laquelle s'appuyer. * +* create = indique si la préparation vise une création ou non. * +* values = couples de champs et de valeurs à lier. [OUT] * +* count = nombre de ces couples. [OUT] * +* * +* Description : Constitue les champs destinés à une insertion / modification.* +* * +* Retour : Bilan de l'opération : succès ou non. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_db_item_prepare_db_statement(const GDbItem *item, bool create, bound_value **values, size_t *count) +{ + *values = NULL; + *count = 0; + + return G_DB_ITEM_GET_CLASS(item)->prepare_stmt(item, create, values, count); + +} diff --git a/src/analysis/db/item.h b/src/analysis/db/item.h index 3938610..2f8ee60 100644 --- a/src/analysis/db/item.h +++ b/src/analysis/db/item.h @@ -29,6 +29,9 @@ #include +#include "../../common/sqlite.h" + + #define G_TYPE_DB_ITEM g_db_item_get_type() #define G_DB_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_db_item_get_type(), GDbItem)) @@ -65,4 +68,19 @@ bool g_db_item_is_volatile(const GDbItem *); +/* --------------------- MANIPULATIONS AVEC UNE BASE DE DONNEES --------------------- */ + + +/* Définition du tronc commun pour les créations SQLite */ +#define SQLITE_DB_ITEM_CREATE \ + "user TEXT, " \ + "created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " \ + "modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " + + +/* Constitue les champs destinés à une insertion / modification. */ +bool g_db_item_prepare_db_statement(const GDbItem *, bool, bound_value **, size_t *); + + + #endif /* _ANALYSIS_DB_ITEM_H */ diff --git a/src/analysis/db/items/bookmark.c b/src/analysis/db/items/bookmark.c index c28a837..6ff386c 100644 --- a/src/analysis/db/items/bookmark.c +++ b/src/analysis/db/items/bookmark.c @@ -75,6 +75,9 @@ static bool g_db_bookmark_recv_from_fd(GDbBookmark *, int, int); /* Exporte la définition d'un signet dans un flux réseau. */ static bool g_db_bookmark_send_to_fd(const GDbBookmark *, int, int); +/* Constitue les champs destinés à une insertion / modification. */ +static bool g_db_bookmark_prepare_db_statement(const GDbBookmark *, bool, bound_value **, size_t *); + @@ -97,10 +100,8 @@ bool create_bookmark_db_table(sqlite3 *db) char *msg; /* Message d'erreur */ sql = "CREATE TABLE Bookmarks (" \ - "id INT PRIMARY KEY NOT NULL, " \ - "user TEXT NOT NULL, " \ - "created INT NOT NULL, " \ - "address INT NOT NULL, " \ + SQLITE_DB_ITEM_CREATE \ + SQLITE_VMPA_CREATE \ "comment TEXT" \ ");"; @@ -157,6 +158,8 @@ static void g_db_bookmark_class_init(GDbBookmarkClass *klass) item->recv = (recv_db_item_fc)g_db_bookmark_recv_from_fd; item->send = (send_db_item_fc)g_db_bookmark_send_to_fd; + item->prepare_stmt = (prepare_db_statement)g_db_bookmark_prepare_db_statement; + } @@ -235,13 +238,7 @@ GDbBookmark *g_db_bookmark_new(const vmpa2t *addr, const char *comment) result = g_object_new(G_TYPE_DB_BOOKMARK, NULL); - - - - /* TODO */ - - //dup addr; - + copy_vmpa(&result->addr, addr); g_db_bookmark_set_comment(result, comment); @@ -351,6 +348,46 @@ static bool g_db_bookmark_send_to_fd(const GDbBookmark *bookmark, int fd, int fl } +/****************************************************************************** +* * +* Paramètres : item = base d'éléments sur laquelle s'appuyer. * +* create = indique si la préparation vise une création ou non. * +* values = couples de champs et de valeurs à lier. [OUT] * +* count = nombre de ces couples. [OUT] * +* * +* Description : Constitue les champs destinés à une insertion / modification.* +* * +* Retour : Etat du besoin en sauvegarde. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_db_bookmark_prepare_db_statement(const GDbBookmark *bookmark, bool create, bound_value **values, size_t *count) +{ + bool status; /* Bilan d'opération initiale */ + bound_value *value; /* Valeur à éditer / définir */ + + status = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->prepare_stmt(G_DB_ITEM(bookmark), create, values, count); + if (!status) return false; + + status = prepare_vmpa_db_statement(&bookmark->addr, create, values, count); + if (!status) return false; + + *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value)); + value = &(*values)[*count - 1]; + + value->name = "comment"; + value->type = SQLITE_TEXT; + value->cstring = g_db_bookmark_get_comment(bookmark); + value->delete = SQLITE_STATIC; + + return true; + +} + + + @@ -370,7 +407,7 @@ static bool g_db_bookmark_send_to_fd(const GDbBookmark *bookmark, int fd, int fl * * ******************************************************************************/ -vmpa2t *g_db_bookmark_get_address(GDbBookmark *bookmark) +const vmpa2t *g_db_bookmark_get_address(GDbBookmark *bookmark) { return &bookmark->addr; diff --git a/src/analysis/db/items/bookmark.h b/src/analysis/db/items/bookmark.h index d1b073c..cd5e202 100644 --- a/src/analysis/db/items/bookmark.h +++ b/src/analysis/db/items/bookmark.h @@ -66,7 +66,7 @@ GType g_db_bookmark_get_type(void); GDbBookmark *g_db_bookmark_new(const vmpa2t *, const char *); /* Fournit l'adresse associée à un signet. */ -vmpa2t *g_db_bookmark_get_address(GDbBookmark *); +const vmpa2t *g_db_bookmark_get_address(GDbBookmark *); /* Fournit le commentaire associé à un signet. */ const char *g_db_bookmark_get_comment(const GDbBookmark *); diff --git a/src/analysis/db/protocol.h b/src/analysis/db/protocol.h index 05b559e..85d44cb 100644 --- a/src/analysis/db/protocol.h +++ b/src/analysis/db/protocol.h @@ -113,6 +113,7 @@ typedef enum _DBCommand { DBC_HELO, /* Connexion initiale C -> S */ DBC_WELCOME, /* Réponse initiale S -> C */ + DBC_SAVE, /* Enregistrement de l'archive */ DBC_COLLECTION, /* Implication d'une collection*/ DBC_COUNT @@ -132,6 +133,8 @@ typedef enum _DBError { DBE_NONE, /* Succès d'une opération */ DBE_WRONG_VERSION, /* Proto Client != Serveur */ + DBE_SYS_ERROR, /* Erreur suite à un appel sys.*/ + DBE_ARCHIVE_ERROR, /* Soucis du côté libarchive */ DBE_COUNT @@ -141,6 +144,30 @@ typedef enum _DBError +/** + * Gestion de la commande 'DBC_SAVE'. + * + * Le client connecté envoie un paquet de la forme suivante : + * + * [ Ordre de sauvegarde : DBC_SAVE ] + * + * Le serveur s'exécute et renvoie un bilan : + * + * [ Ordre de sauvegarde : DBC_SAVE ] + * [ Statut d'exécution ; cf. DBError ] + * + * Les traitements se réalisent dans : + * - g_db_client_save() pour la partie client en émission. + * - g_cdb_archive_process() pour la partie serveur. + * - g_db_client_update() pour la partie client en réception. + * + */ + + + + + + diff --git a/src/arch/vmpa.c b/src/arch/vmpa.c index 6f305fb..024161c 100644 --- a/src/arch/vmpa.c +++ b/src/arch/vmpa.c @@ -482,6 +482,62 @@ vmpa2t *string_to_vmpa_virt(const char *buffer) } +/****************************************************************************** +* * +* Paramètres : addr = adresse virtuelle ou physique à traiter. * +* create = indique si la préparation vise une création ou non. * +* values = couples de champs et de valeurs à lier. [OUT] * +* count = nombre de ces couples. [OUT] * +* * +* Description : Constitue les champs destinés à une insertion / modification.* +* * +* Retour : Bilan de l'opération : succès ou non. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool prepare_vmpa_db_statement(const vmpa2t *addr, bool create, bound_value **values, size_t *count) +{ + bound_value *value; /* Valeur à éditer / définir */ + + *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value)); + value = &(*values)[*count - 1]; + + value->name = "phys"; + + if (addr->physical != VMPA_NO_PHYSICAL) + { + value->type = SQLITE_INT64; + value->integer64 = addr->physical; + } + else + { + value->type = SQLITE_RAW; + value->cstring = "NULL"; + } + + *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value)); + value = &(*values)[*count - 1]; + + value->name = "virt"; + + if (addr->virtual != VMPA_NO_VIRTUAL) + { + value->type = SQLITE_INT64; + value->integer64 = addr->virtual; + } + else + { + value->type = SQLITE_RAW; + value->cstring = "NULL"; + } + + return true; + +} + + /* ---------------------------------------------------------------------------------- */ /* DEFINITION D'UNE ZONE EN MEMOIRE */ diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h index 52c5d6a..f0a8faf 100644 --- a/src/arch/vmpa.h +++ b/src/arch/vmpa.h @@ -34,6 +34,7 @@ #include "archbase.h" #include "../common/cpp.h" +#include "../common/sqlite.h" @@ -117,6 +118,14 @@ vmpa2t *string_to_vmpa_phy(const char *); /* Transforme une chaîne de caractères en adresse virtuelle. */ vmpa2t *string_to_vmpa_virt(const char *); +/* Définition du tronc commun pour les créations SQLite */ +#define SQLITE_VMPA_CREATE \ + "phys INTEGER, " \ + "virt INTEGER, " + +/* Constitue les champs destinés à une insertion / modification. */ +bool prepare_vmpa_db_statement(const vmpa2t *, bool, bound_value **, size_t *); + /* ------------------------ DEFINITION D'UNE ZONE EN MEMOIRE ------------------------ */ diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 7ec85ab..198de32 100755 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -13,6 +13,7 @@ libcommon_la_SOURCES = \ leb128.h leb128.c \ macros.h \ net.h net.c \ + sqlite.h \ xdg.h xdg.c \ xml.h xml.c diff --git a/src/common/sqlite.h b/src/common/sqlite.h new file mode 100644 index 0000000..66fb773 --- /dev/null +++ b/src/common/sqlite.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sqlite.h - prototypes pour une extension des définitions propres à SQLite + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see . + */ + + +#ifndef _COMMON_SQLITE_H +#define _COMMON_SQLITE_H + + +#include + + +/* Type pour les insertions brutes */ +#define SQLITE_RAW 0 +#define SQLITE_INT64 10 + + +/* Description des champs et de leur valeur associée */ +typedef struct _bound_value +{ + const char *name; /* Nom du champ à manipuler */ + unsigned int type; /* Type de valeur à associer */ + + union + { + int64_t integer64; /* Nombre sur 64 bits */ + char *string; /* Chaîne de caractères #1 */ + const char *cstring; /* Chaîne de caractères #2 */ + + }; + + void (* delete) (void *); /* Suppression éventuelle */ + +} bound_value; + + + +#endif /* _COMMON_SQLITE_H */ diff --git a/src/core/collections.c b/src/core/collections.c index 860b7f6..80d2ae3 100644 --- a/src/core/collections.c +++ b/src/core/collections.c @@ -164,7 +164,7 @@ GList *create_collections_list(void) for (i = 0; i < _collection_definitions_count; i++) { def = &_collection_definitions[i]; - collec = g_db_collection_new(i, def->items); + collec = g_db_collection_new(i, def->items, "Bookmarks"); result = g_list_append(result, collec); diff --git a/src/gui/panels/bookmarks.c b/src/gui/panels/bookmarks.c index 56e7119..5d2be18 100644 --- a/src/gui/panels/bookmarks.c +++ b/src/gui/panels/bookmarks.c @@ -110,6 +110,8 @@ static void g_bookmarks_panel_finalize(GBookmarksPanel *); /* Recharge une collection de signets à l'affichage. */ static void reload_bookmarks_into_treeview(GBookmarksPanel *, GLoadedBinary *); +/* Réagit au changement de sélection des signets. */ +static void on_bookmarks_selection_change(GtkTreeSelection *, GBookmarksPanel *); @@ -234,6 +236,7 @@ static void g_bookmarks_panel_init(GBookmarksPanel *panel) GtkCellRenderer *renderer; /* Moteur de rendu de colonne */ GtkTreeViewColumn *column; /* Colonne de la liste */ GtkTreeSortable *sortable; /* Autre vision de la liste */ + GtkTreeSelection *select; /* Sélection dans la liste */ base = G_EDITOR_ITEM(panel); @@ -294,7 +297,7 @@ static void g_bookmarks_panel_init(GBookmarksPanel *panel) renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Physical address"), renderer, - "text", BMC_VIRTUAL, + "text", BMC_PHYSICAL, NULL); gtk_tree_view_column_set_sort_column_id(column, BMC_PHYSICAL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); @@ -330,6 +333,12 @@ static void g_bookmarks_panel_init(GBookmarksPanel *panel) gtk_tree_sortable_set_sort_column_id(sortable, BMC_COMMENT, GTK_SORT_ASCENDING); + /* Prise en compte de la sélection */ + + select = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); + gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE); + g_signal_connect(G_OBJECT(select), "changed", G_CALLBACK(on_bookmarks_selection_change), panel); + /* Préparation du menu contextuel */ panel->menu = build_bookmarks_panel_menu(panel); @@ -464,14 +473,17 @@ static void reload_bookmarks_into_treeview(GBookmarksPanel *panel, GLoadedBinary { GtkTreeStore *store; /* Modèle de gestion */ GDbCollection *collec; /* Collection à lister ici */ + GExeFormat *format; /* Format du fichier binaire */ + GArchProcessor *proc; /* Architecture du binaire */ + MemoryDataSize msize; /* Taille par défaut */ GList *items; /* Liste des éléments groupés */ GList *b; /* Boucle de parcours */ GDbBookmark *bookmark; /* Signet en cours d'étude */ - vmpa2t *addr; /* Adressse associée au signet */ + const vmpa2t *addr; /* Adressse associée au signet */ + VMPA_BUFFER(phys); /* Position physique */ + VMPA_BUFFER(virt); /* Adresse virtuelle */ GtkTreeIter iter; /* Point d'insertion */ - printf("RELOAD :: %p\n", binary); - /* Basculement du binaire utilisé */ if (panel->binary != NULL) @@ -491,7 +503,10 @@ static void reload_bookmarks_into_treeview(GBookmarksPanel *panel, GLoadedBinary /* Actualisation de l'affichage */ - sleep(1); + format = g_loaded_binary_get_format(binary); + proc = get_arch_processor_from_format(format); + + msize = g_arch_processor_get_memory_size(proc); collec = g_loaded_binary_find_collection(binary, DBF_BOOKMARKS); @@ -499,107 +514,65 @@ static void reload_bookmarks_into_treeview(GBookmarksPanel *panel, GLoadedBinary items = g_db_collection_list_items(collec); - - printf(" ... items = %p\n", items); - - /* - gtk_tree_store_append(store, &iter, NULL); - gtk_tree_store_set(store, &iter, - BMC_BOOKMARK, bookmark, - BMC_PICTURE, G_BOOKMARKS_PANEL_GET_CLASS(panel)->bookmark_img, - BMC_PHYSICAL, "0x01", - BMC_VIRTUAL, "0x02", - BMC_COMMENT, "desc", - -1); - */ - - for (b = g_list_first(items); b != NULL; b = g_list_next(b)) { bookmark = G_DB_BOOKMARK(b->data); - - printf("Adding // %p\n", bookmark); - - //printf("add.virt = %s\n", vmpa2_virt_to_string(&addr, MDS_32_BITS)); - - fflush(NULL); - - addr = g_db_bookmark_get_address(bookmark); + vmpa2_phys_to_string(addr, msize, phys, NULL); + vmpa2_virt_to_string(addr, msize, virt, NULL); + gtk_tree_store_append(store, &iter, NULL); gtk_tree_store_set(store, &iter, BMC_BOOKMARK, bookmark, BMC_PICTURE, G_BOOKMARKS_PANEL_GET_CLASS(panel)->bookmark_img, - BMC_PHYSICAL, "vmpa2_phy_to_string(addr, MDS_32_BITS)", /* FIXME : pareil qu'en bas */ - BMC_VIRTUAL, "vmpa2_virt_to_string(&addr, MDS_32_BITS)", /* FIXME : choisir en fonction de l'architecture */ - BMC_COMMENT, "g_db_bookmark_get_comment(bookmark)", + BMC_PHYSICAL, phys, + BMC_VIRTUAL, virt, + BMC_COMMENT, g_db_bookmark_get_comment(bookmark), -1); } g_db_collection_runlock(collec); +} -#if 0 - GtkTreeStore *store; /* Modèle de gestion */ - GList *params; /* Paramètres de configuration */ - GCfgParam *param; /* Paramètre en cours d'étude */ - GList *p; /* Boucle de parcours */ - char *type_desc; /* Type de paramètre */ - GtkTreeIter iter; /* Point d'insertion */ - - store = GTK_TREE_STORE(gtk_tree_view_get_model(panel->treeview)); - gtk_tree_store_clear(store); - - g_generic_config_rlock(config); +/****************************************************************************** +* * +* Paramètres : selection = sélection modifiée. * +* panel = structure contenant les informations maîtresses. * +* * +* Description : Réagit au changement de sélection des signets. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - params = g_generic_config_list_params(config); +static void on_bookmarks_selection_change(GtkTreeSelection *selection, GBookmarksPanel *panel) +{ + GtkTreeIter iter; /* Point de sélection */ + GtkTreeModel *model; /* Modèle de gestion */ + GDbBookmark *bookmark; /* Signet en cours d'étude */ + const vmpa2t *addr; /* Adressse associée au signet */ + GtkViewPanel *vpanel; /* Afficheur effectif de code */ - for (p = g_list_first(params); p != NULL; p = g_list_next(p)) + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { - param = G_CFG_PARAM(p->data); + gtk_tree_model_get(model, &iter, BMC_BOOKMARK, &bookmark, -1); - if (is_param_filtered(panel, g_config_param_get_path(param))) - continue; - - switch (g_config_param_get_ptype(param)) - { - case CPT_BOOLEAN: - type_desc = _("Boolean"); - break; - - case CPT_INTEGER: - type_desc = _("Integer"); - break; - - case CPT_STRING: - type_desc = _("String"); - break; - - default: - type_desc = _(""); - break; - - } - - gtk_tree_store_append(store, &iter, NULL); - gtk_tree_store_set(store, &iter, - CPC_BOOKMARK, param, - CPC_PATH, g_config_param_get_path(param), - CPC_TYPE, type_desc, - -1); + addr = g_db_bookmark_get_address(bookmark); - update_config_param_value(store, &iter); + vpanel = g_editor_item_get_current_view(G_EDITOR_ITEM(panel)); + gtk_view_panel_scroll_to_address(vpanel, addr); - g_signal_connect(param, "modified", G_CALLBACK(on_config_param_modified), panel); + g_object_unref(G_OBJECT(bookmark)); } - g_generic_config_runlock(config); -#endif } @@ -1008,8 +981,39 @@ static bool is_param_filtered(GBookmarksPanel *panel, const char *name) static gboolean on_button_press_over_bookmarks(GtkWidget *widget, GdkEventButton *event, GBookmarksPanel *panel) { - if (event->button == 3) - gtk_menu_popup(panel->menu, NULL, NULL, NULL, NULL, event->button, event->time); + GtkTreeSelection *selection; /* Sélection courante */ + GtkTreeIter iter; /* Point de sélection */ + GtkTreeModel *model; /* Modèle de gestion */ + GDbBookmark *bookmark; /* Signet en cours d'étude */ + const vmpa2t *addr; /* Adressse associée au signet */ + GtkViewPanel *vpanel; /* Afficheur effectif de code */ + + switch (event->button) + { + case 1: + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + gtk_tree_model_get(model, &iter, BMC_BOOKMARK, &bookmark, -1); + + addr = g_db_bookmark_get_address(bookmark); + + vpanel = g_editor_item_get_current_view(G_EDITOR_ITEM(panel)); + gtk_view_panel_scroll_to_address(vpanel, addr); + + g_object_unref(G_OBJECT(bookmark)); + + } + + break; + + case 3: + gtk_menu_popup(panel->menu, NULL, NULL, NULL, NULL, event->button, event->time); + break; + + } return FALSE; -- cgit v0.11.2-87-g4458