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 : }
|