/* Chrysalide - Outil d'analyse de fichiers binaires
 * snapshot.c - encodage des informations utiles aux instantanés
 *
 * Copyright (C) 2019 Cyrille Bagard
 *
 *  This file is part of Chrysalide.
 *
 *  Chrysalide 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.
 *
 *  Chrysalide 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 Chrysalide.  If not, see .
 */
#include "snapshot.h"
#include 
#include 
#include "../../../core/logs.h"
/* ---------------------------------------------------------------------------------- */
/*                            IDENTIFIANTS DES INSTANTANES                            */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
*                                                                             *
*  Paramètres  : id = identifiant d'instantané à initialiser. [OUT]           *
*                                                                             *
*  Description : Prépare un identifiant pour instantané à une définition.     *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void setup_empty_snapshot_id(snapshot_id_t *id)
{
    memset(id, 0, sizeof(snapshot_id_t));
}
/******************************************************************************
*                                                                             *
*  Paramètres  : id = identifiant d'instantané à initialiser. [OUT]           *
*                                                                             *
*  Description : Construit un identifiant pour instantané de base de données. *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
bool init_snapshot_id(snapshot_id_t *id)
{
    bool result;                            /* Bilan à retourner           */
    int ret;                                /* Bilan d'une génération      */
    unsigned char rand[SNAP_ID_RAND_SZ];    /* Tirage aléatoire            */
    size_t i;                               /* Boucle de parcours          */
    static char *alphabet = "0123456789abcdef";
    ret = RAND_bytes(rand, SNAP_ID_RAND_SZ);
    if (ret != 1)
    {
        LOG_ERROR_OPENSSL;
        result = false;
    }
    else
    {
        for (i = 0; i < SNAP_ID_RAND_SZ; i++)
        {
            id->name[i * 2 + 0] = alphabet[rand[i] & 0xf];
            id->name[i * 2 + 1] = alphabet[(rand[i] >> 4) & 0xf];
        }
        id->name[i * 2] = '\0';
        result = true;
    }
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : id   = identifiant d'instantané à initialiser. [OUT]         *
*                text = source de données pour la constitution.               *
*                                                                             *
*  Description : Construit un identifiant pour instantané de base de données. *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
bool init_snapshot_id_from_text(snapshot_id_t *id, const char *text)
{
    bool result;                            /* Bilan à retourner           */
    result = (strlen(text) == (SNAP_ID_HEX_SZ - 1));
    if (result)
        strcpy(id->name, text);
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : dest = destination de la copie d'indentifiant. [OUT]         *
*                src  = source de l'identifiant à copier.                     *
*                                                                             *
*  Description : Effectue une copie d'identifiant d'instantané.               *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void copy_snapshot_id(snapshot_id_t *dest, const snapshot_id_t *src)
{
    memcpy(dest->name, src->name, SNAP_ID_HEX_SZ);
}
/******************************************************************************
*                                                                             *
*  Paramètres  : id1 = premier identifiant à comparer.                        *
*                id2 = second identifiant à comparer.                         *
*                                                                             *
*  Description : Effectue la comparaison entre deux identifiants.             *
*                                                                             *
*  Retour      : Résultat de la comparaison : -1, 0 ou 1.                     *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
int cmp_snapshot_id(const snapshot_id_t *id1, const snapshot_id_t *id2)
{
    int result;                             /* Bilan à retourner           */
    result = memcmp(id1->name, id2->name, SNAP_ID_HEX_SZ);
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : id   = informations à constituer. [OUT]                      *
*                pbuf = paquet de données où venir puiser les infos.          *
*                                                                             *
*  Description : Importe la définition d'un identifiant d'instantané.         *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
bool unpack_snapshot_id(snapshot_id_t *id, packed_buffer *pbuf)
{
    bool result;                            /* Bilan à retourner           */
    result = extract_packed_buffer(pbuf, id->name, SNAP_ID_HEX_SZ, false);
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : id   = informations à sauvegarder.                           *
*                pbuf = paquet de données où venir inscrire les infos.        *
*                                                                             *
*  Description : Exporte la définition d'un identifiant d'instantané.         *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
bool pack_snapshot_id(const snapshot_id_t *id, packed_buffer *pbuf)
{
    bool result;                            /* Bilan à retourner           */
    result = extend_packed_buffer(pbuf, id->name, SNAP_ID_HEX_SZ, false);
    return result;
}
/* ---------------------------------------------------------------------------------- */
/*                             PROPRIETES DES INSTANTANES                             */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
*                                                                             *
*  Paramètres  : info = description d'instantané à initialiser. [OUT]         *
*                                                                             *
*  Description : Prépare une description pour instantané à une définition.    *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void setup_empty_snapshot_info(snapshot_info_t *info)
{
    setup_empty_snapshot_id(&info->parent_id);
    setup_empty_snapshot_id(&info->id);
    setup_empty_timestamp(&info->created);
    info->name = NULL;
    info->desc = NULL;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : info = description d'instantané à initialiser. [OUT]         *
*                                                                             *
*  Description : Construit une description pour instantané de base de données.*
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
bool init_snapshot_info(snapshot_info_t *info)
{
    bool result;                            /* Bilan à retourner           */
    result = init_snapshot_id_from_text(&info->parent_id, NO_SNAPSHOT_ROOT);
    if (result)
        result = init_snapshot_id(&info->id);
    if (result)
        result = init_timestamp(&info->created);
    if (result)
    {
        info->name = NULL;
        info->desc = NULL;
    }
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : info    = description d'instantané à initialiser. [OUT]      *
*                id      = source de données pour l'identifiant.              *
*                created = source de données pour la date de création.        *
*                name    = source de données éventuelle pour le nom.          *
*                desc    = source de données éventuelle pour la description.  *
*                                                                             *
*  Description : Construit une description pour instantané de base de données.*
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
bool init_snapshot_info_from_text(snapshot_info_t *info, const char *id, uint64_t created, const char *name, const char *desc)
{
    bool result;                            /* Bilan à retourner           */
    result = init_snapshot_id_from_text(&info->parent_id, NO_SNAPSHOT_ROOT);
    if (result)
        result = init_snapshot_id_from_text(&info->id, id);
    if (result)
        result = init_timestamp_from_value(&info->created, created);
    if (result)
    {
        if (name == NULL)
            info->name = NULL;
        else
            info->name = strdup(name);
        if (desc == NULL)
            info->desc = NULL;
        else
            info->desc = strdup(desc);
    }
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : info = description d'instantané à initialiser. [OUT]         *
*                                                                             *
*  Description : Libère la mémoire occupée par une description d'instantané.  *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void exit_snapshot_info(snapshot_info_t *info)
{
    if (info->name != NULL)
    {
        free(info->name);
        info->name = NULL;
    }
    if (info->desc != NULL)
    {
        free(info->desc);
        info->desc = NULL;
    }
}
/******************************************************************************
*                                                                             *
*  Paramètres  : dest = destination de la copie de description. [OUT]         *
*                src  = source de la description à copier.                    *
*                                                                             *
*  Description : Effectue une copie de description d'instantané.              *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void copy_snapshot_info(snapshot_info_t *dest, const snapshot_info_t *src)
{
    exit_snapshot_info(dest);
    copy_snapshot_id(&dest->parent_id, &src->parent_id);
    copy_snapshot_id(&dest->id, &src->id);
    copy_timestamp(&dest->created, &src->created);
    if (src->name != NULL)
        dest->name = strdup(src->name);
    if (src->desc != NULL)
        dest->desc = strdup(src->desc);
}
/******************************************************************************
*                                                                             *
*  Paramètres  : info = informations à constituer. [OUT]                      *
*                pbuf = paquet de données où venir puiser les infos.          *
*                                                                             *
*  Description : Importe la description d'un identifiant d'instantané.        *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
bool unpack_snapshot_info(snapshot_info_t *info, packed_buffer *pbuf)
{
    bool result;                            /* Bilan à retourner           */
    rle_string string;                      /* Chaîne à transmettre        */
    const char *text;                       /* Valeur textuelle obtenue    */
    result = unpack_snapshot_id(&info->parent_id, pbuf);
    if (result)
        result = unpack_snapshot_id(&info->id, pbuf);
    if (result)
        result = unpack_timestamp(&info->created, pbuf);
    if (result)
    {
        setup_empty_rle_string(&string);
        result = unpack_rle_string(&string, pbuf);
        if (result)
        {
            text = get_rle_string(&string);
            info->name = (text != NULL ? strdup(text) : NULL);
            exit_rle_string(&string);
        }
    }
    if (result)
    {
        setup_empty_rle_string(&string);
        result = unpack_rle_string(&string, pbuf);
        if (result)
        {
            text = get_rle_string(&string);
            info->desc = (text != NULL ? strdup(text) : NULL);
            exit_rle_string(&string);
        }
    }
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : info = informations à sauvegarder.                           *
*                pbuf = paquet de données où venir inscrire les infos.        *
*                                                                             *
*  Description : Exporte la description d'un identifiant d'instantané.        *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
bool pack_snapshot_info(const snapshot_info_t *info, packed_buffer *pbuf)
{
    bool result;                            /* Bilan à retourner           */
    rle_string string;                      /* Chaîne à transmettre        */
    result = pack_snapshot_id(&info->parent_id, pbuf);
    if (result)
        result = pack_snapshot_id(&info->id, pbuf);
    if (result)
        result = pack_timestamp(&info->created, pbuf);
    if (result)
    {
        init_static_rle_string(&string, info->name);
        result = pack_rle_string(&string, pbuf);
        exit_rle_string(&string);
    }
    if (result)
    {
        init_static_rle_string(&string, info->desc);
        result = pack_rle_string(&string, pbuf);
        exit_rle_string(&string);
    }
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : info = informations à mettre à jour.                         *
*                name = nouvelle désignation à considérer.                    *
*                                                                             *
*  Description : Change la désignation dans les informations d'un instantané. *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void set_snapshot_info_name(snapshot_info_t *info, const char *name)
{
    if (info->name == NULL)
        free(info->name);
    if (name == NULL)
        info->name = NULL;
    else
        info->name = strdup(name);
}
/******************************************************************************
*                                                                             *
*  Paramètres  : info = informations à mettre à jour.                         *
*                desc = nouvelle description à considérer.                    *
*                                                                             *
*  Description : Change la description dans les informations d'un instantané. *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void set_snapshot_info_desc(snapshot_info_t *info, const char *desc)
{
    if (info->desc == NULL)
        free(info->desc);
    if (desc == NULL)
        info->desc = NULL;
    else
        info->desc = strdup(desc);
}