diff options
Diffstat (limited to 'src/analysis/storage/storage.c')
| -rw-r--r-- | src/analysis/storage/storage.c | 424 | 
1 files changed, 394 insertions, 30 deletions
| diff --git a/src/analysis/storage/storage.c b/src/analysis/storage/storage.c index 395d26d..c641a52 100644 --- a/src/analysis/storage/storage.c +++ b/src/analysis/storage/storage.c @@ -28,13 +28,21 @@  #include <malloc.h>  #include <string.h>  #include <unistd.h> +#include <stdarg.h>  #include "storage-int.h" +#include "../db/misc/rlestr.h" +#include "../../common/io.h" +#include "../../common/leb128.h"  #include "../../core/logs.h" +#define STORAGE_MAGIC "CSTR" +#define STORAGE_NUMBER "\x00\x01" + +  /* Initialise la classe des conservations d'objets en place. */  static void g_object_storage_class_init(GObjectStorageClass *); @@ -50,6 +58,15 @@ static void g_object_storage_finalize(GObjectStorage *);  /* Retrouve l'encadrement pour un nouveau groupe d'objets. */  static storage_backend_t *g_object_storage_find_backend(GObjectStorage *, const char *); +/* Ajoute le support d'un nouveau groupe d'objets construits. */ +static bool g_object_storage_add_backend(GObjectStorage *, const char *, storage_backend_t **); + +/* Extrait d'un tampon des enregistrements spécifiques. */ +static bool g_object_storage_load_backend(GObjectStorage *, packed_buffer_t *); + +/* Place dans un tampon les données liées à des enregistrements. */ +static bool pack_storage_backend(const storage_backend_t *, packed_buffer_t *); +  /* Indique le type défini pour une conservation d'objets construits. */ @@ -96,7 +113,7 @@ static void g_object_storage_init(GObjectStorage *storage)  {      storage->tpmem = g_type_memory_new(); -    storage->loaded = NULL; +    storage->hash = NULL;      storage->backends = NULL;      storage->count = 0; @@ -121,8 +138,6 @@ static void g_object_storage_dispose(GObjectStorage *storage)  {      g_clear_object(&storage->tpmem); -    g_clear_object(&storage->loaded); -      G_OBJECT_CLASS(g_object_storage_parent_class)->dispose(G_OBJECT(storage));  } @@ -177,6 +192,9 @@ static void g_object_storage_finalize(GObjectStorage *storage)      g_mutex_clear(&storage->mutex); +    if (storage->hash != NULL) +        free(storage->hash); +      G_OBJECT_CLASS(g_object_storage_parent_class)->finalize(G_OBJECT(storage));  } @@ -194,14 +212,131 @@ static void g_object_storage_finalize(GObjectStorage *storage)  *                                                                             *  ******************************************************************************/ -GObjectStorage *g_object_storage_new(GLoadedContent *loaded) +GObjectStorage *g_object_storage_new(const char *hash)  { -    GObjectStorage *result;                    /* Structure à retourner       */ +    GObjectStorage *result;                 /* Structure à retourner       */ + +    result = g_object_new(G_TYPE_OBJECT_STORAGE, NULL); + +    result->hash = strdup(hash); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : pbuf = zone tampon à lire.                                   * +*                                                                             * +*  Description : Charge le support d'une conservation d'objets en place.      * +*                                                                             * +*  Retour      : Gestionnaire de conservations construit ou NULL si erreur.   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GObjectStorage *g_object_storage_load(packed_buffer_t *pbuf) +{ +    GObjectStorage *result;                 /* Structure à retourner       */ +    char header[6];                         /* Entête attendue des données */ +    bool status;                            /* Bilan d'une extraction      */ +    rle_string str;                         /* Chaîne à conserver          */ +    uleb128_t count;                        /* Nombre de groupes à charger */ +    uleb128_t i;                            /* Boucle de parcours          */ + +    result = NULL; + +    status = extract_packed_buffer(pbuf, header, 6, false); +    if (!status) goto quick_exit; + +    if (strncmp(header, STORAGE_MAGIC STORAGE_NUMBER, 6) != 0) +        goto quick_exit; + +    setup_empty_rle_string(&str); + +    status = unpack_rle_string(&str, pbuf); +    if (!status) goto quick_exit; + +    if (get_rle_string(&str) == NULL) +    { +        exit_rle_string(&str); +        goto quick_exit; +    }      result = g_object_new(G_TYPE_OBJECT_STORAGE, NULL); -    result->loaded = loaded; -    g_object_ref(G_OBJECT(loaded)); +    result->hash = strdup(get_rle_string(&str)); + +    exit_rle_string(&str); + +    status = g_type_memory_load_types(result->tpmem, pbuf); +    if (!status) goto exit_while_loading; + +    status = unpack_uleb128(&count, pbuf); + +    for (i = 0; i < count && status; i++) +        status = g_object_storage_load_backend(result, pbuf); + + exit_while_loading: + +    if (!status) +    { +        g_object_unref(G_OBJECT(result)); +        result = NULL; +    } + + quick_exit: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage = gestionnaire de conservations à manipuler.         * +*                pbuf    = zone tampon à remplir. [OUT]                       * +*                                                                             * +*  Description : Sauvegarde le support d'une conservation d'objets en place.  * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_object_storage_store(GObjectStorage *storage, packed_buffer_t *pbuf) +{ +    bool result;                            /* Bilan à retourner           */ +    rle_string str;                         /* Chaîne à conserver          */ +    size_t i;                               /* Boucle de parcours          */ + +    result = extend_packed_buffer(pbuf, STORAGE_MAGIC STORAGE_NUMBER, 6, false); + +    if (result) +    { +        init_static_rle_string(&str, storage->hash); + +        result = pack_rle_string(&str, pbuf); + +        exit_rle_string(&str); + +    } + +    g_mutex_lock(&storage->mutex); + +    if (result) +        result = g_type_memory_store_types(storage->tpmem, pbuf); + +    if (result) +        result = pack_uleb128((uleb128_t []){ storage->count }, pbuf); + +    for (i = 0; i < storage->count && result; i++) +        result = pack_storage_backend(&storage->backends[i], pbuf); + +    g_mutex_unlock(&storage->mutex);      return result; @@ -244,9 +379,9 @@ static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage,  /******************************************************************************  *                                                                             * -*  Paramètres  : storage  = gestionnaire de conservations à compléter.        * -*                name     = désignation d'un nouveau groupe d'objets.         * -*                filename = éventuel nom de fichier à utiliser ou NULL.       * +*  Paramètres  : storage = gestionnaire de conservations à compléter.         * +*                name    = désignation d'un nouveau groupe d'objets.          * +*                backend = support mis en place pour les enregistrements.     *  *                                                                             *  *  Description : Ajoute le support d'un nouveau groupe d'objets construits.   *  *                                                                             * @@ -256,45 +391,116 @@ static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage,  *                                                                             *  ******************************************************************************/ -bool g_object_storage_add_backend(GObjectStorage *storage, const char *name, const char *filename) +static bool g_object_storage_add_backend(GObjectStorage *storage, const char *name, storage_backend_t **backend)  {      bool result;                            /* Bilan à retourner           */ -    GBinContent *content;                   /* Contenu binaire traité      */ -    const gchar *checksum;                  /* Empreinte de ce contenu     */      char *prefix;                           /* Début de nom de fichier     */ -    storage_backend_t backend;              /* Informations à intégrer     */ +    char *filename;                         /* Chemin d'accès aux données  */ +    int fd;                                 /* Descripteur de flux ouvert  */      result = false; -    g_mutex_lock(&storage->mutex); +    *backend = NULL; + +    assert(!g_mutex_trylock(&storage->mutex));      if (g_object_storage_find_backend(storage, name) != NULL)          goto exit;      /* Préparatifs */ -    content = g_loaded_content_get_content(storage->loaded); +    asprintf(&prefix, "%s-%s", storage->hash, name); + +    fd = make_tmp_file(prefix, "cache", &filename); + +    free(prefix); -    checksum = g_binary_content_get_checksum(content); +    if (fd == -1) +        goto exit; -    asprintf(&prefix, "%s-%s", checksum, name); +    /* Inscription en bonne et due forme */ -    g_object_unref(G_OBJECT(content)); +    storage->backends = realloc(storage->backends, ++storage->count * sizeof(storage_backend_t)); -    backend.fd = make_tmp_file(prefix, "cache", &backend.filename); +    *backend = &storage->backends[storage->count - 1]; -    free(prefix); +    (*backend)->name = strdup(name); + +    (*backend)->filename = filename; +    (*backend)->fd = fd; + +    result = true; + + exit: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage = gestionnaire de conservations à compléter.         * +*                pbuf    = zone tampon à lire.                                * +*                                                                             * +*  Description : Extrait d'un tampon des enregistrements spécifiques.         * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool g_object_storage_load_backend(GObjectStorage *storage, packed_buffer_t *pbuf) +{ +    bool result;                            /* Bilan à retourner           */ +    rle_string str;                         /* Chaîne à conserver          */ +    bool status;                            /* Bilan de lecture de contenu */ +    storage_backend_t *backend;             /* Informations à intégrer     */ +    uleb128_t length;                       /* Taille des données à charger*/ +    off_t moved;                            /* Nouvelle position établie   */ + +    result = false; + +    g_mutex_lock(&storage->mutex); + +    /* Récupération du nom et création du support */ + +    setup_empty_rle_string(&str); -    if (backend.fd == -1) +    status = unpack_rle_string(&str, pbuf); +    if (!status) goto exit; + +    if (get_rle_string(&str) == NULL) +    { +        exit_rle_string(&str);          goto exit; +    } -    /* Inscription en bonne et due forme */ +    status = g_object_storage_add_backend(storage, get_rle_string(&str), &backend); -    backend.name = strdup(name); +    exit_rle_string(&str); -    storage->backends = realloc(storage->backends, ++storage->count * sizeof(storage_backend_t)); +    if (!status) goto exit; + +    /* Récupération du contenu */ + +    status = unpack_uleb128(&length, pbuf); +    if (!status) goto exit; -    storage->backends[storage->count - 1] = backend; +    status = safe_write(backend->fd, pbuf->data + pbuf->pos, length); +    if (!status) goto exit; + +    advance_packed_buffer(pbuf, length); + +    moved = lseek(backend->fd, 0, SEEK_SET); +    if (moved == ((off_t)-1)) +    { +        LOG_ERROR_N("lseek"); +        goto exit; +    } + +    result = true;   exit: @@ -307,6 +513,93 @@ bool g_object_storage_add_backend(GObjectStorage *storage, const char *name, con  /******************************************************************************  *                                                                             * +*  Paramètres  : backend = stockage des enregistrements spécifiques.          * +*                pbuf    = zone tampon à remplir. [OUT]                       * +*                                                                             * +*  Description : Place dans un tampon les données liées à des enregistrements.* +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool pack_storage_backend(const storage_backend_t *backend, packed_buffer_t *pbuf) +{ +    bool result;                            /* Bilan à retourner           */ +    rle_string str;                         /* Chaîne à conserver          */ +    bool status;                            /* Bilan de lecture de contenu */ +    off_t current;                          /* Position courante           */ +    off_t moved;                            /* Nouvelle position établie   */ +    void *data;                             /* Données à transférer        */ + +    result = false; + +    /* Inscription du nom */ + +    init_static_rle_string(&str, backend->name); + +    status = pack_rle_string(&str, pbuf); + +    exit_rle_string(&str); + +    if (!status) goto exit; + +    /* Inscription du contenu */ + +    current = lseek(backend->fd, 0, SEEK_CUR); +    if (current == ((off_t)-1)) +    { +        LOG_ERROR_N("lseek"); +        goto exit; +    } + +    moved = lseek(backend->fd, 0, SEEK_SET); +    if (moved == ((off_t)-1)) +    { +        LOG_ERROR_N("lseek"); +        goto exit; +    } + +    data = malloc(current); +    if (data == NULL) +    { +        LOG_ERROR_N("malloc"); +        goto restore; +    } + +    status = safe_read(backend->fd, data, current); +    if (!status) goto free_mem; + +    status = pack_uleb128((uleb128_t []){ current }, pbuf); +    if (!status) goto free_mem; + +    status = extend_packed_buffer(pbuf, data, current, false); + + free_mem: + +    free(data); + + restore: + +    moved = lseek(backend->fd, current, SEEK_SET); +    if (moved == ((off_t)-1)) +    { +        LOG_ERROR_N("lseek"); +        goto exit; +    } + +    result = status; + + exit: + +    return result; + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : storage = gestionnaire à manipuler.                          *  *                name    = désignation d'un nouveau groupe d'objets.          *  *                pos     = tête de lecture avant écriture.                    * @@ -343,7 +636,7 @@ GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const          if (new == pos)          { -            reset_packed_buffer(&pbuf); +            init_packed_buffer(&pbuf);              status = read_packed_buffer(&pbuf, backend->fd);          } @@ -410,6 +703,67 @@ GSerializableObject *g_object_storage_unpack_object(GObjectStorage *storage, con  /******************************************************************************  *                                                                             * +*  Paramètres  : storage  = gestionnaire à manipuler.                         * +*                name     = désignation d'un nouveau groupe d'objets.         * +*                pbuf     = zone tampon à parcourir.                          * +*                expected = type d'objet attendu.                             * +*                ...      = élément restauré ou NULL en cas d'échec. [OUT]    * +*                                                                             * +*  Description : Charge un objet interne à partir de données rassemblées.     * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_object_storage_unpack_object_2(GObjectStorage *storage, const char *name, packed_buffer_t *pbuf, GType expected, ...) +{ +    bool result;                            /* Bilan d'une opération       */ +    uint64_t pos;                           /* Localisation des données    */ +    GSerializableObject *instance;          /* Objet rechargé à valider    */ +    va_list ap;                             /* Liste d'arguments variables */ +    void **object;                          /* Lieu d'enregistrement final */ + +    result = extract_packed_buffer(pbuf, &pos, sizeof(uint64_t), true); + +    if (result) +    { +        if (pos == 0) +            *object = NULL; + +        else +        { +            instance = g_object_storage_load_object(storage, name, pos); + +            result = G_TYPE_CHECK_INSTANCE_TYPE(instance, expected); + +            if (result) +            { +                va_start(ap, expected); + +                object = va_arg(ap, void **); + +                *object = instance; + +                va_end(ap); + +            } + +            else +                g_clear_object(&instance); + +        } + +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : storage = gestionnaire à manipuler.                          *  *                name    = désignation d'un nouveau groupe d'objets.          *  *                object  = objet sérialisable à traiter.                      * @@ -448,6 +802,9 @@ bool g_object_storage_store_object(GObjectStorage *storage, const char *name, co      backend = g_object_storage_find_backend(storage, name); +    if (backend == NULL) +        g_object_storage_add_backend(storage, name, &backend); +      if (backend != NULL)      {          if (pos == NULL) @@ -492,10 +849,17 @@ bool g_object_storage_pack_object(GObjectStorage *storage, const char *name, con      bool result;                            /* Bilan à retourner           */      off64_t pos;                            /* Localisation des données    */ -    result = g_object_storage_store_object(storage, name, object, &pos); +    if (object == NULL) +        result = extend_packed_buffer(pbuf, (uint64_t []){ 0 }, sizeof(uint64_t), true); -    if (result) -        result = extend_packed_buffer(pbuf, (uint64_t []){ pos }, sizeof(uint64_t), true); +    else +    { +        result = g_object_storage_store_object(storage, name, object, &pos); + +        if (result) +            result = extend_packed_buffer(pbuf, (uint64_t []){ pos }, sizeof(uint64_t), true); + +    }      return result; | 
