LCOV - code coverage report
Current view: top level - libcdpfgl - hashs.c (source / functions) Hit Total Coverage
Test: coverage-libcdpfgl.info Lines: 84 115 73.0 %
Date: 2016-02-03 22:31:46 Functions: 8 10 80.0 %

          Line data    Source code
       1             : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
       2             : /*
       3             :  *    hashs.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 hashs.c
      25             :  * This file contains the functions to deal with hashs in all the programs
      26             :  * of "Sauvegarde" project.
      27             :  */
      28             : 
      29             : #include "libcdpfgl.h"
      30             : 
      31             : /**
      32             :  * Comparison function used to compare two hashs (binary form) mainly
      33             :  * used to sort hashs properly.
      34             :  * @param a is a hash in a binary form (a guint8 *)
      35             :  * @param b is a hash in a binary form to be compared with a. Comparison is
      36             :  *        done comparing byte 1 of a an b, if there equal compares byte 2
      37             :  *        and so on. Worst case is when the two hashs are equals.
      38             :  * @returns a negative value if a < b, zero if a = b and a positive value
      39             :  * if a > b.
      40             :  */
      41     4650647 : gint compare_two_hashs(gconstpointer a, gconstpointer b)
      42             : {
      43     4650647 :     guint8 *hash_a = (guint8 *) a;
      44     4650647 :     guint8 *hash_b = (guint8 *) b;
      45     4650647 :     guint first = 0;
      46     4650647 :     guint second = 0;
      47     4650647 :     guint i = 0;
      48             : 
      49     4650647 :     if (a != NULL)
      50             :         {
      51     4650647 :             if (b != NULL) /* a and b are not NULL -> we can compare them */
      52             :                 {
      53    16267523 :                     while (first == second && i < HASH_LEN)  /* we compare bytes from the hashs (byte to byte) */
      54             :                         {
      55    11616876 :                             first = (guint) hash_a[i];
      56    11616876 :                             second = (guint) hash_b[i];
      57    11616876 :                             i = i + 1;
      58             :                         }
      59             : 
      60     4650647 :                     if (i == HASH_LEN && first == second) /* a is equal to b */
      61             :                         {
      62             :                             return 0;
      63             :                         }
      64     4426487 :                     if (first < second) /* a is first */
      65             :                         {
      66             :                             return -1;
      67             :                         }
      68             :                     else /* b is first */
      69             :                         {
      70     2221504 :                             return 1;
      71             :                         }
      72             :                 }
      73             :             else  /* a is not NULL but b is NULL (a is first) */
      74             :                 {
      75             :                     return -1;
      76             :                 }
      77             :         }
      78             :     else
      79             :         {
      80           0 :             if (b != NULL)  /* a is NULL and b is not NULL (b is first) */
      81             :                 {
      82             :                     return 1;
      83             :                 }
      84             :             else  /* a and b are NULL (they are equal) */
      85             :                 {
      86           0 :                     return 0;
      87             :                 }
      88             :         }
      89             : }
      90             : 
      91             : /**
      92             :  * Transforms a binary hashs into a printable string (gchar *)
      93             :  * @param a_hash is a hash in a binary form that we want to transform into
      94             :  *        a string.
      95             :  * @returns a string that conatins the hash in an hexadecimal form.
      96             :  * @todo manage memory concerns here !
      97             :  */
      98      754485 : gchar *hash_to_string(guint8 *a_hash)
      99             : {
     100      754485 :     gchar *string = NULL;
     101      754485 :     gchar *octet = NULL;
     102      754485 :     guint i = 0;
     103             : 
     104      754485 :     if (a_hash != NULL)
     105             :         {
     106      754485 :             string = (gchar *) g_malloc0(HASH_LEN*2 + 1); /* two char per bytes */
     107             :             /* octet = (gchar *) g_malloc(3); */
     108             : 
     109    24898005 :             for(i = 0; i < HASH_LEN; i++)
     110             :                 {
     111    24143520 :                     octet = g_strdup_printf("%02x", a_hash[i]);
     112    24143520 :                     memmove(string + i*2, octet, 2);
     113    24143520 :                     free_variable(octet);
     114             :                 }
     115             :         }
     116             : 
     117             :     /* free_variable(octet); */
     118      754485 :     return string;
     119             : }
     120             : 
     121             : 
     122             : /**
     123             :  * @param value is the gchar to be evaluated (should be 0 to 9 or a to f)
     124             :  * @returns the guint value of a gchar character.
     125             :  * @note this "stupid" function as a CCN of 17 ! Avoid complexification
     126             :  *       of this function if you want to go for a CCN below 10.
     127             :  */
     128             : static guint int_value(gchar value)
     129             : {
     130           0 :     switch (value)
     131             :         {
     132             :             case '0' :
     133             :                 return 0;
     134             :                 break;
     135             :             case '1' :
     136             :                 return 1;
     137             :                 break;
     138             :             case '2' :
     139             :                 return 2;
     140             :                 break;
     141             :             case '3' :
     142             :                 return 3;
     143             :                 break;
     144             :             case '4' :
     145             :                 return 4;
     146             :                 break;
     147             :             case '5' :
     148             :                 return 5;
     149             :                 break;
     150             :             case '6' :
     151             :                 return 6;
     152             :                 break;
     153             :             case '7' :
     154             :                 return 7;
     155             :                 break;
     156             :             case '8' :
     157             :                 return 8;
     158             :                 break;
     159             :             case '9' :
     160             :                 return 9;
     161             :                 break;
     162             :             case 'a' :
     163             :                 return 10;
     164             :                 break;
     165             :             case 'b' :
     166             :                 return 11;
     167             :                 break;
     168             :             case 'c' :
     169             :                 return 12;
     170             :                 break;
     171             :             case 'd' :
     172             :                 return 13;
     173             :                 break;
     174             :             case 'e' :
     175             :                 return 14;
     176             :                 break;
     177             :             case 'f' :
     178             :                 return 15;
     179             :                 break;
     180             :             default :
     181             :                 return 0;  /* This default case should never happen */
     182             :                 break;
     183             :         }
     184             : }
     185             : 
     186             : 
     187             : /**
     188             :  * Transforms a binary hashs into a printable string (gchar *)
     189             :  * @param str_hash a string (gchar *) that conatins the hash in an
     190             :  *        hexadecimal form.
     191             :  * @returns a hash in a binary form (guint8 *).
     192             :  */
     193           0 : guint8 *string_to_hash(gchar *str_hash)
     194             : {
     195           0 :     guint8 *string = NULL;
     196           0 :     guint8 octet = 0;
     197           0 :     guint i = 0;
     198             : 
     199           0 :     if (str_hash != NULL)
     200             :         {
     201           0 :             string = (guint8 *) g_malloc0(HASH_LEN + 1); /* two char per bytes */
     202             : 
     203           0 :             for(i = 0; i < HASH_LEN * 2; i = i + 2)
     204             :                 {
     205           0 :                     octet = int_value(str_hash[i])*16 + int_value(str_hash[i+1]);
     206           0 :                     memmove(string + i/2, &octet, 1);
     207             :                 }
     208             :         }
     209             : 
     210           0 :     return string;
     211             : }
     212             : 
     213             : 
     214             : /**
     215             :  * Frees hash_data_t *buffer and returns NULL.
     216             :  * @param hash_data : the stucture that contains buffer data, hash data
     217             :  *        and its size to be freed.
     218             :  * @returns always NULL.
     219             :  */
     220     1512285 : gpointer free_hash_data_t(hash_data_t *hash_data)
     221             : {
     222             : 
     223     1512285 :     if (hash_data != NULL)
     224             :         {
     225     1512285 :             free_variable(hash_data->data);
     226     1512285 :             free_variable(hash_data->hash);
     227     1512285 :             free_variable(hash_data);
     228             :         }
     229             : 
     230     1512285 :     return NULL;
     231             : }
     232             : 
     233             : 
     234             : /**
     235             :  * handler for g_slist_free_full
     236             :  * @param data must be a hash_data_t * structure.
     237             :  */
     238     1512189 : void free_hdt_struct(gpointer data)
     239             : {
     240     1512189 :     free_hash_data_t(data);
     241     1512189 : }
     242             : 
     243             : 
     244             : /**
     245             :  * Inits and returns a newly hash_data_t structure.
     246             :  * @returns a newly hash_data_t structure.
     247             :  */
     248     1741463 : hash_data_t *new_hash_data_t(guchar *data, gssize read, guint8 *hash)
     249             : {
     250     1741463 :     hash_data_t *hash_data = NULL;
     251             : 
     252     1741463 :     hash_data = (hash_data_t *) g_malloc(sizeof(hash_data_t));
     253             : 
     254     1741463 :     hash_data->hash = hash;
     255     1741463 :     hash_data->data = data;
     256     1741463 :     hash_data->read = read;
     257             : 
     258     1741463 :     return hash_data;
     259             : }
     260             : 
     261             : 
     262             : /**
     263             :  * Converts the hash list to a list of comma separated hashs in one gchar *
     264             :  * string. Hashs are base64 encoded
     265             :  * @param hash_list a GList of hash_data_t * elements
     266             :  * @returns a list of comma separated hashs in one gchar * string.
     267             :  */
     268       49745 : gchar *convert_hash_data_list_to_gchar(GList *hash_list)
     269             : {
     270       49745 :     GList *head = hash_list;
     271       49745 :     gchar *base64 = NULL;
     272       49745 :     gchar *list = NULL;
     273       49745 :     gchar *old_list = NULL;
     274       49745 :     hash_data_t *hash_data = NULL;
     275             : 
     276      629964 :     while (head != NULL)
     277             :         {
     278      530474 :             hash_data = head->data;
     279      530474 :             base64 = g_base64_encode(hash_data->hash, HASH_LEN);
     280             : 
     281      530474 :             if (old_list == NULL)
     282             :                 {
     283       48763 :                     list = g_strdup_printf("\"%s\"", base64);
     284       48763 :                     old_list = list;
     285             :                 }
     286             :             else
     287             :                 {
     288      481711 :                     list = g_strdup_printf("%s, \"%s\"", old_list, base64);
     289      481711 :                     free_variable(old_list);
     290      481711 :                     old_list = list;
     291             :                 }
     292             : 
     293      530474 :             free_variable(base64);
     294             : 
     295      530474 :             head = g_list_next(head);
     296             :         }
     297             : 
     298       49745 :     list = old_list;
     299             : 
     300       49745 :     return list;
     301             : }
     302             : 
     303             : 
     304             : /**
     305             :  * Makes a path from a binary hash : 0E/39/AF for level 3 with hash (in hex)
     306             :  * begining by 0E39AF.
     307             :  * @param path is a gchar * prefix for the path (ie /var/tmp/cdpfgl for
     308             :  *        instance).
     309             :  * @param hash is a guint8 pointer to the binary representation of a hash.
     310             :  * @param level The level we want the path to have. It is an unsigned int
     311             :  *        and must be less than HASH_LEN. a level of N gives 2^N
     312             :  *        directories. We should add a level when more than 512 files are
     313             :  *        in each last subdirectories.
     314             :  * @returns a string as a gchar * made of the path and the hex
     315             :  *          representation of hash on 'level' levels. With the example above
     316             :  *          it will return /var/tmp/cdpfgl/0E/39/AF
     317             :  */
     318      754389 : gchar *make_path_from_hash(gchar *path, guint8 *hash, guint level)
     319             : {
     320      754389 :     gchar *octet = NULL;
     321      754389 :     gchar *old_path = NULL;
     322      754389 :     gchar *new_path = NULL;
     323      754389 :     guint i = 0;
     324             : 
     325      754389 :     if (path != NULL && hash != NULL && level < HASH_LEN)
     326             :         {
     327             : 
     328      754389 :             old_path = g_strdup(path);
     329             : 
     330     2263167 :             for(i = 0; i < level; i++)
     331             :                 {
     332     1508778 :                     octet = g_strdup_printf("%02x", hash[i]);
     333     1508778 :                     new_path = g_build_filename(old_path, octet, NULL);
     334             : 
     335     1508778 :                     free_variable(old_path);
     336     1508778 :                     free_variable(octet);
     337             : 
     338     1508778 :                     old_path = new_path;
     339             :                 }
     340             :         }
     341             : 
     342      754389 :     return old_path;
     343             : }
     344             : 
     345             : 
     346             : /**
     347             :  * makes a GSList of hash_data_t * element where 'hash' field is base64
     348             :  * decoded hashs from a string containning base64 * encoded hashs that
     349             :  * must be separated by comas.
     350             :  * @param the string containing base64 encoded hashs such as : *
     351             :  *        "cCoCVkt/AABf04jn2+rfDmqJaln6P2A9uKolBjEFJV4=", "0G8MaPZ/AADNyaPW7ZP2s0BI4hAdZZIE2xO1EwdOzhE="
     352             :  *        for instance.
     353             :  * @returns a GSList of hash_data_t * where each elements contains a
     354             :  *          base64 decoded hash (binary form).
     355             :  */
     356           0 : GList *make_hash_data_list_from_string(gchar *hash_string)
     357             : {
     358           0 :     uint i = 0;
     359           0 :     gchar **hashs = NULL;
     360           0 :     gchar *a_hash = NULL;
     361           0 :     hash_data_t *hash_data = NULL;
     362           0 :     GList *hash_list = NULL;
     363           0 :     gsize len = 0;
     364             : 
     365           0 :     if (hash_string != NULL)
     366             :         {
     367             :             /* hash list generation */
     368           0 :             hashs = g_strsplit(hash_string, ",", -1);
     369             : 
     370           0 :             while (hashs[i] != NULL)
     371             :                 {
     372           0 :                     a_hash = g_strndup(g_strchug(hashs[i] + 1), strlen(g_strchug(hashs[i])) - 2);
     373             : 
     374             :                     /* we have to base64 decode it to insert it into the hash_data_t * structure
     375             :                      * and then into the meta_data one.
     376             :                      */
     377           0 :                     hash_data = new_hash_data_t(NULL, 0, g_base64_decode(a_hash, &len));
     378           0 :                     hash_list = g_list_prepend(hash_list, hash_data);
     379           0 :                     free_variable(a_hash);
     380           0 :                     i = i + 1;
     381             :                 }
     382             : 
     383           0 :             g_strfreev(hashs);
     384             : 
     385           0 :             hash_list = g_list_reverse(hash_list);
     386             :         }
     387             : 
     388           0 :     return hash_list;
     389             : }
     390             : 
     391             : 
     392             : /**
     393             :  * Tells wheter a hash (picking it in a hash_data_t structure is in the
     394             :  * needed list of hash_data_t structures.
     395             :  * @param hash_data contains the hash that we are looking for into the
     396             :  *        needed list.
     397             :  * @param needed is a GList of hash_data_t structures that may already
     398             :  *        contain one with the same hash than the one in hash_data
     399             :  * @returns TRUE if the hash is found, FALSE otherwise
     400             :  */
     401      224160 : gboolean hash_data_is_in_list(hash_data_t *hash_data, GList *needed)
     402             : {
     403      224160 :     gboolean found = FALSE;
     404      224160 :     hash_data_t *needed_hash_data = NULL;
     405             : 
     406      224160 :     if (hash_data != NULL)
     407             :         {
     408     4463762 :             while (needed != NULL && found == FALSE)
     409             :                 {
     410     4239602 :                     needed_hash_data = needed->data;
     411     4239602 :                     if (compare_two_hashs(hash_data->hash, needed_hash_data->hash) == 0)
     412             :                         {
     413             :                             found = TRUE;
     414             :                         }
     415             :                     else
     416             :                         {
     417     4239357 :                             needed = g_list_next(needed);
     418             :                         }
     419             :                 }
     420             :         }
     421             : 
     422      224160 :     return found;
     423             : }

Generated by: LCOV version 1.11