diff options
Diffstat (limited to 'src/analysis')
| -rw-r--r-- | src/analysis/db/cdb.c | 287 | ||||
| -rw-r--r-- | src/analysis/db/client.c | 86 | ||||
| -rw-r--r-- | src/analysis/db/client.h | 2 | ||||
| -rw-r--r-- | src/analysis/db/protocol.h | 30 | ||||
| -rw-r--r-- | src/analysis/db/snapshot.c | 419 | ||||
| -rw-r--r-- | src/analysis/db/snapshot.h | 11 | 
6 files changed, 751 insertions, 84 deletions
| diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c index 125f69d..92624f6 100644 --- a/src/analysis/db/cdb.c +++ b/src/analysis/db/cdb.c @@ -147,6 +147,15 @@ static void on_collection_extended(GDbCollection *, GDbItem *, GCdbArchive *);  /* Assure le traitement des requêtes de clients. */  static void *g_cdb_archive_process(GCdbArchive *); +/* Envoie un paquet de données constitué à tous les clients. */ +static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *, packed_buffer *); + +/* Envoie à tous les clients la nouvelle liste d'instantanés. */ +static bool g_cdb_archive_send_snapshot_update(GCdbArchive *, packed_buffer *); + +/* Envoie à tous les clients le nouvel instantané courant. */ +static bool g_cdb_archive_send_snapshot_change(GCdbArchive *, packed_buffer *); +  /* Dissocie un utilisateur de l'archive. */  static void g_cdb_archive_remove_client(GCdbArchive *, size_t); @@ -255,12 +264,18 @@ static void g_cdb_archive_dispose(GCdbArchive *archive)  static void g_cdb_archive_finalize(GCdbArchive *archive)  { +#ifndef NDEBUG      int ret;                                /* Bilan d'un appel            */ +#endif      if (archive->db != NULL)      { +#ifndef NDEBUG          ret = sqlite3_close(archive->db);          assert(ret == SQLITE_OK); +#else +        sqlite3_close(archive->db); +#endif      }      if (archive->xml_desc != NULL) @@ -299,10 +314,6 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl      GCdbArchive *result;                    /* Adresse à retourner         */      int ret;                                /* Retour d'un appel           */      struct stat finfo;                      /* Information sur l'archive   */ -    snapshot_id_t id;                       /* Identifiant d'instantané    */ -#ifndef NDEBUG -    bool status;                            /* Validité de l'identifiant   */ -#endif      result = g_object_new(G_TYPE_CDB_ARCHIVE, NULL); @@ -348,14 +359,7 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl          /* Récupération de la base courante */ -#ifndef NDEBUG -        status = g_db_snapshot_get_current_id(result->snapshot, &id); -        assert(status); -#else -        g_db_snapshot_get_current_id(result->snapshot, &id); -#endif - -        result->db = g_db_snapshot_get_database(result->snapshot, &id); +        result->db = g_db_snapshot_get_database(result->snapshot);          if (result->db == NULL)          { @@ -381,14 +385,7 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl          /* Récupération de la base courante */ -#ifndef NDEBUG -        status = g_db_snapshot_get_current_id(result->snapshot, &id); -        assert(status); -#else -        g_db_snapshot_get_current_id(result->snapshot, &id); -#endif - -        result->db = g_db_snapshot_get_database(result->snapshot, &id); +        result->db = g_db_snapshot_get_database(result->snapshot);          if (result->db == NULL)          { @@ -843,7 +840,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)      DBError error;                          /* Bilan d'une opération       */      packed_buffer out_pbuf;                 /* Tampon d'émission           */      GDbCollection *collec;                  /* Collection visée au final   */ -    snapshot_id_t id;                       /* Identifiant d'instantané    */ +    bool reload;                            /* Besoin de rechargement      */      char *msg;                              /* Erreur à faire remonter     */      void interrupt_poll_with_sigusr1(int sig) { }; @@ -1007,19 +1004,8 @@ static void *g_cdb_archive_process(GCdbArchive *archive)                      case DBC_GET_SNAPSHOTS: - force_snapshots_update: - -                        init_packed_buffer(&out_pbuf); - -                        status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SNAPSHOTS_UPDATED }, -                                                      sizeof(uint32_t), true); -                        if (!status) goto gcap_bad_reply; - -                        status = g_db_snapshot_pack_all(archive->snapshot, &out_pbuf); -                        if (!status) goto gcap_bad_reply; - -                        status = extend_packed_buffer(&out_pbuf, SNAPSHOT_END_MARK, SNAP_ID_HEX_SZ, false); -                        if (!status) goto gcap_bad_reply; +                        if (!g_cdb_archive_send_snapshot_update(archive, &out_pbuf)) +                            goto critical_error;                          status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);                          if (!status) goto gcap_bad_reply; @@ -1030,21 +1016,8 @@ static void *g_cdb_archive_process(GCdbArchive *archive)                      case DBC_GET_CUR_SNAPSHOT: -                        init_packed_buffer(&out_pbuf); - -                        status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_CUR_SNAPSHOT_UPDATED }, -                                                      sizeof(uint32_t), true); -                        if (!status) goto gcap_bad_reply; - -#ifndef NDEBUG -                        status = g_db_snapshot_get_current_id(archive->snapshot, &id); -                        assert(status); -#else -                        g_db_snapshot_get_current_id(archive->snapshot, &id); -#endif - -                        status = pack_snapshot_id(&id, &out_pbuf); -                        if (!status) goto gcap_bad_reply; +                        if (!g_cdb_archive_send_snapshot_change(archive, &out_pbuf)) +                            goto critical_error;                          status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);                          if (!status) goto gcap_bad_reply; @@ -1061,8 +1034,34 @@ static void *g_cdb_archive_process(GCdbArchive *archive)                      case DBC_SET_CUR_SNAPSHOT: +                        error = g_db_snapshot_restore(archive->snapshot, &in_pbuf, &reload); +                        if (error == DBE_NONE) +                        { +#ifndef NDEBUG +                            ret = sqlite3_close(archive->db); +                            assert(ret == SQLITE_OK); +#else +                            sqlite3_close(archive->db); +#endif + +                            archive->db = g_db_snapshot_get_database(archive->snapshot); + +                            if (archive->db == NULL) +                            { +                                error = DBE_SNAPSHOT_RESTORE_FAILURE; +                            } +                            else +                            { +                                if (!g_cdb_archive_send_snapshot_change(archive, NULL)) +                                    goto critical_error; +                            } + +                        } + +                        else if (error == DBE_BAD_EXCHANGE) +                            goto gcap_bad_exchange;                          break; @@ -1071,7 +1070,10 @@ static void *g_cdb_archive_process(GCdbArchive *archive)                          error = g_db_snapshot_set_name(archive->snapshot, &in_pbuf);                          if (error == DBE_NONE) -                            goto force_snapshots_update; +                        { +                            if (!g_cdb_archive_send_snapshot_update(archive, NULL)) +                                goto critical_error; +                        }                          else if (error == DBE_BAD_EXCHANGE)                              goto gcap_bad_exchange; @@ -1083,7 +1085,47 @@ static void *g_cdb_archive_process(GCdbArchive *archive)                          error = g_db_snapshot_set_desc(archive->snapshot, &in_pbuf);                          if (error == DBE_NONE) -                            goto force_snapshots_update; +                        { +                            if (!g_cdb_archive_send_snapshot_update(archive, NULL)) +                                goto critical_error; +                        } + +                        else if (error == DBE_BAD_EXCHANGE) +                            goto gcap_bad_exchange; + +                        break; + +                    case DBC_CREATE_SNAPSHOT: + +                        error = g_db_snapshot_create(archive->snapshot, archive->db); + +                        if (error == DBE_NONE) +                        { +                            if (!g_cdb_archive_send_snapshot_update(archive, NULL)) +                                goto critical_error; +                        } + +                        else if (error == DBE_BAD_EXCHANGE) +                            goto gcap_bad_exchange; + +                        break; + +                    case DBC_REMOVE_SNAPSHOT: + +                        error = g_db_snapshot_remove(archive->snapshot, &in_pbuf, &reload); + +                        if (error == DBE_NONE) +                        { +                            if (!g_cdb_archive_send_snapshot_update(archive, NULL)) +                                goto critical_error; + +                            if (reload) +                            { +                                if (!g_cdb_archive_send_snapshot_change(archive, NULL)) +                                    goto critical_error; +                            } + +                        }                          else if (error == DBE_BAD_EXCHANGE)                              goto gcap_bad_exchange; @@ -1122,6 +1164,14 @@ static void *g_cdb_archive_process(GCdbArchive *archive)                  g_cdb_archive_remove_client(archive, i); +                continue; + + critical_error: + +                LOG_ERROR(LMT_ERROR, _("Internal critical error")); + +                assert(0); +              }          } @@ -1150,6 +1200,141 @@ static void *g_cdb_archive_process(GCdbArchive *archive)  /******************************************************************************  *                                                                             *  *  Paramètres  : archive = archive à connecter avec un utilisateur.           * +*                pbuf    = paquet de données à émettre.                       * +*                                                                             * +*  Description : Envoie un paquet de données constitué à tous les clients.    * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *archive, packed_buffer *pbuf) +{ +    size_t i;                               /* Boucle de parcours          */ +    bool status;                            /* Bilan d'une émission        */ + +    for (i = 0; i < archive->count; i++) +    { +        status = ssl_send_packed_buffer(pbuf, archive->clients[i].ssl_fd); +        if (!status) +        { +            log_variadic_message(LMT_ERROR, _("Error while replying to client %zu"), i); + +            g_cdb_archive_remove_client(archive, i); +            i--; + +        } + +    } + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : archive = archive à connecter avec un utilisateur.           * +*                pbuf    = paquet à consituer pour un envoi unique. [OUT]     * +*                                                                             * +*  Description : Envoie à tous les clients la nouvelle liste d'instantanés.   * +*                                                                             * +*  Retour      : Bilan de constitution de la réponse.                         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool g_cdb_archive_send_snapshot_update(GCdbArchive *archive, packed_buffer *pbuf) +{ +    bool result;                            /* Bilan à retourner           */ +    bool do_send;                           /* Réalisation de l'émission   */ +    packed_buffer out_pbuf;                 /* Tampon d'émission           */ + +    do_send = (pbuf == NULL); + +    if (pbuf == NULL) +        pbuf = &out_pbuf; + +    init_packed_buffer(pbuf); + +    result = extend_packed_buffer(pbuf, (uint32_t []) { DBC_SNAPSHOTS_UPDATED }, +                                  sizeof(uint32_t), true); +    if (!result) goto bad_reply; + +    result = g_db_snapshot_pack_all(archive->snapshot, pbuf); +    if (!result) goto bad_reply; + +    result = extend_packed_buffer(pbuf, SNAPSHOT_END_MARK, SNAP_ID_HEX_SZ, false); +    if (!result) goto bad_reply; + +    if (do_send) +        g_cdb_archive_send_reply_to_all_clients(archive, pbuf); + + bad_reply: + +    if (do_send || !result) +        exit_packed_buffer(pbuf); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : archive = archive à connecter avec un utilisateur.           * +*                pbuf    = paquet à consituer pour un envoi unique. [OUT]     * +*                                                                             * +*  Description : Envoie à tous les clients le nouvel instantané courant.      * +*                                                                             * +*  Retour      : Bilan de constitution de la réponse.                         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool g_cdb_archive_send_snapshot_change(GCdbArchive *archive, packed_buffer *pbuf) +{ +    bool result;                            /* Bilan à retourner           */ +    bool do_send;                           /* Réalisation de l'émission   */ +    packed_buffer out_pbuf;                 /* Tampon d'émission           */ +    snapshot_id_t id;                       /* Identifiant d'instantané    */ + +    do_send = (pbuf == NULL); + +    if (pbuf == NULL) +        pbuf = &out_pbuf; + +    init_packed_buffer(pbuf); + +    result = extend_packed_buffer(pbuf, (uint32_t []) { DBC_CUR_SNAPSHOT_UPDATED }, +                                  sizeof(uint32_t), true); +    if (!result) goto bad_reply; + +    result = g_db_snapshot_get_current_id(archive->snapshot, &id); +    assert(result); +    if (!result) goto bad_reply; + +    result = pack_snapshot_id(&id, pbuf); +    if (!result) goto bad_reply; + +    if (do_send) +        g_cdb_archive_send_reply_to_all_clients(archive, pbuf); + + bad_reply: + +    if (do_send || !result) +        exit_packed_buffer(pbuf); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : archive = archive à connecter avec un utilisateur.           *  *                fd      = canal de communication réseau ouvert.              *  *                                                                             *  *  Description : Associe un nouvel utilisateur à l'archive.                   * diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c index b4e856f..c1bcd28 100644 --- a/src/analysis/db/client.c +++ b/src/analysis/db/client.c @@ -908,6 +908,8 @@ static void *g_hub_client_update(GHubClient *client)                  case DBC_SET_CUR_SNAPSHOT:                  case DBC_SET_SNAPSHOT_NAME:                  case DBC_SET_SNAPSHOT_DESC: +                case DBC_CREATE_SNAPSHOT: +                case DBC_REMOVE_SNAPSHOT:                      log_variadic_message(LMT_INFO,                                           _("This command is not available on this side: 0x%08x"), command);                      goto gdcu_bad_exchange; @@ -1586,9 +1588,32 @@ bool g_hub_client_set_snapshot_desc(GHubClient *client, const snapshot_id_t *id,  bool g_hub_client_restore_snapshot(GHubClient *client, const snapshot_id_t *id)  { -    bool result;                            /* Bilan à retourner           */ +    bool result;                            /* Bilan partiel à remonter    */ +    packed_buffer out_pbuf;                 /* Tampon d'émission           */ +    SSL *tls_fd;                            /* Canal de communication SSL  */ + +    init_packed_buffer(&out_pbuf); + +    tls_fd = g_hub_client_get_ssl_fd(client); + +    if (tls_fd == NULL) +        result = false; -    result = false; +    else +    { +        result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_CUR_SNAPSHOT }, sizeof(uint32_t), true); + +        if (result) +            result = pack_snapshot_id(id, &out_pbuf); + +        if (result) +            result = ssl_send_packed_buffer(&out_pbuf, tls_fd); + +        g_hub_client_put_ssl_fd(client, tls_fd); + +    } + +    exit_packed_buffer(&out_pbuf);      return result; @@ -1598,7 +1623,6 @@ bool g_hub_client_restore_snapshot(GHubClient *client, const snapshot_id_t *id)  /******************************************************************************  *                                                                             *  *  Paramètres  : client = client pour les accès distants à manipuler.         * -*                id     = identifiant d'instantané à traiter.                 *  *                                                                             *  *  Description : Crée un nouvel instantané à partir d'un autre.               *  *                                                                             * @@ -1608,11 +1632,31 @@ bool g_hub_client_restore_snapshot(GHubClient *client, const snapshot_id_t *id)  *                                                                             *  ******************************************************************************/ -bool g_hub_client_create_snapshot(GHubClient *client, const snapshot_id_t *id) +bool g_hub_client_create_snapshot(GHubClient *client)  { -    bool result;                            /* Bilan à retourner           */ +    bool result;                            /* Bilan partiel à remonter    */ +    packed_buffer out_pbuf;                 /* Tampon d'émission           */ +    SSL *tls_fd;                            /* Canal de communication SSL  */ -    result = false; +    init_packed_buffer(&out_pbuf); + +    tls_fd = g_hub_client_get_ssl_fd(client); + +    if (tls_fd == NULL) +        result = false; + +    else +    { +        result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_CREATE_SNAPSHOT }, sizeof(uint32_t), true); + +        if (result) +            result = ssl_send_packed_buffer(&out_pbuf, tls_fd); + +        g_hub_client_put_ssl_fd(client, tls_fd); + +    } + +    exit_packed_buffer(&out_pbuf);      return result; @@ -1635,9 +1679,35 @@ bool g_hub_client_create_snapshot(GHubClient *client, const snapshot_id_t *id)  bool g_hub_client_remove_snapshot(GHubClient *client, const snapshot_id_t *id, bool rec)  { -    bool result;                            /* Bilan à retourner           */ +    bool result;                            /* Bilan partiel à remonter    */ +    packed_buffer out_pbuf;                 /* Tampon d'émission           */ +    SSL *tls_fd;                            /* Canal de communication SSL  */ + +    init_packed_buffer(&out_pbuf); + +    tls_fd = g_hub_client_get_ssl_fd(client); + +    if (tls_fd == NULL) +        result = false; + +    else +    { +        result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_REMOVE_SNAPSHOT }, sizeof(uint32_t), true); + +        if (result) +            result = pack_snapshot_id(id, &out_pbuf); + +        if (result) +            result = extend_packed_buffer(&out_pbuf, (uint8_t []) { rec ? 0x1 : 0x0 }, sizeof(uint8_t), false); -    result = false; +        if (result) +            result = ssl_send_packed_buffer(&out_pbuf, tls_fd); + +        g_hub_client_put_ssl_fd(client, tls_fd); + +    } + +    exit_packed_buffer(&out_pbuf);      return result; diff --git a/src/analysis/db/client.h b/src/analysis/db/client.h index af47b5c..0323349 100644 --- a/src/analysis/db/client.h +++ b/src/analysis/db/client.h @@ -93,7 +93,7 @@ bool g_hub_client_set_snapshot_desc(GHubClient *, const snapshot_id_t *, const c  bool g_hub_client_restore_snapshot(GHubClient *, const snapshot_id_t *);  /* Crée un nouvel instantané à partir d'un autre. */ -bool g_hub_client_create_snapshot(GHubClient *, const snapshot_id_t *); +bool g_hub_client_create_snapshot(GHubClient *);  /* Supprime un ancien instantané. */  bool g_hub_client_remove_snapshot(GHubClient *, const snapshot_id_t *, bool); diff --git a/src/analysis/db/protocol.h b/src/analysis/db/protocol.h index b57c25c..f66d8fc 100644 --- a/src/analysis/db/protocol.h +++ b/src/analysis/db/protocol.h @@ -277,6 +277,34 @@ typedef enum _DBCommand      DBC_SET_SNAPSHOT_DESC,                  /* Description de l'instantané */ +    /** +     * Gestion de la commande 'DBC_CREATE_SNAPSHOT'. +     * +     * Le client connecté envoie un paquet de la forme suivante : +     * +     *    [ Gestion d'instantané : DBC_CREATE_SNAPSHOT          ] +     * +     * Le serveur renvoie ensuite automatiquement un paquet +     * de type 'DBC_SNAPSHOTS_UPDATED'. +     */ + +    DBC_CREATE_SNAPSHOT,                    /* Création d'instantané       */ + +    /** +     * Gestion de la commande 'DBC_REMOVE_SNAPSHOT'. +     * +     * Le client connecté envoie un paquet de la forme suivante : +     * +     *    [ Gestion d'instantané : DBC_REMOVE_SNAPSHOT          ] +     *    [ <identifiant d'instantané>                          ] +     *    [ indicateur de récursivité : octet 0x1 ou 0x0        ] +     * +     * Le serveur renvoie ensuite automatiquement un paquet +     * de type 'DBC_SNAPSHOTS_UPDATED'. +     */ + +    DBC_REMOVE_SNAPSHOT,                    /* Suppression d'instantané    */ +      DBC_COUNT  } DBCommand; @@ -303,6 +331,8 @@ typedef enum _DBError      DBE_XML_ERROR,                          /* Erreur lors d'une définition*/      DBE_SNAPSHOT_NOT_FOUND,                 /* Instantané non trouvé       */ +    DBE_SNAPSHOT_RESTORE_FAILURE,           /* Echec d'une restauration    */ +    DBE_SNAPSHOT_ROOT_REMOVAL,              /* Tentative de suppression    */      DBE_COUNT diff --git a/src/analysis/db/snapshot.c b/src/analysis/db/snapshot.c index 2cd50f6..e07129e 100644 --- a/src/analysis/db/snapshot.c +++ b/src/analysis/db/snapshot.c @@ -38,6 +38,7 @@  #include "../../common/compression.h"  #include "../../common/extstr.h"  #include "../../common/io.h" +#include "../../common/sqlite.h"  #include "../../common/xml.h"  #include "../../core/logs.h" @@ -79,9 +80,15 @@ static DBError save_snapshot_node(const snapshot_node_t *, xmlDocPtr, xmlXPathCo  /* Recherche le noeud d'instantané lié à un identifiant. */  static snapshot_node_t *find_snapshot_node(snapshot_node_t *, const snapshot_id_t *); +/* Détermine si un instantané est compris dans une branche. */ +static bool contain_snapshot_node(const snapshot_node_t *, const snapshot_node_t *); +  /* Ajoute un instantané comme prolongement d'un instantané. */  static void add_snapshot_node(snapshot_node_t *, snapshot_node_t *); +/* Fait disparaître un instantané dans une arborescence. */ +static void remove_snapshot_node(snapshot_node_t *, bool); +  /* Collecte les descriptions d'une arborescence d'instantanés. */  static bool pack_snapshot_node(const snapshot_node_t *, packed_buffer *); @@ -101,6 +108,8 @@ struct _GDbSnapshot      snapshot_node_t *nodes;                 /* Instantanés présents        */      snapshot_node_t *current;               /* Instantané courant          */ +    char *current_db;                       /* Base de données SQLite      */ +  };  /* Gestionnaire d'instantanés de bases de données (classe) */ @@ -487,6 +496,34 @@ static snapshot_node_t *find_snapshot_node(snapshot_node_t *node, const snapshot  /******************************************************************************  *                                                                             * +*  Paramètres  : node   = départ du parcours de recherche.                    * +*                target = instantané recherché.                               * +*                                                                             * +*  Description : Détermine si un instantané est compris dans une branche.     * +*                                                                             * +*  Retour      : Noeud trouvé ou NULL en cas d'échec.                         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool contain_snapshot_node(const snapshot_node_t *node, const snapshot_node_t *target) +{ +    bool result;                            /* Bilan à faire remonter      */ +    size_t i;                               /* Boucle de parcours          */ + +    result = (node == target); + +    for (i = 0; i < node->count && !result; i++) +        result = contain_snapshot_node(node->children[i], target); + +    return result; + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : node  = instantané de rattachement.                          *  *                child = instantané à attacher.                               *  *                                                                             * @@ -507,6 +544,8 @@ static void add_snapshot_node(snapshot_node_t *node, snapshot_node_t *child)      node->children[node->count - 1] = child; +    child->parent = node; +      src = get_snapshot_info_id(&node->info);      dest = get_snapshot_info_parent_id(&child->info); @@ -517,6 +556,78 @@ static void add_snapshot_node(snapshot_node_t *node, snapshot_node_t *child)  /******************************************************************************  *                                                                             * +*  Paramètres  : node = instantané à traiter.                                 * +*                rec  = précise si les enfants sont à rattacher au parent.    * +*                                                                             * +*  Description : Fait disparaître un instantané dans une arborescence.        * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void remove_snapshot_node(snapshot_node_t *node, bool rec) +{ +    snapshot_node_t *parent;                /* Accès direct                */ +    size_t i;                               /* Boucle de parcours          */ + +    parent = node->parent; + +    assert(parent != NULL); + +    /* Coupe de la branche */ + +    assert(parent->count > 0); + +    if (parent->count == 1) +    { +        free(parent->children); + +        parent->children = NULL; +        parent->count = 0; + +    } + +    else +    { +        for (i = 0; i < parent->count; i++) +            if (parent->children[i] == node) +                break; + +        assert(i < parent->count); + +        if ((i + 1) < parent->count) +            memmove(&parent->children[i], &parent->children[i + 1], +                    (parent->count - i - 1) * sizeof(snapshot_node_t *)); + +        parent->children = realloc(parent->children, --parent->count * sizeof(snapshot_node_t *)); + +    } + +    /* Rattachement des enfants ? */ + +    if (!rec) +    { +        for (i = 0; i < node->count; i++) +            add_snapshot_node(parent, node->children[i]); + +        free(node->children); + +        node->children = NULL; +        node->count = 0; + +    } + +    /* Suppression */ + +    destroy_snapshot_node(node); + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : node = définition d'instantané à consulter.                  *  *                pbuf = paquet de données où venir inscrire des infos.        *  *                                                                             * @@ -595,9 +706,10 @@ static void g_db_snapshot_init(GDbSnapshot *snap)      snap->hash = NULL;      snap->nodes = NULL; -      snap->current = NULL; +    snap->current_db = NULL; +  } @@ -643,6 +755,9 @@ static void g_db_snapshot_finalize(GDbSnapshot *snap)      if (snap->nodes != NULL)          destroy_snapshot_node(snap->nodes); +    if (snap->current_db != NULL) +        free(snap->current_db); +      G_OBJECT_CLASS(g_db_snapshot_parent_class)->finalize(G_OBJECT(snap));  } @@ -664,12 +779,30 @@ static void g_db_snapshot_finalize(GDbSnapshot *snap)  static GDbSnapshot *g_db_snapshot_new(const char *tmpdir, const char *hash)  {      GDbSnapshot *result;                    /* Adresse à retourner         */ +    int ret;                                /* Bilan d'une génération      */ +    bool status;                            /* Bilan de la création        */      result = g_object_new(G_TYPE_DB_SNAPSHOT, NULL);      result->tmpdir = strdup(tmpdir);      result->hash = strdup(hash); +    ret = asprintf(&result->current_db, "%s" G_DIR_SEPARATOR_S "%s_current_db.sql", tmpdir, hash); + +    status = (ret > 0); + +    if (status) +    { +        ret = ensure_path_exists(result->current_db); +        status = (ret != -1); +    } + +    if (!status) +    { +        g_object_unref(G_OBJECT(result)); +        result = NULL; +    } +      return result;  } @@ -699,6 +832,7 @@ GDbSnapshot *g_db_snapshot_new_empty(const char *tmpdir, const char *hash, GList      GDbCollection *collec;                  /* Collection visée manipulée  */      result = g_db_snapshot_new(tmpdir, hash); +    if (result == NULL) goto exit;      result->nodes = create_snapshot_node(NULL, 0, NULL, NULL); @@ -728,6 +862,11 @@ GDbSnapshot *g_db_snapshot_new_empty(const char *tmpdir, const char *hash, GList      sqlite3_close(db); +    status = copy_file(result->current_db, result->nodes->path); + +    if (!status) +        goto error; +      return result;   error_db: @@ -738,6 +877,8 @@ GDbSnapshot *g_db_snapshot_new_empty(const char *tmpdir, const char *hash, GList      g_object_unref(G_OBJECT(result)); + exit: +      return NULL;  } @@ -776,6 +917,7 @@ GDbSnapshot *g_db_snapshot_new_from_xml(const char *tmpdir, const char *hash, xm      snapshot_id_t node_id;                  /* Identifiant de noeud courant*/      result = g_db_snapshot_new(tmpdir, hash); +    if (result == NULL) goto exit;      /* Chargement de l'ensemble des instantanés */ @@ -890,6 +1032,8 @@ GDbSnapshot *g_db_snapshot_new_from_xml(const char *tmpdir, const char *hash, xm      g_object_unref(G_OBJECT(result)); + exit: +      return NULL;  } @@ -931,6 +1075,15 @@ bool g_db_snapshot_fill(GDbSnapshot *snap, struct archive *archive)          if (!_endswith(path, ".db", &dot))              continue; +        if (strcmp(path, "current.db") == 0) +        { +            if (!dump_archive_entry_into_file(archive, entry, snap->current_db)) +                break; + +            continue; + +        } +          raw_id = strndup(path, dot - path);          status = init_snapshot_id_from_text(&node_id, raw_id); @@ -988,6 +1141,7 @@ DBError g_db_snapshot_save(const GDbSnapshot *snap, xmlDocPtr xdoc, xmlXPathCont      DBError result;                         /* Conclusion à retourner      */      const snapshot_id_t *id;                /* Identifiant attribué        */      bool status;                            /* Bilan d'un ajout XML        */ +    CPError ret;                            /* Bilan d'une compression     */      assert(snap->current != NULL); @@ -999,8 +1153,32 @@ DBError g_db_snapshot_save(const GDbSnapshot *snap, xmlDocPtr xdoc, xmlXPathCont          result = DBE_XML_ERROR;      else +    { +        ret = add_file_into_archive(archive, snap->current_db, "current.db"); + +        switch (ret) +        { +            case CPE_NO_ERROR: +                break; + +            case CPE_SYSTEM_ERROR: +                result = DBE_SYS_ERROR; +                goto exit; +                break; + +            case CPE_ARCHIVE_ERROR: +                result = DBE_ARCHIVE_ERROR; +                goto exit; +                break; + +        } +          result = save_snapshot_node(snap->nodes, xdoc, context, archive); +    } + + exit: +      return result;  } @@ -1042,7 +1220,6 @@ bool g_db_snapshot_get_current_id(const GDbSnapshot *snap, snapshot_id_t *id)  /******************************************************************************  *                                                                             *  *  Paramètres  : snap = gestionnaire d'instantanés à consulter.               * -*                id   = identifiant de l'instantané visé.                     *  *                                                                             *  *  Description : Fournit la base de données correspondant à instanné donné.   *  *                                                                             * @@ -1052,32 +1229,19 @@ bool g_db_snapshot_get_current_id(const GDbSnapshot *snap, snapshot_id_t *id)  *                                                                             *  ******************************************************************************/ -sqlite3 *g_db_snapshot_get_database(const GDbSnapshot *snap, const snapshot_id_t *id) +sqlite3 *g_db_snapshot_get_database(const GDbSnapshot *snap)  {      sqlite3 *result;                        /* Base SQLite à retourner     */ -    snapshot_node_t *node;                  /* Instantané trouvé           */      int ret;                                /* Bilan d'un appel            */ -    node = find_snapshot_node(snap->nodes, id); - -    if (node == NULL) -    { -        log_variadic_message(LMT_ERROR, _("Snapshot not found for id '%s'"), snapshot_id_as_string(id)); -        result = NULL; -    } +    ret = sqlite3_open(snap->current_db, &result); -    else +    if (ret != SQLITE_OK)      { -        ret = sqlite3_open(node->path, &result); - -        if (ret != SQLITE_OK) -        { -            if (result != NULL) -                sqlite3_close(result); - -            result = NULL; +        if (result != NULL) +            sqlite3_close(result); -        } +        result = NULL;      } @@ -1112,7 +1276,7 @@ bool g_db_snapshot_pack_all(const GDbSnapshot *snap, packed_buffer *pbuf)  /******************************************************************************  *                                                                             * -*  Paramètres  : snap    = gestionnaire d'instantanés à consulter.            * +*  Paramètres  : snap = gestionnaire d'instantanés à consulter.               *  *                pbuf = paquet de données où venir puiser les infos.          *  *                                                                             *  *  Description : Actualise la désignation d'un instantané donné.              * @@ -1177,7 +1341,7 @@ DBError g_db_snapshot_set_name(const GDbSnapshot *snap, packed_buffer *pbuf)  /******************************************************************************  *                                                                             * -*  Paramètres  : snap    = gestionnaire d'instantanés à consulter.            * +*  Paramètres  : snap = gestionnaire d'instantanés à consulter.               *  *                pbuf = paquet de données où venir puiser les infos.          *  *                                                                             *  *  Description : Actualise la description d'un instantané donné.              * @@ -1238,3 +1402,212 @@ DBError g_db_snapshot_set_desc(const GDbSnapshot *snap, packed_buffer *pbuf)      return result;  } + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : snap   = gestionnaire d'instantanés à consulter.             * +*                pbuf   = paquet de données où venir puiser les infos.        * +*                reload = indique un besoin de rechargement de la base. [OUT] * +*                                                                             * +*  Description : Restaure un instantané de l'arborescence.                    * +*                                                                             * +*  Retour      : Bilan de l'opération sous forme de code d'erreur.            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +DBError g_db_snapshot_restore(GDbSnapshot *snap, packed_buffer *pbuf, bool *reload) +{ +    DBError result;                         /* Conclusion à retourner      */ +    snapshot_id_t id;                       /* Identifiant d'instantané    */ +    bool status;                            /* Bilan d'une récupération    */ +    snapshot_node_t *node;                  /* Instantané trouvé           */ + +    result = DBE_NONE; + +    /* Lecture des arguments */ + +    setup_empty_snapshot_id(&id); + +    status = unpack_snapshot_id(&id, pbuf); +    if (!status) +    { +        result = DBE_BAD_EXCHANGE; +        goto bad_exchange; +    } + +    /* Traitement */ + +    node = find_snapshot_node(snap->nodes, &id); + +    if (node == NULL) +    { +        log_variadic_message(LMT_ERROR, _("Snapshot not found for id '%s'"), snapshot_id_as_string(&id)); +        result = DBE_SNAPSHOT_NOT_FOUND; +    } + +    else if (node == snap->current) +    { +        log_simple_message(LMT_WARNING, _("No need to restore the current snapshot")); +        *reload = false; +    } + +    else +    { +        status = copy_file(snap->current_db, node->path); + +        if (!status) +        { +            log_variadic_message(LMT_ERROR, _("Failed to restore snapshot from '%s' to '%s'"), +                                 node->path, snap->current_db); +            result = DBE_SNAPSHOT_RESTORE_FAILURE; +        } + +        else +        { +            snap->current = node; +            *reload = true; +        } + +    } + + bad_exchange: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : snap = gestionnaire d'instantanés à consulter.               * +*                db   = base de données courante.                             * +*                                                                             * +*  Description : Crée un nouvel instantanés dans l'arborescence.              * +*                                                                             * +*  Retour      : Bilan de l'opération sous forme de code d'erreur.            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +DBError g_db_snapshot_create(GDbSnapshot *snap, sqlite3 *db) +{ +    DBError result;                         /* Conclusion à retourner      */ +    snapshot_node_t *new;                   /* Nouvel instantané           */ +    bool status;                            /* Bilan d'une récupération    */ + +    result = DBE_NONE; + +    new = create_snapshot_node(NULL, 0, NULL, NULL); + +    status = setup_snapshot_node_db_path(new, snap->tmpdir, snap->hash); +    if (!status) +    { +        result = DBE_SYS_ERROR; +        destroy_snapshot_node(new); +        goto error; +    } + +    status = backup_db(db, new->path); +    if (!status) +    { +        result = DBE_SYS_ERROR; +        destroy_snapshot_node(new); +        goto error; +    } + +    add_snapshot_node(snap->current, new); + +    snap->current = new; + + error: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : snap    = gestionnaire d'instantanés à consulter.            * +*                pbuf    = paquet de données où venir puiser les infos.       * +*                changed = indique si l'instantané courant a bougé. [OUT]     * +*                                                                             * +*  Description : Supprime un instantané dans l'arborescence.                  * +*                                                                             * +*  Retour      : Bilan de l'opération sous forme de code d'erreur.            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +DBError g_db_snapshot_remove(GDbSnapshot *snap, packed_buffer *pbuf, bool *changed) +{ +    DBError result;                         /* Conclusion à retourner      */ +    snapshot_id_t id;                       /* Identifiant d'instantané    */ +    bool status;                            /* Bilan d'une récupération    */ +    uint8_t tmp;                            /* Stockage temporaire         */ +    bool rec;                               /* Indicateur de récursivité   */ +    snapshot_node_t *node;                  /* Instantané trouvé           */ + +    result = DBE_NONE; + +    *changed = false; + +    /* Lecture des arguments */ + +    setup_empty_snapshot_id(&id); + +    status = unpack_snapshot_id(&id, pbuf); +    if (!status) +    { +        result = DBE_BAD_EXCHANGE; +        goto bad_exchange; +    } + +    status = extract_packed_buffer(pbuf, &tmp, sizeof(uint8_t), false); +    if (!status) +    { +        result = DBE_BAD_EXCHANGE; +        goto bad_exchange; +    } + +    rec = (tmp == 0x1); + +    /* Traitement */ + +    node = find_snapshot_node(snap->nodes, &id); + +    if (node == NULL) +    { +        log_variadic_message(LMT_ERROR, _("Snapshot not found for id '%s'"), snapshot_id_as_string(&id)); +        result = DBE_SNAPSHOT_NOT_FOUND; +    } + +    else if (node == snap->nodes) +    { +        log_simple_message(LMT_ERROR, _("Root snapshot can not be removed")); +        result = DBE_SNAPSHOT_ROOT_REMOVAL; +    } + +    else +    { +        /* Réassignation éventuelle */ +        if ((rec && contain_snapshot_node(node, snap->current)) || (!rec && node == snap->current)) +        { +            snap->current = node->parent; +            *changed = true; +        } + +        remove_snapshot_node(node, rec); + +    } + + bad_exchange: + +    return result; + +} diff --git a/src/analysis/db/snapshot.h b/src/analysis/db/snapshot.h index 457e8c2..8737f8c 100644 --- a/src/analysis/db/snapshot.h +++ b/src/analysis/db/snapshot.h @@ -72,7 +72,7 @@ DBError g_db_snapshot_save(const GDbSnapshot *, xmlDocPtr, xmlXPathContextPtr, s  bool g_db_snapshot_get_current_id(const GDbSnapshot *, snapshot_id_t *);  /* Fournit la base de données correspondant à instanné donné. */ -sqlite3 *g_db_snapshot_get_database(const GDbSnapshot *, const snapshot_id_t *); +sqlite3 *g_db_snapshot_get_database(const GDbSnapshot *);  /* Collecte les descriptions de l'ensemble des instantanés. */  bool g_db_snapshot_pack_all(const GDbSnapshot *, packed_buffer *); @@ -83,6 +83,15 @@ DBError g_db_snapshot_set_name(const GDbSnapshot *, packed_buffer *);  /* Actualise la description d'un instantané donné. */  DBError g_db_snapshot_set_desc(const GDbSnapshot *, packed_buffer *); +/* Restaure un instantané de l'arborescence. */ +DBError g_db_snapshot_restore(GDbSnapshot *, packed_buffer *, bool *); + +/* Crée un nouvel instantanés dans l'arborescence. */ +DBError g_db_snapshot_create(GDbSnapshot *, sqlite3 *); + +/* Supprime un instantané dans l'arborescence. */ +DBError g_db_snapshot_remove(GDbSnapshot *, packed_buffer *, bool *); +  #endif  /* _ANALYSIS_DB_SNAPSHOT_H */ | 
