diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2015-07-28 21:32:57 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2015-07-28 21:32:57 (GMT) |
commit | 41efd099244b53a0edb40d097b34bf28a05b6367 (patch) | |
tree | 90f2419db6584e672b9f190e7e61e589e0345459 /src/analysis/db | |
parent | e56a0553f710235d829f36b1edbf3cea00148a98 (diff) |
Begun to manage collection items as active or inactive using timestamps.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@558 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src/analysis/db')
-rwxr-xr-x | src/analysis/db/Makefile.am | 1 | ||||
-rw-r--r-- | src/analysis/db/cdb.c | 22 | ||||
-rw-r--r-- | src/analysis/db/cdb.h | 5 | ||||
-rw-r--r-- | src/analysis/db/client.c | 30 | ||||
-rw-r--r-- | src/analysis/db/client.h | 3 | ||||
-rw-r--r-- | src/analysis/db/collection.c | 429 | ||||
-rw-r--r-- | src/analysis/db/collection.h | 26 | ||||
-rw-r--r-- | src/analysis/db/core.c | 207 | ||||
-rw-r--r-- | src/analysis/db/core.h | 70 | ||||
-rw-r--r-- | src/analysis/db/item-int.h | 22 | ||||
-rw-r--r-- | src/analysis/db/item.c | 260 | ||||
-rw-r--r-- | src/analysis/db/item.h | 24 | ||||
-rw-r--r-- | src/analysis/db/items/bookmark.c | 40 | ||||
-rw-r--r-- | src/analysis/db/items/comment.c | 13 | ||||
-rw-r--r-- | src/analysis/db/items/switcher.c | 22 | ||||
-rwxr-xr-x | src/analysis/db/misc/Makefile.am | 3 | ||||
-rw-r--r-- | src/analysis/db/misc/timestamp.c | 263 | ||||
-rw-r--r-- | src/analysis/db/misc/timestamp.h | 80 | ||||
-rw-r--r-- | src/analysis/db/protocol.h | 33 |
19 files changed, 1106 insertions, 447 deletions
diff --git a/src/analysis/db/Makefile.am b/src/analysis/db/Makefile.am index 2e8e0f1..797025c 100755 --- a/src/analysis/db/Makefile.am +++ b/src/analysis/db/Makefile.am @@ -6,7 +6,6 @@ libanalysisdb_la_SOURCES = \ client.h client.c \ collection-int.h \ collection.h collection.c \ - core.h core.c \ item-int.h \ item.h item.c \ protocol.h \ diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c index 96e69d5..70e0dc5 100644 --- a/src/analysis/db/cdb.c +++ b/src/analysis/db/cdb.c @@ -140,8 +140,9 @@ static bool g_cdb_archive_check_xml_version(const GCdbArchive *); /* ------------------------- ACCES A LA BASE DE DONNEES SQL ------------------------- */ + /* Crée la base de données correspondant à l'archive. */ -static bool g_cdb_archive_create_db(const GCdbArchive *, const core_db_info *); +static bool g_cdb_archive_create_db(const GCdbArchive *); @@ -333,7 +334,7 @@ GCdbArchive *g_cdb_archive_new(const char *owner, const rle_string *hash, const if (errno != ENOENT) goto gcan_error; g_cdb_archive_create_xml_desc(result, user); - g_cdb_archive_create_db(result, NULL); + g_cdb_archive_create_db(result); *error = g_cdb_archive_write(result); @@ -623,7 +624,8 @@ int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *has static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive, const rle_string *user) { bool result; /* Bilan à retourner */ - char tmp[sizeof(XSTR(UINT32_MAX))]; /* Stockage temporaire */ + 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) return false; @@ -640,7 +642,8 @@ static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive, const rle_string result &= add_content_to_node(archive->xdoc, archive->context, "/ChrysalideBinary/Creation/Author", user->data); - snprintf(tmp, sizeof(tmp), "%" PRIu64, (uint64_t)time(NULL)); + init_timestamp(×tamp); + snprintf(tmp, sizeof(tmp), "%" PRIu64, timestamp); result &= add_content_to_node(archive->xdoc, archive->context, "/ChrysalideBinary/Creation/Date", tmp); @@ -694,7 +697,6 @@ static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive) /****************************************************************************** * * * Paramètres : archive = archive à constituer. * -* info = informations de base associées à la requête. * * * * Description : Crée la base de données correspondant à l'archive. * * * @@ -704,7 +706,7 @@ static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive) * * ******************************************************************************/ -static bool g_cdb_archive_create_db(const GCdbArchive *archive, const core_db_info *info) +static bool g_cdb_archive_create_db(const GCdbArchive *archive) { bool result; /* Bilan à retourner */ sqlite3 *db; /* Base de données à constituer*/ @@ -728,7 +730,6 @@ static bool g_cdb_archive_create_db(const GCdbArchive *archive, const core_db_in { collec = G_DB_COLLECTION(iter->data); result = g_db_collection_create_db_table(collec, db); - fprintf(stderr, "STATUS :: %d\n", result); } sqlite3_close(db); @@ -953,6 +954,13 @@ static void *g_cdb_archive_process(GCdbArchive *archive) break; + case DBC_SET_LAST_ACTIVE: + + status = update_activity_in_collections(archive->collections, fds[i].fd, archive->db); + if (!status) goto gcap_bad_exchange; + + break; + default: printf("bad command :: 0x%08x\n", command); goto gcap_bad_exchange; diff --git a/src/analysis/db/cdb.h b/src/analysis/db/cdb.h index e9abb02..d6b03fb 100644 --- a/src/analysis/db/cdb.h +++ b/src/analysis/db/cdb.h @@ -32,11 +32,6 @@ #include "protocol.h" #include "misc/rlestr.h" -////// -#include "client.h" -#include "core.h" -////////// - #define G_TYPE_CDB_ARCHIVE g_cdb_archive_get_type() diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c index f0d3d4b..2a5a185 100644 --- a/src/analysis/db/client.c +++ b/src/analysis/db/client.c @@ -525,3 +525,33 @@ bool g_db_client_save(GDbClient *client) return result; } + + +/****************************************************************************** +* * +* Paramètres : client = client pour les accès distants à manipuler. * +* timestamp = date du dernier élément à garder comme actif. * +* * +* Description : Active les éléments en amont d'un horodatage donné. * +* * +* Retour : true si la commande a bien été envoyée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_db_client_set_last_active(GDbClient *client, timestamp_t timestamp) +{ + bool result; /* Bilan partiel à remonter */ + + g_db_client_get_fd(client); + + result = safe_send(client->fd, (uint32_t []) { htobe32(DBC_SET_LAST_ACTIVE) }, sizeof(uint32_t), 0); + + result &= send_timestamp(×tamp, client->fd, MSG_MORE); + + g_db_client_put_fd(client); + + return result; + +} diff --git a/src/analysis/db/client.h b/src/analysis/db/client.h index 6e9f10b..0304786 100644 --- a/src/analysis/db/client.h +++ b/src/analysis/db/client.h @@ -68,6 +68,9 @@ void g_db_client_put_fd(GDbClient *); /* Effectue une demande de sauvegarde de l'état courant. */ bool g_db_client_save(GDbClient *); +/* Active les éléments en amont d'un horodatage donné. */ +bool g_db_client_set_last_active(GDbClient *, timestamp_t); + #endif /* _ANALYSIS_DB_CLIENT_H */ diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c index c3b9f2c..91f9872 100644 --- a/src/analysis/db/collection.c +++ b/src/analysis/db/collection.c @@ -68,6 +68,8 @@ static bool g_db_collection_setup_load(GDbCollection *, bound_value **, size_t * /* Enregistre un élément de collection dans une base de données. */ static bool g_db_collection_store_item(const GDbCollection *, const GDbItem *, sqlite3 *); +/* Met à jour un élément de collection dans une base de données. */ +static bool g_db_collection_store_updated_item(const GDbCollection *, const GDbItem *, sqlite3 *); @@ -285,6 +287,9 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db) item = g_object_new(collec->type, NULL); + if (db != NULL) + g_db_item_set_server_side(item); + status = g_db_item_recv(item, fd, 0); if (!status) return false; @@ -312,8 +317,13 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db) case DBA_REM_ITEM: break; - case DBA_MOD_ITEM: - result = g_db_collection_modify_item(collec, item); + case DBA_CHANGE_STATE: + + if (db == NULL) + result = g_db_collection_update_item_activity(collec, item); + else + result = false; + break; default: @@ -322,6 +332,8 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db) } + g_object_unref(G_OBJECT(item)); + return result; } @@ -511,7 +523,7 @@ bool g_db_collection_has_item(GDbCollection *collec, GDbItem *item) printf(" --- has\n"); - found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare); + found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare_with_timestamp); printf(" --- has: %p\n", found); @@ -539,33 +551,23 @@ bool g_db_collection_has_item(GDbCollection *collec, GDbItem *item) bool _g_db_collection_add_item(GDbCollection *collec, GDbItem *item, bool lock) { bool result; /* Bilan à faire remonter */ - GList *found; /* Test de présence existante */ + + result = true; if (lock) g_db_collection_wlock(collec); - found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare); - - if (found != NULL) - result = g_db_collection_modify_item(collec, item); - - else - { - g_object_ref(G_OBJECT(item)); - collec->items = g_list_append(collec->items, item); - - g_object_ref(G_OBJECT(item)); - collec->sorted = g_list_insert_sorted(collec->sorted, item, (GCompareFunc)g_db_item_compare); + g_object_ref(G_OBJECT(item)); + collec->items = g_list_append(collec->items, item); - g_signal_emit_by_name(collec, "content-changed", DBA_ADD_ITEM, item); + g_object_ref(G_OBJECT(item)); + collec->sorted = g_list_insert_sorted(collec->sorted, item, (GCompareFunc)g_db_item_compare_with_timestamp); + g_signal_emit_by_name(collec, "content-changed", DBA_ADD_ITEM, item); - printf(" ==== CONTENT CHANGED (-> %u) !!!\n", g_list_length(collec->items)); + printf(" ==== CONTENT CHANGED (-> %u) !!!\n", g_list_length(collec->items)); - result = true; - - } if (lock) g_db_collection_wunlock(collec); @@ -578,10 +580,10 @@ bool _g_db_collection_add_item(GDbCollection *collec, GDbItem *item, bool lock) /****************************************************************************** * * * Paramètres : collec = ensemble d'éléments à considérer. * -* item = élément de collection à copier. * +* item = élément de collection à manipuler. * * lock = indique si le verrou d'écriture doit être posé. * * * -* Description : Procède à la modification d'un élément dans la collection. * +* Description : Met à jour le statut d'activité d'un élément de collection. * * * * Retour : Bilan de l'exécution de l'opération. * * * @@ -589,26 +591,127 @@ bool _g_db_collection_add_item(GDbCollection *collec, GDbItem *item, bool lock) * * ******************************************************************************/ -bool _g_db_collection_modify_item(GDbCollection *collec, GDbItem *item, bool lock) +bool _g_db_collection_update_item_activity(GDbCollection *collec, GDbItem *item, bool lock) { bool result; /* Bilan à faire remonter */ GList *found; /* Test de présence existante */ + GDbItem *internal; /* Elément interne à modifier */ - found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare); + if (lock) + g_db_collection_wlock(collec); + found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare_without_timestamp); + result = (found != NULL); - result = true; + if (result) + { + internal = G_DB_ITEM(found->data); + + g_db_item_set_activity(internal, (timestamp_t []) { g_db_item_get_timestamp(item) + 1 }); + + g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, internal); + + } + + if (lock) + g_db_collection_wunlock(collec); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : collec = ensemble d'éléments à considérer. * +* timestamp = date du dernier élément à garder comme actif. * +* inactive = date du premier élément inactif rencontré. [OUT] * +* db = base de données à mettre à jour. * +* * +* Description : Active les éléments en amont d'un horodatage donné. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +GList *g_db_collection_set_last_active(GDbCollection *collec, timestamp_t timestamp, timestamp_t *inactive, sqlite3 *db) +{ + GList *result; /* Liste d'inactifs à renvoyer */ + GList *i; /* Parcours des éléments */ + GDbItem *item; /* Elément à traiter */ + timestamp_t stamp; /* Horodatage de l'élément */ + result = NULL; + for (i = g_list_first(collec->items); i != NULL; i = g_list_next(i)) + { + item = G_DB_ITEM(i->data); + stamp = g_db_item_get_timestamp(item); + if (timestamp_is_younger(stamp, timestamp)) + { + if (!g_db_item_is_active(item)) + { + g_db_item_set_activity(item, NULL); + /* ... */g_db_collection_store_updated_item(collec, item, db); + g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, item); + } + } + + else + { + if (!g_db_item_is_active(item)) + { + if (timestamp_is_younger(stamp, *inactive)) + *inactive = stamp; + } + + else + result = g_list_append(result, item); + + } + + } return result; } +/****************************************************************************** +* * +* Paramètres : collec = ensemble d'éléments à considérer. * +* item = élément à désactiver. * +* timestamp = date du premier élément inactif rencontré. [OUT] * +* * +* Description : Désactive les éléments en aval d'un horodatage donné. * +* * +* Retour : true si l'élément a été traité, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_db_collection_set_inactive(GDbCollection *collec, GDbItem *item, timestamp_t *timestamp) +{ + /* Si cette collection n'est pas concernée, on ne bouge pas ! */ + if (G_OBJECT_TYPE(G_OBJECT(item)) != collec->type) return false; + + assert(g_db_item_is_active(item)); + + g_db_item_set_activity(item, timestamp); + + g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, item); + + return true; + +} + + /* ---------------------------------------------------------------------------------- */ /* MANIPULATIONS AVEC UNE BASE DE DONNEES */ @@ -630,8 +733,6 @@ bool _g_db_collection_modify_item(GDbCollection *collec, GDbItem *item, bool loc bool g_db_collection_create_db_table(const GDbCollection *collec, sqlite3 *db) { - fprintf(stderr, "CREATE '%s'\n", collec->name); - return G_DB_COLLECTION_GET_CLASS(collec)->create_table(collec, db); } @@ -653,12 +754,11 @@ bool g_db_collection_create_db_table(const GDbCollection *collec, sqlite3 *db) static bool _g_db_collection_setup_load(GDbCollection *collec, bound_value **values, size_t *count) { - *count += 2; - *values = (bound_value *)realloc(*values, *count * sizeof(bound_value)); - - (*values)[*count - 2].name = "created"; + if (!setup_load_of_timestamp(NULL, "created", values, count)) + return false; - (*values)[*count - 1].name = "modified"; + if (!setup_load_of_timestamp(NULL, "timestamp", values, count)) + return false; if (!setup_load_of_rle_string(NULL, "author", values, count)) return false; @@ -666,9 +766,6 @@ static bool _g_db_collection_setup_load(GDbCollection *collec, bound_value **val if (!setup_load_of_rle_string(NULL, "tool", values, count)) return false; - if (!setup_load_of_rle_string(NULL, "label", values, count)) - return false; - return true; } @@ -796,6 +893,8 @@ bool g_db_collection_load_all_items(GDbCollection *collec, sqlite3 *db) new = g_object_new(G_DB_COLLECTION(collec)->type, NULL); + g_db_item_set_server_side(new); + result = g_db_item_load(new, values, count); result &= g_db_collection_add_item(G_DB_COLLECTION(collec), new); @@ -931,13 +1030,157 @@ static bool g_db_collection_store_item(const GDbCollection *collec, const GDbIte free(sql); - printf("INSERT ? %d\n", result); - return result; } +/****************************************************************************** +* * +* Paramètres : collec = ensemble d'éléments à considérer. * +* item = élément de collection à enregistrer. * +* db = base de données à mettre à jour. * +* * +* Description : Met à jour 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_updated_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 */ + bool first; /* Première valeur ? */ + 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 */ + const bound_value *timestamp; /* Valeur de l'horodatage */ + + if (!g_db_item_prepare_db_statement(item, &values, &count)) + return false; + + result = false; + + /* Préparation de la requête */ + + sql = strdup("UPDATE "); + sql = stradd(sql, collec->name); + + sql = stradd(sql, " SET timestamp = ? "); + + sql = stradd(sql, "WHERE "); + + first = true; + + for (i = 0; i < count; i++) + { + if (strcmp(values[i].name, "timestamp") == 0) + continue; + + if (first) + first = false; + else + sql = stradd(sql, " AND "); + + sql = stradd(sql, values[i].name); + + sql = stradd(sql, " = "); + + if (values[i].type == SQLITE_RAW) + sql = stradd(sql, values[i].cstring); + else + sql = stradd(sql, "?"); + + } + + sql = stradd(sql, ";"); + + fprintf(stderr, "UPDATE SQL '%s'\n", 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; + + timestamp = find_bound_value(values, count, "timestamp"); + assert(timestamp->type == SQLITE_INT64); + + ret = sqlite3_bind_int64(stmt, index, values[i].integer64); + index++; + + 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; + } + + for (i = 0; i < count; i++) + { + if (strcmp(values[i].name, "timestamp") == 0) + continue; + + 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, "UPDATE 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); + + return result; + +} + /* ---------------------------------------------------------------------------------- */ @@ -1007,3 +1250,113 @@ GDbCollection *find_collection_in_list(GList *list, uint32_t id) return (iter != NULL ? result : NULL); } + + +/****************************************************************************** +* * +* Paramètres : list = ensemble de collectons à parcourir. * +* write = précise le type d'accès prévu (lecture/écriture). * +* lock = indique le sens du verrouillage à mener. * +* * +* Description : Met à disposition un encadrement des accès aux éléments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void lock_unlock_collections(GList *list, bool write, bool lock) +{ + GList *iter; /* Boucle de parcours */ + + for (iter = g_list_first(list); + iter != NULL; + iter = g_list_next(iter)) + { + g_db_collection_lock_unlock(G_DB_COLLECTION(iter->data), write, lock); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble de collectons à traiter. * +* fd = canal de communication ouvert en lecture. * +* db = base de données à mettre à jour. * +* * +* Description : Met à jour les statuts d'activité des éléments. * +* * +* Retour : Bilan du déroulement des opérations. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool update_activity_in_collections(GList *list, int fd, sqlite3 *db) +{ + bool result; /* Résultat global à renvoyer */ + bool status; /* Bilan de lecture initiale */ + timestamp_t timestamp; /* Horodatage de limite */ + timestamp_t inactive; /* Date du premier inactif */ + GList *remaining; /* Eléments restants à traiter */ + GList *c; /* Boucle de parcours #1 */ + GDbCollection *collec; /* Collection à manipuler */ + GList *got; /* Eléments restants à traiter */ + GList *i; /* Boucle de parcours #2 */ + GDbItem *item; /* Elément collecté à manipuler*/ + + status = recv_timestamp(×tamp, fd, 0); + if (!status) return false; + + inactive = TIMESTAMP_ALL_ACTIVE; + + remaining = NULL; + + wlock_collections(list); + + for (c = g_list_first(list); c != NULL; c = g_list_next(c)) + { + collec = G_DB_COLLECTION(c->data); + + got = g_db_collection_set_last_active(collec, timestamp, &inactive, db); + remaining = g_list_concat(remaining, got); + + } + + gint sort_with_timestamp(GDbItem *a, GDbItem *b) + { + return g_db_item_cmp(a, b, false); + } + + remaining = g_list_sort(remaining, (GCompareFunc)sort_with_timestamp); + + result = true; + + for (i = g_list_last(remaining); i != NULL && result; i = g_list_previous(i)) + { + item = G_DB_ITEM(i->data); + + for (c = g_list_first(list); c != NULL && result; c = g_list_next(c)) + { + collec = G_DB_COLLECTION(c->data); + + if (g_db_collection_set_inactive(collec, item, &inactive)) + { + result = g_db_collection_store_updated_item(collec, item, db); + break; + } + + } + + } + + wunlock_collections(list); + + g_list_free(remaining); + + return result; + +} diff --git a/src/analysis/db/collection.h b/src/analysis/db/collection.h index e550009..ac3e60f 100644 --- a/src/analysis/db/collection.h +++ b/src/analysis/db/collection.h @@ -84,14 +84,12 @@ bool g_db_collection_send_all_updates(GDbCollection *, int); /* Met à disposition un encadrement des accès aux éléments. */ void g_db_collection_lock_unlock(GDbCollection *, bool, bool); - #define g_db_collection_wlock(col) g_db_collection_lock_unlock(col, true, true); #define g_db_collection_wunlock(col) g_db_collection_lock_unlock(col, true, false); #define g_db_collection_rlock(col) g_db_collection_lock_unlock(col, false, true); #define g_db_collection_runlock(col) g_db_collection_lock_unlock(col, false, false); - /* Renvoie la liste des éléments rassemblés. */ GList *g_db_collection_list_items(const GDbCollection *); @@ -104,11 +102,17 @@ bool g_db_collection_has_item(GDbCollection *, GDbItem *); /* Procède à l'ajout d'un nouvel élément dans la collection. */ bool _g_db_collection_add_item(GDbCollection *, GDbItem *, bool); -/* Procède à la modification d'un élément dans la collection. */ -bool _g_db_collection_modify_item(GDbCollection *, GDbItem *, bool); +/* Met à jour le statut d'activité d'un élément de collection. */ +bool _g_db_collection_update_item_activity(GDbCollection *, GDbItem *, bool); #define g_db_collection_add_item(c, i) _g_db_collection_add_item(c, i, true) -#define g_db_collection_modify_item(c, i) _g_db_collection_modify_item(c, i, true) +#define g_db_collection_update_item_activity(c, i) _g_db_collection_update_item_activity(c, i, true) + +/* Active les éléments en amont d'un horodatage donné. */ +GList *g_db_collection_set_last_active(GDbCollection *, timestamp_t, timestamp_t *, sqlite3 *); + +/* Désactive les éléments en aval d'un horodatage donné. */ +bool g_db_collection_set_inactive(GDbCollection *, GDbItem *, timestamp_t *); @@ -132,6 +136,18 @@ void attach_binary_to_collections(GList *, GLoadedBinary *); /* Recherche une collection correspondant à un type donné. */ GDbCollection *find_collection_in_list(GList *, uint32_t); +/* Met à disposition un encadrement des accès aux éléments. */ +void lock_unlock_collections(GList *, bool, bool); + +#define wlock_collections(lst) lock_unlock_collections(lst, true, true); +#define wunlock_collections(lst) lock_unlock_collections(lst, true, false); + +#define rlock_collections(lst) lock_unlock_collections(lst, false, true); +#define runlock_collections(lst) lock_unlock_collections(lst, false, false); + +/* Met à jour les statuts d'activité des éléments. */ +bool update_activity_in_collections(GList *, int, sqlite3 *); + #endif /* _ANALYSIS_DB_COLLECTION_H */ diff --git a/src/analysis/db/core.c b/src/analysis/db/core.c deleted file mode 100644 index 81ea117..0000000 --- a/src/analysis/db/core.c +++ /dev/null @@ -1,207 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * core.c - prototypes pour les informations de base pour tout élément ajouté - * - * 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 <http://www.gnu.org/licenses/>. - */ - - -#include "core.h" - - -#include <endian.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> - - -#include "../../common/io.h" - - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Détermine une fois pour toute la désignation de l'usager. * -* * -* Retour : Nom statique déterminé. * -* * -* Remarques : - * -* * -******************************************************************************/ - -const char *get_local_author_name(void) -{ - static char result[MAX_DB_AUTHOR_LEN]; /* Désignation à retourner */ - char *chrysalide_user; /* Eventuel nom spécifique */ - char *logname; /* Nom depuis l'environnement */ - char hostname[HOST_NAME_MAX]; /* Nom de la machine courante */ - int ret; /* Bilan d'un appel */ - - if (result[0] == '\0') - { - chrysalide_user = getenv("CHRYSALIDE_USER"); - - if (chrysalide_user != NULL) - { - strncpy(result, chrysalide_user, MAX_DB_AUTHOR_LEN - 1); - result[MAX_DB_AUTHOR_LEN - 1] = '\0'; - } - else - { - logname = getenv("LOGNAME"); - if (logname == NULL) - logname = ""; - - ret = gethostname(hostname, HOST_NAME_MAX); - if (ret != 0) - hostname[0] = '\0'; - - if (logname != NULL && hostname[0] != '\0') - snprintf(result, MAX_DB_AUTHOR_LEN, "%s@%s", logname, hostname); - - else if (logname != NULL && hostname[0] == '\0') - snprintf(result, MAX_DB_AUTHOR_LEN, "%s", logname); - - else if (logname == NULL && hostname[0] != '\0') - snprintf(result, MAX_DB_AUTHOR_LEN, "@%s", hostname); - - else - snprintf(result, MAX_DB_AUTHOR_LEN, "anonymous"); - - } - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : info = informations à constituer. [OUT] * -* type = type de l'élément à mettre en place. * -* user = provenance des informations ou NULL si machine. * -* * -* Description : Initialise le coeur des informations d'un élément ajouté. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void init_core_db_info(core_db_info *info, uint64_t type, const char *user) -{ - info->type = type; - - strncpy(info->user, user, MAX_DB_AUTHOR_LEN - 1); - info->user[MAX_DB_AUTHOR_LEN - 1] = '\0'; - - info->created = time(NULL); - info->modified = info->created; - - info->saved = 0; - -} - - -/****************************************************************************** -* * -* Paramètres : info = informations à constituer. [OUT] * -* type = type de l'élément, lu en avance de phase. * -* fd = flux ouvert en lecture pour l'importation. * -* * -* Description : Importe le coeur des informations d'un élément ajouté. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool load_core_db_info(core_db_info *info, uint64_t type, int fd) -{ -#if 0 - ssize_t got; /* Quantité de données reçues */ - uint64_t val64; /* Valeur sur 64 bits */ - - info->type = type; - - got = safe_recv(fd, info->user, MAX_DB_AUTHOR_LEN, MSG_WAITALL); - if (got != MAX_DB_AUTHOR_LEN) return false; - - info->user[MAX_DB_AUTHOR_LEN - 1] = '\0'; - - got = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL); - if (got != sizeof(uint64_t)) return false; - - info->created = be64toh(val64); - - got = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL); - if (got != sizeof(uint64_t)) return false; - - info->modified = be64toh(val64); - - info->saved = info->modified; -#endif - return true; - -} - - -/****************************************************************************** -* * -* Paramètres : info = informations à sauvegarer. * -* fd = flux ouvert en écriture pour l'exportation. * -* * -* Description : Exporte le coeur des informations d'un élément ajouté. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool store_core_db_info(core_db_info *info, int fd) -{ -#if 0 - ssize_t got; /* Quantité de données reçues */ - - got = safe_send(fd, (uint64_t []) { htobe64(info->type) }, sizeof(uint64_t), MSG_WAITALL); - if (got != sizeof(uint64_t)) return false; - - got = safe_send(fd, info->user, MAX_DB_AUTHOR_LEN, MSG_WAITALL); - if (got != MAX_DB_AUTHOR_LEN) return false; - - got = safe_send(fd, (uint64_t []) { htobe64(info->created) }, sizeof(uint64_t), MSG_WAITALL); - if (got != sizeof(uint64_t)) return false; - - got = safe_send(fd, (uint64_t []) { htobe64(info->modified) }, sizeof(uint64_t), MSG_WAITALL); - if (got != sizeof(uint64_t)) return false; - - info->saved = time(NULL); -#endif - return true; - -} diff --git a/src/analysis/db/core.h b/src/analysis/db/core.h deleted file mode 100644 index b53b250..0000000 --- a/src/analysis/db/core.h +++ /dev/null @@ -1,70 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * core.h - prototypes pour les informations de base pour tout élément ajouté - * - * 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 <http://www.gnu.org/licenses/>. - */ - - -#ifndef _ANALYSIS_DB_CORE_H -#define _ANALYSIS_DB_CORE_H - - -#include <inttypes.h> -#include <stdbool.h> - - - -/** - * Taille maximale pour un nom d'auteur. - * On considère comme exemple large '"Nom Prénom" xxx@yyy.tld' - */ -#define MAX_DB_AUTHOR_LEN 128 - - -/* Informations de base pour tout élément ajouté */ -typedef struct _core_db_info -{ - uint64_t type; /* Type de l'élément */ - char hash[65]; /* Empreinte SHA256 */ - - char user[MAX_DB_AUTHOR_LEN]; /* Auteur humain ou NULL */ - - uint64_t created; /* Date de création */ - uint64_t modified; /* Date de modification */ - - uint64_t saved; /* Statut de l'élément */ - -} core_db_info; - - -/* Détermine une fois pour toute la désignation de l'usager. */ -const char *get_local_author_name(void); - -/* Initialise le coeur des informations d'un élément ajouté. */ -void init_core_db_info(core_db_info *, uint64_t, const char *); - -/* Importe le coeur des informations d'un élément ajouté. */ -bool load_core_db_info(core_db_info *, uint64_t, int); - -/* Exporte le coeur des informations d'un élément ajouté. */ -bool store_core_db_info(core_db_info *, int); - - - -#endif /* _ANALYSIS_DB_CORE_H */ diff --git a/src/analysis/db/item-int.h b/src/analysis/db/item-int.h index 12c69f3..1af1048 100644 --- a/src/analysis/db/item-int.h +++ b/src/analysis/db/item-int.h @@ -36,12 +36,18 @@ +/* Effectue la comparaison entre deux éléments de collection. */ +typedef gint (* cmp_db_item_fc) (GDbItem *, GDbItem *, bool); + /* 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); +/* Construit la description humaine d'un signet sur un tampon. */ +typedef void (* build_item_label_fc) (GDbItem *); + /* Exécute un élément de collection sur un binaire. */ typedef bool (* run_item_fc) (GDbItem *, GLoadedBinary *); @@ -57,13 +63,15 @@ struct _GDbItem { GObject parent; /* A laisser en premier */ - uint64_t created; /* Date de création */ - uint64_t modified; /* Date de modification */ + bool server_side; /* Instance côté serveur */ + + timestamp_t created; /* Date de création */ + timestamp_t timestamp; /* Date dernière activité */ rle_string author; /* Utilisateur d'origine */ rle_string tool; /* Eventuel outil automatique ?*/ - rle_string label; /* Représentation humaine */ + char *label; /* Représentation humaine */ bool is_volatile; /* Pas besoin de sauvegarde ? */ @@ -78,10 +86,12 @@ struct _GDbItemClass { GObjectClass parent; /* A laisser en premier */ - GCompareFunc cmp; /* Comparaison entre éléments */ + cmp_db_item_fc cmp; /* Comparaison entre éléments */ recv_db_item_fc recv; /* Réception depuis le réseau */ send_db_item_fc send; /* Emission depuis le réseau */ + + build_item_label_fc build_label; /* Construction de description */ run_item_fc apply; /* Application de l'élément */ run_item_fc cancel; /* Retrait de l'élément */ @@ -93,8 +103,8 @@ struct _GDbItemClass /* Définition du tronc commun pour les créations SQLite */ #define SQLITE_DB_ITEM_CREATE \ - "created INTEGER, " \ - "modified INTEGER, " \ + SQLITE_TIMESTAMP_CREATE("created") ", " \ + SQLITE_TIMESTAMP_CREATE("timestamp") ", " \ SQLITE_RLESTR_CREATE("author") ", " \ SQLITE_RLESTR_CREATE("tool") ", " \ SQLITE_RLESTR_CREATE("label") diff --git a/src/analysis/db/item.c b/src/analysis/db/item.c index d2f87c3..5463e85 100644 --- a/src/analysis/db/item.c +++ b/src/analysis/db/item.c @@ -26,6 +26,7 @@ #include <assert.h> #include <malloc.h> +#include <string.h> #include <sqlite3.h> @@ -47,9 +48,6 @@ static void g_db_item_dispose(GDbItem *); /* Procède à la libération totale de la mémoire. */ static void g_db_item_finalize(GDbItem *); -/* Effectue la comparaison entre deux éléments de collection. */ -static gint g_db_item_cmp(GDbItem *, GDbItem *); - /* Importe la définition d'une base d'éléments pour collection. */ static bool g_db_item_recv_from_fd(GDbItem *, int, int); @@ -94,7 +92,7 @@ static void g_db_item_class_init(GDbItemClass *klass) object->dispose = (GObjectFinalizeFunc/* ! */)g_db_item_dispose; object->finalize = (GObjectFinalizeFunc)g_db_item_finalize; - klass->cmp = (GCompareFunc)g_db_item_cmp; + klass->cmp = (cmp_db_item_fc)g_db_item_cmp; klass->recv = (recv_db_item_fc)g_db_item_recv_from_fd; klass->send = (send_db_item_fc)g_db_item_send_to_fd; @@ -165,6 +163,12 @@ static void g_db_item_dispose(GDbItem *item) static void g_db_item_finalize(GDbItem *item) { + exit_rle_string(&item->author); + exit_rle_string(&item->tool); + + if (item->label != NULL) + free(item->label); + G_OBJECT_CLASS(g_db_item_parent_class)->finalize(G_OBJECT(item)); } @@ -172,8 +176,31 @@ static void g_db_item_finalize(GDbItem *item) /****************************************************************************** * * -* Paramètres : a = premier élément à analyser. * -* b = second élément à analyser. * +* Paramètres : item = élément de collection à traiter. * +* * +* Description : Indique à l'élément qu'il se trouve du côté serveur. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_db_item_set_server_side(GDbItem *item) +{ + init_timestamp(&item->created); + item->timestamp = item->created; + + item->server_side = true; + +} + + +/****************************************************************************** +* * +* Paramètres : a = premier élément à analyser. * +* b = second élément à analyser. * +* with = précise les horodatages à prendre en compte. * * * * Description : Effectue la comparaison entre deux éléments de collection. * * * @@ -183,35 +210,42 @@ static void g_db_item_finalize(GDbItem *item) * * ******************************************************************************/ -static gint g_db_item_cmp(GDbItem *a, GDbItem *b) +gint g_db_item_cmp(GDbItem *a, GDbItem *b, bool with) { gint result; /* Bilan à retourner */ - /** - * A n'utiliser qu'en dernier recours, pour départager deux - * éléments par un serveur NTP... - */ + if (with) + result = cmp_timestamp(&a->timestamp, &b->timestamp); + else + result = 0; - if (a->modified > b->modified) - result = 1; + if (result == 0) + result = cmp_timestamp(&a->created, &b->created); - else if (a->modified < b->modified) - result = -1; + if (result == 0) + result = strcmp(a->label, b->label); - else - { - if (a->created > b->created) - result = 1; + return result; - else if (a->created < b->created) - result = -1; +} - else - result = cmp_rle_string(&a->label, &b->label); - } +/****************************************************************************** +* * +* Paramètres : a = premier élément à analyser. * +* b = second élément à analyser. * +* * +* Description : Effectue la comparaison entre deux éléments de collection. * +* * +* Retour : Bilan de la comparaison : -1, 0 ou 1. * +* * +* Remarques : - * +* * +******************************************************************************/ - return result; +gint g_db_item_compare_with_timestamp(GDbItem *a, GDbItem *b) +{ + return G_DB_ITEM_GET_CLASS(a)->cmp(a, b, true); } @@ -229,18 +263,18 @@ static gint g_db_item_cmp(GDbItem *a, GDbItem *b) * * ******************************************************************************/ -gint g_db_item_compare(GDbItem *a, GDbItem *b) +gint g_db_item_compare_without_timestamp(GDbItem *a, GDbItem *b) { - return G_DB_ITEM_GET_CLASS(a)->cmp(a, b); + return G_DB_ITEM_GET_CLASS(a)->cmp(a, b, false); } /****************************************************************************** * * -* Paramètres : item = base d'éléments à charger. [OUT] * -* fd = flux ouvert en lecture pour l'importation. * -* flags = éventuelles options d'envoi supplémentaires. * +* Paramètres : item = base d'éléments à charger. [OUT] * +* fd = flux ouvert en lecture pour l'importation. * +* flags = éventuelles options d'envoi supplémentaires. * * * * Description : Importe la définition d'une base d'éléments pour collection. * * * @@ -252,18 +286,17 @@ gint g_db_item_compare(GDbItem *a, GDbItem *b) static bool g_db_item_recv_from_fd(GDbItem *item, int fd, int flags) { - uint64_t val64; /* Valeur sur 64 bits */ bool status; /* Bilan d'une réception */ - status = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL | flags); - if (!status) return false; - - item->created = be64toh(val64); + if (!item->server_side) + { + status = recv_timestamp(&item->created, fd, flags); + if (!status) return false; - status = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL | flags); - if (!status) return false; + status = recv_timestamp(&item->timestamp, fd, flags); + if (!status) return false; - item->modified = be64toh(val64); + } status = recv_rle_string(&item->author, fd, flags); if (!status) return false; @@ -271,9 +304,6 @@ static bool g_db_item_recv_from_fd(GDbItem *item, int fd, int flags) status = recv_rle_string(&item->tool, fd, flags); if (!status) return false; - status = recv_rle_string(&item->label, fd, flags); - if (!status) return false; - return true; } @@ -295,7 +325,13 @@ static bool g_db_item_recv_from_fd(GDbItem *item, int fd, int flags) bool g_db_item_recv(GDbItem *item, int fd, int flags) { - return G_DB_ITEM_GET_CLASS(item)->recv(item, fd, flags); + bool result; /* Bilan à retourner */ + + result = G_DB_ITEM_GET_CLASS(item)->recv(item, fd, flags); + + G_DB_ITEM_GET_CLASS(item)->build_label(item); + + return result; } @@ -318,19 +354,20 @@ static bool g_db_item_send_to_fd(const GDbItem *item, int fd, int flags) { bool status; /* Bilan d'une émission */ - status = safe_send(fd, (uint64_t []) { htobe64(item->created) }, sizeof(uint64_t), MSG_MORE | flags); - if (!status) return false; + if (item->server_side) + { + status = send_timestamp(&item->created, fd, MSG_MORE | flags); + if (!status) return false; - status = safe_send(fd, (uint64_t []) { htobe64(item->modified) }, sizeof(uint64_t), MSG_MORE | flags); - if (!status) return false; + status = send_timestamp(&item->timestamp, fd, MSG_MORE | flags); + if (!status) return false; - status = send_rle_string(&item->author, fd, MSG_MORE | flags); - if (!status) return false; + } - status = send_rle_string(&item->tool, fd, MSG_MORE | flags); + status = send_rle_string(&item->author, fd, MSG_MORE | flags); if (!status) return false; - status = send_rle_string(&item->label, fd, flags); + status = send_rle_string(&item->tool, fd, flags); if (!status) return false; return true; @@ -417,6 +454,86 @@ bool g_db_item_cancel(GDbItem *item, GLoadedBinary *binary) /****************************************************************************** * * +* Paramètres : item = élément de collection à consulter. * +* * +* Description : Décrit l'élément de collection en place. * +* * +* Retour : Chaîne de caractère correspondante. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_db_item_get_label(const GDbItem *item) +{ + return item->label; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément de collection à consulter. * +* * +* Description : Fournit l'horodatage associé à l'élément de collection. * +* * +* Retour : Date d'activité de l'élément. * +* * +* Remarques : - * +* * +******************************************************************************/ + +timestamp_t g_db_item_get_timestamp(const GDbItem *item) +{ + return item->timestamp; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément de collection à mettre à jour. * +* first = horodatage du premier élément désactivé ou NULL. * +* * +* Description : Active ou désactive un élément de collection en place. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_db_item_set_activity(GDbItem *item, timestamp_t *first) +{ + if (first == NULL) + item->timestamp = item->created; + else + item->timestamp = --(*first); + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément de collection à consulter. * +* * +* Description : Indique si l'élément est activé ou désactivé. * +* * +* Retour : Etat de l'activité de l'élément. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_db_item_is_active(const GDbItem *item) +{ + return (cmp_timestamp(&item->created, &item->timestamp) == 0); + +} + + +/****************************************************************************** +* * * Paramètres : item = base d'éléments à modifier. * * is_volatile = état du besoin en sauvegarde. * * * @@ -477,31 +594,17 @@ bool g_db_item_is_volatile(const GDbItem *item) static bool _g_db_item_prepare_db_statement(const GDbItem *item, bound_value **values, size_t *count) { bool result; /* Bilan à retourner */ - bound_value *value; /* Valeur à éditer / définir */ result = true; - *count += 2; - *values = (bound_value *)realloc(*values, *count * sizeof(bound_value)); - - value = &(*values)[*count - 2]; - - value->name = "created"; - value->type = SQLITE_INT64; - value->integer64 = item->created; + result &= prepare_db_statement_for_timestamp(&item->created, "created", values, count); - value = &(*values)[*count - 1]; - - value->name = "modified"; - value->type = SQLITE_INT64; - value->integer64 = item->modified; + result &= prepare_db_statement_for_timestamp(&item->timestamp, "timestamp", values, count); result &= prepare_db_statement_for_rle_string(&item->author, "author", values, count); result &= prepare_db_statement_for_rle_string(&item->tool, "tool", values, count); - result &= prepare_db_statement_for_rle_string(&item->label, "label", values, count); - return result; } @@ -548,28 +651,17 @@ bool g_db_item_prepare_db_statement(const GDbItem *item, bound_value **values, s static bool _g_db_item_load(GDbItem *item, const bound_value *values, size_t count) { bool result; /* Bilan global à retourner */ - const bound_value *value; /* Valeur à éditer / définir */ - - value = find_bound_value(values, count, "created"); - if (value == NULL) return false; - if (value->type != SQLITE_INT64) return false; - - item->created = value->integer64; - value = find_bound_value(values, count, "modified"); - if (value == NULL) return false; - if (value->type != SQLITE_INT64) return false; + result = true; - item->modified = value->integer64; + result &= load_timestamp(&item->created, "created", values, count); - result = true; + result &= load_timestamp(&item->timestamp, "timestamp", values, count); result &= load_rle_string(&item->author, "author", values, count); result &= load_rle_string(&item->tool, "tool", values, count); - result &= load_rle_string(&item->label, "label", values, count); - return result; } @@ -591,6 +683,12 @@ static bool _g_db_item_load(GDbItem *item, const bound_value *values, size_t cou bool g_db_item_load(GDbItem *item, const bound_value *values, size_t count) { - return G_DB_ITEM_GET_CLASS(item)->load(item, values, count); + bool result; /* Bilan à retourner */ + + result = G_DB_ITEM_GET_CLASS(item)->load(item, values, count); + + G_DB_ITEM_GET_CLASS(item)->build_label(item); + + return result; } diff --git a/src/analysis/db/item.h b/src/analysis/db/item.h index 09ac45c..7d3392c 100644 --- a/src/analysis/db/item.h +++ b/src/analysis/db/item.h @@ -29,6 +29,7 @@ #include <stdbool.h> +#include "misc/timestamp.h" #include "../../common/sqlite.h" @@ -55,8 +56,17 @@ typedef struct _GDbItemClass GDbItemClass; /* Indique le type défini pour une base d'élément de collection générique. */ GType g_db_item_get_type(void); +/* Indique à l'élément qu'il se trouve du côté serveur. */ +void g_db_item_set_server_side(GDbItem *); + +/* Effectue la comparaison entre deux éléments de collection. */ +gint g_db_item_cmp(GDbItem *, GDbItem *, bool); + +/* Effectue la comparaison entre deux éléments de collection. */ +gint g_db_item_compare_with_timestamp(GDbItem *, GDbItem *); + /* Effectue la comparaison entre deux éléments de collection. */ -gint g_db_item_compare(GDbItem *, GDbItem *); +gint g_db_item_compare_without_timestamp(GDbItem *, GDbItem *); /* Importe la définition d'une base d'éléments pour collection. */ bool g_db_item_recv(GDbItem *, int, int); @@ -70,6 +80,18 @@ bool g_db_item_apply(GDbItem *, GLoadedBinary *); /* Annule une bascule d'affichage d'opérande sur un binaire. */ bool g_db_item_cancel(GDbItem *, GLoadedBinary *); +/* Décrit l'élément de collection en place. */ +const char *g_db_item_get_label(const GDbItem *); + +/* Fournit l'horodatage associé à l'élément de collection. */ +timestamp_t g_db_item_get_timestamp(const GDbItem *); + +/* Active ou désactive un élément de collection en place. */ +void g_db_item_set_activity(GDbItem *, timestamp_t *); + +/* Indique si l'élément est activé ou désactivé. */ +bool g_db_item_is_active(const GDbItem *); + /* Définit si l'élément contient des données à oublier ou non. */ void g_db_item_set_volatile(GDbItem *, bool); diff --git a/src/analysis/db/items/bookmark.c b/src/analysis/db/items/bookmark.c index 8512406..ba64491 100644 --- a/src/analysis/db/items/bookmark.c +++ b/src/analysis/db/items/bookmark.c @@ -28,6 +28,9 @@ #include <sys/socket.h> +#include <i18n.h> + + #include "../collection-int.h" #include "../item-int.h" @@ -69,7 +72,7 @@ static void g_db_bookmark_dispose(GDbBookmark *); static void g_db_bookmark_finalize(GDbBookmark *); /* Effectue la comparaison entre deux signets de collection. */ -static gint g_db_bookmark_cmp(GDbBookmark *, GDbBookmark *); +static gint g_db_bookmark_cmp(GDbBookmark *, GDbBookmark *, bool); /* Importe la définition d'un signet dans un flux réseau. */ static bool g_db_bookmark_recv_from_fd(GDbBookmark *, int, int); @@ -80,6 +83,9 @@ static bool g_db_bookmark_send_to_fd(const GDbBookmark *, int, int); /* Exécute un signet sur un tampon de binaire chargé. */ static bool g_db_bookmark_run(GDbBookmark *, GLoadedBinary *, bool *, bool); +/* Construit la description humaine d'un signet sur un tampon. */ +static void g_db_bookmark_build_label(GDbBookmark *); + /* Applique un signet sur un tampon de binaire chargé. */ static bool g_db_bookmark_apply(GDbBookmark *, GLoadedBinary *); @@ -168,10 +174,12 @@ static void g_db_bookmark_class_init(GDbBookmarkClass *klass) item = G_DB_ITEM_CLASS(klass); - item->cmp = (GCompareFunc)g_db_bookmark_cmp; + item->cmp = (cmp_db_item_fc)g_db_bookmark_cmp; 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->build_label = (build_item_label_fc)g_db_bookmark_build_label; item->apply = (run_item_fc)g_db_bookmark_apply; item->cancel = (run_item_fc)g_db_bookmark_cancel; @@ -269,8 +277,9 @@ GDbBookmark *g_db_bookmark_new(const vmpa2t *addr, const char *comment) /****************************************************************************** * * -* Paramètres : a = premier élément à analyser. * -* b = second élément à analyser. * +* Paramètres : a = premier élément à analyser. * +* b = second élément à analyser. * +* with = précise les horodatages à prendre en compte. * * * * Description : Effectue la comparaison entre deux signets de collection. * * * @@ -280,7 +289,7 @@ GDbBookmark *g_db_bookmark_new(const vmpa2t *addr, const char *comment) * * ******************************************************************************/ -static gint g_db_bookmark_cmp(GDbBookmark *a, GDbBookmark *b) +static gint g_db_bookmark_cmp(GDbBookmark *a, GDbBookmark *b, bool with) { gint result; /* Bilan de la comparaison */ @@ -290,7 +299,7 @@ static gint g_db_bookmark_cmp(GDbBookmark *a, GDbBookmark *b) result = cmp_rle_string(&a->comment, &b->comment); if (result == 0) - result = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b)); + result = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b), with); return result; @@ -413,6 +422,25 @@ static bool g_db_bookmark_run(GDbBookmark *bookmark, GLoadedBinary *binary, bool /****************************************************************************** * * * Paramètres : bookmark = signet à manipuler. * +* * +* Description : Construit la description humaine d'un signet sur un tampon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_db_bookmark_build_label(GDbBookmark *bookmark) +{ + asprintf(&G_DB_ITEM(bookmark)->label, _("Bookmark \"%s\""), get_rle_string(&bookmark->comment)); + +} + + +/****************************************************************************** +* * +* Paramètres : bookmark = signet à manipuler. * * binary = binaire chargé en mémoire à modifier. * * * * Description : Applique un signet sur un tampon de binaire chargé. * diff --git a/src/analysis/db/items/comment.c b/src/analysis/db/items/comment.c index 1bed0ab..249620b 100644 --- a/src/analysis/db/items/comment.c +++ b/src/analysis/db/items/comment.c @@ -67,7 +67,7 @@ static void g_db_comment_dispose(GDbComment *); static void g_db_comment_finalize(GDbComment *); /* Effectue la comparaison entre deux commentaires enregistrés. */ -static gint g_db_comment_cmp(GDbComment *, GDbComment *); +static gint g_db_comment_cmp(GDbComment *, GDbComment *, bool); /* Importe la définition d'un commentaire dans un flux réseau. */ static bool g_db_comment_recv_from_fd(GDbComment *, int, int); @@ -157,7 +157,7 @@ static void g_db_comment_class_init(GDbCommentClass *klass) item = G_DB_ITEM_CLASS(klass); - item->cmp = (GCompareFunc)g_db_comment_cmp; + item->cmp = (cmp_db_item_fc)g_db_comment_cmp; item->recv = (recv_db_item_fc)g_db_comment_recv_from_fd; item->send = (send_db_item_fc)g_db_comment_send_to_fd; @@ -259,8 +259,9 @@ GDbComment *g_db_comment_new(const vmpa2t *addr, const char *text, bool is_volat /****************************************************************************** * * -* Paramètres : a = premier élément à analyser. * -* b = second élément à analyser. * +* Paramètres : a = premier élément à analyser. * +* b = second élément à analyser. * +* with = précise les horodatages à prendre en compte. * * * * Description : Effectue la comparaison entre deux commentaires enregistrés. * * * @@ -270,7 +271,7 @@ GDbComment *g_db_comment_new(const vmpa2t *addr, const char *text, bool is_volat * * ******************************************************************************/ -static gint g_db_comment_cmp(GDbComment *a, GDbComment *b) +static gint g_db_comment_cmp(GDbComment *a, GDbComment *b, bool with) { gint result; /* Bilan de la comparaison */ @@ -280,7 +281,7 @@ static gint g_db_comment_cmp(GDbComment *a, GDbComment *b) result = cmp_rle_string(&a->text, &b->text); if (result == 0) - result = G_DB_ITEM_CLASS(g_db_comment_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b)); + result = G_DB_ITEM_CLASS(g_db_comment_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b), with); return 0; diff --git a/src/analysis/db/items/switcher.c b/src/analysis/db/items/switcher.c index 2168e6b..67187aa 100644 --- a/src/analysis/db/items/switcher.c +++ b/src/analysis/db/items/switcher.c @@ -75,7 +75,7 @@ static void g_db_switcher_dispose(GDbSwitcher *); static void g_db_switcher_finalize(GDbSwitcher *); /* Effectue la comparaison entre deux signets de collection. */ -static gint g_db_switcher_cmp(GDbSwitcher *, GDbSwitcher *); +static gint g_db_switcher_cmp(GDbSwitcher *, GDbSwitcher *, bool); /* Importe la définition d'un signet dans un flux réseau. */ static bool g_db_switcher_recv_from_fd(GDbSwitcher *, int, int); @@ -175,10 +175,11 @@ static void g_db_switcher_class_init(GDbSwitcherClass *klass) item = G_DB_ITEM_CLASS(klass); - item->cmp = (GCompareFunc)g_db_switcher_cmp; + item->cmp = (cmp_db_item_fc)g_db_switcher_cmp; item->recv = (recv_db_item_fc)g_db_switcher_recv_from_fd; item->send = (send_db_item_fc)g_db_switcher_send_to_fd; + item->apply = (run_item_fc)g_db_switcher_apply; item->cancel = (run_item_fc)g_db_switcher_cancel; @@ -190,7 +191,7 @@ static void g_db_switcher_class_init(GDbSwitcherClass *klass) /****************************************************************************** * * -* Paramètres : switcher = instance à initialiser. * +* Paramètres : switcher = instance à initialiser. * * * * Description : Initialise une bascule d'affichage pour opérande numérique. * * * @@ -208,7 +209,7 @@ static void g_db_switcher_init(GDbSwitcher *switcher) /****************************************************************************** * * -* Paramètres : switcher = instance d'objet GLib à traiter. * +* Paramètres : switcher = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -227,7 +228,7 @@ static void g_db_switcher_dispose(GDbSwitcher *switcher) /****************************************************************************** * * -* Paramètres : switcher = instance d'objet GLib à traiter. * +* Paramètres : switcher = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -259,7 +260,7 @@ static void g_db_switcher_finalize(GDbSwitcher *switcher) GDbSwitcher *g_db_switcher_new(const GArchInstruction *instr, const GImmOperand *imm, ImmOperandDisplay display) { - GDbSwitcher *result; /* Instance à retourner */ + GDbSwitcher *result; /* Instance à retourner */ size_t count; /* Nombre d'opérandes à visiter*/ size_t i; /* Boucle de parcours */ const mrange_t *range; /* Localisation de l'instruct° */ @@ -299,8 +300,9 @@ GDbSwitcher *g_db_switcher_new(const GArchInstruction *instr, const GImmOperand /****************************************************************************** * * -* Paramètres : a = premier élément à analyser. * -* b = second élément à analyser. * +* Paramètres : a = premier élément à analyser. * +* b = second élément à analyser. * +* with = précise les horodatages à prendre en compte. * * * * Description : Effectue la comparaison entre deux signets de collection. * * * @@ -310,7 +312,7 @@ GDbSwitcher *g_db_switcher_new(const GArchInstruction *instr, const GImmOperand * * ******************************************************************************/ -static gint g_db_switcher_cmp(GDbSwitcher *a, GDbSwitcher *b) +static gint g_db_switcher_cmp(GDbSwitcher *a, GDbSwitcher *b, bool with) { gint result; /* Bilan de la comparaison */ @@ -337,7 +339,7 @@ static gint g_db_switcher_cmp(GDbSwitcher *a, GDbSwitcher *b) } if (result == 0) - result = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b)); + result = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b), with); return result; diff --git a/src/analysis/db/misc/Makefile.am b/src/analysis/db/misc/Makefile.am index b3829e3..dde6026 100755 --- a/src/analysis/db/misc/Makefile.am +++ b/src/analysis/db/misc/Makefile.am @@ -2,7 +2,8 @@ noinst_LTLIBRARIES = libanalysisdbmisc.la libanalysisdbmisc_la_SOURCES = \ - rlestr.h rlestr.c + rlestr.h rlestr.c \ + timestamp.h timestamp.c libanalysisdbmisc_la_LIBADD = diff --git a/src/analysis/db/misc/timestamp.c b/src/analysis/db/misc/timestamp.c new file mode 100644 index 0000000..624c811 --- /dev/null +++ b/src/analysis/db/misc/timestamp.c @@ -0,0 +1,263 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * rlestr.c - encodage par plage unique d'une chaîne de caractères + * + * 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 <http://www.gnu.org/licenses/>. + */ + + +#include "timestamp.h" + + +#include <endian.h> +#include <malloc.h> +#include <sqlite3.h> +#include <time.h> + + +#include "../../../common/io.h" + + + +/****************************************************************************** +* * +* Paramètres : timestamp = horodatage à initialiser. [OUT] * +* * +* Description : Obtient un horodatage initialisé au moment même. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void init_timestamp(timestamp_t *timestamp) +{ + struct timespec info; /* Détails sur l'époque */ + + clock_gettime(CLOCK_REALTIME, &info); + + *timestamp = info.tv_sec * 1000000 + info.tv_nsec / 1000; + +} + + +/****************************************************************************** +* * +* Paramètres : stamp = horodatage d'un élément à tester. * +* limit = horodatage en limite d'activité (incluse). * +* * +* Description : Définit si un horodatage est plus récent qu'un autre ou non. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool timestamp_is_younger(timestamp_t stamp, timestamp_t limit) +{ + if (limit == TIMESTAMP_ALL_ACTIVE) + return true; + + if (limit == TIMESTAMP_ALL_INACTIVE) + return false; + + return (stamp <= limit); + +} + + +/****************************************************************************** +* * +* Paramètres : t1 = première chaîne à comparer. * +* t2 = seconde chaîne à comparer. * +* * +* Description : Effectue la comparaison entre deux horodatages. * +* * +* Retour : Résultat de la comparaison : -1, 0 ou 1. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int cmp_timestamp(const timestamp_t *t1, const timestamp_t *t2) +{ + int result; /* Bilan à retourner */ + + if (*t1 < *t2) + result = -1; + + else if (*t1 > *t2) + result = 1; + + else + result = 0; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : timestamp = informations à constituer. [OUT] * +* fd = flux ouvert en lecture pour l'importation. * +* flags = éventuelles options de réception supplémentaires.* +* * +* Description : Importe la définition d'un horodatage. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool recv_timestamp(timestamp_t *timestamp, int fd, int flags) +{ + uint64_t val64; /* Valeur sur 64 bits */ + bool status; /* Bilan d'une opération */ + + status = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL | flags); + if (!status) return false; + + *timestamp = be64toh(val64); + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : timestamp = informations à sauvegarer. * +* fd = flux ouvert en écriture pour l'exportation. * +* flags = éventuelles options d'envoi supplémentaires. * +* * +* Description : Exporte la définition d'un horodatage. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool send_timestamp(const timestamp_t *timestamp, int fd, int flags) +{ + bool status; /* Bilan d'une opération */ + + status = safe_send(fd, (uint64_t []) { htobe64(*timestamp) }, sizeof(uint64_t), flags); + if (!status) return false; + + return true; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* MANIPULATIONS AVEC UNE BASE DE DONNEES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : timestamp = horodatage aux informations inutiles. * +* name = désignation personnalisée du champ dans la BD. * +* 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_db_statement_for_timestamp(const timestamp_t *timestamp, const char *name, 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 = name; + value->type = SQLITE_INT64; + value->integer64 = *timestamp; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : timestamp = horodatage aux informations inutiles. * +* name = désignation personnalisée du champ dans la BD. * +* values = tableau d'éléments à compléter. [OUT] * +* count = nombre de descriptions renseignées. [OUT] * +* * +* Description : Décrit les colonnes utiles à un horodatage. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool setup_load_of_timestamp(const timestamp_t *timestamp, const char *name, bound_value **values, size_t *count) +{ + *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value)); + + (*values)[*count - 1].name = name; + + return true; + + +} + + +/****************************************************************************** +* * +* Paramètres : timestamp = horodatage à compléter. * +* name = désignation personnalisée du champ dans la BD. * +* values = tableau d'éléments à consulter. * +* count = nombre de descriptions renseignées. * +* * +* Description : Charge les valeurs utiles pour un horodatage. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool load_timestamp(timestamp_t *timestamp, const char *name, const bound_value *values, size_t count) +{ + const bound_value *value; /* Valeur à intégrer */ + + value = find_bound_value(values, count, name); + if (value == NULL) return false; + if (value->type != SQLITE_INT64) return false; + + *timestamp = value->integer64; + + return true; + +} diff --git a/src/analysis/db/misc/timestamp.h b/src/analysis/db/misc/timestamp.h new file mode 100644 index 0000000..1efbb15 --- /dev/null +++ b/src/analysis/db/misc/timestamp.h @@ -0,0 +1,80 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * timestamp.h - prototypes pour l'encodage par plage unique d'une chaîne de caractères + * + * 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_DB_MISC_TIMESTAMP_H +#define _ANALYSIS_DB_MISC_TIMESTAMP_H + + +#include <stdbool.h> +#include <stdint.h> + + +#include "../../../common/sqlite.h" + + + +/* Représentation d'un horodatage */ +typedef uint64_t timestamp_t; + + +/* Valeurs particulières */ +#define TIMESTAMP_ALL_ACTIVE 0 +#define TIMESTAMP_ALL_INACTIVE 1 + + +/* Obtient un horodatage initialisé au moment même. */ +void init_timestamp(timestamp_t *); + +/* Définit si un horodatage est plus récent qu'un autre ou non. */ +bool timestamp_is_younger(timestamp_t, timestamp_t); + +/* Effectue la comparaison entre deux horodatages. */ +int cmp_timestamp(const timestamp_t *, const timestamp_t *); + +/* Importe la définition d'un horodatage. */ +bool recv_timestamp(timestamp_t *, int, int); + +/* Exporte la définition d'un horodatage. */ +bool send_timestamp(const timestamp_t *, int, int); + + + +/* --------------------- MANIPULATIONS AVEC UNE BASE DE DONNEES --------------------- */ + + +/* Définition du tronc commun pour les créations SQLite */ +#define SQLITE_TIMESTAMP_CREATE(n) \ + n " INTEGER" + +/* Constitue les champs destinés à une insertion / modification. */ +bool prepare_db_statement_for_timestamp(const timestamp_t *, const char *, bound_value **, size_t *); + +/* Décrit les colonnes utiles à un horodatage. */ +bool setup_load_of_timestamp(const timestamp_t *, const char *, bound_value **, size_t *); + +/* Charge les valeurs utiles pour un horodatage. */ +bool load_timestamp(timestamp_t *, const char *, const bound_value *, size_t); + + + +#endif /* _ANALYSIS_DB_MISC_TIMESTAMP_H */ diff --git a/src/analysis/db/protocol.h b/src/analysis/db/protocol.h index 04bbd33..ab12654 100644 --- a/src/analysis/db/protocol.h +++ b/src/analysis/db/protocol.h @@ -95,7 +95,8 @@ typedef enum _DBAction { DBA_ADD_ITEM, /* Ajout d'un élément */ DBA_REM_ITEM, /* Suppression d'un élément */ - DBA_MOD_ITEM, /* Modification de l'existant */ + + DBA_CHANGE_STATE, /* Changement d'activité */ DBA_COUNT @@ -116,6 +117,34 @@ typedef enum _DBCommand DBC_SAVE, /* Enregistrement de l'archive */ DBC_COLLECTION, /* Implication d'une collection*/ + + + /** + * Gestion de la commande 'DBC_SET_LAST_ACTIVE'. + * + * Le client connecté envoie un paquet de la forme suivante : + * + * [ Statut d'historique : DBC_SET_LAST_ACTIVE ] + * [ <horodatage du dernier élément actif ] + * + * Le serveur s'exécute et notifie le client d'éventuels changements, + * avec une série de paquets de la forme : + * + * [ Traitement de collection : DBC_COLLECTION ] + * [ Action : DBC_SET_LAST_ACTIVE ] + * [ <élément dont le statut a évolué> ] + * + * Les traitements se réalisent dans : + * - g_db_collection_set_last_active() pour la partie serveur. + * - g_db_client_set_last_active() pour la partie client. + * + */ + + DBC_SET_LAST_ACTIVE, /* Définition du dernier actif */ + + + + DBC_COUNT } DBCommand; @@ -174,6 +203,4 @@ typedef enum _DBError - - #endif /* _ANALYSIS_DB_PROTOCOL_H */ |