LCOV - code coverage report
Current view: top level - libcdpfgl - unpacking.c (source / functions) Hit Total Coverage
Test: coverage-libcdpfgl.info Lines: 135 162 83.3 %
Date: 2016-02-03 22:31:46 Functions: 13 15 86.7 %

          Line data    Source code
       1             : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
       2             : /*
       3             :  *    unpacking.c
       4             :  *    This file is part of "Sauvegarde" project.
       5             :  *
       6             :  *    (C) Copyright 2014 - 2016 Olivier Delhomme
       7             :  *     e-mail : olivier.delhomme@free.fr
       8             :  *
       9             :  *    "Sauvegarde" is free software: you can redistribute it and/or modify
      10             :  *    it under the terms of the GNU General Public License as published by
      11             :  *    the Free Software Foundation, either version 3 of the License, or
      12             :  *    (at your option) any later version.
      13             :  *
      14             :  *    "Sauvegarde" is distributed in the hope that it will be useful,
      15             :  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :  *    GNU General Public License for more details.
      18             :  *
      19             :  *    You should have received a copy of the GNU General Public License
      20             :  *    along with "Sauvegarde".  If not, see <http://www.gnu.org/licenses/>
      21             :  */
      22             : 
      23             : /**
      24             :  * @file unpacking.c
      25             :  * This file contains the functions to unpack messages for all the
      26             :  * programs of "Sauvegarde" project.
      27             :  */
      28             : 
      29             : #include "libcdpfgl.h"
      30             : 
      31             : static guint8 get_guint8_from_json_root(json_t *root, gchar *keyname);
      32             : static guint32 get_guint32_from_json_root(json_t *root, gchar *keyname);
      33             : static guint64 get_guint64_from_json_root(json_t *root, gchar *keyname);
      34             : 
      35             : /**
      36             :  * gets a json_t *value into the json_t *root array.
      37             :  * @param[in,out] root is the root that contains all meta data values
      38             :  * @param keyname is the keyname associated with the value that we want to
      39             :  *        get back.
      40             :  * @returns the json_t "encoded" value from key keyname from the root
      41             :  */
      42     1579533 : json_t *get_json_value_from_json_root(json_t *root, gchar *keyname)
      43             : {
      44     1579533 :     json_t *value = NULL;
      45             : 
      46     1579533 :     if (root != NULL && keyname != NULL)
      47             :         {
      48     1579533 :             value = json_object_get(root, keyname);
      49             : 
      50     1579533 :             if (value == NULL)
      51             :                 {
      52           0 :                     print_error(__FILE__, __LINE__, _("Error while converting to JSON from keyname %s\n"), keyname);
      53             :                 }
      54             :         }
      55             : 
      56     1579533 :     return value;
      57             : }
      58             : 
      59             : 
      60             : /**
      61             :  * returns the boolean with key keyname from the json tree root. It is used
      62             :  * by server to get the hostname from the json received message.
      63             :  * @note Freeing json_t *str here is a bad idea as it will free it into
      64             :  *       json_t *root variable that is freed afterwards.
      65             :  * @param[in,out] root is the main json tree
      66             :  * @param keyname is the key for which we seek the string value.
      67             :  * @returns a newlly allocated gchar * string that is the value associated
      68             :  *          with key keyname. It can be freed with free_variable() when no longer
      69             :  *          needed.
      70             :  */
      71       49926 : gboolean get_boolean_from_json_root(json_t *root, gchar *keyname)
      72             : {
      73       49926 :     json_t *bool = NULL;
      74             : 
      75       49926 :     if (root != NULL && keyname != NULL)
      76             :         {
      77       49926 :             bool = get_json_value_from_json_root(root, keyname);
      78             : 
      79       49926 :             if (bool == json_true())
      80             :                 {
      81             :                     return TRUE;
      82             :                 }
      83             :             else
      84             :                 {
      85       49923 :                     return FALSE;
      86             :                 }
      87             :         }
      88             : 
      89             :     return FALSE;
      90             : }
      91             : 
      92             : 
      93             : /**
      94             :  * returns the string with key keyname from the json tree root. It is used
      95             :  * by server to get the hostname from the json received message.
      96             :  * @note Freeing json_t *str here is a bad idea as it will free it into
      97             :  *       json_t *root variable that is freed afterwards.
      98             :  * @param[in,out] root is the main json tree
      99             :  * @param keyname is the key for which we seek the string value.
     100             :  * @returns a newlly allocated gchar * string that is the value associated
     101             :  *          with key keyname. It can be freed with free_variable() when no longer
     102             :  *          needed.
     103             :  */
     104      249630 : gchar *get_string_from_json_root(json_t *root, gchar *keyname)
     105             : {
     106      249630 :     json_t *str = NULL;
     107      249630 :     gchar *a_string = NULL;
     108             : 
     109      249630 :     if (root != NULL && keyname != NULL)
     110             :         {
     111      249630 :             str = get_json_value_from_json_root(root, keyname);
     112      249630 :             a_string = g_strdup(json_string_value(str));
     113             :         }
     114             : 
     115      249630 :     return a_string;
     116             : }
     117             : 
     118             : 
     119             : /**
     120             :  * returns the guint8 value associated with key keyname from the json tree
     121             :  * root.
     122             :  * @note Freeing json_t *value here is a bad idea as it will free it into
     123             :  *       json_t *root variable that is freed afterwards.
     124             :  * @param[in,out] root is the main json tree
     125             :  * @param keyname is the key for which we seek the guint8 value.
     126             :  * @returns a guint8 number that is the value associated with key keyname.
     127             :  */
     128       49926 : static guint8 get_guint8_from_json_root(json_t *root, gchar *keyname)
     129             : {
     130       49926 :     json_t *value = NULL;
     131       49926 :     guint8 number = 0;
     132             : 
     133       49926 :     if (root != NULL && keyname != NULL)
     134             :         {
     135       49926 :             value = get_json_value_from_json_root(root, keyname);
     136       49926 :             number = (guint8) json_integer_value(value);
     137             :         }
     138             : 
     139       49926 :     return number;
     140             : }
     141             : 
     142             : 
     143             : /**
     144             :  * returns the guint32 value associated with key keyname from the json tree
     145             :  * root.
     146             :  * @note Freeing json_t *value here is a bad idea as it will free it into
     147             :  *       json_t *root variable that is freed afterwards.
     148             :  * @param[in,out] root is the main json tree
     149             :  * @param keyname is the key for which we seek the guint32 value.
     150             :  * @returns a guint32 number that is the value associated with key keyname.
     151             :  */
     152      149778 : static guint32 get_guint32_from_json_root(json_t *root, gchar *keyname)
     153             : {
     154      149778 :     json_t *value = NULL;
     155      149778 :     guint32 number = 0;
     156             : 
     157      149778 :     if (root != NULL && keyname != NULL)
     158             :         {
     159      149778 :             value = get_json_value_from_json_root(root, keyname);
     160      149778 :             number = (guint32) json_integer_value(value);
     161             :         }
     162             : 
     163      149778 :     return number;
     164             : }
     165             : 
     166             : 
     167             : /**
     168             :  * returns the guint64 value associated with key keyname from the json tree
     169             :  * root.
     170             :  * @note Freeing json_t *value here is a bad idea as it will free it into
     171             :  *       json_t *root variable that is freed afterwards.
     172             :  * @param[in,out] root is the main json tree
     173             :  * @param keyname is the key for which we seek the guint64 value.
     174             :  * @returns a guint64 number that is the value associated with key keyname.
     175             :  */
     176      478904 : static guint64 get_guint64_from_json_root(json_t *root, gchar *keyname)
     177             : {
     178      478904 :     json_t *value = NULL;
     179      478904 :     guint64 number = 0;
     180             : 
     181      478904 :     if (root != NULL && keyname != NULL)
     182             :         {
     183      478904 :             value = get_json_value_from_json_root(root, keyname);
     184      478904 :             number = (guint64) json_integer_value(value);
     185             :         }
     186             : 
     187      478904 :     return number;
     188             : }
     189             : 
     190             : 
     191             : /**
     192             :  * This function loads a JSON string into a json_t struture
     193             :  * @param json_str is the json string
     194             :  * @returns a pointer to a filled json_t * structure or NULL upon error
     195             :  */
     196      145753 : json_t *load_json(gchar *json_str)
     197             : {
     198      145753 :     json_t *root = NULL;   /** json_t *root is the json tree where we will extract things */
     199             :     json_error_t error;    /** json_error_t *error handle json errors if any.             */
     200             : 
     201      145753 :     if (json_str != NULL)
     202             :         {
     203      145753 :             root = json_loads(json_str, 0, &error);
     204             : 
     205      145753 :             if (root == NULL)
     206             :                 {
     207           0 :                      print_error(__FILE__, __LINE__, _("Error while trying to load JSON: %s\nline: %d, column: %d, position: %d, string: %s\n"), error.text, error.line, error.column, error.position, json_str);
     208             :                 }
     209             :         }
     210             : 
     211      145753 :     return root;
     212             : }
     213             : 
     214             : 
     215             : /**
     216             :  * This function returns the MESSAGE_ID from msg_id JSON field
     217             :  * @param json_str : a gchar * containing the JSON formated string.
     218             :  * @returns a gint that correspond to the msg_id field found in json_str.
     219             :  *          If the field is not found it returns ENC_NOT_FOUND. This field
     220             :  *          is based on ENC_* constants that are also used for the
     221             :  *          communication between threads in client
     222             :  */
     223           0 : gint get_json_message_id(gchar *json_str)
     224             : {
     225           0 :     json_t *root = NULL;           /** json_t *root is the json tree from which we will extract msg_id                   */
     226           0 :     gint msg_id = ENC_NOT_FOUND;   /** gint msg_id is the message id from the JSON string by default it is ENC_NOT_FOUND */
     227             : 
     228           0 :     if (json_str != NULL)
     229             :         {
     230           0 :             root = load_json(json_str);
     231             : 
     232           0 :             if (root != NULL)
     233             :                 {
     234           0 :                     msg_id = get_guint8_from_json_root(root, "msg_id");
     235             : 
     236           0 :                     json_decref(root);
     237             :                 }
     238             :         }
     239             : 
     240           0 :     return msg_id;
     241             : }
     242             : 
     243             : 
     244             : /**
     245             :  * Gets the version of a version json string as returned by server's
     246             :  * server.
     247             :  * @param json_str : a gchar * containing the JSON formated string.
     248             :  * @returns version string or NULL
     249             :  */
     250           0 : gchar *get_json_version(gchar *json_str)
     251             : {
     252           0 :     json_t *root = NULL;     /** json_t *root is the json tree from which we will extract version's string */
     253           0 :     gchar *version = NULL;   /** version'string has extracted or NULL                                      */
     254             : 
     255           0 :     if (json_str != NULL)
     256             :         {
     257           0 :             root = load_json(json_str);
     258             : 
     259           0 :             if (root != NULL)
     260             :                 {
     261           0 :                     version = get_string_from_json_root(root, "version");
     262             : 
     263           0 :                     json_decref(root);
     264             :                 }
     265             :         }
     266             : 
     267           0 :     return version;
     268             : }
     269             : 
     270             : 
     271             : /**
     272             :  * This function returns a list of hash_data_t * from an json array
     273             :  * @param root is the root json string that may contain an array named "name"
     274             :  * @param name is the name of the array to look for into
     275             :  * @param only_hash is a boolean saying that we only have a hash list in
     276             :  *        root if set to TRUE and that we have a complete hash_data_t list
     277             :  *        if set to FALSE.
     278             :  * @returns a GSList that me be composed of 0 element (ie NULL). Elements
     279             :  *          are of type hash_data_t *.
     280             :  */
     281      142809 : GList *extract_glist_from_array(json_t *root, gchar *name, gboolean only_hash)
     282             : {
     283      142809 :     json_t *array =  NULL;   /** json_t *array is the retrieved array used to iter over to fill the list     */
     284      142809 :     size_t index = 0;        /** size_t index is the iterator to iter over the array                         */
     285      142809 :     json_t *value = NULL;    /** json_t *value : value = array[index] when iterating with json_array_foreach */
     286      142809 :     GList *head = NULL;      /** GSList *head the list to build and iclude into meta_data_t *meta            */
     287      142809 :     guchar *a_hash = NULL;   /** guchar *a_hash is one base64 decoded hash (binary format)                   */
     288      142809 :     gsize hash_len = 0;      /** gsize hash_len is the length of the decoded hash (must alwas be HASH_LEN)   */
     289      142809 :     hash_data_t *hash_data = NULL;
     290             : 
     291      142809 :     if (root != NULL && name != NULL)
     292             :         {
     293             : 
     294             :             /* creating a list with the json array found in root json string */
     295      142809 :             array = get_json_value_from_json_root(root, name);
     296             : 
     297             :             /**
     298             :              * @note : This is a loop from jansson library for the array.
     299             :              *         One needs at least jansson 2.5 to compile this.
     300             :              */
     301     1126752 :             json_array_foreach(array, index, value)
     302             :                 {
     303      983943 :                     if (only_hash == TRUE)
     304             :                         {
     305      757782 :                             a_hash = g_base64_decode(json_string_value(value), &hash_len);
     306      757782 :                             hash_data = new_hash_data_t(NULL, 0, a_hash);
     307             :                         }
     308             :                     else
     309             :                         {
     310      226161 :                             hash_data = convert_json_t_to_hash_data(value);
     311             :                         }
     312             : 
     313      983943 :                     head = g_list_prepend(head, hash_data);
     314             :                 }
     315             : 
     316      142809 :             head = g_list_reverse(head);
     317             :         }
     318             : 
     319      142809 :     return head;
     320             : }
     321             : 
     322             : 
     323             : /**
     324             :  * Fills a server_meta_data_t from data that are in json_t *root
     325             :  * @param root is the JSON string that should contain all data needed
     326             :  *        to fill the server_meta_data_t * structure.
     327             :  * @returns a newly allocated server_meta_data_t * structure filled
     328             :  *          accordingly.
     329             :  */
     330       49926 : static server_meta_data_t *fills_server_meta_data_t_from_json_t(json_t *root)
     331             : {
     332       49926 :     meta_data_t *meta = NULL;          /** meta_data_t *meta will be returned in smeta and contain file's metadata     */
     333       49926 :     server_meta_data_t *smeta = NULL; /** server_meta_data_t *smeta will be returned at the end                      */
     334             : 
     335       49926 :     if (root != NULL)
     336             :         {
     337       49926 :             smeta = new_smeta_data_t();
     338       49926 :             meta = new_meta_data_t();
     339             : 
     340       49926 :             meta->file_type = get_guint8_from_json_root(root, "filetype");
     341       49926 :             meta->mode = get_guint32_from_json_root(root, "mode");
     342             : 
     343       49926 :             meta->atime = get_guint64_from_json_root(root, "atime");
     344       49926 :             meta->ctime = get_guint64_from_json_root(root, "ctime");
     345       49926 :             meta->mtime = get_guint64_from_json_root(root, "mtime");
     346       49926 :             meta->size  = get_guint64_from_json_root(root, "fsize");
     347       49926 :             meta->inode = get_guint64_from_json_root(root, "inode");
     348             : 
     349       49926 :             meta->owner = get_string_from_json_root(root, "owner");
     350       49926 :             meta->group = get_string_from_json_root(root, "group");
     351             : 
     352       49926 :             meta->uid = get_guint32_from_json_root(root, "uid");
     353       49926 :             meta->gid = get_guint32_from_json_root(root, "gid");
     354             : 
     355       49926 :             meta->name = get_string_from_json_root(root, "name");
     356       49926 :             meta->link = get_string_from_json_root(root, "link");
     357             : 
     358       49926 :             meta->hash_data_list = extract_glist_from_array(root, "hash_list", TRUE);
     359             : 
     360       49926 :             smeta->meta = meta;
     361       49926 :             smeta->hostname = get_string_from_json_root(root, "hostname");
     362       49926 :             smeta->data_sent = get_boolean_from_json_root(root, "data_sent");
     363             :         }
     364             : 
     365       49926 :     return smeta;
     366             : }
     367             : 
     368             : 
     369             : /**
     370             :  * This function returns a list from an json array.
     371             :  * @param root is the root json string that must contain an array named
     372             :  *        "file_list"
     373             :  * @returns a GSList that may be composed of 0 element (ie NULL). Elements
     374             :  *          are of type server_meta_data_t *.
     375             :  */
     376          12 : GSList *extract_smeta_gslist_from_file_list(json_t *root)
     377             : {
     378          12 :     json_t *array =  NULL;   /** json_t *array is the retrieved array used to iter over to fill the list     */
     379          12 :     size_t index = 0;        /** size_t index is the iterator to iter over the array                         */
     380          12 :     json_t *value = NULL;    /** json_t *value : value = array[index] when iterating with json_array_foreach */
     381          12 :     GSList *head = NULL;     /** GSList *head the list to build and iclude into meta_data_t *meta            */
     382          12 :     server_meta_data_t *smeta = NULL; /** server_meta_data_t *smeta will be returned at the end                      */
     383             : 
     384          12 :     if (root != NULL)
     385             :         {
     386             : 
     387             :             /* creating a list with the json array found in root json string */
     388          12 :             array = get_json_value_from_json_root(root, "file_list");
     389             : 
     390             :             /**
     391             :              * @note : This is a loop from jansson library for the array.
     392             :              *         One needs at least jansson 2.5 to compile this.
     393             :              */
     394         193 :             json_array_foreach(array, index, value)
     395             :                 {
     396         181 :                     smeta = fills_server_meta_data_t_from_json_t(value);
     397         181 :                     head = g_slist_prepend(head, smeta);
     398             :                 }
     399             :         }
     400             : 
     401          12 :     return head;
     402             : }
     403             : 
     404             : 
     405             : /**
     406             :  * Function that converts json_t * root containing the keys "hash", "data"
     407             :  * and "read" into hash_data_t structure.
     408             :  * @param root is a json_t * variable containing the keys "hash", "data"
     409             :  *        and read
     410             :  * @returns a newly allocated hash_data_t structure with the
     411             :  *          corresponding data in it.
     412             :  */
     413      229274 : hash_data_t *convert_json_t_to_hash_data(json_t *root)
     414             :  {
     415      229274 :     guchar *data = NULL;
     416      229274 :     guint8 *hash = NULL;
     417      229274 :     gsize data_len = 0;
     418      229274 :     gsize hash_len = 0;
     419      229274 :     gssize read = 0;
     420      229274 :     gchar *string_read = NULL;
     421      229274 :     gchar *string_hash_len = NULL;
     422      229274 :     gchar *string_data_len = NULL;
     423             : 
     424      229274 :     hash_data_t *hash_data = NULL;
     425             : 
     426      229274 :     if (root != NULL)
     427             :         {
     428             :             /* This code is 10% faster then the older one (which was clearer) */
     429      229274 :             data = (guchar *) g_base64_decode(json_string_value(get_json_value_from_json_root(root, "data")), &data_len);
     430      229274 :             hash = (guint8 *) g_base64_decode(json_string_value(get_json_value_from_json_root(root, "hash")), &hash_len);
     431             : 
     432      229274 :             read = get_guint64_from_json_root(root, "size");
     433             : 
     434             :             /* Some basic verifications */
     435      229274 :             if (data_len == read && hash_len == HASH_LEN)
     436             :                 {
     437      229274 :                     hash_data = new_hash_data_t(data, read, hash);
     438             :                 }
     439             :             else
     440             :                 {
     441             :                     /**
     442             :                      * We need to translated this number into a string before
     443             :                      * inserting it into the final string in order to allow
     444             :                      * this final string to be translated in an other language.
     445             :                      */
     446           0 :                     string_data_len = g_strdup_printf("%" G_GSIZE_FORMAT, data_len);
     447           0 :                     string_hash_len = g_strdup_printf("%" G_GSIZE_FORMAT, hash_len);
     448           0 :                     string_read = g_strdup_printf("%" G_GSSIZE_FORMAT, read);
     449             : 
     450           0 :                     print_error(__FILE__, __LINE__, _("Something is wrong with lengths: data_len = %s, read = %s, hash_len = %s, HASH_LEN = %d\n"), string_data_len, string_read, string_hash_len, HASH_LEN);
     451             : 
     452           0 :                     free_variable(string_data_len);
     453           0 :                     free_variable(string_hash_len);
     454           0 :                     free_variable(string_read);
     455             :                 }
     456             :         }
     457             : 
     458      229274 :     return hash_data;
     459             : }
     460             : 
     461             : 
     462             : /**
     463             :  * Function that converts json_str containing the keys "hash", "data"
     464             :  * and "read" into hash_data_t structure.
     465             :  * @param json_str is a json string containing the keys "hash", "data"
     466             :  *        and read
     467             :  * @returns a newly allocated hash_data_t structure with the
     468             :  *          corresponding data in it.
     469             :  */
     470        3113 : hash_data_t *convert_string_to_hash_data(gchar *json_str)
     471             :  {
     472        3113 :     json_t *root = NULL;
     473             : 
     474        3113 :     hash_data_t *hash_data = NULL;
     475             : 
     476        3113 :     if (json_str != NULL)
     477             :         {
     478        3113 :             root = load_json(json_str);
     479             : 
     480        3113 :             if (root != NULL)
     481             :                 {
     482        3113 :                    hash_data = convert_json_t_to_hash_data(root);
     483        3113 :                    json_decref(root);
     484             :                 }
     485             :         }
     486             : 
     487        3113 :     return hash_data;
     488             : }
     489             : 
     490             : 
     491             : /**
     492             :  * This function should return a newly allocated server_meta_data_t *
     493             :  * structure with all informations included from the json string.
     494             :  * @param json_str is a gchar * containing the JSON formated string.
     495             :  * @returns a newly_allocated server_meta_data_t * structure that can be
     496             :  *          freed when no longer needed with free_smeta_data_t() function.
     497             :  *          This function can return NULL if json_str is NULL itself.
     498             :  */
     499       49745 : server_meta_data_t *convert_json_to_smeta_data(gchar *json_str)
     500             : {
     501       49745 :     json_t *root = NULL;                 /** json_t *root is the json tree from which we will extract everything         */
     502       49745 :     server_meta_data_t *smeta = NULL;    /** server_meta_data_t *smeta will be returned at the end                      */
     503             : 
     504             :     /**
     505             :      * @todo : validate that we have a json string and make
     506             :      *         sure that this is a meta_data one.
     507             :      */
     508             : 
     509       49745 :     if (json_str != NULL)
     510             :         {
     511             : 
     512       49745 :             root = load_json(json_str);
     513             : 
     514       49745 :             if (root != NULL)
     515             :                 {
     516       49745 :                     smeta = fills_server_meta_data_t_from_json_t(root);
     517             : 
     518       49745 :                     json_decref(root);
     519             :                 }
     520             :         }
     521             : 
     522       49745 :     return smeta;
     523             : }

Generated by: LCOV version 1.11