summaryrefslogtreecommitdiff
path: root/src/analysis/db
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2015-07-28 21:32:57 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2015-07-28 21:32:57 (GMT)
commit41efd099244b53a0edb40d097b34bf28a05b6367 (patch)
tree90f2419db6584e672b9f190e7e61e589e0345459 /src/analysis/db
parente56a0553f710235d829f36b1edbf3cea00148a98 (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-xsrc/analysis/db/Makefile.am1
-rw-r--r--src/analysis/db/cdb.c22
-rw-r--r--src/analysis/db/cdb.h5
-rw-r--r--src/analysis/db/client.c30
-rw-r--r--src/analysis/db/client.h3
-rw-r--r--src/analysis/db/collection.c429
-rw-r--r--src/analysis/db/collection.h26
-rw-r--r--src/analysis/db/core.c207
-rw-r--r--src/analysis/db/core.h70
-rw-r--r--src/analysis/db/item-int.h22
-rw-r--r--src/analysis/db/item.c260
-rw-r--r--src/analysis/db/item.h24
-rw-r--r--src/analysis/db/items/bookmark.c40
-rw-r--r--src/analysis/db/items/comment.c13
-rw-r--r--src/analysis/db/items/switcher.c22
-rwxr-xr-xsrc/analysis/db/misc/Makefile.am3
-rw-r--r--src/analysis/db/misc/timestamp.c263
-rw-r--r--src/analysis/db/misc/timestamp.h80
-rw-r--r--src/analysis/db/protocol.h33
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(&timestamp);
+ 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(&timestamp, 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(&timestamp, 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 */